From b266e886294aeadb947b5f05888029a6b4045461 Mon Sep 17 00:00:00 2001 From: SungHwan Yu Date: Wed, 18 Oct 2023 11:03:17 +0900 Subject: [PATCH] audio_hal: play youtube with a2dp audio breadk [1/1] PD#OTT-50503 Problem: The Q code is older and needs to be updated. Solution: Merge a2dp code from R to Q Verify: s905x2 Change-Id: I908b28659ad743ea34343e5a70ba59d7ec20373e Signed-off-by: SungHwan Yu --- audio/audio_hal/a2dp_hal.cpp | 850 +++++++++++++++---------- audio/audio_hal/a2dp_hal.h | 15 +- audio/audio_hal/amlAudioMixer.c | 478 ++++++-------- audio/audio_hal/aml_audio_stream.h | 9 +- audio/audio_hal/aml_audio_timer.h | 8 + audio/audio_hal/audio_hw.c | 80 +-- audio/audio_hal/audio_hw.h | 3 +- audio/audio_hal/audio_hw_utils.c | 17 +- audio/audio_hal/audio_hw_utils.h | 57 +- audio/audio_hal/audio_port.c | 38 +- audio/audio_hal/audio_port.h | 8 +- audio/audio_hal/sub_mixing_factory.c | 38 +- audio/utils/aml_malloc_debug.c | 22 + audio/utils/include/aml_malloc_debug.h | 1 + 14 files changed, 907 insertions(+), 717 deletions(-) diff --git a/audio/audio_hal/a2dp_hal.cpp b/audio/audio_hal/a2dp_hal.cpp index 48ad717..3ae830c 100644 --- a/audio/audio_hal/a2dp_hal.cpp +++ b/audio/audio_hal/a2dp_hal.cpp @@ -15,118 +15,78 @@ */ #define LOG_TAG "a2dp_hal" - +//#define LOG_NDEBUG 0 #include +#include #include #include #include +#include + +#include "BluetoothAudioSession.h" #include "a2dp_hal.h" #include "a2dp_hw.h" -#include "audio_hw.h" -using ::android::bluetooth::audio::BluetoothAudioPortOut; +extern "C" { +#include "aml_malloc_debug.h" +#include "aml_audio_resampler.h" +#include "audio_hw_utils.h" +#include "aml_audio_stream.h" +#include "aml_audio_timer.h" +} -#define MAX_RESAMPLE_CHANNEL 8 -struct aml_resample { - unsigned int FractionStep; - unsigned int SampleFraction; - unsigned int input_sr; - unsigned int output_sr; - unsigned int channels; - int16_t lastsample[MAX_RESAMPLE_CHANNEL]; -}; +using ::android::bluetooth::audio::BluetoothAudioPortOut; +using ::android::bluetooth::audio::BluetoothAudioSession; +using ::android::bluetooth::audio::BluetoothAudioSessionInstance; +using ::android::hardware::bluetooth::audio::V2_0::SessionType; + +#define A2DP_RING_BUFFER_DELAY_TIME_MS (64) +#define A2DP_SEND_DATA_TIMEOUT_RESET_MS (300) +#define A2DP_WAIT_STATE_DELAY_TIME_US (8000) +#define DEFAULT_A2DP_LATENCY_NS (100 * NSEC_PER_MSEC) // Default delay to use when BT device does not report a delay +#define A2DP_STATIC_DELAY_MS (0) // Additional device-specific delay +#define AUDIO_HAL_FIXED_CFG_CHANNEL (AUDIO_CHANNEL_OUT_STEREO) +#define AUDIO_HAL_FIXED_CFG_FORMAT (AUDIO_FORMAT_PCM_16_BIT) struct aml_a2dp_hal { BluetoothAudioPortOut a2dphw; audio_config config; - struct aml_resample * resample; - char* buff; - size_t buffsize; + struct resample_para *resample; int64_t last_write_time; - mutable std::mutex mutex_; + uint64_t mute_time; + char * buff_conv_format; + size_t buff_size_conv_format; + BluetoothStreamState state; + bool is_sending_data; + bool exit_out_monitor_thread; + pthread_t out_monitor_thread_id; + pthread_mutex_t out_monitor_thread_mutex; + pthread_cond_t out_monitor_thread_cond; + uint32_t resample_size; + char * resample_buffer; }; -inline static short clip(int x) { - if (x < -32768) { - return -32768; - } else if (x > 32767) { - return 32767; - } else { - return x; - } -} - -int resampler_init(struct aml_resample *resample) { +static int a2dp_out_standby(struct aml_audio_device *adev); - ALOGD("%s, Init Resampler: input_sr = %d, output_sr = %d \n", - __FUNCTION__,resample->input_sr,resample->output_sr); - - static const double kPhaseMultiplier = 1L << 28; - unsigned int i; - - if (resample->channels > MAX_RESAMPLE_CHANNEL) { - ALOGE("Error: %s, max support channels: %d\n", - __FUNCTION__, MAX_RESAMPLE_CHANNEL); - return -1; - } - - resample->FractionStep = (unsigned int) (resample->input_sr * kPhaseMultiplier - / resample->output_sr); - resample->SampleFraction = 0; - for (i = 0; i < resample->channels; i++) - resample->lastsample[i] = 0; - - return 0; +const char* a2dpStatus2String(BluetoothStreamState type) +{ + ENUM_TYPE_TO_STR_START("BluetoothStreamState::"); + ENUM_TYPE_TO_STR(BluetoothStreamState::DISABLED) + ENUM_TYPE_TO_STR(BluetoothStreamState::STANDBY) + ENUM_TYPE_TO_STR(BluetoothStreamState::STARTING) + ENUM_TYPE_TO_STR(BluetoothStreamState::STARTED) + ENUM_TYPE_TO_STR(BluetoothStreamState::SUSPENDING) + ENUM_TYPE_TO_STR(BluetoothStreamState::UNKNOWN) + ENUM_TYPE_TO_STR_END } -int resample_process(struct aml_resample *resample, unsigned int in_frame, - int16_t* input, int16_t* output) { - unsigned int inputIndex = 0; - unsigned int outputIndex = 0; - unsigned int FractionStep = resample->FractionStep; - int16_t last_sample[MAX_RESAMPLE_CHANNEL]; - unsigned int i; - unsigned int channels = resample->channels; - - static const unsigned int kPhaseMask = (1LU << 28) - 1; - unsigned int frac = resample->SampleFraction; - - for (i = 0; i < channels; i++) - last_sample[i] = resample->lastsample[i]; - - - while (inputIndex == 0) { - for (i = 0; i < channels; i++) { - *output++ = clip((int) last_sample[i] + - ((((int) input[i] - (int) last_sample[i]) * ((int) frac >> 13)) >> 15)); - } - - frac += FractionStep; - inputIndex += (frac >> 28); - frac = (frac & kPhaseMask); - outputIndex++; - } - - while (inputIndex < in_frame) { - for (i = 0; i < channels; i++) { - *output++ = clip((int) input[channels * (inputIndex - 1) + i] + - ((((int) input[channels * inputIndex + i] - - (int) input[channels * (inputIndex - 1) + i]) * ((int) frac >> 13)) >> 15)); - } - - frac += FractionStep; - inputIndex += (frac >> 28); - frac = (frac & kPhaseMask); - outputIndex++; - } - - resample->SampleFraction = frac; - - for (i = 0; i < channels; i++) - resample->lastsample[i] = input[channels * (in_frame - 1) + i]; - - return outputIndex; +struct timespec aml_audio_ns_to_time(uint64_t ns) +{ + struct timespec time; + time.tv_sec = ns / 1000000000; + time.tv_nsec = ns - ((uint64_t)time.tv_sec * 1000000000); + return time; } std::unordered_map ParseAudioParams(const std::string& params) { @@ -138,7 +98,7 @@ std::unordered_map ParseAudioParams(const std::string& } std::vector kv = android::base::Split(segment, "="); if (kv[0].empty()) { - //ALOGD("%s: Invalid audio parameter: ", __func__, segment.char()); + //AM_LOGD("Invalid audio parameter: ", segment.char()); continue; } params_map[kv[0]] = (kv.size() > 1 ? kv[1] : ""); @@ -146,357 +106,532 @@ std::unordered_map ParseAudioParams(const std::string& return params_map; } -int a2dp_out_open(struct audio_hw_device* dev) { - struct aml_audio_device *adev = (struct aml_audio_device *)dev; +static bool a2dp_wait_status(struct aml_a2dp_hal *hal) { + hal->state = hal->a2dphw.GetState(); + int retry = 0; + while (retry < 100) { + if ((hal->state != BluetoothStreamState::STARTING) && (hal->state != BluetoothStreamState::SUSPENDING)) { + if (retry > 0) { + AM_LOGD("a2dp wait for %d ms, state:%s", + retry * A2DP_WAIT_STATE_DELAY_TIME_US / 1000, a2dpStatus2String(hal->state)); + } + return true; + } + usleep(A2DP_WAIT_STATE_DELAY_TIME_US); + retry++; + hal->state = hal->a2dphw.GetState(); + } + AM_LOGW("a2dp wait timeout for %d ms, state:%s", + retry * A2DP_WAIT_STATE_DELAY_TIME_US / 1000, a2dpStatus2String(hal->state)); + return false; +} + +static void dump_a2dp_output_data(aml_a2dp_hal *hal, const void *buffer, uint32_t size) { + if (getprop_bool("vendor.media.audiohal.a2dpdump")) { + char acFilePathStr[ENUM_TYPE_STR_MAX_LEN]; + size_t out_per_sample_byte = audio_bytes_per_sample(hal->config.format); + size_t out_channel_byte = audio_channel_count_from_out_mask(hal->config.channel_mask); + sprintf(acFilePathStr, "/data/audio/a2dp_%0.1fK_%zuC_%zuB.pcm", hal->config.sample_rate/1000.0, out_channel_byte, out_per_sample_byte); + aml_audio_dump_audio_bitstreams(acFilePathStr, buffer, size); + } +} + +static void a2dp_notify_monitor(aml_a2dp_hal *hal, bool is_sending = false) { + pthread_mutex_lock(&hal->out_monitor_thread_mutex); + hal->is_sending_data = is_sending; + pthread_cond_signal(&hal->out_monitor_thread_cond); + pthread_mutex_unlock(&hal->out_monitor_thread_mutex); +} + +static void *a2dp_out_monitor_thread(void *arg) { + struct aml_audio_device *adev = (struct aml_audio_device *)arg; + aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal; + struct timespec next_time; + uint32_t timeout_ms = 0; + bool is_standby = true; + int ret = 0; + AM_LOGI("Start monitoring the write rate+++"); + uint64_t time_ns; + while (hal->exit_out_monitor_thread == false) { + pthread_mutex_lock(&hal->out_monitor_thread_mutex); + if (is_standby) { + ret = pthread_cond_wait(&hal->out_monitor_thread_cond, &hal->out_monitor_thread_mutex); + } else { + timeout_ms = A2DP_RING_BUFFER_DELAY_TIME_MS; // 64 ms + if (hal->is_sending_data) { + timeout_ms = A2DP_SEND_DATA_TIMEOUT_RESET_MS; // 300ms + } + /* Here is an empirical value 64ms, when each write interval is greater than this value, we think standby BT, + * needed to reduce power consumption. + */ + time_ns = aml_audio_get_systime_ns(); + next_time = aml_audio_ns_to_time(time_ns + timeout_ms * NSEC_PER_MSEC); + ret = pthread_cond_timedwait(&hal->out_monitor_thread_cond, &hal->out_monitor_thread_mutex, &next_time); + } + + if (timeout_ms == A2DP_SEND_DATA_TIMEOUT_RESET_MS) { + AM_LOGV("send bt elapsed time: %" PRIu64 " ms", (aml_audio_get_systime_ns() - time_ns) / NSEC_PER_MSEC); + } + pthread_mutex_unlock(&hal->out_monitor_thread_mutex); + if (ret == ETIMEDOUT && hal->exit_out_monitor_thread == false) { + if (timeout_ms == A2DP_SEND_DATA_TIMEOUT_RESET_MS) { + AM_LOGW("send BT stack timeout %dms, need standby, cur_state:%s", timeout_ms, a2dpStatus2String(hal->state)); + } else { + AM_LOGI("audio write timeout %dms, need standby, cur_state:%s", timeout_ms, a2dpStatus2String(hal->state)); + } + a2dp_out_standby(adev); + is_standby = true; + } else { + is_standby = false; + } + } + AM_LOGI("Exit the monitor---"); + return NULL; +} + +int a2dp_out_open(struct aml_audio_device *adev) { struct aml_a2dp_hal * hal = NULL; + struct timespec ts = {.tv_sec = 0, .tv_nsec = 0}; + pthread_mutex_lock(&adev->a2dp_lock); if (adev->a2dp_hal != NULL) { - ALOGE("BluetoothAudioPortOut already exist"); + AM_LOGW("already open"); + pthread_mutex_unlock(&adev->a2dp_lock); return 0; } - ALOGD("%s: open", __func__); - - hal = new aml_a2dp_hal; + hal = (struct aml_a2dp_hal *)aml_audio_calloc(1, sizeof(struct aml_a2dp_hal)); if (hal == NULL) { - ALOGE("new BluetoothAudioPortOut fail"); + AM_LOGE("new BluetoothAudioPortOut fail"); + pthread_mutex_unlock(&adev->a2dp_lock); return -1; } hal->resample = NULL; - hal->buff = NULL; - hal->buffsize = 0; + hal->buff_conv_format = NULL; + hal->buff_size_conv_format = 0; + hal->state = BluetoothStreamState::UNKNOWN; if (!hal->a2dphw.SetUp(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP)) { - ALOGE("BluetoothAudioPortOut setup fail"); + AM_LOGE("BluetoothAudioPortOut setup fail"); + pthread_mutex_unlock(&adev->a2dp_lock); + delete hal; return -1; } if (!hal->a2dphw.LoadAudioConfig(&hal->config)) { - ALOGE("LoadAudioConfig fail"); + AM_LOGE("LoadAudioConfig fail"); } if (hal->config.channel_mask == AUDIO_CHANNEL_OUT_MONO) hal->a2dphw.ForcePcmStereoToMono(true); - + clock_gettime(CLOCK_MONOTONIC, &ts); + hal->mute_time = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000; + hal->mute_time += 1000000LL; // mute for 1s adev->a2dp_hal = (void*)hal; - ALOGD("LoadAudioConfig: rate=%d, format=%x, ch=%d", - hal->config.sample_rate, hal->config.format, hal->config.channel_mask); + pthread_mutex_unlock(&adev->a2dp_lock); + + pthread_condattr_t condattr; + pthread_mutex_init(&hal->out_monitor_thread_mutex, NULL); + pthread_condattr_init(&condattr); + pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC); + pthread_cond_init(&hal->out_monitor_thread_cond, &condattr); + pthread_condattr_destroy(&condattr); + hal->exit_out_monitor_thread = false; + hal->is_sending_data = false; + int pthread_ret = pthread_create(&hal->out_monitor_thread_id, NULL, &a2dp_out_monitor_thread, adev); + if (pthread_ret != 0) { + AM_LOGE("pthread_create fail"); + return -1; + } + AM_LOGI("Rx param rate:%d, bytes_per_sample:%zu, ch:%d", hal->config.sample_rate, + audio_bytes_per_sample(hal->config.format), audio_channel_count_from_out_mask(hal->config.channel_mask)); return 0; } -int a2dp_out_close(struct audio_hw_device* dev) { - struct aml_audio_device *adev = (struct aml_audio_device *)dev; - struct aml_a2dp_hal * hal = (struct aml_a2dp_hal *)adev->a2dp_hal; +int a2dp_out_close(struct aml_audio_device *adev) { + pthread_mutex_lock(&adev->a2dp_lock); + struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal; if (hal == NULL) { - ALOGE("a2dp hw already release"); + AM_LOGW("a2dp hw is already closed."); + pthread_mutex_unlock(&adev->a2dp_lock); return -1; } + + hal->exit_out_monitor_thread = true; + a2dp_notify_monitor(hal); + pthread_join(hal->out_monitor_thread_id, NULL); + pthread_cond_destroy(&hal->out_monitor_thread_cond); + pthread_mutex_destroy(&hal->out_monitor_thread_mutex); adev->a2dp_hal = NULL; - hal->mutex_.lock(); - ALOGD("%s: close", __func__); + AM_LOGI(""); + /*coverity[sleep]*/ + a2dp_wait_status(hal); hal->a2dphw.Stop(); hal->a2dphw.TearDown(); - if (hal->resample) - delete hal->resample; - if (hal->buff) - delete hal->buff; - hal->mutex_.unlock(); + if (hal->resample) { + aml_audio_free(hal->resample); + hal->resample = NULL; + } + if (hal->resample_buffer) { + aml_audio_free(hal->resample_buffer); + hal->resample_buffer = NULL; + hal->resample_size = 0; + } + if (hal->buff_conv_format) + aml_audio_free(hal->buff_conv_format); + pthread_mutex_unlock(&adev->a2dp_lock); delete hal; - adev->a2dp_active = 0; return 0; } -int a2dp_out_resume(struct audio_stream_out* stream) { - struct aml_stream_out* out = (struct aml_stream_out*)stream; - struct aml_audio_device *adev = out->dev; - struct aml_a2dp_hal * hal = (struct aml_a2dp_hal *)adev->a2dp_hal; - BluetoothStreamState state; - - if (hal == NULL) { - ALOGE("%s: a2dp hw is release", __func__); - return -1; - } - - std::unique_lock lock(hal->mutex_); - state = hal->a2dphw.GetState(); - ALOGD("%s: state=%d", __func__, (uint8_t)state); - if (state == BluetoothStreamState::STANDBY) { +static int a2dp_out_resume_l(aml_audio_device *adev) { + struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal; + a2dp_wait_status(hal); + if (hal->state == BluetoothStreamState::STARTED) { + AM_LOGI("A2dp already resumed. status:%s", a2dpStatus2String(hal->state)); + return 0; + } else if (hal->state == BluetoothStreamState::STANDBY) { if (hal->a2dphw.Start()) { - if ((out->flags & AUDIO_OUTPUT_FLAG_PRIMARY) == 0) - adev->a2dp_active = 1; + BluetoothStreamState cur_status = hal->a2dphw.GetState(); + AM_LOGI("status: %s -> %s Resume in progress...", a2dpStatus2String(hal->state), a2dpStatus2String(cur_status)); + hal->state = cur_status; return 0; } } + AM_LOGW("error state:%s", a2dpStatus2String(hal->state)); return -1; } -int a2dp_out_standby(struct audio_stream* stream) { - struct aml_stream_out* out = (struct aml_stream_out*)stream; - struct aml_audio_device *adev = out->dev; - struct aml_a2dp_hal * hal = (struct aml_a2dp_hal *)adev->a2dp_hal; - BluetoothStreamState state; - +static int a2dp_out_resume(struct aml_audio_device *adev) { + pthread_mutex_lock(&adev->a2dp_lock); + struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal; if (hal == NULL) { - ALOGE("%s: a2dp hw is release", __func__); + AM_LOGW("a2dp has been released."); + pthread_mutex_unlock(&adev->a2dp_lock); return -1; } + /*coverity[sleep]*/ + int32_t ret = a2dp_out_resume_l(adev); + pthread_mutex_unlock(&adev->a2dp_lock); + return ret; +} - if (adev->hal_audio_open_times > 0) { - ALOGE("%s: hal_audio_open_times=%d, not close", - __func__, adev->hal_audio_open_times); +static int a2dp_out_standby_l(struct aml_audio_device *adev) { + struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal; + a2dp_wait_status(hal); + if (hal->state == BluetoothStreamState::STANDBY) { + AM_LOGI("A2dp already standby. status:%s", a2dpStatus2String(hal->state)); return 0; - } - - std::unique_lock lock(hal->mutex_); - state = hal->a2dphw.GetState(); - ALOGD("%s: state=%d", __func__, (uint8_t)state); - if (state == BluetoothStreamState::STARTED) { + } else if (hal->state == BluetoothStreamState::STARTED) { if (hal->a2dphw.Suspend()) { - if ((out->flags & AUDIO_OUTPUT_FLAG_PRIMARY) == 0) - adev->a2dp_active = 0; + BluetoothStreamState cur_status = hal->a2dphw.GetState(); + AM_LOGI("status: %s -> %s Standby in progress...", a2dpStatus2String(hal->state), a2dpStatus2String(cur_status)); + hal->state = cur_status; return 0; } } + AM_LOGW("error state:%s", a2dpStatus2String(hal->state)); return -1; } - - -ssize_t a2dp_out_write_new(void *adev_ptr, void *hal_ptr, int is_tv_platform, int hal_rate, unsigned int flags, const void* buffer, size_t bytes) -{ - struct aml_audio_device *adev = (struct aml_audio_device *)adev_ptr; - struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)hal_ptr; - BluetoothStreamState state; - size_t totalWritten = 0; - int frame_size = 4; //2ch 16bits - size_t frames = bytes / frame_size; - +static int a2dp_out_standby(struct aml_audio_device *adev) { + pthread_mutex_lock(&adev->a2dp_lock); + struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal; if (hal == NULL) { - ALOGE("%s: a2dp hw is release", __func__); + AM_LOGW("a2dp has been released."); + pthread_mutex_unlock(&adev->a2dp_lock); return -1; } - std::unique_lock lock(hal->mutex_); - state = hal->a2dphw.GetState(); - lock.unlock(); - - if (state != BluetoothStreamState::STARTED) - { - bool wait = true; - { - lock.lock(); - state = hal->a2dphw.GetState(); - ALOGD("%s: state=%d", __func__, (uint8_t)state); - if (state == BluetoothStreamState::STANDBY) - { - if (hal->a2dphw.Start()) - { - if ((flags & AUDIO_OUTPUT_FLAG_PRIMARY) == 0) adev->a2dp_active = 1; - wait = false; - } + if (adev->hal_audio_open_times > 0) { + ALOGE("%s: hal_audio_open_times=%d, not close", + __func__, adev->hal_audio_open_times); + pthread_mutex_unlock(&adev->a2dp_lock); + return 0; + } + /*coverity[sleep]*/ + int32_t ret = a2dp_out_standby_l(adev); + pthread_mutex_unlock(&adev->a2dp_lock); + return ret; +} + +static bool a2dp_state_process(struct aml_audio_device *adev, audio_config_base_t *config, size_t cur_frames) { + aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal; + BluetoothStreamState cur_state = hal->a2dphw.GetState(); + const int64_t cur_write_time_us = aml_audio_get_systime(); + bool prepared = false; + + const int64_t write_delta_time_us = cur_write_time_us - hal->last_write_time; + int64_t data_delta_time_us = (int64_t)(cur_frames * USEC_PER_SEC / config->sample_rate) - write_delta_time_us; + hal->last_write_time = cur_write_time_us; + if (hal->state != cur_state) { + AM_LOGI("a2dp state changed: %s -> %s", a2dpStatus2String(hal->state), a2dpStatus2String(cur_state)); + hal->state = cur_state; + } + if (adev->debug_flag) { + AM_LOGD("cur_state:%s, frames:%zu, gap:%" PRId64 " ms", a2dpStatus2String(cur_state), cur_frames, write_delta_time_us / 1000); + } + + if (cur_state == BluetoothStreamState::STARTING) { + if (data_delta_time_us > 0) { + if (adev->debug_flag) { + AM_LOGD("write too fast, need sleep:%" PRId64 " ms", data_delta_time_us / 1000); } - lock.unlock(); + usleep(data_delta_time_us); } - - if (wait) usleep(10 * 1000); - return totalWritten; + } else if (cur_state == BluetoothStreamState::STARTED) { + if (adev->audio_patch && adev->tv_mute) { + /* tv_mute for atv switch channel */ + AM_LOGI("tv_mute:%d, start standby", adev->tv_mute); + a2dp_out_standby_l(adev); + } else { + prepared = true; + } + } else if (cur_state == BluetoothStreamState::DISABLED) { + // TODO: A2DP is disconnected. do nothing. + } else { + struct aml_audio_patch *patch = adev->audio_patch; + if (!(adev->tv_mute && patch)) { + a2dp_out_resume_l(adev); + } + // a2dp_out_resume maybe cause over 100ms, so set last_write_time after resume, + // otherwise, the gap would always over 64ms, and always standby in dtv + hal->last_write_time = aml_audio_get_systime(); } + return prepared; +} - if (is_tv_platform == 1) { - int16_t *tmp_buffer = (int16_t *)buffer; +static ssize_t a2dp_in_data_process(aml_a2dp_hal *hal, audio_config_base_t *config, const void *buffer, size_t bytes) { + size_t frames = 0; + int realloc_ret = 0; + if (config->channel_mask == AUDIO_CHANNEL_OUT_7POINT1 && config->format == AUDIO_FORMAT_PCM_32_BIT) { + frames = bytes / (4 * 8); + realloc_ret = aml_audio_check_and_realloc((void **)&hal->buff_conv_format, &hal->buff_size_conv_format, frames * 4); + if (realloc_ret != 0) { + AM_LOGE("aml_audio_check_and_realloc fail"); + return -1; + } + int16_t *tmp_buffer = (int16_t *)hal->buff_conv_format; int32_t *tmp_buffer_8ch = (int32_t *)buffer; - frames = bytes/32; // 8ch 32bit - for (int i=0; i<(int)frames; i++) { - tmp_buffer[2*i] = (tmp_buffer_8ch[8*i]>>16); - tmp_buffer[2*i+1] = (tmp_buffer_8ch[8*i+1]>>16); + for (int i=0; i> 16); + tmp_buffer[2 * i + 1] = (tmp_buffer_8ch[8 * i + 1] >> 16); + } + } else if (config->channel_mask == AUDIO_CHANNEL_OUT_STEREO && config->format == AUDIO_FORMAT_PCM_16_BIT) { + frames = bytes / (2 * 2); + realloc_ret = aml_audio_check_and_realloc((void **)&hal->buff_conv_format, &hal->buff_size_conv_format, bytes); + if (realloc_ret != 0) { + AM_LOGE("aml_audio_check_and_realloc fail"); + return -1; } + memcpy(hal->buff_conv_format, buffer, bytes); + } else { + AM_LOGW("not support param, channel_cnt:%d, format:%#x", + audio_channel_count_from_out_mask(config->channel_mask), config->format); + return -1; } - struct timespec ts = {.tv_sec = 0, .tv_nsec = 0}; - clock_gettime(CLOCK_MONOTONIC, &ts); + const int64_t cur_write_time_us = aml_audio_get_systime(); + if (hal->mute_time > 0) { + if (hal->mute_time > cur_write_time_us) { + memset((void*)buffer, 0, bytes); + } else { + hal->mute_time = 0; + } + } + return frames; +} - if (hal_rate != hal->config.sample_rate) { - int out_frames = 0; - int out_size = frames*hal->config.sample_rate*frame_size/hal_rate+32; - if (hal->resample == NULL) { - hal->resample = new aml_resample; +static ssize_t a2dp_data_resample_process(aml_a2dp_hal *hal, audio_config_base_t *input_cfg, + const void *buffer, size_t in_frames, const void **output_buffer) { + int out_frames = in_frames; + *output_buffer = buffer; + if (input_cfg->sample_rate != hal->config.sample_rate) { + size_t in_frame_size = audio_channel_count_from_out_mask(AUDIO_HAL_FIXED_CFG_CHANNEL) * + audio_bytes_per_sample(AUDIO_HAL_FIXED_CFG_FORMAT); + /* The resampled frames may be large than the theoretical value. + * So, there is an extra 32 bytes allocated to prevent overflows. + */ + int resample_out_buffer_size = in_frames * hal->config.sample_rate * in_frame_size / input_cfg->sample_rate + 32; + if (hal->resample == NULL || hal->resample->input_sr != input_cfg->sample_rate) { + if (hal->resample) { + delete hal->resample; + hal->resample = NULL; + } + hal->resample = (struct resample_para *)aml_audio_calloc(1, sizeof(struct resample_para)); if (hal->resample == NULL) { - ALOGD("%s: new resample_para error", __func__); - return bytes; + AM_LOGE("new aml_resample error"); + return 0; } - hal->resample->input_sr = hal_rate; + hal->resample->input_sr = input_cfg->sample_rate; hal->resample->output_sr = hal->config.sample_rate; - hal->resample->channels = 2; + hal->resample->channels = audio_channel_count_from_out_mask(AUDIO_HAL_FIXED_CFG_CHANNEL); resampler_init(hal->resample); } - if (hal->buffsize < out_size) { - if (hal->buff) - delete[] hal->buff; - hal->buff = new char[out_size]; - if (hal->buff == NULL) { - ALOGD("%s: new buff error", __func__); - return bytes; - } - hal->buffsize = out_size; + int out_size = in_frames * in_frame_size * hal->resample->output_sr / hal->resample->input_sr + 32; + int realloc_ret = aml_audio_check_and_realloc((void **)&hal->resample_buffer, &hal->resample_size, out_size); + if (realloc_ret != 0) { + AM_LOGE("aml_audio_check_and_realloc fail"); + return -1; } - out_frames = resample_process(hal->resample, frames, (int16_t*) buffer, (int16_t*) hal->buff); + out_frames = resample_process(hal->resample, in_frames, (int16_t*)buffer, (int16_t*)hal->resample_buffer); if (out_frames == 0) { - return bytes; + AM_LOGW("resample_process return 0."); + return 0; } - out_size = out_frames * frame_size; - frames = out_frames; - if (property_get_int32("vendor.media.audiohal.a2dp", 0) > 0) { - FILE *fp = fopen("/data/audio/a2dp.pcm", "a+"); - if (fp) { - int flen = fwrite((char *)hal->buff, 1, out_size, fp); - fclose(fp); - } + *output_buffer = hal->resample_buffer; + } + return out_frames; +} + +static ssize_t a2dp_out_data_process(aml_a2dp_hal *hal, audio_config_base_t *config __unused, + const void *buffer, size_t in_frames, const void **output_buffer) { + size_t in_frame_size = audio_channel_count_from_out_mask(AUDIO_HAL_FIXED_CFG_CHANNEL) * + audio_bytes_per_sample(AUDIO_HAL_FIXED_CFG_FORMAT); + ssize_t out_size = in_frames * in_frame_size; + if (hal->config.channel_mask == AUDIO_CHANNEL_OUT_MONO) { + int16_t *tmp_buffer = (int16_t *)buffer; + for (int i=0; ia2dphw.WriteData(hal->buff, out_size); - lock.unlock(); + out_size = in_frames * 1 * audio_bytes_per_sample(AUDIO_HAL_FIXED_CFG_FORMAT); + } else if (hal->config.channel_mask == AUDIO_CHANNEL_OUT_STEREO) { + /* 2channel do nothing*/ } else { - lock.lock(); - totalWritten = hal->a2dphw.WriteData(buffer, bytes); - lock.unlock(); - if (property_get_int32("vendor.media.audiohal.a2dp", 0) > 0) { - FILE *fp = fopen("/data/audio/a2dp.pcm", "a+"); - if (fp) { - int flen = fwrite((char *)buffer, 1, bytes, fp); - fclose(fp); - } - } + AM_LOGW("not support a2dp output channel_cnt:%#x", + audio_channel_count_from_out_mask(AUDIO_HAL_FIXED_CFG_CHANNEL)); + return 0; } - if (totalWritten) { - hal->last_write_time = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000; - } else { - const int64_t now = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000; - const int64_t gap = now - hal->last_write_time; - int64_t sleep_time = frames * 1000000LL / hal->config.sample_rate - gap; - hal->last_write_time = now; - if (sleep_time > 0) { - hal->last_write_time += sleep_time; - usleep(sleep_time); + + size_t out_per_sample_byte = audio_bytes_per_sample(hal->config.format); + size_t out_channel_byte = audio_channel_count_from_out_mask(hal->config.channel_mask); + out_size = out_per_sample_byte * out_channel_byte * in_frames; + if (hal->config.format != AUDIO_FORMAT_PCM_16_BIT) { + int realloc_ret = aml_audio_check_and_realloc((void **)&hal->buff_conv_format, &hal->buff_size_conv_format, out_size); + if (realloc_ret != 0) { + AM_LOGE("aml_audio_check_and_realloc fail"); + return 0; } + R_CHECK_RET(0, "realloc buff_conv_format size:%zu fail", out_size); + if (hal->config.format == AUDIO_FORMAT_PCM_32_BIT) { + memcpy_to_i32_from_i16((int32_t *)hal->buff_conv_format, (int16_t *)buffer, in_frames * out_channel_byte); + } else if (hal->config.format == AUDIO_FORMAT_PCM_24_BIT_PACKED) { + memcpy_to_p24_from_i16((uint8_t *)hal->buff_conv_format, (int16_t *)buffer, in_frames * out_channel_byte); + } else { + AM_LOGW("not support a2dp output format:%#x", hal->config.format); + return 0; + } + *output_buffer = hal->buff_conv_format; } - return totalWritten; + return out_size; } +static ssize_t a2dp_out_write_l(struct aml_audio_device *adev, audio_config_base_t *config, const void* buffer, size_t bytes) { + aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal; + int wr_size = 0; + const void *wr_buff = NULL; + ssize_t cur_frames = 0; + ssize_t resample_frames = 0; + uint32_t bytes_written = 0; + uint64_t pre_time_us = 0; + size_t sent = 0; + + if (adev->a2dp_hal == NULL) { + if (adev->debug_flag) { + AM_LOGW("a2dp_hal is null pointer"); + } + return bytes; + } + + cur_frames = a2dp_in_data_process(hal, config, buffer, bytes); + if (cur_frames < 0) { + return bytes; + } + if (!a2dp_state_process(adev, config, cur_frames)) { + a2dp_notify_monitor(hal); + return bytes; + } -ssize_t a2dp_out_write(struct audio_stream_out* stream, const void* buffer, size_t bytes) { - struct aml_stream_out* out = (struct aml_stream_out*)stream; - struct aml_audio_device *adev = out->dev; - struct aml_a2dp_hal * hal = (struct aml_a2dp_hal *)adev->a2dp_hal; - BluetoothStreamState state; - size_t totalWritten = 0; - int frame_size = 4; //2ch 16bits - size_t frames = bytes / frame_size; + resample_frames = a2dp_data_resample_process(hal, config, hal->buff_conv_format, cur_frames, &wr_buff); + if (resample_frames < 0) { + return bytes; + } - if (hal == NULL) { - ALOGE("%s: a2dp hw is release", __func__); - return -1; + wr_size = a2dp_out_data_process(hal, config, wr_buff, resample_frames, &wr_buff); + if (wr_size == 0) { + return bytes; } - std::unique_lock lock(hal->mutex_); - state = hal->a2dphw.GetState(); - if (adev->debug_flag) - ALOGD("%s:%p bytes=%d, state=%d, format=0x%x, hwsync=%d, continuous=%d,out->hal_rate=%d,hal->config.sample_rate=%d", - __func__, out, bytes, (uint8_t)state, out->hal_internal_format, - out->hw_sync_mode, adev->continuous_audio_mode, out->hal_rate, hal->config.sample_rate); - if (state != BluetoothStreamState::STARTED) { - lock.unlock(); - if (a2dp_out_resume(stream)) { - usleep(10 * 1000); - } - return totalWritten; + + if (adev->patch_src == SRC_DTV && adev->parental_control_av_mute) { + memset((void*)wr_buff, 0, wr_size); } - if (out->is_tv_platform == 1) { - int16_t *tmp_buffer = (int16_t *)buffer; - int32_t *tmp_buffer_8ch = (int32_t *)buffer; - frames = bytes/32; // 8ch 32bit - for (int i=0; i<(int)frames; i++) { - tmp_buffer[2*i] = (tmp_buffer_8ch[8*i]>>16); - tmp_buffer[2*i+1] = (tmp_buffer_8ch[8*i+1]>>16); + dump_a2dp_output_data(hal, wr_buff, wr_size); + pre_time_us = aml_audio_get_systime(); + while (bytes_written < wr_size) { + a2dp_notify_monitor(hal, true); + sent = hal->a2dphw.WriteData((char *)wr_buff + bytes_written, wr_size - bytes_written); + a2dp_notify_monitor(hal); + bytes_written += sent; + /* The cache of BT stack is about 40ms data, and exit from writing data + * after timeout of 64ms here. */ + if (bytes_written < wr_size && (aml_audio_get_systime() - pre_time_us) > 64 * USEC_PER_MSEC) { + AM_LOGW("WriteData timeout 100 ms, quit now."); + break; } } - struct timespec ts = {.tv_sec = 0, .tv_nsec = 0}; - clock_gettime(CLOCK_MONOTONIC, &ts); + return bytes; +} - if (out->hal_rate != hal->config.sample_rate) { - int out_frames = 0; - int out_size = frames*hal->config.sample_rate*frame_size/out->hal_rate+32; - if (hal->resample == NULL) { - hal->resample = new aml_resample; - if (hal->resample == NULL) { - ALOGD("%s: new resample_para error", __func__); - return bytes; - } - hal->resample->input_sr = out->hal_rate; - hal->resample->output_sr = hal->config.sample_rate; - hal->resample->channels = 2; - resampler_init(hal->resample); - } - if (hal->buffsize < out_size) { - if (hal->buff) - delete[] hal->buff; - hal->buff = new char[out_size]; - if (hal->buff == NULL) { - ALOGD("%s: new buff error", __func__); - return bytes; - } - hal->buffsize = out_size; - } - out_frames = resample_process(hal->resample, frames, (int16_t*) buffer, (int16_t*) hal->buff); - if (out_frames == 0) { - return bytes; - } - out_size = out_frames * frame_size; - frames = out_frames; - - if (property_get_int32("vendor.media.audiohal.a2dp", 0) > 0) { - FILE *fp = fopen("/data/audio/a2dp.pcm", "a+"); - if (fp) { - int flen = fwrite((char *)hal->buff, 1, out_size, fp); - fclose(fp); - } - } +ssize_t a2dp_out_write(struct aml_audio_device *adev, audio_config_base_t *config, const void* buffer, size_t bytes) { + size_t in_frame_size = audio_channel_count_from_out_mask(config->channel_mask) * audio_bytes_per_sample(config->format); + uint32_t one_ms_data = in_frame_size * config->sample_rate / 1000; + uint32_t date_len_ms = bytes / one_ms_data; + const uint32_t period_time_ms = 32; + const uint32_t period_time_size = one_ms_data * period_time_ms; - totalWritten = hal->a2dphw.WriteData(hal->buff, out_size); - } else { - totalWritten = hal->a2dphw.WriteData(buffer, bytes); - if (property_get_int32("vendor.media.audiohal.a2dp", 0) > 0) { - FILE *fp = fopen("/data/audio/a2dp.pcm", "a+"); - if (fp) { - int flen = fwrite((char *)buffer, 1, bytes, fp); - fclose(fp); - } - } + if (bytes == 0) { + AM_LOGW("bytes is 0"); + return -1; } - if (totalWritten) { - hal->last_write_time = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000; - } else { - const int64_t now = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000; - const int64_t gap = now - hal->last_write_time; - int64_t sleep_time = frames * 1000000LL / hal->config.sample_rate - gap; - hal->last_write_time = now; - if (sleep_time > 0) { - hal->last_write_time += sleep_time; - lock.unlock(); - usleep(sleep_time); + R_CHECK_POINTER_LEGAL(-1, config, ""); + R_CHECK_POINTER_LEGAL(-1, buffer, ""); + + uint32_t written_size = 0; + pthread_mutex_lock(&adev->a2dp_lock); + while (bytes > written_size) { + uint32_t remain_size = bytes - written_size; + size_t sent = remain_size; + if (remain_size > period_time_ms * one_ms_data) { + sent = period_time_size; } + /*coverity[sleep]*/ + a2dp_out_write_l(adev, config, (char *)buffer + written_size, sent); + AM_LOGV("written_size:%d, remain_size:%d, sent:%zu", written_size, remain_size, sent); + written_size += sent; } - return totalWritten; + pthread_mutex_unlock(&adev->a2dp_lock); + return written_size; } -uint32_t a2dp_out_get_latency(const struct audio_stream_out* stream) { - (void *)stream; - return 200; +uint32_t a2dp_out_get_latency(struct aml_audio_device *adev __unused) { + uint64_t remote_delay_report_ns = 0; + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH); + bool success = session_ptr->GetPresentationPosition(&remote_delay_report_ns, nullptr, nullptr); + if (!success || remote_delay_report_ns == 0) { + remote_delay_report_ns = DEFAULT_A2DP_LATENCY_NS; + } + return static_cast(remote_delay_report_ns / NSEC_PER_MSEC + A2DP_STATIC_DELAY_MS); } -int a2dp_out_set_parameters (struct audio_stream *stream, const char *kvpairs) { - struct aml_stream_out* out = (struct aml_stream_out*)stream; - struct aml_audio_device *adev = out->dev; +int a2dp_out_get_status(struct aml_audio_device *adev) { struct aml_a2dp_hal * hal = (struct aml_a2dp_hal *)adev->a2dp_hal; - - if (hal == NULL) { - ALOGE("%s: a2dp hw is release", __func__); + if (!hal) { + AM_LOGW("a2dp_hal is null"); return -1; } + return (int)hal->state; +} + +int a2dp_out_set_parameters(struct aml_audio_device *adev, const char *kvpairs) { + struct aml_a2dp_hal * hal = (struct aml_a2dp_hal *)adev->a2dp_hal; + R_CHECK_POINTER_LEGAL(-1, hal, "a2dp hw is released"); std::unordered_map params = ParseAudioParams(kvpairs); if (params.empty()) @@ -518,3 +653,18 @@ int a2dp_out_set_parameters (struct audio_stream *stream, const char *kvpairs) { return 0; } +int a2dp_hal_dump(struct aml_audio_device *adev, int fd) { + struct aml_a2dp_hal *hal = (struct aml_a2dp_hal *)adev->a2dp_hal; + if (hal) { + dprintf(fd, "-------------[AM_HAL][A2DP]-------------\n"); + dprintf(fd, "-[AML_HAL] out_rate : %10d | out_ch :%10d\n", hal->config.sample_rate, audio_channel_count_from_out_mask(hal->config.channel_mask)); + dprintf(fd, "-[AML_HAL] out_format : %#10x | cur_state :%10s\n", hal->config.format, a2dpStatus2String(hal->a2dphw.GetState())); + struct resample_para *resample = hal->resample; + if (resample) { + dprintf(fd, "-[AML_HAL] resample in_sr : %10d | out_sr :%10d\n", resample->input_sr, resample->output_sr); + dprintf(fd, "-[AML_HAL] resample ch : %10d\n", resample->channels); + } + } + return 0; +} + diff --git a/audio/audio_hal/a2dp_hal.h b/audio/audio_hal/a2dp_hal.h index afc7a1e..3102d80 100644 --- a/audio/audio_hal/a2dp_hal.h +++ b/audio/audio_hal/a2dp_hal.h @@ -24,14 +24,13 @@ extern "C" { #endif -int a2dp_out_open(struct audio_hw_device* stream); -int a2dp_out_close(struct audio_hw_device* stream); -int a2dp_out_resume(struct audio_stream_out* stream); -int a2dp_out_standby(struct audio_stream* stream); -ssize_t a2dp_out_write(struct audio_stream_out* stream, const void* buffer, size_t bytes); -ssize_t a2dp_out_write_new(void *adev_ptr, void *hal_ptr, int is_tv_platform, int hal_rate, unsigned int flags, const void* buffer, size_t bytes); -uint32_t a2dp_out_get_latency(const struct audio_stream_out* stream); -int a2dp_out_set_parameters (struct audio_stream *stream, const char *kvpairs); +int a2dp_out_open(struct aml_audio_device *adev); +int a2dp_out_close(struct aml_audio_device *adev); +ssize_t a2dp_out_write(struct aml_audio_device *adev, audio_config_base_t *config, const void* buffer, size_t bytes); +uint32_t a2dp_out_get_latency(struct aml_audio_device *adev); +int a2dp_out_set_parameters (struct aml_audio_device *adev, const char *kvpairs); +int a2dp_out_get_status(struct aml_audio_device *adev) ; +int a2dp_hal_dump(struct aml_audio_device *adev, int fd); #ifdef __cplusplus } diff --git a/audio/audio_hal/amlAudioMixer.c b/audio/audio_hal/amlAudioMixer.c index 37bd172..0c68e3b 100644 --- a/audio/audio_hal/amlAudioMixer.c +++ b/audio/audio_hal/amlAudioMixer.c @@ -15,7 +15,7 @@ */ #define LOG_TAG "amlaudioMixer" -//#define LOG_NDEBUG 0 +#define LOG_NDEBUG 0 #define DEBUG_DUMP 0 #define __USE_GNU @@ -81,7 +81,6 @@ struct amlAudioMixer { uint32_t hwsync_frame_size; pthread_t out_mixer_tid; pthread_mutex_t lock; - pthread_mutex_t locks[NR_INPORTS]; int exit_thread : 1; int mixing_enable : 1; enum mixer_state state; @@ -145,18 +144,17 @@ int init_mixer_input_port(struct amlAudioMixer *audio_mixer, ALOGE("[%s:%d] NULL pointer", __func__, __LINE__); return -EINVAL; } - + if (aml_out->inputPortID != -1) { + ALOGI("%s stream input port id %d exits delete it ",__FUNCTION__,aml_out->inputPortID); + delete_mixer_input_port(audio_mixer, aml_out->inputPortID); + aml_out->inputPortID = -1; + } /* if direct on, ie. the ALSA buffer is full, no need padding data anymore */ - - - pthread_mutex_lock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_DIRECT]); direct_on = (audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_DIRECT] != NULL); - pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_DIRECT]); port = new_input_port(MIXER_FRAME_COUNT, config, flags, volume, direct_on); port_index = mixer_get_inport_index(audio_mixer); LOG_ALWAYS_FATAL_IF(port_index > NR_INPORTS); - pthread_mutex_lock(&audio_mixer->locks[port_index]); if (audio_mixer->in_ports[port_index] != NULL) { ALOGW("[%s:%d] inport index:%s already exists! recreate", __func__, __LINE__, inportType2Str(port_index)); free_input_port(audio_mixer->in_ports[port_index]); @@ -177,7 +175,6 @@ int init_mixer_input_port(struct amlAudioMixer *audio_mixer, set_port_meta_data_cbk(port, on_meta_data_cbk, meta_data); } port->initial_frames = aml_out->frame_write_sum; - pthread_mutex_unlock(&audio_mixer->locks[port_index]); return 0; } @@ -185,47 +182,30 @@ int delete_mixer_input_port(struct amlAudioMixer *audio_mixer, unsigned int port_index) { ALOGI("[%s:%d] input port:%d", __func__, __LINE__, port_index); - pthread_mutex_lock(&audio_mixer->locks[port_index]); + if (!is_inport_valid(port_index)) + return -EINVAL; + if (audio_mixer->in_ports[port_index]) { + pthread_mutex_lock(&audio_mixer->inport_lock); free_input_port(audio_mixer->in_ports[port_index]); audio_mixer->in_ports[port_index] = NULL; audio_mixer->inportsMasks &= ~(1 << port_index); + pthread_mutex_unlock(&audio_mixer->inport_lock); } - pthread_mutex_unlock(&audio_mixer->locks[port_index]); return 0; } -void reset_mixer_all_input_port_cbk_data(struct amlAudioMixer *audio_mixer, void *data) -{ - size_t i = 0 ; - for (i = 0; i < NR_INPORTS; i++) - { - struct input_port *in_port = NULL; - pthread_mutex_lock(&audio_mixer->locks[i]); - in_port = audio_mixer->in_ports[i]; - if (in_port && in_port->notify_cbk_data == data) - { - reset_port_cbk(in_port); - } - pthread_mutex_unlock(&audio_mixer->locks[i]); - } -} - int send_mixer_inport_message(struct amlAudioMixer *audio_mixer, aml_mixer_input_port_type_e port_index , enum PORT_MSG msg) { - int ret = 0; - struct input_port *port = NULL; - pthread_mutex_lock(&audio_mixer->locks[port_index]); - port = audio_mixer->in_ports[port_index]; - if (port) ret = send_inport_message(port, msg); - else - { + struct input_port *port = audio_mixer->in_ports[port_index]; + + if (port == NULL) { ALOGE("%s(), port index %d, inval", __func__, port_index); - ret = -EINVAL; + return -EINVAL; } - pthread_mutex_unlock(&audio_mixer->locks[port_index]); - return ret; + + return send_inport_message(port, msg); } void set_mixer_hwsync_frame_size(struct amlAudioMixer *audio_mixer, @@ -273,70 +253,62 @@ uint32_t get_mixer_inport_consumed_frames( int set_mixer_inport_volume(struct amlAudioMixer *audio_mixer, aml_mixer_input_port_type_e port_index, float vol) { - struct input_port *port = NULL; - int ret = 0; - pthread_mutex_lock(&audio_mixer->locks[port_index]); - port = audio_mixer->in_ports[port_index]; + struct input_port *port = audio_mixer->in_ports[port_index]; - if (!port) - { - ALOGE("%s(), NULL pointer", __func__); - ret = -EINVAL; + if (!port) { + ALOGE("%s(), NULL pointer", __func__); + return -EINVAL; } - else - { - if (vol > 1.0 || vol < 0) - { + + if (vol > 1.0 || vol < 0) { ALOGE("%s(), invalid vol %f", __func__, vol); - ret = -EINVAL; - } - else - { - set_inport_volume(port, vol); - } + return -EINVAL; } - - pthread_mutex_unlock(&audio_mixer->locks[port_index]); - return ret; + set_inport_volume(port, vol); + return 0; } float get_mixer_inport_volume(struct amlAudioMixer *audio_mixer, aml_mixer_input_port_type_e port_index) { - float ret = 0; - struct input_port *port = NULL; - pthread_mutex_lock(&audio_mixer->locks[port_index]); - port = audio_mixer->in_ports[port_index]; - if (!port) ALOGE("%s(), NULL pointer", __func__); - else ret = get_inport_volume(port); - pthread_mutex_unlock(&audio_mixer->locks[port_index]); - return ret; + struct input_port *port = audio_mixer->in_ports[port_index]; + + if (!port) { + ALOGE("%s(), NULL pointer", __func__); + return 0; + } + return get_inport_volume(port); } int mixer_write_inport(struct amlAudioMixer *audio_mixer, unsigned int port_index, const void *buffer, int bytes) { - struct input_port *port = NULL; - int written = 0; - pthread_mutex_lock(&audio_mixer->locks[port_index]); - port = audio_mixer->in_ports[port_index]; + struct input_port *port = audio_mixer->in_ports[port_index]; + int written = 0; + int64_t cur_time_ns = 0; + struct timespec cur_timestamp; if (!port) { ALOGE("%s(), NULL pointer", __func__); - written = -EINVAL; + return -EINVAL; } - else - { - written = port->write(port, buffer, bytes); - if (get_inport_state(port) != ACTIVE) { - ALOGI("[%s:%d] input port:%s is active now", __func__, __LINE__, inportType2Str(port->enInPortType)); - set_inport_state(port, ACTIVE); - } + clock_gettime(CLOCK_MONOTONIC, &cur_timestamp); + cur_time_ns = (long long)cur_timestamp.tv_sec * 1000000000 + (long long)cur_timestamp.tv_nsec; + if (cur_time_ns - port->last_write_time_ns > port->buffer_len_ns) { + ALOGI("[%s:%d] input port:%s start write to input buffer", __func__, __LINE__, inportType2Str(port->enInPortType)); + port->first_write = true; } + port->last_write_time_ns = cur_time_ns; + + written = port->write(port, buffer, bytes); + if (get_inport_state(port) != ACTIVE) { + ALOGI("[%s:%d] input port:%s is active now", __func__, __LINE__, inportType2Str(port->enInPortType)); + set_inport_state(port, ACTIVE); + } + ALOGV("%s(), signal line %d portIndex %d", __func__, __LINE__, port_index); - pthread_mutex_unlock(&audio_mixer->locks[port_index]); return written; } @@ -344,38 +316,30 @@ int mixer_read_inport(struct amlAudioMixer *audio_mixer, unsigned int port_index, void *buffer, int bytes) { struct input_port *port = audio_mixer->in_ports[port_index]; - if (port) return port->read(port, buffer, bytes); + if (!port) { + ALOGE("%s(), NULL pointer", __func__); + return -EINVAL; + } - ALOGE("%s(), NULL pointer", __func__); - return -EINVAL; + return port->read(port, buffer, bytes); } //not used function int mixer_set_inport_state(struct amlAudioMixer *audio_mixer, aml_mixer_input_port_type_e port_index, enum port_state state) { - int ret = 0; - struct input_port *port = NULL; - pthread_mutex_lock(&audio_mixer->locks[port_index]); - port = audio_mixer->in_ports[port_index]; - if (!port) ret = -EINVAL; - else ret = set_inport_state(port, state); - pthread_mutex_unlock(&audio_mixer->locks[port_index]); - return ret; + struct input_port *port = audio_mixer->in_ports[port_index]; + + return set_inport_state(port, state); } //use used function enum port_state mixer_get_inport_state(struct amlAudioMixer *audio_mixer, aml_mixer_input_port_type_e port_index) { - enum port_state ret = IDLE; - struct input_port *port = NULL; - //pthread_mutex_lock(&audio_mixer->locks[port_index]); - port = audio_mixer->in_ports[port_index]; - if (!port) ALOGE("%s %d: no inport for index %d", __func__, __LINE__, (int)port_index); - else ret = get_inport_state(port); - //pthread_mutex_unlock(&audio_mixer->locks[port_index]); - return ret; + struct input_port *port = audio_mixer->in_ports[port_index]; + + return get_inport_state(port); } //TODO: handle message queue static void mixer_procs_msg_queue(struct amlAudioMixer *audio_mixer __unused) @@ -452,63 +416,47 @@ int delete_mixer_output_port(struct amlAudioMixer *audio_mixer, static int mixer_output_write(struct amlAudioMixer *audio_mixer) { + struct aml_audio_device *adev = audio_mixer->adev; enum MIXER_OUTPUT_PORT port_index = 0; struct output_port *out_port = audio_mixer->out_ports[port_index]; - struct input_port *in_port_direct = NULL; - struct input_port *in_port_system = NULL; struct aml_stream_out *out = NULL; - struct aml_a2dp_hal *hal = NULL; - struct aml_audio_device *adev = NULL; - int64_t elasp = 0; - unsigned int hal_rate = 0; - int is_tv_platform = 0; - bool is_a2dp = false; - unsigned int flags = 0; - - pthread_mutex_lock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_DIRECT]); - pthread_mutex_lock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]); - - in_port_direct = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_DIRECT]; - in_port_system = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_SYSTEM]; - - if (in_port_direct) pthread_mutex_lock(&in_port_direct->cbk_lock); - if (in_port_system) pthread_mutex_lock(&in_port_system->cbk_lock); - - if (in_port_direct && in_port_direct->notify_cbk_data) { - out = (struct aml_stream_out *)in_port_direct->notify_cbk_data; - } else if (in_port_system && in_port_system->notify_cbk_data) { - out = (struct aml_stream_out *)in_port_system->notify_cbk_data; - } - out_port->sound_track_mode = audio_mixer->adev->sound_track_mode; - if (out) - { - is_a2dp = (out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP); - hal = out->dev->a2dp_hal; - is_tv_platform = out->is_tv_platform; - hal_rate = out->hal_rate; - flags = out->flags; - adev = out->dev; + struct input_port *in_port; + audio_config_base_t in_data_config = {48000, AUDIO_CHANNEL_OUT_STEREO, AUDIO_FORMAT_PCM_16_BIT}; + unsigned int masks = 0; + pthread_mutex_lock(&audio_mixer->inport_lock); + masks = audio_mixer->inportsMasks; + while (masks) { + int i = 31 - __builtin_clz(masks); + masks &= ~(1 << i); + in_port = audio_mixer->in_ports[i]; + if (NULL == in_port) { + continue; + } + if (in_port->enInPortType == AML_MIXER_INPUT_PORT_PCM_DIRECT && in_port->notify_cbk_data) { + out = (struct aml_stream_out *)in_port->notify_cbk_data; + break; + } + if ((in_port->enInPortType == AML_MIXER_INPUT_PORT_PCM_SYSTEM) && in_port->notify_cbk_data) { + out = (struct aml_stream_out *)in_port->notify_cbk_data; + } + if ((in_port->enInPortType == AML_MIXER_INPUT_PORT_PCM_MMAP) && (out == NULL) && in_port->notify_cbk_data) { + out = (struct aml_stream_out *)in_port->notify_cbk_data; + } } + pthread_mutex_unlock(&audio_mixer->inport_lock); - if (in_port_direct) pthread_mutex_unlock(&in_port_direct->cbk_lock); - if (in_port_system) pthread_mutex_unlock(&in_port_system->cbk_lock); - - //NOTE: Please unlock mutex here or serious BT audio discontinous problem - pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_DIRECT]); - pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]); - - while (is_output_data_avail(audio_mixer, port_index)) - { - if (is_a2dp && adev) - a2dp_out_write_new(adev, hal, is_tv_platform, hal_rate, flags, out_port->data_buf, out_port->bytes_avail); - else { - pthread_mutex_lock(&audio_mixer->adev->alsa_pcm_lock); - out_port->write(out_port, out_port->data_buf, out_port->bytes_avail); - pthread_mutex_unlock(&audio_mixer->adev->alsa_pcm_lock); - } + out_port->sound_track_mode = audio_mixer->adev->sound_track_mode; + while (is_output_data_avail(audio_mixer, port_index)) { + // out_write_callbacks(); + if (out && (adev->out_device & AUDIO_DEVICE_OUT_ALL_A2DP)) { + a2dp_out_write(adev, &in_data_config, out_port->data_buf, out_port->bytes_avail); + } else { + pthread_mutex_lock(&audio_mixer->adev->alsa_pcm_lock); + out_port->write(out_port, out_port->data_buf, out_port->bytes_avail); + pthread_mutex_unlock(&audio_mixer->adev->alsa_pcm_lock); + } set_outport_data_avail(out_port, 0); } - return 0; } @@ -516,38 +464,45 @@ static int mixer_output_write(struct amlAudioMixer *audio_mixer) static int mixer_update_tstamp(struct amlAudioMixer *audio_mixer) { - struct input_port *in_port = NULL; struct output_port *out_port = audio_mixer->out_ports[MIXER_OUTPUT_PORT_PCM]; + struct input_port *in_port = NULL; unsigned int avail; + unsigned int masks = audio_mixer->inportsMasks; //struct timespec *timestamp; - pthread_mutex_lock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]); - in_port = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_SYSTEM]; + while (masks) { + int i = 31 - __builtin_clz(masks); + masks &= ~(1 << i); + if (NULL == audio_mixer->in_ports[i]) { + continue; + } + if (audio_mixer->in_ports[i]->enInPortType == AML_MIXER_INPUT_PORT_PCM_SYSTEM) { + in_port = audio_mixer->in_ports[i]; + } - /*only deal with system audio */ - if (in_port == NULL || out_port == NULL) - { - pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]); - return 0; - } + /*only deal with system audio */ + if (in_port == NULL || out_port == NULL) + continue; + if (out_port->pcm_handle == NULL) + continue; - if (pcm_get_htimestamp(out_port->pcm_handle, &avail, &in_port->timestamp) == 0) { - size_t kernel_buf_size = DEFAULT_KERNEL_FRAMES; - int64_t signed_frames = (int64_t)in_port->mix_consumed_frames - kernel_buf_size + avail; - if (signed_frames < 0) { - signed_frames = 0; + if (pcm_get_htimestamp(out_port->pcm_handle, &avail, &in_port->timestamp) == 0) { + size_t kernel_buf_size = DEFAULT_KERNEL_FRAMES; + int64_t signed_frames = in_port->mix_consumed_frames - kernel_buf_size + avail; + if (signed_frames < 0) { + signed_frames = 0; + } + in_port->presentation_frames = in_port->initial_frames + signed_frames; + ALOGV("%s() present frames:%lld, initial %lld, consumed %lld, sec:%ld, nanosec:%ld", + __func__, + in_port->presentation_frames, + in_port->initial_frames, + in_port->mix_consumed_frames, + in_port->timestamp.tv_sec, + in_port->timestamp.tv_nsec); } - in_port->presentation_frames = in_port->initial_frames + signed_frames; - ALOGV("%s() present frames:%lld, initial %lld, consumed %lld, sec:%ld, nanosec:%ld", - __func__, - in_port->presentation_frames, - in_port->initial_frames, - in_port->mix_consumed_frames, - in_port->timestamp.tv_sec, - in_port->timestamp.tv_nsec); } - pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]); return 0; } @@ -560,7 +515,7 @@ static bool is_mixer_inports_ready(struct amlAudioMixer *audio_mixer) ALOGV("%s() port index %d, port ptr %p", __func__, port_index, in_port); if (in_port) { port_cnt++; - if (in_port->rbuf_ready(in_port)) { + if (in_port->rbuf_avail(in_port) >= in_port->data_len_bytes) { ALOGV("port %d data ready", port_index); ready++; } else { @@ -616,8 +571,7 @@ static int update_inport_avail(struct input_port *in_port) { // first throw away the padding frames if (in_port->padding_frames > 0) { - if (in_port->data_buf_frame_cnt > in_port->padding_frames) in_port->padding_frames -= in_port->data_buf_frame_cnt; - else in_port->padding_frames = 0; + in_port->padding_frames -= in_port->data_buf_frame_cnt; set_inport_pts_valid(in_port, false); } else { in_port->mix_consumed_frames += in_port->data_buf_frame_cnt; @@ -664,13 +618,11 @@ int mixer_flush_inport(struct amlAudioMixer *audio_mixer, int ret = 0; struct input_port *in_port = NULL; //NOTE: Do not lock here - //pthread_mutex_lock(&audio_mixer->locks[port_index]); in_port = audio_mixer->in_ports[port_index]; if (!in_port) ret = -EINVAL; else ret = reset_input_port(in_port); - //pthread_mutex_unlock(&audio_mixer->locks[port_index]); return ret; } @@ -678,16 +630,15 @@ static int mixer_inports_read(struct amlAudioMixer *audio_mixer) { unsigned int port_index = 0; - unsigned int masks = audio_mixer->inportsMasks; - + unsigned int masks = 0; ALOGV("++%s(), line %d", __func__, __LINE__); + pthread_mutex_lock(&audio_mixer->inport_lock); + masks = audio_mixer->inportsMasks; while (masks) { struct input_port *in_port; int ID = 31 - __builtin_clz(masks); masks &= ~(1 << ID); - - pthread_mutex_lock(&audio_mixer->locks[ID]); in_port = audio_mixer->in_ports[ID]; if (in_port) { int ret = 0, fade_out = 0, fade_in = 0; @@ -707,29 +658,36 @@ static int mixer_inports_read(struct amlAudioMixer *audio_mixer) set_inport_state(in_port, ACTIVE); } else if (state == STOPPED || state == PAUSED || state == FLUSHED) { ALOGV("[%s:%d] input port:%s stopped, paused or flushed", __func__, __LINE__, inportType2Str(type)); - pthread_mutex_unlock(&audio_mixer->locks[ID]); continue; } else if (state == FLUSHING) { mixer_flush_inport(audio_mixer, ID); ALOGI("[%s:%d] input port:%s flushing->flushed", __func__, __LINE__, inportType2Str(type)); set_inport_state(in_port, FLUSHED); - pthread_mutex_unlock(&audio_mixer->locks[ID]); continue; } if (get_inport_state(in_port) == ACTIVE && in_port->data_valid) { ALOGI("[%s:%d] input port:%s data already valid", __func__, __LINE__, inportType2Str(type)); - pthread_mutex_unlock(&audio_mixer->locks[ID]); continue; } } else { if (in_port->data_valid) { ALOGI("[%s:%d] input port ID:%d data already valid", __func__, __LINE__, ID); - pthread_mutex_unlock(&audio_mixer->locks[ID]); continue; } } - if (in_port->rbuf_ready(in_port)) { + int input_avail_size = in_port->rbuf_avail(in_port); + ALOGV("[%s:%d] input port:%s, portId:%d, avail:%d, masks:%#x, inportsMasks:%#x, data_len_bytes:%d", __func__, __LINE__, + inportType2Str(type), ID, input_avail_size, masks, audio_mixer->inportsMasks, in_port->data_len_bytes); + if (input_avail_size >= in_port->data_len_bytes) { + if (in_port->first_write == true) { + if (input_avail_size < in_port->inport_start_threshold) { + continue; + } else { + ALOGI("[%s:%d] input port:%s first start, portId:%d, avail:%d", __func__, __LINE__, inportType2Str(type), ID, input_avail_size); + in_port->first_write = false; + } + } ret = mixer_read_inport(audio_mixer, ID, in_port->data, in_port->data_len_bytes); if (ret == (int)in_port->data_len_bytes) { if (fade_out) { @@ -760,10 +718,8 @@ static int mixer_inports_read(struct amlAudioMixer *audio_mixer) } } } - - pthread_mutex_unlock(&audio_mixer->locks[ID]); } - + pthread_mutex_unlock(&audio_mixer->inport_lock); return 0; } @@ -1120,10 +1076,11 @@ static int mixer_add_mixing_data(void *pMixedBuf, struct input_port *pInputPort, static int mixer_do_mixing_16bit(struct amlAudioMixer *audio_mixer) { + bool is_data_valid = false; struct input_port *pstInputPort = NULL; struct output_port *pstOutPort = audio_mixer->out_ports[MIXER_OUTPUT_PORT_PCM]; struct aml_audio_device *adev = audio_mixer->adev; - unsigned int masks = audio_mixer->inportsMasks; + unsigned int masks = 0; if (NULL == pstOutPort) { ALOGE("[%s:%d] outport is null", __func__, __LINE__); @@ -1131,27 +1088,27 @@ static int mixer_do_mixing_16bit(struct amlAudioMixer *audio_mixer) } memset(audio_mixer->tmp_buffer, 0, MIXER_FRAME_COUNT * MIXER_OUT_FRAME_SIZE); + pthread_mutex_lock(&audio_mixer->inport_lock); + masks = audio_mixer->inportsMasks; while (masks) { struct input_port *in_port; int i = 31 - __builtin_clz(masks); masks &= ~(1 << i); - pthread_mutex_lock(&audio_mixer->locks[i]); pstInputPort = audio_mixer->in_ports[i]; if (NULL == pstInputPort) { - pthread_mutex_unlock(&audio_mixer->locks[i]); continue; } if (0 == pstInputPort->data_valid) { if (adev->debug_flag) { - ALOGI("[%s:%d] inport:%s, but no valid data, maybe underrun", __func__, __LINE__, inportType2Str(i)); + ALOGI("[%s:%d] inport:%s, but no valid data, maybe underrun", __func__, __LINE__, inportType2Str(pstInputPort->enInPortType)); } - pthread_mutex_unlock(&audio_mixer->locks[i]); continue; } + is_data_valid = true; if (getprop_bool("vendor.media.audiohal.indump")) { char acFilePathStr[ENUM_TYPE_STR_MAX_LEN]; - sprintf(acFilePathStr, "/data/audio/%s.pcm", inportType2Str(i)); + sprintf(acFilePathStr, "/data/audio/%s_%d", inportType2Str(pstInputPort->enInPortType), pstInputPort->ID); aml_audio_dump_audio_bitstreams(acFilePathStr, pstInputPort->data, pstInputPort->data_len_bytes); } if (AML_MIXER_INPUT_PORT_PCM_DIRECT == pstInputPort->enInPortType) { @@ -1162,13 +1119,23 @@ static int mixer_do_mixing_16bit(struct amlAudioMixer *audio_mixer) pstInputPort->bytes_to_insert -= pstInputPort->data_len_bytes; ALOGD("[%s:%d] PCM_DIRECT inport insert mute data, still need %zu, inserted length %zu", __func__, __LINE__, pstInputPort->bytes_to_insert, pstInputPort->data_len_bytes); - pthread_mutex_unlock(&audio_mixer->locks[i]); continue; } } mixer_add_mixing_data(audio_mixer->tmp_buffer, pstInputPort, pstOutPort); - pthread_mutex_unlock(&audio_mixer->locks[i]); } + + /* only check the valid on a2dp case, normal alsa output we need continuous output, + * otherwise it will cause noise at the end + */ + if (!is_data_valid && (adev->out_device & AUDIO_DEVICE_OUT_ALL_A2DP)) { + if (adev->debug_flag) { + ALOGI("[%s:%d] inport no valid data", __func__, __LINE__); + } + pthread_mutex_unlock(&audio_mixer->inport_lock); + return -1; + } + if (adev->is_TV) { apply_volume(adev->sink_gain[OUTPORT_SPEAKER], audio_mixer->tmp_buffer, sizeof(uint16_t), MIXER_FRAME_COUNT * pstOutPort->cfg.frame_size); @@ -1194,6 +1161,7 @@ static int mixer_do_mixing_16bit(struct amlAudioMixer *audio_mixer) adev->wifi_audio_mode_started = false; } set_outport_data_avail(pstOutPort, MIXER_FRAME_COUNT * pstOutPort->cfg.frame_size); + pthread_mutex_unlock(&audio_mixer->inport_lock); return 0; } @@ -1201,19 +1169,9 @@ int notify_mixer_input_avail(struct amlAudioMixer *audio_mixer) { aml_mixer_input_port_type_e port_index = 0; for (port_index = 0; port_index < AML_MIXER_INPUT_PORT_BUTT; port_index++) { - struct input_port *in_port = NULL; - pthread_mutex_lock(&audio_mixer->locks[port_index]); - in_port = audio_mixer->in_ports[port_index]; - if (in_port) - { - pthread_mutex_lock(&in_port->cbk_lock); - if (in_port->on_input_avail_cbk) - { - in_port->on_input_avail_cbk(in_port->input_avail_cbk_data); - } - pthread_mutex_unlock(&in_port->cbk_lock); - } - pthread_mutex_unlock(&audio_mixer->locks[port_index]); + struct input_port *in_port = audio_mixer->in_ports[port_index]; + if (in_port && in_port->on_input_avail_cbk) + in_port->on_input_avail_cbk(in_port->input_avail_cbk_data); } return 0; @@ -1223,11 +1181,9 @@ int notify_mixer_exit(struct amlAudioMixer *audio_mixer) { aml_mixer_input_port_type_e port_index = 0; for (port_index = 0; port_index < AML_MIXER_INPUT_PORT_BUTT; port_index++) { - pthread_mutex_lock(&audio_mixer->locks[port_index]); struct input_port *in_port = audio_mixer->in_ports[port_index]; if (in_port && in_port->on_notify_cbk) in_port->on_notify_cbk(in_port->notify_cbk_data); - pthread_mutex_unlock(&audio_mixer->locks[port_index]); } return 0; @@ -1326,8 +1282,8 @@ static uint32_t get_mixer_inport_count(struct amlAudioMixer *audio_mixer) static void mixer_outport_feed_silence_frames(struct amlAudioMixer *audio_mixer) { struct output_port *out_port = get_outport(audio_mixer, MIXER_OUTPUT_PORT_PCM); - struct input_port *in_port_direct = NULL; - struct input_port *in_port_system = NULL; + struct input_port *in_port_direct = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_DIRECT]; + struct input_port *in_port_system = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_SYSTEM]; struct aml_stream_out *out = NULL; if (out_port == NULL) { @@ -1341,22 +1297,12 @@ static void mixer_outport_feed_silence_frames(struct amlAudioMixer *audio_mixer) size_t bytes = frames * out_port->cfg.frame_size; - pthread_mutex_lock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_DIRECT]); - pthread_mutex_lock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]); - in_port_direct = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_DIRECT]; - in_port_system = audio_mixer->in_ports[AML_MIXER_INPUT_PORT_PCM_SYSTEM]; - - if (in_port_direct && in_port_direct->notify_cbk_data) { out = (struct aml_stream_out *)in_port_direct->notify_cbk_data; } else if (in_port_system && in_port_system->notify_cbk_data) { out = (struct aml_stream_out *)in_port_system->notify_cbk_data; } - - pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_DIRECT]); - pthread_mutex_unlock(&audio_mixer->locks[AML_MIXER_INPUT_PORT_PCM_SYSTEM]); - /*for a2dp, we don't need feed silence data*/ if (out && (out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP)) { return; @@ -1422,14 +1368,15 @@ static void *mixer_16b_threadloop(void *data) uint32_t mixer_get_inport_latency_frames(struct amlAudioMixer *audio_mixer, aml_mixer_input_port_type_e port_index) { - struct input_port *port = NULL; - uint32_t frames = 0; - pthread_mutex_lock(&audio_mixer->locks[port_index]); - port = audio_mixer->in_ports[port_index]; - if (port) frames = port->get_latency_frames(port); - else ALOGE("%s(), NULL pointer", __func__); - pthread_mutex_unlock(&audio_mixer->locks[port_index]); - return frames; + struct input_port *port = audio_mixer->in_ports[port_index]; + int written = 0; + + if (!port) { + ALOGE("%s(), NULL pointer", __func__); + return 0; + } + + return port->get_latency_frames(port); } int32_t mixer_get_outport_latency_frames(struct amlAudioMixer *audio_mixer) @@ -1506,8 +1453,6 @@ struct amlAudioMixer *newAmlAudioMixer( { struct amlAudioMixer *audio_mixer = NULL; int ret = 0; - size_t i = 0; - ALOGD("%s()", __func__); if (!pcm_handle) { @@ -1530,19 +1475,17 @@ struct amlAudioMixer *newAmlAudioMixer( audio_mixer->frame_size_tmp = 2 * audio_bytes_per_sample(cfg.format); mixer_set_state(audio_mixer, MIXER_IDLE); + audio_mixer->adev = adev; ret = init_mixer_output_port(audio_mixer, pcm_handle, cfg, MIXER_FRAME_COUNT); if (ret < 0) { ALOGE("%s(), init mixer out port failed", __func__); goto err_state; } - audio_mixer->adev = adev; audio_mixer->inportsMasks = 0; audio_mixer->supportedInportsMasks = (1 << NR_INPORTS) - 1; pthread_mutex_init(&audio_mixer->lock, NULL); - for (i = 0 ; i < NR_INPORTS; i++) pthread_mutex_init(&audio_mixer->locks[i], NULL); - - + pthread_mutex_init(&audio_mixer->inport_lock, NULL); return audio_mixer; err_state: @@ -1557,10 +1500,9 @@ err_tmp: void freeAmlAudioMixer(struct amlAudioMixer *audio_mixer) { - size_t i = 0; if (audio_mixer) { pthread_mutex_destroy(&audio_mixer->lock); - for (i = 0 ; i < NR_INPORTS; i++) pthread_mutex_destroy(&audio_mixer->locks[i]); + pthread_mutex_destroy(&audio_mixer->inport_lock); free(audio_mixer); } } @@ -1580,29 +1522,38 @@ int mixer_get_presentation_position( uint64_t *frames, struct timespec *timestamp) { + pthread_mutex_lock(&audio_mixer->inport_lock); + struct input_port *port = NULL; + + if (!frames || !timestamp) { + pthread_mutex_unlock(&audio_mixer->inport_lock); + return -EINVAL; + } + + if (!is_inport_valid(port_index)) { + *frames = 0; + timestamp->tv_sec = 0; + timestamp->tv_nsec = 0; + pthread_mutex_unlock(&audio_mixer->inport_lock); + return -EINVAL; + } - int ret = 0; - struct input_port *port = NULL; - pthread_mutex_lock(&audio_mixer->locks[port_index]); port = audio_mixer->in_ports[port_index]; - if (port) - { - *frames = port->presentation_frames; - *timestamp = port->timestamp; - if (!is_inport_pts_valid(port)) - { - ALOGW("%s(), not valid now", __func__); - ret = -EINVAL; - } + if (!port) { + ALOGW("%s(), port not ready now", __func__); + pthread_mutex_unlock(&audio_mixer->inport_lock); + return -EINVAL; } - else - { - ALOGW("%s(), port not ready now", __func__); - ret = -EINVAL; + + *frames = port->presentation_frames; + *timestamp = port->timestamp; + if (!is_inport_pts_valid(port)) { + ALOGW("%s(), not valid now", __func__); + pthread_mutex_unlock(&audio_mixer->inport_lock); + return -EINVAL; } - pthread_mutex_unlock(&audio_mixer->locks[port_index]); - - return ret; + pthread_mutex_unlock(&audio_mixer->inport_lock); + return 0; } int mixer_set_padding_size( @@ -1610,17 +1561,12 @@ int mixer_set_padding_size( aml_mixer_input_port_type_e port_index, int padding_bytes) { - int ret = 0; - struct input_port *port = NULL; - pthread_mutex_lock(&audio_mixer->locks[port_index]); - port = audio_mixer->in_ports[port_index]; + struct input_port *port = audio_mixer->in_ports[port_index]; if (!port) { ALOGE("%s(), NULL pointer", __func__); - ret = -EINVAL; + return -EINVAL; } - ret = set_inport_padding_size(port, padding_bytes); - pthread_mutex_unlock(&audio_mixer->locks[port_index]); - return ret; + return set_inport_padding_size(port, padding_bytes); } int mixer_outport_pcm_restart(struct amlAudioMixer *audio_mixer) diff --git a/audio/audio_hal/aml_audio_stream.h b/audio/audio_hal/aml_audio_stream.h index 380a4e5..0543756 100755 --- a/audio/audio_hal/aml_audio_stream.h +++ b/audio/audio_hal/aml_audio_stream.h @@ -69,8 +69,13 @@ enum digital_format { enum stream_write_func { OUT_WRITE_NEW = 0, MIXER_AUX_BUFFER_WRITE_SM = 1, - MIXER_AUX_BUFFER_WRITE = 2, - MIXER_MAIN_BUFFER_WRITE = 3, + MIXER_MAIN_BUFFER_WRITE_SM = 2, + MIXER_MMAP_BUFFER_WRITE_SM = 3, + MIXER_AUX_BUFFER_WRITE = 4, + MIXER_MAIN_BUFFER_WRITE = 5, + MIXER_APP_BUFFER_WRITE = 6, + PROCESS_BUFFER_WRITE = 7, + MIXER_WRITE_FUNC_MAX }; diff --git a/audio/audio_hal/aml_audio_timer.h b/audio/audio_hal/aml_audio_timer.h index 74d7158..6b74b4c 100644 --- a/audio/audio_hal/aml_audio_timer.h +++ b/audio/audio_hal/aml_audio_timer.h @@ -20,6 +20,14 @@ #include +#define MSEC_PER_SEC 1000L +#define USEC_PER_MSEC 1000L +#define NSEC_PER_USEC 1000L +#define NSEC_PER_MSEC 1000000L +#define USEC_PER_SEC 1000000L +#define NSEC_PER_SEC 1000000000LL +#define FSEC_PER_SEC 1000000000000000LL + int aml_audio_sleep(uint64_t us); uint64_t aml_audio_get_systime(void); diff --git a/audio/audio_hal/audio_hw.c b/audio/audio_hal/audio_hw.c index 16193a8..47ea49a 100755 --- a/audio/audio_hal/audio_hw.c +++ b/audio/audio_hal/audio_hw.c @@ -160,28 +160,24 @@ #define DISABLE_CONTINUOUS_OUTPUT "persist.vendor.audio.continuous.disable" -#define ENUM_USECASE_TYPE_TO_STR(x, pStr) ENUM_TYPE_TO_STR(x, strlen("STREAM_"), pStr) + struct amlAudioMixer; -extern void reset_mixer_all_input_port_cbk_data(struct amlAudioMixer *audio_mixer, void *data); +//extern void reset_mixer_all_input_port_cbk_data(struct amlAudioMixer *audio_mixer, void *data); -const char* usecase2Str(stream_usecase_t enUsecase) +const char* usecase2Str(stream_usecase_t type) { - static char acTypeStr[ENUM_TYPE_STR_MAX_LEN]; - char *pStr = "INVALID"; - switch (enUsecase) { - ENUM_USECASE_TYPE_TO_STR(STREAM_PCM_NORMAL, pStr) - ENUM_USECASE_TYPE_TO_STR(STREAM_PCM_DIRECT, pStr) - ENUM_USECASE_TYPE_TO_STR(STREAM_PCM_HWSYNC, pStr) - ENUM_USECASE_TYPE_TO_STR(STREAM_RAW_DIRECT, pStr) - ENUM_USECASE_TYPE_TO_STR(STREAM_RAW_HWSYNC, pStr) - ENUM_USECASE_TYPE_TO_STR(STREAM_PCM_PATCH, pStr) - ENUM_USECASE_TYPE_TO_STR(STREAM_RAW_PATCH, pStr) - ENUM_USECASE_TYPE_TO_STR(STREAM_PCM_MMAP, pStr) - ENUM_USECASE_TYPE_TO_STR(STREAM_USECASE_MAX, pStr) - } - sprintf(acTypeStr, "[%d]%s", enUsecase, pStr); - return acTypeStr; + ENUM_TYPE_TO_STR_START("STREAM_"); + ENUM_TYPE_TO_STR(STREAM_PCM_NORMAL) + ENUM_TYPE_TO_STR(STREAM_PCM_DIRECT) + ENUM_TYPE_TO_STR(STREAM_PCM_HWSYNC) + ENUM_TYPE_TO_STR(STREAM_RAW_DIRECT) + ENUM_TYPE_TO_STR(STREAM_RAW_HWSYNC) + ENUM_TYPE_TO_STR(STREAM_PCM_PATCH) + ENUM_TYPE_TO_STR(STREAM_RAW_PATCH) + ENUM_TYPE_TO_STR(STREAM_PCM_MMAP) + ENUM_TYPE_TO_STR(STREAM_USECASE_MAX) + ENUM_TYPE_TO_STR_END } static const struct pcm_config pcm_config_out = { @@ -1200,10 +1196,6 @@ static int do_output_standby (struct aml_stream_out *out) int i = 0; ALOGD ("%s(%p)", __FUNCTION__, out); - - if ((out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) && adev->a2dp_hal) - a2dp_out_standby(&out->stream.common); - if (!out->standby) { //commit here for hwsync/mix stream hal mixer //pcm_close(out->pcm); @@ -1270,10 +1262,6 @@ static int do_output_standby_direct (struct aml_stream_out *out) struct aml_audio_device *adev = out->dev; ALOGI ("%s,out %p, out->standby=%d", __FUNCTION__, out, out->standby); - - if ((out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) && adev->a2dp_hal) - a2dp_out_standby(&out->stream.common); - if (!out->standby) { if (out->buffer) { free (out->buffer); @@ -4853,12 +4841,6 @@ static void adev_close_output_stream(struct audio_hw_device *dev, out->resample_outbuf = NULL; } pthread_mutex_unlock(&out->lock); - - if (out->dev && out->dev->sm && out->dev->sm->mixerData) - { - reset_mixer_all_input_port_cbk_data(out->dev->sm->mixerData, out); - } - free(stream); ALOGD("%s: exit", __func__); } @@ -5143,12 +5125,19 @@ static int adev_set_parameters (struct audio_hw_device *dev, const char *kvpairs adev->a2dp_connect = 0; adev->out_device &= (~val); adev->out_devices &= (~val); - a2dp_out_close(dev); + a2dp_out_close(adev); + adev->bt_avrcp_supported = false; ALOGI("adev_set_parameters a2dp disconnect: %x, device=%x\n", val, adev->out_device); } goto exit; } + ret = str_parms_get_int(parms, "hal_param_bt_avrcp_supported", &val); + if (ret >= 0) { + adev->bt_avrcp_supported = (val != 0); + goto exit; + } + // HDMI cable plug in ret = str_parms_get_int(parms, "connect", &val); if (ret >= 0) { @@ -5168,7 +5157,7 @@ static int adev_set_parameters (struct audio_hw_device *dev, const char *kvpairs adev->a2dp_connect = 1; adev->out_device |= val; adev->out_devices |= val; - a2dp_out_open(dev); + a2dp_out_open(adev); ALOGI("adev_set_parameters a2dp connect: %x, device=%x\n", val, adev->out_device); } goto exit; @@ -6539,7 +6528,6 @@ int do_output_standby_l(struct audio_stream *stream) if ((eDolbyMS12Lib == adev->dolby_lib_type) && (ms12->dolby_ms12_enable == true)) { get_dolby_ms12_cleanup(&adev->ms12); } - a2dp_out_standby(stream); } /* @@ -7477,6 +7465,7 @@ ssize_t hw_write (struct audio_stream_out *stream ALOGV ("+%s() buffer %p bytes %zu", __func__, buffer, bytes); struct aml_stream_out *aml_out = (struct aml_stream_out *) stream; struct aml_audio_device *adev = aml_out->dev; + audio_config_base_t in_data_config = {48000, AUDIO_CHANNEL_OUT_STEREO, AUDIO_FORMAT_PCM_16_BIT}; const uint16_t *tmp_buffer = buffer; int16_t *effect_tmp_buf = NULL; bool is_dtv = (adev->patch_src == SRC_DTV); @@ -7490,6 +7479,11 @@ ssize_t hw_write (struct audio_stream_out *stream int adjust_ms = 0; int alsa_port = -1; + if (adev->is_TV && audio_is_linear_pcm(output_format)) { + in_data_config.channel_mask = AUDIO_CHANNEL_OUT_7POINT1; + in_data_config.format = AUDIO_FORMAT_PCM_32_BIT; + } + adev->debug_flag = aml_audio_get_debug_flag(); if (adev->debug_flag) { ALOGI("+%s() buffer %p bytes %zu, format %#x", __func__, buffer, bytes, output_format); @@ -7660,7 +7654,7 @@ ssize_t hw_write (struct audio_stream_out *stream while (adjust_bytes > 0) { write_size = adjust_bytes > 1024 ? 1024 : adjust_bytes; if (adev->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) { - ret = a2dp_out_write(stream, (void*)buf, write_size); + a2dp_out_write(adev, &in_data_config, (void*)buf, write_size); } else { ret = aml_alsa_output_write(stream, (void*)buf, write_size); } @@ -7683,7 +7677,7 @@ ssize_t hw_write (struct audio_stream_out *stream } } if (adev->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) { - ret = a2dp_out_write(stream, buffer, bytes); + a2dp_out_write(adev, &in_data_config, buffer, bytes); } else { ret = aml_alsa_output_write(stream, (void *) buffer, bytes); } @@ -9499,6 +9493,7 @@ int adev_open_output_stream_new(struct audio_hw_device *dev, } ret = initSubMixingInput(aml_out, config); aml_out->bypass_submix = false; + aml_out->inputPortID = -1; if (ret < 0) { ALOGE("initSub mixing input failed"); } @@ -11174,6 +11169,13 @@ static int adev_set_audio_port_config (struct audio_hw_device *dev, const struct case OUTPORT_HDMI_ARC: aml_dev->sink_gain[outport] = 1.0; break; + case OUTPORT_A2DP: + /* For scenarios that do not support AVRCP, audio_hal control is required. */ + aml_dev->sink_gain[outport] = DbToAmpl((float)(config->gain.values[0] / 100)); + if (aml_dev->bt_avrcp_supported && aml_dev->sink_gain[outport] > FLOAT_ZERO) { + aml_dev->sink_gain[outport] = 1.0; + } + break; case OUTPORT_SPEAKER: aml_dev->sink_gain[outport] = DbToAmpl((float)(config->gain.values[0] / 100)); break; @@ -11215,7 +11217,11 @@ static int adev_set_audio_port_config (struct audio_hw_device *dev, const struct case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER: outport = OUTPORT_A2DP; + /* For scenarios that do not support AVRCP, audio_hal control is required. */ aml_dev->sink_gain[outport] = DbToAmpl((float)(config->gain.values[0] / 100)); + if (aml_dev->bt_avrcp_supported && aml_dev->sink_gain[outport] > FLOAT_ZERO) { + aml_dev->sink_gain[outport] = 1.0; + } break; default: ALOGE ("%s: invalid out device type %#x", diff --git a/audio/audio_hal/audio_hw.h b/audio/audio_hal/audio_hw.h index 698b8f1..9ea22b0 100644 --- a/audio/audio_hal/audio_hw.h +++ b/audio/audio_hal/audio_hw.h @@ -310,9 +310,10 @@ struct aml_audio_device { struct audio_config output_config; struct aml_arc_hdmi_desc hdmi_descs; int arc_hdmi_updated; - int a2dp_active; int a2dp_updated; void * a2dp_hal; + pthread_mutex_t a2dp_lock; + bool bt_avrcp_supported; int a2dp_connect; int hdmi_format_updated; struct aml_native_postprocess native_postprocess; diff --git a/audio/audio_hal/audio_hw_utils.c b/audio/audio_hal/audio_hw_utils.c index 0516638..2653701 100755 --- a/audio/audio_hal/audio_hw_utils.c +++ b/audio/audio_hal/audio_hw_utils.c @@ -47,6 +47,7 @@ #include "alsa_device_parser.h" #include "a2dp_hal.h" #include "aml_audio_avsync_table.h" +#include "dolby_lib_api.h" #ifdef LOG_NDEBUG_FUNCTION #define LOGFUNC(...) ((void)0) @@ -782,7 +783,7 @@ uint32_t out_get_outport_latency(const struct audio_stream_out *stream) int frames = 0, latency_ms = 0; if (out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) { - return a2dp_out_get_latency(stream); + return a2dp_out_get_latency(adev); } if (is_stream_using_mixer(out)) { @@ -809,6 +810,7 @@ static bool is_4x_rate_fmt(int codec_type) uint32_t out_get_latency_frames(const struct audio_stream_out *stream) { const struct aml_stream_out *out = (const struct aml_stream_out *)stream; + struct aml_audio_device *adev = out->dev; snd_pcm_sframes_t frames = 0; uint32_t whole_latency_frames; int ret = 0; @@ -819,7 +821,10 @@ uint32_t out_get_latency_frames(const struct audio_stream_out *stream) mul = 4; if (out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) { - return a2dp_out_get_latency(stream)*out->hal_rate/1000; + if (eDolbyMS12Lib == adev->dolby_lib_type) + return a2dp_out_get_latency(adev)*48; + else + return a2dp_out_get_latency(adev)*out->hal_rate/1000; } whole_latency_frames = out->config.period_size * out->config.period_count; @@ -836,6 +841,7 @@ uint32_t out_get_latency_frames(const struct audio_stream_out *stream) uint32_t out_get_alsa_latency_frames(const struct audio_stream_out *stream) { const struct aml_stream_out *out = (const struct aml_stream_out *)stream; + struct aml_audio_device *adev = out->dev; snd_pcm_sframes_t frames = 0; uint32_t whole_latency_frames; int ret = 0; @@ -846,7 +852,10 @@ uint32_t out_get_alsa_latency_frames(const struct audio_stream_out *stream) mul = 4; if (out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) { - return a2dp_out_get_latency(stream)*out->hal_rate/1000; + if (eDolbyMS12Lib == adev->dolby_lib_type) + return a2dp_out_get_latency(adev)*48; + else + return a2dp_out_get_latency(adev)*out->hal_rate/1000; } whole_latency_frames = out->config.period_size * out->config.period_count / 2; @@ -880,7 +889,7 @@ uint32_t out_get_ms12_latency_frames(const struct audio_stream_out *stream) } if (ms12_out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) { - return a2dp_out_get_latency(stream)*ms12_out->hal_rate/1000; + return a2dp_out_get_latency(adev)*48; } whole_latency_frames = config->start_threshold; diff --git a/audio/audio_hal/audio_hw_utils.h b/audio/audio_hal/audio_hw_utils.h index 78d5ba3..7316451 100644 --- a/audio/audio_hal/audio_hw_utils.h +++ b/audio/audio_hal/audio_hw_utils.h @@ -24,16 +24,57 @@ #include "aml_audio_stream.h" #define ENUM_TYPE_STR_MAX_LEN (100) +#define REPORT_DECODED_INFO "/sys/class/amaudio/codec_report_info" +#define AML_DEBUG_AUDIOINFO_REPORT_PROPERTY "vendor.media.audio.info.report.debug" +#define DUMP_AUDIO_INFO_DECODE (0x1000) //use to enable the audio report info prop -#define ENUM_TYPE_TO_STR(x, offset, pStr) \ -case x: { \ - pStr = #x; \ - pStr += offset; \ - if (strlen(#x) - offset > 70) { \ - pStr += 70; \ +#define ENUM_TYPE_TO_STR_DEFAULT_STR "INVALID_ENUM" +#define ENUM_TYPE_TO_STR_START(prefix) \ + const char *pStr = ENUM_TYPE_TO_STR_DEFAULT_STR; \ + int prefixLen = strlen(prefix); \ + switch (type) { +#define ENUM_TYPE_TO_STR(x) \ + case x: \ + pStr = #x; \ + pStr += prefixLen; \ + if (strlen(#x) - prefixLen > 70) { \ + pStr += 70; \ + } \ + break; +#define ENUM_TYPE_TO_STR_END \ + default: \ + break; \ } \ - break; \ -} + return pStr; + +#define AM_LOGV(fmt, ...) ALOGV("[%s:%d] " fmt, __func__,__LINE__, ##__VA_ARGS__) +#define AM_LOGD(fmt, ...) ALOGD("[%s:%d] " fmt, __func__,__LINE__, ##__VA_ARGS__) +#define AM_LOGI(fmt, ...) ALOGI("[%s:%d] " fmt, __func__,__LINE__, ##__VA_ARGS__) +#define AM_LOGW(fmt, ...) ALOGW("[%s:%d] " fmt, __func__,__LINE__, ##__VA_ARGS__) +#define AM_LOGE(fmt, ...) ALOGE("[%s:%d] " fmt, __func__,__LINE__, ##__VA_ARGS__) + +#define R_CHECK_RET(ret, fmt, ...) \ + if (ret != 0) { \ + AM_LOGE("ret:%d " fmt, ret, ##__VA_ARGS__); \ + return ret; \ + } + +#define NO_R_CHECK_RET(ret, fmt, ...) \ + if (ret != 0) { \ + AM_LOGE("ret:%d " fmt, ret, ##__VA_ARGS__); \ + } + +#define R_CHECK_PARAM_LEGAL(ret, param, min, max, fmt, ...) \ + if ((int)param < min || param > max) { \ + AM_LOGE("%s:%d is illegal, min:%d, max:%d " fmt, #param, param, min, max, ##__VA_ARGS__);\ + return ret; \ + } + +#define R_CHECK_POINTER_LEGAL(ret, pointer, fmt, ...) \ + if (pointer == NULL) { \ + AM_LOGE("%s is null pointer " fmt, #pointer, ##__VA_ARGS__); \ + return ret; \ + } int64_t aml_gettime(void); int get_sysfs_uint(const char *path, uint *value); diff --git a/audio/audio_hal/audio_port.c b/audio/audio_hal/audio_port.c index ce3212e..4640b98 100644 --- a/audio/audio_hal/audio_port.c +++ b/audio/audio_hal/audio_port.c @@ -32,21 +32,15 @@ #define BUFF_CNT (4) #define SYS_BUFF_CNT (4) -#define ENUM_INPUT_PORT_TYPE_TO_STR(x, pStr) ENUM_TYPE_TO_STR(x, strlen("AML_MIXER_INPUT_PORT_"), pStr) - -const char *inportType2Str(aml_mixer_input_port_type_e enInportType) -{ - static char acTypeStr[ENUM_TYPE_STR_MAX_LEN]; - char *pStr = "INVALID"; - switch (enInportType) { - ENUM_INPUT_PORT_TYPE_TO_STR(AML_MIXER_INPUT_PORT_INVAL, pStr) - ENUM_INPUT_PORT_TYPE_TO_STR(AML_MIXER_INPUT_PORT_PCM_SYSTEM, pStr) - ENUM_INPUT_PORT_TYPE_TO_STR(AML_MIXER_INPUT_PORT_PCM_DIRECT, pStr) - ENUM_INPUT_PORT_TYPE_TO_STR(AML_MIXER_INPUT_PORT_PCM_MMAP, pStr) - ENUM_INPUT_PORT_TYPE_TO_STR(AML_MIXER_INPUT_PORT_BUTT, pStr) - } - sprintf(acTypeStr, "[%d]%s", enInportType, pStr); - return acTypeStr; +const char* inportType2Str(aml_mixer_input_port_type_e type) +{ + ENUM_TYPE_TO_STR_START("AML_MIXER_INPUT_PORT_"); + ENUM_TYPE_TO_STR(AML_MIXER_INPUT_PORT_INVAL) + ENUM_TYPE_TO_STR(AML_MIXER_INPUT_PORT_PCM_SYSTEM) + ENUM_TYPE_TO_STR(AML_MIXER_INPUT_PORT_PCM_DIRECT) + ENUM_TYPE_TO_STR(AML_MIXER_INPUT_PORT_PCM_MMAP) + ENUM_TYPE_TO_STR(AML_MIXER_INPUT_PORT_BUTT) + ENUM_TYPE_TO_STR_END } static ssize_t input_port_write(struct input_port *port, const void *buffer, int bytes) @@ -82,7 +76,7 @@ int inport_buffer_level(struct input_port *port) return get_buffer_read_space(port->r_buf); } -bool ring_buf_ready(struct input_port *port) +int get_inport_avail_size(struct input_port *port) { int read_avail = get_buffer_read_space(port->r_buf); @@ -91,7 +85,7 @@ bool ring_buf_ready(struct input_port *port) __func__, port->enInPortType, read_avail, port->data_len_bytes); } - return (read_avail >= (int)port->data_len_bytes); + return read_avail; } bool is_direct_flags(audio_output_flags_t flags) { @@ -312,6 +306,11 @@ struct input_port *new_input_port( ALOGE("init ring buffer fail, buffer_size = %d", input_port_rbuf_size); goto err_rbuf_init; } + port->inport_start_threshold = 0; + /* increase the input size to prevent underrun */ + if (enPortType == AML_MIXER_INPUT_PORT_PCM_MMAP) { + port->inport_start_threshold = input_port_rbuf_size / 2; + } port->enInPortType = enPortType; //port->format = config->format; @@ -320,9 +319,12 @@ struct input_port *new_input_port( port->data = data; port->data_buf_frame_cnt = buf_frames; port->data_len_bytes = thunk_size; + port->buffer_len_ns = (input_port_rbuf_size / port->cfg.frame_size) * 1000000000LL / port->cfg.sampleRate; + port->first_write = true; + port->last_write_time_ns = 0; port->read = input_port_read; port->write = input_port_write; - port->rbuf_ready = ring_buf_ready; + port->rbuf_avail = get_inport_avail_size; port->get_latency_frames = inport_get_latency_frames; port->port_status = STOPPED; port->is_hwsync = false; diff --git a/audio/audio_hal/audio_port.h b/audio/audio_hal/audio_port.h index 90977b8..e0be4ce 100644 --- a/audio/audio_hal/audio_port.h +++ b/audio/audio_hal/audio_port.h @@ -87,6 +87,7 @@ struct input_port { char *data; /* input port temp buffer. */ size_t data_buf_frame_cnt; /* input port temp buffer, data frames for one cycle. */ size_t data_len_bytes; /* input port temp buffer, data size for one cycle. */ + int64_t buffer_len_ns; /* input port temp buffer, input buffer size, the unit is ns. */ int data_valid; size_t bytes_to_insert; /* insert 0 data count index. Units: Byte */ @@ -97,7 +98,7 @@ struct input_port { ssize_t (*write)(struct input_port *port, const void *buffer, int bytes); ssize_t (*read)(struct input_port *port, void *buffer, int bytes); uint32_t (*get_latency_frames)(struct input_port *port); - bool (*rbuf_ready)(struct input_port *port); + int (*rbuf_avail)(struct input_port *port); void *notify_cbk_data; int (*on_notify_cbk)(void *data); void *input_avail_cbk_data; @@ -117,6 +118,9 @@ struct input_port { uint64_t presentation_frames; int padding_frames; bool pts_valid; + bool first_write; + int inport_start_threshold; + int64_t last_write_time_ns; pthread_mutex_t cbk_lock; }; @@ -199,6 +203,6 @@ int set_inport_pts_valid(struct input_port *in_port, bool valid); bool is_inport_pts_valid(struct input_port *in_port); void outport_pcm_restart(struct output_port *port); -const char *inportType2Str(aml_mixer_input_port_type_e enInportType); +const char *inportType2Str(aml_mixer_input_port_type_e type); #endif /* _AUDIO_PORT_H_ */ diff --git a/audio/audio_hal/sub_mixing_factory.c b/audio/audio_hal/sub_mixing_factory.c index baa175a..ee6d2bc 100755 --- a/audio/audio_hal/sub_mixing_factory.c +++ b/audio/audio_hal/sub_mixing_factory.c @@ -1,6 +1,6 @@ #define LOG_TAG "audio-subMixingFactory" -//#define LOG_NDEBUG 0 +#define LOG_NDEBUG 0 #define __USE_GNU #include @@ -109,7 +109,9 @@ static int initSubMixngOutput( } return 0; err: - pcm_close(pcm); + if (pcm != NULL) { + pcm_close(pcm); + } return res; }; @@ -171,7 +173,7 @@ static ssize_t aml_out_write_to_mixer(struct audio_stream_out *stream, const voi //usleep((bytes- written_total) * 1000 / 5 / 48); //if (out->port_index == 1) { - ts_wait_time_us(&ts, 1000); + ts_wait_time_us(&ts, 5000); ALOGV("-%s() wait....", __func__); pthread_mutex_lock(&out->cond_lock); pthread_cond_timedwait(&out->cond, &out->cond_lock, &ts); @@ -313,7 +315,7 @@ exit: //TODO if (out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) latency_frames = mixer_get_inport_latency_frames(audio_mixer, out->inputPortID) - + a2dp_out_get_latency(stream) * out->hal_rate / 1000; + + a2dp_out_get_latency(adev) * out->hal_rate / 1000; else { int outport_latency_frame = mixer_get_outport_latency_frames(audio_mixer); @@ -779,7 +781,8 @@ static int deleteSubMixingInputPcm(struct aml_stream_out *out) ALOGI("%s(), cnt_stream_using_mixer %d", __func__, sm->cnt_stream_using_mixer); - //delete_mixer_input_port(audio_mixer, out->port_index); + delete_mixer_input_port(audio_mixer, out->inputPortID); + out->inputPortID = -1; struct meta_data_list *mdata_list; struct listnode *item; @@ -1119,15 +1122,10 @@ ssize_t mixer_aux_buffer_write_sm(struct audio_stream_out *stream, const void *b } if (adev->debug_flag) { - ALOGD("[%s:%d] stream:%p, out_device:%#x, bytes:%d, a2dp_active=%d, out->flags=0x%x,hal_internal_format=0x%x", __func__, __LINE__, - stream, aml_out->out_device, bytes, adev->a2dp_active, aml_out->flags, aml_out->hal_internal_format); + ALOGD("[%s:%d] stream:%p, out_device:%#x, bytes:%d, out->flags=0x%x,hal_internal_format=0x%x", __func__, __LINE__, + stream, aml_out->out_device, bytes, aml_out->flags, aml_out->hal_internal_format); } - if ((aml_out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) && (adev->a2dp_active == 1) - && (aml_out->hal_internal_format != AUDIO_FORMAT_PCM_16_BIT)) { - //aml_hw_mixer_write(&adev->hw_mixer, buffer, bytes); - goto exit; - } if (adev->out_device != aml_out->out_device) { ALOGD("[%s:%d] stream:%p, switch from device:%#x to device:%#x", __func__, __LINE__, stream, adev->out_device, aml_out->out_device); @@ -1142,6 +1140,8 @@ ssize_t mixer_aux_buffer_write_sm(struct audio_stream_out *stream, const void *b if (aml_out->standby) { char *padding_buf = NULL; int padding_bytes = 512 * 4 * 8; + if (aml_out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) + padding_bytes = 0; //set_thread_affinity(); init_mixer_input_port(sm->mixerData, &aml_out->audioCfg, aml_out->flags, @@ -1201,8 +1201,8 @@ exit: if (aml_out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) { - uint64_t latency_frames = mixer_get_inport_latency_frames(sm->mixerData, aml_out->enInputPortType) - + a2dp_out_get_latency(stream) * aml_out->hal_rate / 1000; + uint64_t latency_frames = mixer_get_inport_latency_frames(sm->mixerData, aml_out->inputPortID) + + a2dp_out_get_latency(adev) * aml_out->hal_rate / 1000; if (aml_out->frame_write_sum > latency_frames) aml_out->last_frames_postion = aml_out->frame_write_sum - latency_frames; else @@ -1353,9 +1353,11 @@ static int usecase_change_validate_l_sm(struct aml_stream_out *aml_out, bool is_ } } else if (STREAM_PCM_MMAP == aml_out->usecase) { aml_out->write = mixer_mmap_buffer_write_sm; + aml_out->write_func = MIXER_MMAP_BUFFER_WRITE_SM; ALOGI("%s(), mixer_mmap_buffer_write_sm !", __FUNCTION__); } else { aml_out->write = mixer_main_buffer_write_sm; + aml_out->write_func = MIXER_MAIN_BUFFER_WRITE_SM; ALOGI("%s(), mixer_main_buffer_write_sm !", __FUNCTION__); } @@ -1440,9 +1442,7 @@ int out_standby_subMixingPCM(struct audio_stream *stream) aml_out->status = STREAM_STANDBY; aml_out->standby = true; delete_mixer_input_port(audio_mixer, aml_out->inputPortID); - - if ((aml_out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) && adev->a2dp_hal) - a2dp_out_standby(stream); + aml_out->inputPortID = -1; if (aml_out->hwsync_extractor) { delete_hw_avsync_header_extractor(aml_out->hwsync_extractor); @@ -1484,8 +1484,6 @@ static int out_pause_subMixingPCM(struct audio_stream_out *stream) send_mixer_inport_message(audio_mixer, aml_out->inputPortID, MSG_PAUSE); aml_out->pause_status = true; - if (aml_out->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) - a2dp_out_standby(&stream->common); ALOGI("-%s()", __func__); return 0; } @@ -1607,13 +1605,11 @@ int switchNormalStream(struct aml_stream_out *aml_out, bool on) aml_out->stream.write = out_write_subMixingPCM; aml_out->stream.common.standby = out_standby_subMixingPCM; out_standby_subMixingPCM((struct audio_stream *)aml_out); - aml_out->write_func = MIXER_AUX_BUFFER_WRITE_SM; } else { aml_out->stream.write = out_write_new;//mixer_aux_buffer_write; aml_out->stream.common.standby = out_standby_new; deleteSubMixingInputPcm(aml_out); out_standby_new((struct audio_stream *)aml_out); - aml_out->write_func = OUT_WRITE_NEW; } return 0; diff --git a/audio/utils/aml_malloc_debug.c b/audio/utils/aml_malloc_debug.c index 5c3dde4..ea3698f 100644 --- a/audio/utils/aml_malloc_debug.c +++ b/audio/utils/aml_malloc_debug.c @@ -247,3 +247,25 @@ void aml_audio_debug_malloc_showinfo(uint32_t level) return; } + +int aml_audio_check_and_realloc(void** pointer, size_t* cur_size, size_t need_size) +{ + if (pointer == NULL || cur_size == NULL) { + ALOGE("[%s:%d] pointer:%p or cur_size:%p is null", __func__, __LINE__, pointer, cur_size); + return -1; + } + + if (*cur_size < need_size || *pointer == NULL) { + void *p = aml_audio_realloc(*pointer, need_size); + if (p == NULL) { + ALOGE("[%s:%d] realloc buffer failed size:%zu", __func__, __LINE__, need_size); + return -ENOMEM; + } else { + memset(p, 0, need_size); + *pointer = p; + } + *cur_size = need_size; + } + return 0; +} + diff --git a/audio/utils/include/aml_malloc_debug.h b/audio/utils/include/aml_malloc_debug.h index df689f1..99c44fe 100644 --- a/audio/utils/include/aml_malloc_debug.h +++ b/audio/utils/include/aml_malloc_debug.h @@ -41,5 +41,6 @@ void* aml_audio_debug_realloc(void* pointer, size_t bytes, char * file_name, uin void* aml_audio_debug_calloc(size_t nmemb, size_t bytes, char * file_name, uint32_t line); void aml_audio_debug_free(void* pointer); void aml_audio_debug_malloc_showinfo(uint32_t level); +int aml_audio_check_and_realloc(void** pointer, size_t* cur_size, size_t need_size); #endif -- 2.17.1