| /* |
| * Copyright (c) 2019-2021, The Linux Foundation. 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. |
| * * 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 Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * 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. |
| * |
| * Changes from Qualcomm Innovation Center are provided under the following license: |
| * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. |
| * SPDX-License-Identifier: BSD-3-Clause-Clear |
| */ |
| |
| #define LOG_TAG "AHAL: AudioExtn" |
| #include <dlfcn.h> |
| #include <unistd.h> |
| #include "AudioExtn.h" |
| #include "AudioDevice.h" |
| #include "PalApi.h" |
| #include <cutils/properties.h> |
| #include "AudioCommon.h" |
| #define AUDIO_OUTPUT_BIT_WIDTH ((config_->offload_info.bit_width == 32) ? 24:config_->offload_info.bit_width) |
| |
| #ifdef PAL_HIDL_ENABLED |
| #include <hidl/HidlTransportSupport.h> |
| #include <hidl/LegacySupport.h> |
| |
| #include <pal_server_wrapper.h> |
| #include <vendor/qti/hardware/pal/1.0/IPAL.h> |
| using vendor::qti::hardware::pal::V1_0::IPAL; |
| using vendor::qti::hardware::pal::V1_0::implementation::PAL; |
| #ifdef AGM_HIDL_ENABLED |
| #include <agm_server_wrapper.h> |
| #include <vendor/qti/hardware/AGMIPC/1.0/IAGM.h> |
| using vendor::qti::hardware::AGMIPC::V1_0::IAGM; |
| using vendor::qti::hardware::AGMIPC::V1_0::implementation::AGM; |
| #endif |
| using android::hardware::defaultPassthroughServiceImplementation; |
| using android::sp; |
| using namespace android::hardware; |
| using android::OK; |
| #endif |
| |
| #ifdef __LP64__ |
| #define LIBS "/vendor/lib64/" |
| #else |
| #define LIBS "/vendor/lib/" |
| #endif |
| |
| #define BATTERY_LISTENER_LIB_PATH LIBS"libbatterylistener.so" |
| #define HFP_LIB_PATH LIBS"libhfp_pal.so" |
| #define FM_LIB_PATH LIBS"libfmpal.so" |
| |
| #define BT_IPC_SOURCE_LIB_NAME LIBS"btaudio_offload_if.so" |
| |
| static batt_listener_init_t batt_listener_init; |
| static batt_listener_deinit_t batt_listener_deinit; |
| static batt_prop_is_charging_t batt_prop_is_charging; |
| static bool battery_listener_enabled; |
| static void *batt_listener_lib_handle; |
| static bool audio_extn_kpi_optimize_feature_enabled = false; |
| //TODO make this mutex part of class |
| std::mutex reconfig_wait_mutex_; |
| std::mutex AudioExtn::sLock; |
| |
| std::atomic<bool> AudioExtn::sServicesRegistered = false; |
| |
| int AudioExtn::audio_extn_parse_compress_metadata(struct audio_config *config_, pal_snd_dec_t *pal_snd_dec, |
| str_parms *parms, uint32_t *sr, uint16_t *ch, bool *isCompressMetadataAvail) { |
| |
| if (config_ == NULL || pal_snd_dec == NULL || parms == NULL || |
| sr == NULL || ch == NULL || isCompressMetadataAvail == NULL) { |
| return -EINVAL; |
| } |
| |
| int ret = 0; |
| char value[32]; |
| *sr = 0; |
| *ch = 0; |
| uint16_t flac_sample_size = ((config_->offload_info.bit_width == 32) ? 24:config_->offload_info.bit_width); |
| |
| if (config_->offload_info.format == AUDIO_FORMAT_FLAC) { |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE, value, sizeof(value)); |
| if (ret >= 0) { |
| pal_snd_dec->flac_dec.min_blk_size = atoi(value); |
| *isCompressMetadataAvail = true; |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE, value, sizeof(value)); |
| if (ret >= 0) { |
| pal_snd_dec->flac_dec.max_blk_size = atoi(value); |
| *isCompressMetadataAvail = true; |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE, value, sizeof(value)); |
| if (ret >= 0) { |
| pal_snd_dec->flac_dec.min_frame_size = atoi(value); |
| *isCompressMetadataAvail = true; |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE, value, sizeof(value)); |
| if (ret >= 0) { |
| pal_snd_dec->flac_dec.max_frame_size = atoi(value); |
| *isCompressMetadataAvail = true; |
| } |
| pal_snd_dec->flac_dec.sample_size = flac_sample_size; |
| AHAL_DBG("FLAC metadata: sample_size %d min_blk_size %d, max_blk_size %d min_frame_size %d max_frame_size %d", |
| pal_snd_dec->flac_dec.sample_size, |
| pal_snd_dec->flac_dec.min_blk_size, |
| pal_snd_dec->flac_dec.max_blk_size, |
| pal_snd_dec->flac_dec.min_frame_size, |
| pal_snd_dec->flac_dec.max_frame_size); |
| } |
| |
| else if (config_->offload_info.format == AUDIO_FORMAT_ALAC) { |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_FRAME_LENGTH, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->alac_dec.frame_length = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_COMPATIBLE_VERSION, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->alac_dec.compatible_version = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_BIT_DEPTH, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->alac_dec.bit_depth = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_PB, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->alac_dec.pb = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_MB, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->alac_dec.mb = atoi(value); |
| } |
| |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_KB, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->alac_dec.kb = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_NUM_CHANNELS, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->alac_dec.num_channels = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_MAX_RUN, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->alac_dec.max_run = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_MAX_FRAME_BYTES, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->alac_dec.max_frame_bytes = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_AVG_BIT_RATE, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->alac_dec.avg_bit_rate = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_SAMPLING_RATE, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->alac_dec.sample_rate = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_CHANNEL_LAYOUT_TAG, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->alac_dec.channel_layout_tag = atoi(value); |
| } |
| *sr = pal_snd_dec->alac_dec.sample_rate; |
| *ch = pal_snd_dec->alac_dec.num_channels; |
| AHAL_DBG("ALAC CSD values: frameLength %d bitDepth %d numChannels %d" |
| " maxFrameBytes %d, avgBitRate %d, sampleRate %d", |
| pal_snd_dec->alac_dec.frame_length, |
| pal_snd_dec->alac_dec.bit_depth, |
| pal_snd_dec->alac_dec.num_channels, |
| pal_snd_dec->alac_dec.max_frame_bytes, |
| pal_snd_dec->alac_dec.avg_bit_rate, |
| pal_snd_dec->alac_dec.sample_rate); |
| } |
| |
| else if (config_->offload_info.format == AUDIO_FORMAT_APE) { |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_COMPATIBLE_VERSION, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->ape_dec.compatible_version = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_COMPRESSION_LEVEL, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->ape_dec.compression_level = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_FORMAT_FLAGS, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->ape_dec.format_flags = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_BLOCKS_PER_FRAME, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->ape_dec.blocks_per_frame = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_FINAL_FRAME_BLOCKS, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->ape_dec.final_frame_blocks = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_TOTAL_FRAMES, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->ape_dec.total_frames = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_BITS_PER_SAMPLE, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->ape_dec.bits_per_sample = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_NUM_CHANNELS, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->ape_dec.num_channels = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_SAMPLE_RATE, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->ape_dec.sample_rate = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_SEEK_TABLE_PRESENT, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->ape_dec.seek_table_present = atoi(value); |
| } |
| *sr = pal_snd_dec->ape_dec.sample_rate; |
| *ch = pal_snd_dec->ape_dec.num_channels; |
| AHAL_DBG("APE CSD values: compatibleVersion %d compressionLevel %d" |
| " formatFlags %d blocksPerFrame %d finalFrameBlocks %d" |
| " totalFrames %d bitsPerSample %d numChannels %d" |
| " sampleRate %d seekTablePresent %d", |
| pal_snd_dec->ape_dec.compatible_version, |
| pal_snd_dec->ape_dec.compression_level, |
| pal_snd_dec->ape_dec.format_flags, |
| pal_snd_dec->ape_dec.blocks_per_frame, |
| pal_snd_dec->ape_dec.final_frame_blocks, |
| pal_snd_dec->ape_dec.total_frames, |
| pal_snd_dec->ape_dec.bits_per_sample, |
| pal_snd_dec->ape_dec.num_channels, |
| pal_snd_dec->ape_dec.sample_rate, |
| pal_snd_dec->ape_dec.seek_table_present); |
| } |
| else if (config_->offload_info.format == AUDIO_FORMAT_VORBIS) { |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_VORBIS_BITSTREAM_FMT, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->vorbis_dec.bit_stream_fmt = atoi(value); |
| } |
| } |
| else if (config_->offload_info.format == AUDIO_FORMAT_WMA || config_->offload_info.format == AUDIO_FORMAT_WMA_PRO) { |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_FORMAT_TAG, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->wma_dec.fmt_tag = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->wma_dec.avg_bit_rate = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->wma_dec.super_block_align = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->wma_dec.bits_per_sample = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->wma_dec.channelmask = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->wma_dec.encodeopt = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->wma_dec.encodeopt1 = atoi(value); |
| } |
| ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2, value, sizeof(value)); |
| if (ret >= 0) { |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->wma_dec.encodeopt2 = atoi(value); |
| } |
| AHAL_DBG("WMA params: fmt %x, bit rate %x, balgn %x, sr %d, chmsk %x" |
| " encop %x, op1 %x, op2 %x", |
| pal_snd_dec->wma_dec.fmt_tag, |
| pal_snd_dec->wma_dec.avg_bit_rate, |
| pal_snd_dec->wma_dec.super_block_align, |
| pal_snd_dec->wma_dec.bits_per_sample, |
| pal_snd_dec->wma_dec.channelmask, |
| pal_snd_dec->wma_dec.encodeopt, |
| pal_snd_dec->wma_dec.encodeopt1, |
| pal_snd_dec->wma_dec.encodeopt2); |
| } |
| |
| else if ((config_->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC || |
| (config_->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS || |
| (config_->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADIF || |
| (config_->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_LATM) { |
| |
| *isCompressMetadataAvail = true; |
| pal_snd_dec->aac_dec.audio_obj_type = 29; |
| pal_snd_dec->aac_dec.pce_bits_size = 0; |
| AHAL_VERBOSE("AAC params: aot %d pce %d", pal_snd_dec->aac_dec.audio_obj_type, pal_snd_dec->aac_dec.pce_bits_size); |
| AHAL_VERBOSE("format %x", config_->offload_info.format); |
| } |
| return 0; |
| } |
| |
| int AudioExtn::GetProxyParameters(std::shared_ptr<AudioDevice> adev __unused, |
| struct str_parms *query, struct str_parms *reply) |
| { |
| int ret, val = 0; |
| char value[32] = {0}; |
| |
| ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_CAN_OPEN_PROXY, value, |
| sizeof(value)); |
| if (ret >= 0) { |
| val = 1; |
| str_parms_add_int(reply, AUDIO_PARAMETER_KEY_CAN_OPEN_PROXY, val); |
| } |
| AHAL_VERBOSE("called ... can_use_proxy %d", val); |
| return 0; |
| } |
| |
| void AudioExtn::audio_extn_get_parameters(std::shared_ptr<AudioDevice> adev, |
| struct str_parms *query, struct str_parms *reply) |
| { |
| char *kv_pairs = NULL; |
| |
| audio_extn_fm_get_parameters(adev, query, reply); |
| GetProxyParameters(adev, query, reply); |
| kv_pairs = str_parms_to_str(reply); |
| if (kv_pairs != NULL) { |
| AHAL_VERBOSE("returns %s", kv_pairs); |
| } |
| free(kv_pairs); |
| } |
| |
| void AudioExtn::audio_extn_set_parameters(std::shared_ptr<AudioDevice> adev, |
| struct str_parms *params){ |
| audio_extn_hfp_set_parameters(adev, params); |
| audio_extn_fm_set_parameters(adev, params); |
| } |
| |
| int AudioExtn::get_controller_stream_from_params(struct str_parms *parms, |
| int *controller, int *stream) { |
| if ((str_parms_get_int(parms, "controller", controller) >= 0) |
| && (str_parms_get_int(parms, "stream", stream) >=0 )) { |
| if (*controller < 0 || *controller >= MAX_CONTROLLERS || |
| *stream < 0 || *stream >= MAX_STREAMS_PER_CONTROLLER) { |
| *controller = 0; |
| *stream = 0; |
| return -EINVAL; |
| } |
| } else { |
| *controller = -1; |
| *stream = -1; |
| } |
| return 0; |
| } |
| |
| // START: BATTERY_LISTENER ================================================== |
| |
| void AudioExtn::battery_listener_feature_init(bool is_feature_enabled) { |
| battery_listener_enabled = is_feature_enabled; |
| if (is_feature_enabled) { |
| batt_listener_lib_handle = dlopen(BATTERY_LISTENER_LIB_PATH, RTLD_NOW); |
| |
| if (!batt_listener_lib_handle) { |
| AHAL_ERR("dlopen failed"); |
| goto feature_disabled; |
| } |
| if (!(batt_listener_init = (batt_listener_init_t)dlsym( |
| batt_listener_lib_handle, "battery_properties_listener_init")) || |
| !(batt_listener_deinit = |
| (batt_listener_deinit_t)dlsym( |
| batt_listener_lib_handle, "battery_properties_listener_deinit")) || |
| !(batt_prop_is_charging = |
| (batt_prop_is_charging_t)dlsym( |
| batt_listener_lib_handle, "battery_properties_is_charging"))) { |
| AHAL_ERR("dlsym failed"); |
| goto feature_disabled; |
| } |
| AHAL_DBG("---- Feature BATTERY_LISTENER is enabled ----"); |
| return; |
| } |
| |
| feature_disabled: |
| if (batt_listener_lib_handle) { |
| dlclose(batt_listener_lib_handle); |
| batt_listener_lib_handle = NULL; |
| } |
| |
| batt_listener_init = NULL; |
| batt_listener_deinit = NULL; |
| batt_prop_is_charging = NULL; |
| AHAL_INFO("---- Feature BATTERY_LISTENER is disabled ----"); |
| } |
| |
| void AudioExtn::battery_properties_listener_init(battery_status_change_fn_t fn) |
| { |
| if(batt_listener_init) |
| batt_listener_init(fn); |
| } |
| void AudioExtn::battery_properties_listener_deinit() |
| { |
| if(batt_listener_deinit) |
| batt_listener_deinit(); |
| } |
| bool AudioExtn::battery_properties_is_charging() |
| { |
| return (batt_prop_is_charging)? batt_prop_is_charging(): false; |
| } |
| // END: BATTERY_LISTENER ================================================================ |
| |
| // START: HFP ====================================================================== |
| |
| static void *hfp_lib_handle = NULL; |
| static hfp_init_t hfp_init; |
| static hfp_is_active_t hfp_is_active; |
| static hfp_get_usecase_t hfp_get_usecase; |
| static hfp_set_mic_mute_t hfp_set_mic_mute; |
| static set_parameters_t hfp_set_parameters; |
| static hfp_set_mic_mute2_t hfp_set_mic_mute2; |
| |
| int AudioExtn::hfp_feature_init(bool is_feature_enabled) |
| { |
| AHAL_DBG("Called with feature %s", |
| is_feature_enabled ? "Enabled" : "NOT Enabled"); |
| if (is_feature_enabled) { |
| // dlopen lib |
| hfp_lib_handle = dlopen(HFP_LIB_PATH, RTLD_NOW); |
| |
| if (!hfp_lib_handle) { |
| AHAL_ERR("dlopen failed with: %s", dlerror()); |
| goto feature_disabled; |
| } |
| |
| if (!(hfp_init = (hfp_init_t)dlsym( |
| hfp_lib_handle, "hfp_init")) || |
| !(hfp_is_active = |
| (hfp_is_active_t)dlsym( |
| hfp_lib_handle, "hfp_is_active")) || |
| !(hfp_get_usecase = |
| (hfp_get_usecase_t)dlsym( |
| hfp_lib_handle, "hfp_get_usecase")) || |
| !(hfp_set_mic_mute = |
| (hfp_set_mic_mute_t)dlsym( |
| hfp_lib_handle, "hfp_set_mic_mute")) || |
| !(hfp_set_mic_mute2 = |
| (hfp_set_mic_mute2_t)dlsym( |
| hfp_lib_handle, "hfp_set_mic_mute2")) || |
| !(hfp_set_parameters = |
| (set_parameters_t)dlsym( |
| hfp_lib_handle, "hfp_set_parameters"))) { |
| AHAL_ERR("dlsym failed"); |
| goto feature_disabled; |
| } |
| |
| AHAL_DBG("---- Feature HFP is Enabled ----"); |
| |
| return 0; |
| } |
| |
| feature_disabled: |
| if (hfp_lib_handle) { |
| dlclose(hfp_lib_handle); |
| hfp_lib_handle = NULL; |
| } |
| |
| hfp_init = NULL; |
| hfp_is_active = NULL; |
| hfp_get_usecase = NULL; |
| hfp_set_mic_mute = NULL; |
| hfp_set_mic_mute2 = NULL; |
| hfp_set_parameters = NULL; |
| |
| AHAL_INFO("---- Feature HFP is disabled ----"); |
| return -ENOSYS; |
| } |
| |
| bool AudioExtn::audio_extn_hfp_is_active(std::shared_ptr<AudioDevice> adev) |
| { |
| return ((hfp_is_active) ? |
| hfp_is_active(adev) : false); |
| } |
| |
| audio_usecase_t AudioExtn::audio_extn_hfp_get_usecase() |
| { |
| return ((hfp_get_usecase) ? |
| hfp_get_usecase() : -1); |
| } |
| |
| int AudioExtn::audio_extn_hfp_set_mic_mute(bool state) |
| { |
| return ((hfp_set_mic_mute) ? |
| hfp_set_mic_mute(state) : -1); |
| } |
| |
| static int reconfig_cb (tSESSION_TYPE session_type, int state) |
| { |
| int ret = 0; |
| pal_param_bta2dp_t param_bt_a2dp; |
| AHAL_DBG("reconfig_cb enter with state %s for %s", reconfigStateName.at(state).c_str(), |
| deviceNameLUT.at(SessionTypePalDevMap.at(session_type)).c_str()); |
| if (session_type == LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) { |
| |
| /* If reconfiguration is in progress state, we do a2dp suspend. |
| * If reconfiguration is in complete state, we do a2dp resume. |
| */ |
| if ((tRECONFIG_STATE)state == SESSION_SUSPEND) { |
| std::unique_lock<std::mutex> guard(reconfig_wait_mutex_); |
| param_bt_a2dp.a2dp_suspended = true; |
| param_bt_a2dp.dev_id = PAL_DEVICE_OUT_BLUETOOTH_BLE; |
| |
| ret = pal_set_param(PAL_PARAM_ID_BT_A2DP_SUSPENDED, (void *)¶m_bt_a2dp, |
| sizeof(pal_param_bta2dp_t)); |
| } else if ((tRECONFIG_STATE)state == SESSION_RESUME) { |
| param_bt_a2dp.a2dp_suspended = false; |
| param_bt_a2dp.dev_id = PAL_DEVICE_OUT_BLUETOOTH_BLE; |
| |
| ret = pal_set_param(PAL_PARAM_ID_BT_A2DP_SUSPENDED, (void *)¶m_bt_a2dp, |
| sizeof(pal_param_bta2dp_t)); |
| } |
| } else if (session_type == LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) { |
| if ((tRECONFIG_STATE)state == SESSION_SUSPEND) { |
| std::unique_lock<std::mutex> guard(reconfig_wait_mutex_); |
| param_bt_a2dp.a2dp_capture_suspended = true; |
| param_bt_a2dp.dev_id = PAL_DEVICE_IN_BLUETOOTH_BLE; |
| |
| ret = pal_set_param(PAL_PARAM_ID_BT_A2DP_CAPTURE_SUSPENDED, (void *)¶m_bt_a2dp, |
| sizeof(pal_param_bta2dp_t)); |
| } else if ((tRECONFIG_STATE)state == SESSION_RESUME) { |
| param_bt_a2dp.a2dp_capture_suspended = false; |
| param_bt_a2dp.dev_id = PAL_DEVICE_IN_BLUETOOTH_BLE; |
| |
| ret = pal_set_param(PAL_PARAM_ID_BT_A2DP_CAPTURE_SUSPENDED, (void *)¶m_bt_a2dp, |
| sizeof(pal_param_bta2dp_t)); |
| } |
| } |
| AHAL_DBG("reconfig_cb exit with state %s for %s", reconfigStateName.at(state).c_str(), |
| deviceNameLUT.at(SessionTypePalDevMap.at(session_type)).c_str()); |
| return ret; |
| } |
| |
| void AudioExtn::audio_extn_hfp_set_parameters(std::shared_ptr<AudioDevice> adev, |
| struct str_parms *parms) |
| { |
| if (hfp_set_parameters) |
| hfp_set_parameters(adev, parms); |
| } |
| |
| int AudioExtn::audio_extn_hfp_set_mic_mute2(std::shared_ptr<AudioDevice> adev, bool state) |
| { |
| return ((hfp_set_mic_mute2) ? |
| hfp_set_mic_mute2(adev, state) : -1); |
| } |
| // END: HFP ======================================================================== |
| |
| // START: A2DP ====================================================================== |
| // Need to call this init for BT HIDL registration. It is expected that Audio HAL |
| // do need to do this initialization. Hence - |
| typedef void (*a2dp_bt_audio_pre_init_t)(void); |
| static void *a2dp_bt_lib_source_handle = NULL; |
| static a2dp_bt_audio_pre_init_t a2dp_bt_audio_pre_init = nullptr; |
| typedef void (*register_reconfig_cb_t)(int (*reconfig_cb)(tSESSION_TYPE, int)); |
| static register_reconfig_cb_t register_reconfig_cb = nullptr; |
| |
| int AudioExtn::a2dp_source_feature_init(bool is_feature_enabled) |
| { |
| AHAL_DBG("Called with feature %s", |
| is_feature_enabled ? "Enabled" : "NOT Enabled"); |
| |
| if (is_feature_enabled && |
| (access(BT_IPC_SOURCE_LIB_NAME, R_OK) == 0)) { |
| // dlopen lib |
| a2dp_bt_lib_source_handle = dlopen(BT_IPC_SOURCE_LIB_NAME, RTLD_NOW); |
| |
| if (!a2dp_bt_lib_source_handle) { |
| AHAL_ERR("dlopen %s failed with: %s", BT_IPC_SOURCE_LIB_NAME, dlerror()); |
| goto feature_disabled; |
| } |
| |
| if (!(a2dp_bt_audio_pre_init = (a2dp_bt_audio_pre_init_t)dlsym( |
| a2dp_bt_lib_source_handle, "bt_audio_pre_init")) ) { |
| AHAL_ERR("dlsym failed"); |
| goto feature_disabled; |
| } |
| |
| if (a2dp_bt_lib_source_handle && a2dp_bt_audio_pre_init) { |
| AHAL_DBG("calling BT module preinit"); |
| // fwk related check's will be done in the BT layer |
| a2dp_bt_audio_pre_init(); |
| } |
| |
| if (!(register_reconfig_cb = (register_reconfig_cb_t)dlsym( |
| a2dp_bt_lib_source_handle, "register_reconfig_cb")) ) { |
| AHAL_ERR("dlsym failed"); |
| goto feature_disabled; |
| } |
| |
| if (a2dp_bt_lib_source_handle && register_reconfig_cb) { |
| AHAL_DBG("calling BT module register reconfig"); |
| int (*reconfig_cb_ptr)(tSESSION_TYPE, int) = &reconfig_cb; |
| register_reconfig_cb(reconfig_cb_ptr); |
| } |
| |
| AHAL_DBG("---- Feature A2DP offload is Enabled ----"); |
| return 0; |
| } |
| |
| feature_disabled: |
| if (a2dp_bt_lib_source_handle) { |
| dlclose(a2dp_bt_lib_source_handle); |
| a2dp_bt_lib_source_handle = NULL; |
| } |
| |
| a2dp_bt_audio_pre_init = nullptr; |
| AHAL_INFO("---- Feature A2DP offload is disabled ----"); |
| return -ENOSYS; |
| } |
| // END: A2DP |
| |
| // START: DEVICE UTILS ============================================================= |
| bool AudioExtn::audio_devices_cmp(const std::set<audio_devices_t>& devs, audio_device_cmp_fn_t fn) { |
| for(auto dev : devs) |
| if(fn(dev)) |
| return true; |
| return false; |
| } |
| |
| bool AudioExtn::audio_devices_cmp(const std::set<audio_devices_t>& devs, audio_devices_t dev) { |
| for(auto d : devs) |
| if(d == dev) |
| return true; |
| return false; |
| } |
| |
| audio_devices_t AudioExtn::get_device_types(const std::set<audio_devices_t>& devs){ |
| audio_devices_t device = AUDIO_DEVICE_NONE; |
| for(auto d : devs) |
| device = (audio_devices_t) (device | d); |
| return device; |
| } |
| |
| bool AudioExtn::audio_devices_empty(const std::set<audio_devices_t>& devs){ |
| return devs.empty(); |
| } |
| // END: DEVICE UTILS =============================================================== |
| |
| // START: KARAOKE ================================================================== |
| int AudioExtn::karaoke_open(pal_device_id_t device_out, pal_stream_callback pal_callback, pal_channel_info ch_info) { |
| std::shared_ptr<AudioDevice> adevice = AudioDevice::GetInstance(); |
| const int num_pal_devs = 2; |
| struct pal_device pal_devs[num_pal_devs]; |
| karaoke_stream_handle = NULL; |
| pal_device_id_t device_in; |
| dynamic_media_config_t dynamic_media_config; |
| size_t payload_size = 0; |
| |
| // Configuring Hostless Loopback |
| if (device_out == PAL_DEVICE_OUT_WIRED_HEADSET) |
| device_in = PAL_DEVICE_IN_WIRED_HEADSET; |
| else if (device_out == PAL_DEVICE_OUT_USB_HEADSET) { |
| device_in = PAL_DEVICE_IN_USB_HEADSET; |
| // get capability from device of USB |
| } else |
| return 0; |
| |
| sattr.type = PAL_STREAM_LOOPBACK; |
| sattr.info.opt_stream_info.loopback_type = PAL_STREAM_LOOPBACK_KARAOKE; |
| sattr.direction = PAL_AUDIO_INPUT_OUTPUT; |
| sattr.in_media_config.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE; |
| sattr.in_media_config.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH; |
| sattr.in_media_config.ch_info = ch_info; |
| sattr.in_media_config.aud_fmt_id = PAL_AUDIO_FMT_DEFAULT_PCM; |
| sattr.out_media_config.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE; |
| sattr.out_media_config.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH; |
| sattr.out_media_config.ch_info = ch_info; |
| sattr.out_media_config.aud_fmt_id = PAL_AUDIO_FMT_DEFAULT_PCM; |
| for (int i = 0; i < num_pal_devs; ++i) { |
| pal_devs[i].id = i ? device_in : device_out; |
| if (device_out == PAL_DEVICE_OUT_USB_HEADSET || device_in == PAL_DEVICE_IN_USB_HEADSET) { |
| //Configure USB Digital Headset parameters |
| pal_param_device_capability_t *device_cap_query = (pal_param_device_capability_t *) |
| malloc(sizeof(pal_param_device_capability_t)); |
| if (!device_cap_query) { |
| AHAL_ERR("Failed to allocate mem for device_cap_query"); |
| return 0; |
| } |
| |
| if (pal_devs[i].id == PAL_DEVICE_OUT_USB_HEADSET) { |
| device_cap_query->id = PAL_DEVICE_OUT_USB_DEVICE; |
| device_cap_query->is_playback = true; |
| } else { |
| device_cap_query->id = PAL_DEVICE_IN_USB_DEVICE; |
| device_cap_query->is_playback = false; |
| } |
| device_cap_query->addr.card_id = adevice->usb_card_id_; |
| device_cap_query->addr.device_num = adevice->usb_dev_num_; |
| device_cap_query->config = &dynamic_media_config; |
| pal_get_param(PAL_PARAM_ID_DEVICE_CAPABILITY, |
| (void **)&device_cap_query, |
| &payload_size, nullptr); |
| pal_devs[i].address.card_id = adevice->usb_card_id_; |
| pal_devs[i].address.device_num = adevice->usb_dev_num_; |
| pal_devs[i].config.sample_rate = dynamic_media_config.sample_rate[0]; |
| pal_devs[i].config.ch_info = ch_info; |
| pal_devs[i].config.aud_fmt_id = (pal_audio_fmt_t)dynamic_media_config.format[0]; |
| free(device_cap_query); |
| } else { |
| pal_devs[i].config.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE; |
| pal_devs[i].config.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH; |
| pal_devs[i].config.ch_info = ch_info; |
| pal_devs[i].config.aud_fmt_id = PAL_AUDIO_FMT_DEFAULT_PCM; |
| } |
| } |
| return pal_stream_open(&sattr, |
| num_pal_devs, pal_devs, |
| 0, |
| NULL, |
| pal_callback, |
| (uint64_t) this, |
| &karaoke_stream_handle); |
| } |
| |
| int AudioExtn::karaoke_start() { |
| return pal_stream_start(karaoke_stream_handle); |
| } |
| |
| int AudioExtn::karaoke_stop() { |
| return pal_stream_stop(karaoke_stream_handle); |
| } |
| |
| int AudioExtn::karaoke_close(){ |
| return pal_stream_close(karaoke_stream_handle); |
| } |
| // END: KARAOKE ==================================================================== |
| |
| // START: PAL HIDL ================================================= |
| |
| int AudioExtn::audio_extn_hidl_init() { |
| std::lock_guard<std::mutex> lock(AudioExtn::sLock); |
| if (sServicesRegistered) { |
| AHAL_DBG("HIDLs are already registered"); |
| return 0; |
| } |
| |
| #ifdef PAL_HIDL_ENABLED |
| /* register audio PAL HIDL */ |
| sp<IPAL> service = new PAL(); |
| if(android::OK != service->registerAsService()) { |
| AHAL_ERR("Could not register PAL service"); |
| return -EINVAL; |
| } else { |
| AHAL_DBG("successfully registered PAL service"); |
| } |
| #endif |
| |
| #ifdef AGM_HIDL_ENABLED |
| /* register AGM HIDL */ |
| sp<IAGM> agm_service = new AGM(); |
| AGM *temp = static_cast<AGM *>(agm_service.get()); |
| if (temp->is_agm_initialized()) { |
| if(android::OK != agm_service->registerAsService()) { |
| AHAL_ERR("Could not register AGM service"); |
| return -EINVAL; |
| } else { |
| AHAL_DBG("successfully registered AGM service"); |
| } |
| } else { |
| AHAL_ERR("Failed to initialize AGM service"); |
| return -EINVAL; |
| } |
| #endif |
| /* to register other hidls */ |
| sServicesRegistered = true; |
| return 0; |
| } |
| |
| |
| // END: PAL HIDL =================================================== |
| static set_parameters_t fm_set_params; |
| static get_parameters_t fm_get_params; |
| static void* libfm; |
| |
| void AudioExtn::audio_extn_fm_init(bool enabled) |
| { |
| |
| AHAL_DBG("Enter: enabled: %d", enabled); |
| |
| if(enabled){ |
| if(!libfm) |
| libfm = dlopen(FM_LIB_PATH, RTLD_NOW); |
| |
| if (!libfm) { |
| AHAL_ERR("dlopen failed with: %s", dlerror()); |
| return; |
| } |
| |
| fm_set_params = (set_parameters_t) dlsym(libfm, "fm_set_parameters"); |
| fm_get_params = (get_parameters_t) dlsym(libfm, "fm_get_parameters"); |
| |
| if(!fm_set_params || !fm_get_params){ |
| AHAL_ERR("%s", dlerror()); |
| dlclose(libfm); |
| } |
| } |
| AHAL_DBG("Exit"); |
| } |
| |
| |
| void AudioExtn::audio_extn_fm_set_parameters(std::shared_ptr<AudioDevice> adev, struct str_parms *params){ |
| if(fm_set_params) |
| fm_set_params(adev, params); |
| } |
| |
| void AudioExtn::audio_extn_fm_get_parameters(std::shared_ptr<AudioDevice> adev, struct str_parms *query, struct str_parms *reply){ |
| if(fm_get_params) |
| fm_get_params(adev, query, reply); |
| } |
| |
| //START: KPI_OPTIMIZE ============================================================================= |
| void AudioExtn::audio_extn_kpi_optimize_feature_init(bool is_feature_enabled) |
| { |
| audio_extn_kpi_optimize_feature_enabled = is_feature_enabled; |
| AHAL_DBG("---- Feature KPI_OPTIMIZE is %s ----", is_feature_enabled? "ENABLED": " NOT ENABLED"); |
| } |
| |
| typedef int (*perf_lock_acquire_t)(int, int, int*, int); |
| typedef int (*perf_lock_release_t)(int); |
| |
| static void *qcopt_handle; |
| static perf_lock_acquire_t perf_lock_acq; |
| static perf_lock_release_t perf_lock_rel; |
| |
| char opt_lib_path[512] = {0}; |
| |
| int AudioExtn::audio_extn_perf_lock_init(void) |
| { |
| int ret = 0; |
| |
| //if feature is disabled, exit immediately |
| if(!audio_extn_kpi_optimize_feature_enabled) |
| goto err; |
| |
| if (qcopt_handle == NULL) { |
| if (property_get("ro.vendor.extension_library", |
| opt_lib_path, NULL) <= 0) { |
| AHAL_ERR("Failed getting perf property"); |
| ret = -EINVAL; |
| goto err; |
| } |
| if ((qcopt_handle = dlopen(opt_lib_path, RTLD_NOW)) == NULL) { |
| AHAL_ERR("Failed to open perf handle"); |
| ret = -EINVAL; |
| goto err; |
| } else { |
| perf_lock_acq = (perf_lock_acquire_t)dlsym(qcopt_handle, |
| "perf_lock_acq"); |
| if (perf_lock_acq == NULL) { |
| AHAL_ERR("Perf lock Acquire NULL"); |
| dlclose(qcopt_handle); |
| ret = -EINVAL; |
| goto err; |
| } |
| perf_lock_rel = (perf_lock_release_t)dlsym(qcopt_handle, |
| "perf_lock_rel"); |
| if (perf_lock_rel == NULL) { |
| AHAL_ERR("Perf lock Release NULL"); |
| dlclose(qcopt_handle); |
| ret = -EINVAL; |
| goto err; |
| } |
| ALOGE("%s: Perf lock handles Success \n", __func__); |
| } |
| } |
| err: |
| return ret; |
| } |
| |
| void AudioExtn::audio_extn_perf_lock_acquire(int *handle, int duration, |
| int *perf_lock_opts, int size) |
| { |
| if (audio_extn_kpi_optimize_feature_enabled) |
| { |
| if (!perf_lock_opts || !size || !perf_lock_acq || !handle) { |
| AHAL_ERR("Incorrect params, Failed to acquire perf lock, err "); |
| return; |
| } |
| /* |
| * Acquire performance lock for 1 sec during device path bringup. |
| * Lock will be released either after 1 sec or when perf_lock_release |
| * function is executed. |
| */ |
| *handle = perf_lock_acq(*handle, duration, perf_lock_opts, size); |
| if (*handle <= 0) |
| AHAL_ERR("Failed to acquire perf lock, err: %d\n", *handle); |
| } |
| } |
| |
| void AudioExtn::audio_extn_perf_lock_release(int *handle) |
| { |
| if (audio_extn_kpi_optimize_feature_enabled) { |
| if (perf_lock_rel && handle && (*handle > 0)) { |
| perf_lock_rel(*handle); |
| *handle = 0; |
| } else |
| AHAL_ERR("Perf lock release error"); |
| } |
| } |
| |
| //END: KPI_OPTIMIZE ============================================================================= |
| |
| // START: compress_capture ===================================================== |
| |
| std::vector<uint32_t> CompressCapture::sAacSampleRates = { |
| 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}; |
| |
| std::unordered_map<uint32_t, int32_t> |
| CompressCapture::sSampleRateToDefaultBitRate = { |
| {8000, 36000}, {11025, 48000}, {12000, 56000}, |
| {16000, 64000}, {22050, 82500}, {24000, 96000}, |
| {32000, 110000}, {44100, 128000}, {48000, 156000}}; |
| |
| bool CompressCapture::parseMetadata(str_parms *parms, |
| struct audio_config *config, |
| int32_t &compressStreamAdjBitRate) { |
| bool ret = false; |
| int32_t value = 0; |
| |
| if (config->format == AUDIO_FORMAT_AAC_LC || |
| config->format == AUDIO_FORMAT_AAC_ADTS_LC || |
| config->format == AUDIO_FORMAT_AAC_ADTS_HE_V1 || |
| config->format == AUDIO_FORMAT_AAC_ADTS_HE_V2) { |
| /* query for AAC bitrate */ |
| if (!str_parms_get_int(parms, kAudioParameterDSPAacBitRate, |
| &value)) { |
| uint32_t channelCount = |
| audio_channel_count_from_in_mask(config->channel_mask); |
| int32_t minValue = 0; |
| int32_t maxValue = UINT32_MAX; |
| auto it = std::find(sAacSampleRates.cbegin(), |
| sAacSampleRates.cend(), config->sample_rate); |
| if (it != sAacSampleRates.cend() && |
| getAACMinBitrateValue(config->sample_rate, channelCount, |
| minValue) && |
| getAACMaxBitrateValue(config->sample_rate, channelCount, |
| maxValue)) { |
| AHAL_INFO("client requested AAC bitrate: %d", value); |
| if (value < minValue) { |
| value = minValue; |
| AHAL_WARN("Adjusting AAC bitrate to minimum: %d", value); |
| } else if (value > maxValue) { |
| value = maxValue; |
| AHAL_WARN("Adjusting AAC bitrate to maximum: %d", value); |
| } |
| compressStreamAdjBitRate = value; |
| ret = true; |
| } |
| } |
| } |
| |
| return ret; |
| } |
| |
| bool CompressCapture::getAACMinBitrateValue(uint32_t sampleRate, |
| uint32_t channelCount, |
| int32_t &minValue) { |
| if (channelCount == 1) { |
| minValue = kAacMonoMinSupportedBitRate; |
| } else if (channelCount == 2) { |
| minValue = kAacStereoMinSupportedBitRate; |
| } else { |
| return false; |
| } |
| return true; |
| } |
| |
| bool CompressCapture::getAACMaxBitrateValue(uint32_t sampleRate, |
| uint32_t channelCount, |
| int32_t &maxValue) { |
| if (channelCount == 1) { |
| maxValue = (int32_t)std::min((uint32_t)kAacMonoMaxSupportedBitRate, |
| 6 * sampleRate); |
| } else if (channelCount == 2) { |
| maxValue = (int32_t)std::min((uint32_t)kAacStereoMaxSupportedBitRate, |
| 12 * sampleRate); |
| } else { |
| return false; |
| } |
| return true; |
| } |
| |
| bool CompressCapture::getAACMaxBufferSize(struct audio_config *config, |
| uint32_t &maxBufSize) { |
| int32_t maxBitRate = 0; |
| if (getAACMaxBitrateValue( |
| config->sample_rate, |
| audio_channel_count_from_in_mask(config->channel_mask), |
| maxBitRate)) { |
| /** |
| * AAC Encoder 1024 PCM samples => 1 compress AAC frame; |
| * 1 compress AAC frame => max possible length => max-bitrate bits; |
| * let's take example of 48K HZ; |
| * 1 second ==> 384000 bits ; 1 second ==> 48000 PCM samples; |
| * 1 AAC frame ==> 1024 PCM samples; |
| * Max buffer size possible; |
| * 48000/1024 = (8/375) seconds ==> ( 8/375 ) * 384000 bits |
| * ==> ( (8/375) * 384000 / 8 ) bytes; |
| **/ |
| maxBufSize = (uint32_t)((((((double)kAacPCMSamplesPerFrame) / |
| config->sample_rate) * |
| ((uint32_t)(maxBitRate))) / |
| 8) + |
| /* Just in case; not to miss precision */ 1); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| // END: compress_capture ======================================================= |