pinebuds/services/audioflinger/audioflinger.c

3141 lines
84 KiB
C

/***************************************************************************
*
* Copyright 2015-2019 BES.
* All rights reserved. All unpublished rights reserved.
*
* No part of this work may be used or reproduced in any form or by any
* means, or stored in a database or retrieval system, without prior written
* permission of BES.
*
* Use of this work is governed by a license granted by BES.
* This work contains confidential and proprietary information of
* BES. which is protected by copyright, trade secret,
* trademark and other intellectual property rights.
*
****************************************************************************/
#include "audioflinger.h"
#include "codec_int.h"
#include "codec_tlv32aic32.h"
#include "hal_btpcm.h"
#include "hal_codec.h"
#include "hal_dma.h"
#include "hal_i2s.h"
#include "hal_spdif.h"
#include "hal_tdm.h"
#include "analog.h"
#include "hal_cmu.h"
#include "hal_timer.h"
#include "hal_trace.h"
#include "pmu.h"
#include "string.h"
#include "tgt_hardware.h"
#include "cmsis.h"
#ifdef __RAND_FROM_MIC__
#include "randfrommic.h"
#endif
#ifdef TWS_PROMPT_SYNC
extern void tws_playback_ticks_check_for_mix_prompt(void);
#endif
#ifdef RTOS
#include "cmsis_os.h"
#else
#include "hal_sleep.h"
#endif
#ifdef AUDIO_OUTPUT_SW_LIMITER
#include "floatlimiter.h"
#endif
#define AF_TRACE_DEBUG() // TRACE(2,"%s:%d\n", __func__, __LINE__)
// #define AF_STREAM_ID_0_PLAYBACK_FADEOUT
// #define CORRECT_SAMPLE_VALUE
#ifdef AUDIO_OUTPUT_DC_CALIB
#ifdef CHIP_BEST1000
#define AUDIO_OUTPUT_DC_CALIB_SW
#define AUDIO_OUTPUT_PA_ON_FADE_IN
#if !(defined(__TWS__) || defined(IBRT))
#define AUDIO_OUTPUT_PA_OFF_FADE_OUT
#endif
#elif (defined(__TWS__) || defined(IBRT)) && !defined(ANC_APP)
#define AUDIO_OUTPUT_PA_ON_FADE_IN
#endif // !CHIP_BEST1000 && __TWS__
#elif defined(AUDIO_OUTPUT_DC_CALIB_ANA) && \
(defined(__TWS__) || defined(IBRT)) && !defined(ANC_APP)
#define AUDIO_OUTPUT_PA_ON_FADE_IN
#endif // !AUDIO_OUTPUT_DC_CALIB && AUDIO_OUTPUT_DC_CALIB_ANA && __TWS__
#define AF_FADE_OUT_SIGNAL_ID 15
#define AF_FADE_IN_SIGNAL_ID 14
/* config params */
#define AF_CODEC_INST HAL_CODEC_ID_0
#define AF_SPDIF_INST HAL_SPDIF_ID_0
#define AF_BTPCM_INST HAL_BTPCM_ID_0
#define AF_CPU_WAKE_USER HAL_CPU_WAKE_LOCK_USER_AUDIOFLINGER
#define AF_CODEC_RIGHT_CHAN_ATTN 0.968277856 // -0.28 dB
#define AF_CODEC_VOL_UPDATE_STEP 0.00002
#define AF_CODEC_DC_MAX_SCALE 32767
#define AF_CODEC_DC_STABLE_INTERVAL MS_TO_TICKS(4)
#ifdef AUDIO_OUTPUT_PA_OFF_FADE_OUT
#define AF_CODEC_PA_RESTART_INTERVAL MS_TO_TICKS(160)
#else
#define AF_CODEC_PA_RESTART_INTERVAL MS_TO_TICKS(8)
#endif
// The following might have been defined in tgt_hardware.h
#ifndef AF_CODEC_FADE_IN_MS
#define AF_CODEC_FADE_IN_MS 20
#endif
#ifndef AF_CODEC_FADE_OUT_MS
#define AF_CODEC_FADE_OUT_MS 20
#endif
#define AF_CODEC_FADE_MIN_SAMPLE_CNT 200
#define PP_PINGPANG(v) (v == PP_PING ? PP_PANG : PP_PING)
#ifdef AUDIO_ANC_FB_ADJ_MC
#define AF_STACK_SIZE (1024 * 10)
#else
#ifndef AF_STACK_SIZE
#define AF_STACK_SIZE (1024 * 8)
#endif
#endif
#if defined(AUDIO_ANC_FB_MC) && defined(ANC_APP)
#define DYNAMIC_AUDIO_BUFFER_COUNT
#endif
#ifdef DYNAMIC_AUDIO_BUFFER_COUNT
#define MAX_AUDIO_BUFFER_COUNT 16
#define MIN_AUDIO_BUFFER_COUNT 2
#define AUDIO_BUFFER_COUNT (role->dma_desc_cnt)
#else
#define MAX_AUDIO_BUFFER_COUNT 4
#define AUDIO_BUFFER_COUNT MAX_AUDIO_BUFFER_COUNT
#if (AUDIO_BUFFER_COUNT & 0x1)
#error "AUDIO_BUFFER_COUNT must be an even number"
#endif
#endif
/* internal use */
enum AF_BOOL_T { AF_FALSE = 0, AF_TRUE = 1 };
enum AF_RESULT_T { AF_RES_SUCCESS = 0, AF_RES_FAILD = 1 };
enum AF_DAC_PA_STATE_T {
AF_DAC_PA_NULL,
AF_DAC_PA_ON_TRIGGER,
AF_DAC_PA_ON_SOFT_START,
AF_DAC_PA_OFF_TRIGGER,
AF_DAC_PA_OFF_SOFT_END,
AF_DAC_PA_OFF_SOFT_END_DONE,
AF_DAC_PA_OFF_DC_START,
};
// status machine
enum AF_STATUS_T {
AF_STATUS_NULL = 0x00,
AF_STATUS_OPEN_CLOSE = 0x01,
AF_STATUS_STREAM_OPEN_CLOSE = 0x02,
AF_STATUS_STREAM_START_STOP = 0x04,
AF_STATUS_STREAM_PAUSE_RESTART = 0x08,
AF_STATUS_MASK = 0x0F,
};
struct af_stream_ctl_t {
enum AF_PP_T pp_index; // pingpong operate
uint8_t pp_cnt; // use to count the lost signals
uint8_t status; // status machine
enum AUD_STREAM_USE_DEVICE_T use_device;
};
struct af_stream_cfg_t {
// used inside
struct af_stream_ctl_t ctl;
// dma buf parameters, RAM can be alloced in different way
uint8_t *dma_buf_ptr;
uint32_t dma_buf_size;
// store stream cfg parameters
struct AF_STREAM_CONFIG_T cfg;
// dma cfg parameters
#ifdef DYNAMIC_AUDIO_BUFFER_COUNT
uint8_t dma_desc_cnt;
#endif
struct HAL_DMA_DESC_T dma_desc[MAX_AUDIO_BUFFER_COUNT];
struct HAL_DMA_CH_CFG_T dma_cfg;
// callback function
AF_STREAM_HANDLER_T handler;
};
static struct af_stream_cfg_t af_stream[AUD_STREAM_ID_NUM][AUD_STREAM_NUM];
static uint8_t af_sig_lost_cnt[AUD_STREAM_ID_NUM][AUD_STREAM_NUM];
static AF_CODEC_PLAYBACK_POST_HANDLER_T codec_play_post_hdlr;
#ifdef AUDIO_OUTPUT_SW_GAIN
volatile static float saved_output_coef;
#ifdef AUDIO_OUTPUT_SW_LIMITER
static FloatLimiterPtr FloatLimiterP;
#else
typedef struct {
float coefs_b[3];
float coefs_a[3];
float history_x[2];
float history_y[2];
} SW_GAIN_IIR_T;
SW_GAIN_IIR_T sw_gain_iir = {
.coefs_b = {0.00000042780818597736f, 0.00000085561637195472f,
0.00000042780818597736f},
.coefs_a = {1.00000000000000000000f, -1.99738371810092970000f,
0.99738542933367369000f},
.history_x = {0, 0},
.history_y = {0, 0},
};
#endif
#endif
#ifdef AUDIO_OUTPUT_DC_CALIB
static bool dac_dc_valid;
#ifdef AUDIO_OUTPUT_DC_CALIB_SW
static int16_t dac_dc[2];
#endif
#endif
#if defined(AUDIO_OUTPUT_PA_ON_FADE_IN) || defined(AUDIO_OUTPUT_PA_OFF_FADE_OUT)
static volatile enum AF_DAC_PA_STATE_T dac_pa_state;
static uint32_t dac_dc_start_time;
static uint32_t dac_pa_stop_time;
#endif
#if defined(AUDIO_OUTPUT_PA_OFF_FADE_OUT) && defined(RTOS)
static osThreadId fade_thread_id;
#ifdef AF_STREAM_ID_0_PLAYBACK_FADEOUT
#error "Cannot enable 2 kinds of fade out codes at the same time"
#endif
#endif
#ifdef RTOS
#ifdef AF_STREAM_ID_0_PLAYBACK_FADEOUT
struct af_stream_fade_out_t {
bool stop_on_process;
uint8_t stop_process_cnt;
osThreadId stop_request_tid;
uint32_t need_fadeout_len;
uint32_t need_fadeout_len_processed;
};
static struct af_stream_fade_out_t af_stream_fade_out = {
.stop_on_process = false,
.stop_process_cnt = 0,
.stop_request_tid = NULL,
.need_fadeout_len = 0,
.need_fadeout_len_processed = 0,
};
#endif
static osThreadId af_thread_tid;
static void af_thread(void const *argument);
osThreadDef(af_thread, osPriorityAboveNormal, 1, AF_STACK_SIZE,
"audio_flinger");
static int af_default_priority;
osMutexId audioflinger_mutex_id = NULL;
osMutexDef(audioflinger_mutex);
static AF_IRQ_NOTIFICATION_T irq_notif;
#else // !RTOS
static volatile uint32_t af_flag_lock;
#endif // RTOS
#ifdef CODEC_DSD
static bool af_dsd_enabled;
#endif
void af_lock_thread(void) {
void *POSSIBLY_UNUSED lr = __builtin_return_address(0);
#ifdef RTOS
osMutexWait(audioflinger_mutex_id, osWaitForever);
#else
static void *POSSIBLY_UNUSED locked_lr;
ASSERT(af_flag_lock == 0, "audioflinger has been locked by %p. LR=%p",
(void *)locked_lr, (void *)lr);
af_flag_lock = 1;
locked_lr = lr;
#endif
}
void af_unlock_thread(void) {
void *POSSIBLY_UNUSED lr = __builtin_return_address(0);
#ifdef RTOS
osMutexRelease(audioflinger_mutex_id);
#else
static void *POSSIBLY_UNUSED unlocked_lr;
ASSERT(af_flag_lock == 1,
"audioflinger not locked before (lastly unlocked by %p). LR=%p",
(void *)unlocked_lr, (void *)lr);
af_flag_lock = 0;
unlocked_lr = lr;
#endif
}
#if defined(RTOS) && defined(AF_STREAM_ID_0_PLAYBACK_FADEOUT)
int af_stream_fadeout_start(uint32_t sample) {
TRACE(1, "fadein_config sample:%d", sample);
af_stream_fade_out.need_fadeout_len = sample;
af_stream_fade_out.need_fadeout_len_processed = sample;
return 0;
}
int af_stream_fadeout_stop(void) {
af_stream_fade_out.stop_process_cnt = 0;
af_stream_fade_out.stop_on_process = false;
return 0;
}
uint32_t af_stream_fadeout(int16_t *buf, uint32_t len,
enum AUD_CHANNEL_NUM_T num) {
uint32_t i;
uint32_t j = 0;
uint32_t start;
uint32_t end;
start = af_stream_fade_out.need_fadeout_len_processed;
end = af_stream_fade_out.need_fadeout_len_processed > len
? af_stream_fade_out.need_fadeout_len_processed - len
: 0;
if (start <= end) {
// TRACE(0,"skip fadeout");
memset(buf, 0, len * 2);
return len;
}
// TRACE(3,"fadeout l:%d start:%d end:%d", len, start, end);
// DUMP16("%05d ", buf, 10);
// DUMP16("%05d ", buf+len-10, 10);
if (num == AUD_CHANNEL_NUM_1) {
for (i = start; i > end; i--) {
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
}
} else if (num == AUD_CHANNEL_NUM_2) {
for (i = start; i > end; i -= 2) {
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
}
} else if (num == AUD_CHANNEL_NUM_4) {
for (i = start; i > end; i -= 4) {
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
}
} else if (num == AUD_CHANNEL_NUM_8) {
for (i = start; i > end; i -= 8) {
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
*(buf + j) = *(buf + j) * i / af_stream_fade_out.need_fadeout_len;
j++;
}
}
af_stream_fade_out.need_fadeout_len_processed -= j;
// TRACE(3,"out i:%d process:%d x:%d", i,
// af_stream_fade_out.need_fadeout_len_processed,
// end+((start-end)/AUD_CHANNEL_NUM_2)); DUMP16("%05d ", buf, 10);
// DUMP16("%05d ", buf+len-10, 10);
return len;
}
void af_stream_stop_wait_finish() {
af_stream_fade_out.stop_on_process = true;
af_stream_fade_out.stop_request_tid = osThreadGetId();
osSignalClear(af_stream_fade_out.stop_request_tid,
(1 << AF_FADE_OUT_SIGNAL_ID));
af_unlock_thread();
osSignalWait((1 << AF_FADE_OUT_SIGNAL_ID), 300);
af_lock_thread();
}
void af_stream_stop_process(struct af_stream_cfg_t *af_cfg, uint8_t *buf,
uint32_t len) {
af_lock_thread();
if (af_stream_fade_out.stop_on_process) {
// TRACE(5,"%s num:%d size:%d len:%d cnt:%d", __func__,
// af_cfg->cfg.channel_num, af_cfg->cfg.data_size, len,
// af_stream_fade_out.stop_process_cnt);
af_stream_fadeout((int16_t *)buf, len / 2, af_cfg->cfg.channel_num);
// TRACE(3,"process ret:%d %d %d", *(int16_t *)(buf+len-2-2-2),
// *(int16_t *)(buf+len-2-2), *(int16_t *)(buf+len-2));
if (af_stream_fade_out.stop_process_cnt++ > 3) {
TRACE(0, "stop_process end");
osSignalSet(af_stream_fade_out.stop_request_tid,
(1 << AF_FADE_OUT_SIGNAL_ID));
}
}
af_unlock_thread();
}
#endif // RTOS && AF_STREAM_ID_0_PLAYBACK_FADEOUT
// used by dma irq and af_thread
static inline struct af_stream_cfg_t *
af_get_stream_role(enum AUD_STREAM_ID_T id, enum AUD_STREAM_T stream) {
ASSERT(id < AUD_STREAM_ID_NUM, "[%s] Bad id=%d", __func__, id);
ASSERT(stream < AUD_STREAM_NUM, "[%s] Bad stream=%d", __func__, stream);
return &af_stream[id][stream];
}
static void af_set_status(enum AUD_STREAM_ID_T id, enum AUD_STREAM_T stream,
enum AF_STATUS_T status) {
struct af_stream_cfg_t *role = NULL;
role = af_get_stream_role(id, stream);
role->ctl.status |= status;
}
static void af_clear_status(enum AUD_STREAM_ID_T id, enum AUD_STREAM_T stream,
enum AF_STATUS_T status) {
struct af_stream_cfg_t *role = NULL;
role = af_get_stream_role(id, stream);
role->ctl.status &= ~status;
}
// get current stream config parameters
uint32_t af_stream_get_cfg(enum AUD_STREAM_ID_T id, enum AUD_STREAM_T stream,
struct AF_STREAM_CONFIG_T **cfg, bool needlock) {
AF_TRACE_DEBUG();
struct af_stream_cfg_t *role;
enum AF_RESULT_T ret;
if (needlock) {
af_lock_thread();
}
role = af_get_stream_role(id, stream);
// check stream is open
if (role->ctl.status & AF_STATUS_STREAM_OPEN_CLOSE) {
*cfg = &(role->cfg);
ret = AF_RES_SUCCESS;
} else {
ret = AF_RES_FAILD;
}
if (needlock) {
af_unlock_thread();
}
return ret;
}
#if 0
static void af_dump_cfg()
{
struct af_stream_cfg_t *role = NULL;
TRACE(0,"dump cfg.........start");
//initial parameter
for(uint8_t id=0; id< AUD_STREAM_ID_NUM; id++)
{
for(uint8_t stream=0; stream < AUD_STREAM_NUM; stream++)
{
role = af_get_stream_role((enum AUD_STREAM_ID_T)id, (enum AUD_STREAM_T)stream);
TRACE(2,"id = %d, stream = %d:", id, stream);
TRACE(1,"ctl.use_device = %d", role->ctl.use_device);
TRACE(1,"cfg.device = %d", role->cfg.device);
TRACE(1,"dma_cfg.ch = %d", role->dma_cfg.ch);
}
}
TRACE(0,"dump cfg.........end");
}
#endif
#ifdef AUDIO_OUTPUT_SW_GAIN
static void af_codec_output_gain_changed(float coef) {
saved_output_coef = coef;
}
#ifndef AUDIO_OUTPUT_SW_LIMITER
static float af_codec_sw_gain_filter(float gain_in) {
float gain_out = saved_output_coef * sw_gain_iir.coefs_b[0] +
sw_gain_iir.history_x[0] * sw_gain_iir.coefs_b[1] +
sw_gain_iir.history_x[1] * sw_gain_iir.coefs_b[2] -
sw_gain_iir.history_y[0] * sw_gain_iir.coefs_a[1] -
sw_gain_iir.history_y[1] * sw_gain_iir.coefs_a[2];
sw_gain_iir.history_y[1] = sw_gain_iir.history_y[0];
sw_gain_iir.history_y[0] = gain_out;
sw_gain_iir.history_x[1] = sw_gain_iir.history_x[0];
sw_gain_iir.history_x[0] = saved_output_coef;
return gain_out;
}
static void af_codec_sw_gain_process(uint8_t *buf, uint32_t size,
enum AUD_BITS_T bits,
enum AUD_CHANNEL_NUM_T chans) {
uint32_t i, pcm_len;
int32_t pcm_out;
float output_gain = 1.0f;
// TRACE(1,"af_codec_sw_gain_process:%d",(int32_t)(saved_output_coef*1000));
if (chans == AUD_CHANNEL_NUM_1) {
if (bits <= AUD_BITS_16) {
pcm_len = size / sizeof(int16_t);
int16_t *pcm_buf = (int16_t *)buf;
for (i = 0; i < pcm_len; i++) {
output_gain = af_codec_sw_gain_filter(saved_output_coef);
pcm_out = (int32_t)(pcm_buf[i] * output_gain);
pcm_buf[i] = __SSAT(pcm_out, 16);
}
} else {
pcm_len = size / sizeof(int32_t);
int32_t *pcm_buf = (int32_t *)buf;
for (i = 0; i < pcm_len; i++) {
output_gain = af_codec_sw_gain_filter(saved_output_coef);
pcm_out = (int32_t)(pcm_buf[i] * output_gain);
pcm_buf[i] = __SSAT(pcm_out, 24);
}
}
} else if (chans == AUD_CHANNEL_NUM_2) {
if (bits <= AUD_BITS_16) {
pcm_len = size / sizeof(int16_t);
int16_t *pcm_buf = (int16_t *)buf;
for (i = 0; i < pcm_len; i = i + 2) {
output_gain = af_codec_sw_gain_filter(saved_output_coef);
pcm_out = (int32_t)(pcm_buf[i] * output_gain);
pcm_buf[i] = __SSAT(pcm_out, 16);
pcm_out = (int32_t)(pcm_buf[i + 1] * output_gain);
pcm_buf[i + 1] = __SSAT(pcm_out, 16);
}
} else {
pcm_len = size / sizeof(int32_t);
int32_t *pcm_buf = (int32_t *)buf;
for (i = 0; i < pcm_len; i = i + 2) {
output_gain = af_codec_sw_gain_filter(saved_output_coef);
pcm_out = (int32_t)(pcm_buf[i] * output_gain);
pcm_buf[i] = __SSAT(pcm_out, 24);
pcm_out = (int32_t)(pcm_buf[i + 1] * output_gain);
pcm_buf[i + 1] = __SSAT(pcm_out, 24);
}
}
}
}
#endif
#endif // AUDIO_OUTPUT_SW_GAIN
static uint32_t POSSIBLY_UNUSED af_codec_get_sample_count(
uint32_t size, enum AUD_BITS_T bits, enum AUD_CHANNEL_NUM_T chans) {
uint32_t div;
if (bits <= AUD_BITS_16) {
div = 2;
} else {
div = 4;
}
div *= chans;
return size / div;
}
static void POSSIBLY_UNUSED af_zero_mem(void *dst, unsigned int size) {
uint32_t *d = dst;
uint32_t count = size / 4;
while (count--) {
*d++ = 0;
}
}
static bool af_codec_playback_pre_handler(uint8_t *buf, uint32_t len,
const struct af_stream_cfg_t *role) {
uint32_t POSSIBLY_UNUSED time;
if (0) {
#ifdef AUDIO_OUTPUT_PA_ON_FADE_IN
} else if (dac_pa_state == AF_DAC_PA_ON_TRIGGER &&
(time = hal_sys_timer_get()) - dac_dc_start_time >=
AF_CODEC_DC_STABLE_INTERVAL &&
time - dac_pa_stop_time >= AF_CODEC_PA_RESTART_INTERVAL) {
analog_aud_codec_speaker_enable(true);
dac_pa_state = AF_DAC_PA_NULL;
#endif // AUDIO_OUTPUT_PA_ON_FADE_IN
#ifdef AUDIO_OUTPUT_PA_OFF_FADE_OUT
} else if (dac_pa_state == AF_DAC_PA_OFF_TRIGGER) {
dac_dc_start_time = hal_sys_timer_get();
dac_pa_state = AF_DAC_PA_OFF_DC_START;
} else if (dac_pa_state == AF_DAC_PA_OFF_DC_START) {
time = hal_sys_timer_get();
if (time - dac_dc_start_time >= AF_CODEC_DC_STABLE_INTERVAL) {
dac_pa_state = AF_DAC_PA_NULL;
analog_aud_codec_speaker_enable(false);
dac_pa_stop_time = time;
#ifdef RTOS
osSignalSet(fade_thread_id, (1 << AF_FADE_OUT_SIGNAL_ID));
#endif
}
#endif // AUDIO_OUTPUT_PA_OFF_FADE_OUT
}
#if defined(AUDIO_OUTPUT_PA_ON_FADE_IN) || defined(AUDIO_OUTPUT_PA_OFF_FADE_OUT)
if (dac_pa_state == AF_DAC_PA_ON_TRIGGER ||
dac_pa_state == AF_DAC_PA_OFF_DC_START) {
af_zero_mem(buf, len);
return true;
}
#endif
return false;
}
#ifdef AUDIO_OUTPUT_DC_CALIB_SW
static void af_codec_playback_sw_dc_calib(uint8_t *buf, uint32_t len,
enum AUD_BITS_T bits,
enum AUD_CHANNEL_NUM_T chans) {
uint32_t cnt;
if (bits <= AUD_BITS_16) {
int16_t *ptr16 = (int16_t *)buf;
#ifdef AUDIO_OUTPUT_DC_CALIB_SW
int16_t dc_l = dac_dc[0];
int16_t dc_r = dac_dc[1];
#endif
if (chans == AUD_CHANNEL_NUM_1) {
cnt = len / sizeof(int16_t);
while (cnt-- > 0) {
#ifdef AUDIO_OUTPUT_DC_CALIB_SW
*ptr16 = __SSAT(*ptr16 + dc_l, 16);
#endif
ptr16++;
}
} else {
cnt = len / sizeof(int16_t) / 2;
while (cnt-- > 0) {
#ifdef AUDIO_OUTPUT_DC_CALIB_SW
*ptr16 = __SSAT(*ptr16 + dc_l, 16);
*(ptr16 + 1) = __SSAT(*(ptr16 + 1) + dc_r, 16);
#endif
ptr16 += 2;
}
}
} else {
int32_t *ptr32 = (int32_t *)buf;
int32_t dac_bits =
#ifdef CHIP_BEST1000
CODEC_PLAYBACK_BIT_DEPTH;
#else
24;
#endif
int32_t val_shift;
if (dac_bits < 24) {
val_shift = 24 - dac_bits;
} else {
val_shift = 0;
}
#ifdef AUDIO_OUTPUT_DC_CALIB_SW
int32_t dc_l = dac_dc[0] << 8;
int32_t dc_r = dac_dc[1] << 8;
#endif
if (chans == AUD_CHANNEL_NUM_1) {
cnt = len / sizeof(int32_t);
while (cnt-- > 0) {
#ifdef CORRECT_SAMPLE_VALUE
*ptr32 = ((*ptr32) << (32 - dac_bits)) >> (32 - dac_bits);
#endif
#ifdef AUDIO_OUTPUT_DC_CALIB_SW
*ptr32 = __SSAT((*ptr32 + dc_l) >> val_shift, dac_bits);
#elif defined(CORRECT_SAMPLE_VALUE)
*ptr32 = __SSAT(*ptr32 >> val_shift, dac_bits);
#else
*ptr32 = *ptr32 >> val_shift;
#endif
ptr32++;
}
} else {
cnt = len / sizeof(int32_t) / 2;
while (cnt-- > 0) {
#ifdef CORRECT_SAMPLE_VALUE
*ptr32 = ((*ptr32) << (32 - dac_bits)) >> (32 - dac_bits);
*(ptr32 + 1) = ((*(ptr32 + 1)) << (32 - dac_bits)) >> (32 - dac_bits);
#endif
#ifdef AUDIO_OUTPUT_DC_CALIB_SW
*ptr32 = __SSAT((*ptr32 + dc_l) >> val_shift, dac_bits);
*(ptr32 + 1) = __SSAT((*(ptr32 + 1) + dc_r) >> val_shift, dac_bits);
#elif defined(CORRECT_SAMPLE_VALUE)
*ptr32 = __SSAT(*ptr32 >> val_shift, dac_bits);
*(ptr32 + 1) = __SSAT(*(ptr32 + 1) >> val_shift, dac_bits);
#else
*ptr32 = *ptr32 >> val_shift;
*(ptr32 + 1) = *(ptr32 + 1) >> val_shift;
#endif
ptr32 += 2;
}
}
}
}
#endif // AUDIO_OUTPUT_DC_CALIB_SW
static void af_codec_playback_post_handler(uint8_t *buf, uint32_t len,
const struct af_stream_cfg_t *role) {
POSSIBLY_UNUSED enum AUD_BITS_T bits;
POSSIBLY_UNUSED enum AUD_CHANNEL_NUM_T chans;
POSSIBLY_UNUSED uint32_t cnt;
bits = role->cfg.bits;
chans = role->cfg.channel_num;
#ifdef AUDIO_OUTPUT_SW_GAIN
#ifdef AUDIO_OUTPUT_SW_LIMITER
if (bits <= AUD_BITS_16) {
cnt = len / sizeof(int16_t);
} else {
cnt = len / sizeof(int32_t);
}
ApplyFloatLimiter(FloatLimiterP, buf, saved_output_coef, cnt);
#else
af_codec_sw_gain_process(buf, len, bits, chans);
#endif
#endif
if (codec_play_post_hdlr) {
codec_play_post_hdlr(buf, len, (void *)&role->cfg);
}
#if defined(AUDIO_OUTPUT_INVERT_RIGHT_CHANNEL)
if (chans == AUD_CHANNEL_NUM_2) {
if (bits == AUD_BITS_16) {
int16_t *buf16 = (int16_t *)buf;
for (int i = 1; i < len / sizeof(int16_t); i += 2) {
int32_t tmp = -buf16[i];
buf16[i] = __SSAT(tmp, 16);
}
} else {
int32_t *buf32 = (int32_t *)buf;
for (int i = 1; i < len / sizeof(int32_t); i += 2) {
int32_t tmp = -buf32[i];
buf32[i] = __SSAT(tmp, 24);
}
}
}
#endif
#if (defined(CHIP_BEST1000) || defined(CHIP_BEST2000)) && \
defined(AUDIO_OUTPUT_CALIB_GAIN_MISSMATCH)
// gain must less than 1.0
float gain = 0.9441f;
if (chans == AUD_CHANNEL_NUM_2) {
if (bits == AUD_BITS_16) {
int16_t *buf16 = (int16_t *)buf;
for (int i = 1; i < len / sizeof(int16_t); i += 2) {
int32_t tmp = (int)(buf16[i + 1] * gain);
buf16[i + 1] = __SSAT(tmp, 16);
}
} else {
int32_t *buf32 = (int32_t *)buf;
for (int i = 1; i < len / sizeof(int32_t); i += 2) {
int32_t tmp = (int)(buf32[i + 1] * gain);
buf32[i + 1] = __SSAT(tmp, 24);
}
}
}
#endif
#if defined(AUDIO_OUTPUT_DC_CALIB_SW)
af_codec_playback_sw_dc_calib(buf, len, bits, chans);
#elif defined(CHIP_BEST1000)
if (bits == AUD_BITS_24 || bits == AUD_BITS_32) {
int32_t *ptr32 = (int32_t *)buf;
int32_t val_shift;
if (bits == AUD_BITS_24) {
val_shift = 24 - CODEC_PLAYBACK_BIT_DEPTH;
} else {
val_shift = 32 - CODEC_PLAYBACK_BIT_DEPTH;
}
cnt = len / sizeof(int32_t);
while (cnt-- > 0) {
*ptr32 >>= val_shift;
ptr32++;
}
}
#endif
#if defined(CHIP_BEST1000) && defined(AUDIO_OUTPUT_GAIN_M60DB_CHECK)
hal_codec_dac_gain_m60db_check(HAL_CODEC_PERF_TEST_M60DB);
#endif
}
static inline void af_thread_stream_handler(enum AUD_STREAM_ID_T id,
enum AUD_STREAM_T stream) {
uint32_t lock;
struct af_stream_cfg_t *role;
uint32_t dma_addr, hw_pos;
uint8_t *buf;
uint32_t len;
uint32_t pp_cnt;
bool codec_playback;
bool skip_handler;
enum AF_PP_T pp_index;
role = af_get_stream_role(id, stream);
af_lock_thread();
if (role->handler && (role->ctl.status & AF_STATUS_STREAM_START_STOP)) {
lock = int_lock();
pp_cnt = role->ctl.pp_cnt;
role->ctl.pp_cnt = 0;
int_unlock(lock);
af_sig_lost_cnt[id][stream] = pp_cnt - 1;
if (af_sig_lost_cnt[id][stream]) {
TRACE(3, "af_thread:WARNING: id=%d stream=%d lost %u signals", id, stream,
af_sig_lost_cnt[id][stream]);
}
pp_index = PP_PINGPANG(role->ctl.pp_index);
// Get PP index from accurate DMA pos
dma_addr = af_stream_get_cur_dma_addr(id, stream);
hw_pos = dma_addr - (uint32_t)role->dma_buf_ptr;
if (hw_pos > role->dma_buf_size) {
TRACE(
3,
"af_thread: Failed to get valid dma addr for id=%d stream=%d: 0x%08x",
id, stream, dma_addr);
}
#ifndef CHIP_BEST1000
if (role->cfg.chan_sep_buf && role->cfg.channel_num > AUD_CHANNEL_NUM_1) {
uint32_t chan_size;
chan_size = role->dma_buf_size / role->cfg.channel_num;
if (hw_pos <= role->dma_buf_size) {
hw_pos = hw_pos % chan_size;
if (hw_pos < chan_size / 2) {
pp_index = PP_PANG;
} else if (hw_pos < chan_size) {
pp_index = PP_PING;
}
}
if (pp_index == PP_PING) {
buf = role->dma_buf_ptr;
} else {
buf = role->dma_buf_ptr + chan_size / 2;
}
} else
#endif
{
if (hw_pos < role->dma_buf_size / 2) {
pp_index = PP_PANG;
} else if (hw_pos < role->dma_buf_size) {
pp_index = PP_PING;
}
if (pp_index == PP_PING) {
buf = role->dma_buf_ptr;
} else {
buf = role->dma_buf_ptr + role->dma_buf_size / 2;
}
}
if (stream == AUD_STREAM_PLAYBACK &&
role->ctl.use_device == AUD_STREAM_USE_INT_CODEC) {
codec_playback = true;
} else {
codec_playback = false;
}
skip_handler = false;
len = role->dma_buf_size / 2;
if (codec_playback) {
skip_handler = af_codec_playback_pre_handler(buf, len, role);
}
if (!skip_handler) {
#ifdef __RAND_FROM_MIC__
if ((AUD_STREAM_CAPTURE == stream) &&
(AUD_STREAM_USE_INT_CODEC == role->cfg.device)) {
random_data_process(buf, role->dma_buf_size / 2, role->cfg.bits,
role->cfg.channel_num);
}
#endif
role->handler(buf, len);
}
if (codec_playback) {
af_codec_playback_post_handler(buf, len, role);
}
#if defined(RTOS) && defined(AF_STREAM_ID_0_PLAYBACK_FADEOUT)
af_stream_stop_process(role, buf, len);
#endif
if (role->ctl.pp_cnt) {
TRACE(3,
"af_thread:WARNING: id=%d stream=%d hdlr ran too long (pp_cnt=%u)",
id, stream, role->ctl.pp_cnt);
}
}
af_unlock_thread();
}
#ifdef RTOS
static void af_thread(void const *argument) {
osEvent evt;
uint32_t signals = 0;
enum AUD_STREAM_ID_T id;
enum AUD_STREAM_T stream;
while (1) {
// wait any signal
evt = osSignalWait(0x0, osWaitForever);
signals = evt.value.signals;
// TRACE(3,"[%s] status = %x, signals = %d", __func__, evt.status,
// evt.value.signals);
if (evt.status == osEventSignal) {
for (uint8_t i = 0; i < AUD_STREAM_ID_NUM * AUD_STREAM_NUM; i++) {
if (signals & (1 << i)) {
id = (enum AUD_STREAM_ID_T)(i >> 1);
stream = (enum AUD_STREAM_T)(i & 1);
af_thread_stream_handler(id, stream);
}
}
} else {
TRACE(2, "[%s] ERROR: evt.status = %d", __func__, evt.status);
continue;
}
}
}
#else // !RTOS
#include "cmsis.h"
static volatile uint32_t af_flag_open;
static volatile uint32_t af_flag_signal;
static void af_set_flag(volatile uint32_t *flag, uint32_t set) {
uint32_t lock;
lock = int_lock();
*flag |= set;
int_unlock(lock);
}
static void af_clear_flag(volatile uint32_t *flag, uint32_t clear) {
uint32_t lock;
lock = int_lock();
*flag &= ~clear;
int_unlock(lock);
}
static bool af_flag_active(volatile uint32_t *flag, uint32_t bits) {
return !!(*flag & bits);
}
void af_thread(void const *argument) {
uint32_t lock;
uint32_t i;
enum AUD_STREAM_ID_T id;
enum AUD_STREAM_T stream;
if (af_flag_open == 0) {
return;
}
for (i = 0; i < AUD_STREAM_ID_NUM * AUD_STREAM_NUM; i++) {
if (!af_flag_active(&af_flag_signal, 1 << i)) {
continue;
}
af_clear_flag(&af_flag_signal, 1 << i);
id = (enum AUD_STREAM_ID_T)(i >> 1);
stream = (enum AUD_STREAM_T)(i & 1);
af_thread_stream_handler(id, stream);
}
lock = int_lock();
if (af_flag_signal == 0) {
hal_cpu_wake_unlock(AF_CPU_WAKE_USER);
}
int_unlock(lock);
}
#endif // !RTOS
static void af_dma_irq_handler(uint8_t ch, uint32_t remain_dst_tsize,
uint32_t error, struct HAL_DMA_DESC_T *lli) {
struct af_stream_cfg_t *role = NULL;
// initial parameter
for (uint8_t id = 0; id < AUD_STREAM_ID_NUM; id++) {
for (uint8_t stream = 0; stream < AUD_STREAM_NUM; stream++) {
role = af_get_stream_role((enum AUD_STREAM_ID_T)id,
(enum AUD_STREAM_T)stream);
if (role->dma_cfg.ch == ch) {
role->ctl.pp_index = PP_PINGPANG(role->ctl.pp_index);
role->ctl.pp_cnt++;
// TRACE(4,"[%s] id = %d, stream = %d, ch = %d", __func__, id, stream,
// ch); TRACE(2,"[%s] PLAYBACK pp_cnt = %d", __func__,
// role->ctl.pp_cnt);
#ifdef RTOS
if (irq_notif) {
irq_notif(id, stream);
}
osSignalSet(af_thread_tid, 0x01 << (id * 2 + stream));
#else
af_set_flag(&af_flag_signal, 0x01 << (id * 2 + stream));
hal_cpu_wake_lock(AF_CPU_WAKE_USER);
#endif
return;
}
}
}
// invalid dma irq
ASSERT(0, "[%s] ERROR: channel id = %d", __func__, ch);
}
#ifdef __CODEC_ASYNC_CLOSE__
static void af_codec_async_close(void) {
af_lock_thread();
codec_int_close(CODEC_CLOSE_ASYNC_REAL);
af_unlock_thread();
}
#endif
void *af_thread_tid_get(void) {
#ifdef RTOS
return (void *)af_thread_tid;
#else
return NULL;
#endif
}
#ifdef CODEC_ANC_BOOST
static void af_codec_anc_boost_delay(uint32_t ms) {
af_unlock_thread();
osDelay(ms);
af_lock_thread();
}
#endif
uint32_t af_open(void) {
AF_TRACE_DEBUG();
struct af_stream_cfg_t *role = NULL;
#ifdef RTOS
if (audioflinger_mutex_id == NULL) {
audioflinger_mutex_id = osMutexCreate((osMutex(audioflinger_mutex)));
}
#endif
af_lock_thread();
#ifdef AUDIO_OUTPUT_DC_CALIB
if (!dac_dc_valid) {
int16_t dc_l, dc_r;
uint16_t max_dc;
float attn;
dac_dc_valid = true;
analog_aud_get_dc_calib_value(&dc_l, &dc_r);
if (ABS(dc_l) >= ABS(dc_r)) {
max_dc = ABS(dc_l);
} else {
max_dc = ABS(dc_r);
}
ASSERT(max_dc + 1 < AF_CODEC_DC_MAX_SCALE, "Bad dc values: (%d, %d)", dc_l,
dc_r);
if (max_dc) {
attn = 1 - (float)(max_dc + 1) / AF_CODEC_DC_MAX_SCALE;
} else {
attn = 1;
}
hal_codec_set_dac_dc_gain_attn(attn);
#ifdef AUDIO_OUTPUT_DC_CALIB_SW
dac_dc[0] = dc_l;
dac_dc[1] = dc_r;
#else
hal_codec_set_dac_dc_offset(dc_l, dc_r);
#endif
}
#endif
#ifdef AUDIO_OUTPUT_SW_GAIN
hal_codec_set_sw_output_coef_callback(af_codec_output_gain_changed);
#endif
#ifdef __CODEC_ASYNC_CLOSE__
codec_int_set_close_handler(af_codec_async_close);
#endif
#ifdef CODEC_ANC_BOOST
codec_set_anc_boost_delay_func(af_codec_anc_boost_delay);
#endif
// initial parameters
for (uint8_t id = 0; id < AUD_STREAM_ID_NUM; id++) {
for (uint8_t stream = 0; stream < AUD_STREAM_NUM; stream++) {
role = af_get_stream_role((enum AUD_STREAM_ID_T)id,
(enum AUD_STREAM_T)stream);
if (role->ctl.status == AF_STATUS_NULL) {
role->dma_buf_ptr = NULL;
role->dma_buf_size = 0;
role->ctl.pp_index = PP_PING;
role->ctl.status = AF_STATUS_OPEN_CLOSE;
role->ctl.use_device = AUD_STREAM_USE_DEVICE_NULL;
role->dma_cfg.ch = HAL_DMA_CHAN_NONE;
} else {
ASSERT(0, "[%s] ERROR: id = %d, stream = %d", __func__, id, stream);
}
}
}
#ifdef RTOS
af_thread_tid = osThreadCreate(osThread(af_thread), NULL);
af_default_priority = af_get_priority();
osSignalSet(af_thread_tid, 0x0);
#endif
#ifdef __RAND_FROM_MIC__
randInit();
#endif
af_unlock_thread();
return AF_RES_SUCCESS;
}
static void af_stream_update_dma_buffer(enum AUD_STREAM_T stream,
struct af_stream_cfg_t *role,
const struct AF_STREAM_CONFIG_T *cfg) {
int i;
enum HAL_DMA_RET_T dma_ret;
struct HAL_DMA_DESC_T *dma_desc, *next_desc;
struct HAL_DMA_CH_CFG_T *dma_cfg;
int irq;
uint32_t desc_xfer_size;
uint32_t align;
uint8_t samp_size;
enum HAL_DMA_WDITH_T width;
#ifndef CHIP_BEST1000
bool dma_2d_en;
uint32_t chan_desc_xfer_size = 0;
#endif
dma_desc = &role->dma_desc[0];
dma_cfg = &role->dma_cfg;
#ifdef CODEC_DSD
if (stream == AUD_STREAM_PLAYBACK &&
role->cfg.device == AUD_STREAM_USE_INT_CODEC) {
if (dma_cfg->dst_periph == HAL_AUDMA_DSD_TX) {
dma_cfg->dst_bsize = HAL_DMA_BSIZE_1;
} else {
dma_cfg->dst_bsize = HAL_DMA_BSIZE_4;
}
}
#endif
if (role->cfg.device == AUD_STREAM_USE_BT_PCM) {
dma_cfg->dst_bsize = HAL_DMA_BSIZE_1;
dma_cfg->src_bsize = HAL_DMA_BSIZE_1;
dma_cfg->try_burst = 0;
}
role->dma_buf_ptr = cfg->data_ptr;
role->dma_buf_size = cfg->data_size;
if (cfg->bits == AUD_BITS_24 || cfg->bits == AUD_BITS_32) {
width = HAL_DMA_WIDTH_WORD;
samp_size = 4;
} else if (cfg->bits == AUD_BITS_16) {
width = HAL_DMA_WIDTH_HALFWORD;
samp_size = 2;
} else {
ASSERT(false, "%s: Invalid stream config bits=%d", __func__, cfg->bits);
width = HAL_DMA_WIDTH_BYTE;
samp_size = 1;
}
#ifdef DYNAMIC_AUDIO_BUFFER_COUNT
uint32_t desc_cnt;
desc_cnt = (cfg->data_size / samp_size + HAL_DMA_MAX_DESC_XFER_SIZE - 1) /
HAL_DMA_MAX_DESC_XFER_SIZE;
if (desc_cnt < 2) {
desc_cnt = 2;
} else if (desc_cnt & (desc_cnt - 1)) {
desc_cnt = 1 << (31 - __CLZ(desc_cnt) + 1);
}
TRACE(4, "%s: desc_cnt=%u data_size=%u samp_size=%u", __func__, desc_cnt,
cfg->data_size, samp_size);
ASSERT(MIN_AUDIO_BUFFER_COUNT <= desc_cnt &&
desc_cnt <= MAX_AUDIO_BUFFER_COUNT,
"%s: Bad desc_cnt=%u", __func__, desc_cnt);
role->dma_desc_cnt = desc_cnt;
#endif
desc_xfer_size = cfg->data_size / AUDIO_BUFFER_COUNT;
#ifndef CHIP_BEST1000
if (cfg->chan_sep_buf && cfg->channel_num > AUD_CHANNEL_NUM_1) {
dma_2d_en = true;
} else {
dma_2d_en = false;
}
if (dma_2d_en) {
enum HAL_DMA_BSIZE_T bsize;
uint8_t burst_size;
chan_desc_xfer_size = desc_xfer_size / cfg->channel_num;
if (stream == AUD_STREAM_PLAYBACK) {
bsize = dma_cfg->src_bsize;
} else {
bsize = dma_cfg->dst_bsize;
}
if (bsize == HAL_DMA_BSIZE_1) {
burst_size = 1;
} else if (bsize == HAL_DMA_BSIZE_4) {
burst_size = 4;
} else {
burst_size = 8;
}
align = burst_size * samp_size * cfg->channel_num;
// Ensure word-aligned too
if (align & 0x1) {
align *= 4;
} else if (align & 0x2) {
align *= 2;
}
} else
#endif
{
align = 4;
}
ASSERT(desc_xfer_size * AUDIO_BUFFER_COUNT == cfg->data_size &&
(desc_xfer_size % align) == 0,
"%s: Dma data size is not aligned: data_size=%u AUDIO_BUFFER_COUNT=%u "
"align=%u",
__func__, cfg->data_size, AUDIO_BUFFER_COUNT, align);
dma_cfg->dst_width = width;
dma_cfg->src_width = width;
dma_cfg->src_tsize = desc_xfer_size / samp_size;
for (i = 0; i < AUDIO_BUFFER_COUNT; i++) {
if (i == AUDIO_BUFFER_COUNT - 1) {
next_desc = &dma_desc[0];
irq = 1;
} else {
next_desc = &dma_desc[i + 1];
if (i == AUDIO_BUFFER_COUNT / 2 - 1) {
irq = 1;
} else {
irq = 0;
}
}
if (stream == AUD_STREAM_PLAYBACK) {
#ifndef CHIP_BEST1000
if (dma_2d_en) {
dma_cfg->src = (uint32_t)(role->dma_buf_ptr + chan_desc_xfer_size * i);
} else
#endif
{
dma_cfg->src = (uint32_t)(role->dma_buf_ptr + desc_xfer_size * i);
}
} else {
#ifndef CHIP_BEST1000
if (dma_2d_en) {
dma_cfg->dst = (uint32_t)(role->dma_buf_ptr + chan_desc_xfer_size * i);
} else
#endif
{
dma_cfg->dst = (uint32_t)(role->dma_buf_ptr + desc_xfer_size * i);
}
}
dma_ret = hal_audma_init_desc(&dma_desc[i], dma_cfg, next_desc, irq);
ASSERT(dma_ret == HAL_DMA_OK,
"[%s] Failed to init dma desc for stream %d: ret=%d", __func__,
stream, dma_ret);
}
}
// Support memory<-->peripheral
// Note: Do not support peripheral <--> peripheral
uint32_t af_stream_open(enum AUD_STREAM_ID_T id, enum AUD_STREAM_T stream,
const struct AF_STREAM_CONFIG_T *cfg) {
AF_TRACE_DEBUG();
struct af_stream_cfg_t *role;
enum AF_RESULT_T ret;
enum AUD_STREAM_USE_DEVICE_T device;
struct HAL_DMA_CH_CFG_T *dma_cfg = NULL;
#ifdef __RAND_FROM_MIC__
random_status_sync();
#endif
role = af_get_stream_role(id, stream);
TRACE(3, "[%s] id = %d, stream = %d", __func__, id, stream);
ASSERT(cfg->data_ptr != NULL, "[%s] ERROR: data_ptr == NULL!!!", __func__);
ASSERT(((uint32_t)cfg->data_ptr) % 4 == 0,
"[%s] ERROR: data_ptr(%p) is not align!!!", __func__, cfg->data_ptr);
ASSERT(cfg->data_size != 0, "[%s] ERROR: data_size == 0!!!", __func__);
#ifndef CHIP_BEST1000
if (cfg->chan_sep_buf && cfg->channel_num > AUD_CHANNEL_NUM_1) {
ASSERT(cfg->device == AUD_STREAM_USE_INT_CODEC ||
cfg->device == AUD_STREAM_USE_I2S0_MASTER ||
cfg->device == AUD_STREAM_USE_I2S0_SLAVE ||
cfg->device == AUD_STREAM_USE_I2S1_MASTER ||
cfg->device == AUD_STREAM_USE_I2S1_SLAVE ||
cfg->device == AUD_STREAM_USE_TDM0_MASTER ||
cfg->device == AUD_STREAM_USE_TDM0_SLAVE ||
cfg->device == AUD_STREAM_USE_TDM1_MASTER ||
cfg->device == AUD_STREAM_USE_TDM1_SLAVE,
"[%s] ERROR: Unsupport chan_sep_buf for device %d", __func__,
cfg->device);
}
#endif
ret = AF_RES_FAILD;
af_lock_thread();
// check af is open
if (role->ctl.status != AF_STATUS_OPEN_CLOSE) {
TRACE(2, "[%s] ERROR: status = %d", __func__, role->ctl.status);
goto _exit;
}
role->cfg = *cfg;
device = cfg->device;
role->ctl.use_device = device;
dma_cfg = &role->dma_cfg;
memset(dma_cfg, 0, sizeof(*dma_cfg));
if (device == AUD_STREAM_USE_BT_PCM) {
dma_cfg->dst_bsize = HAL_DMA_BSIZE_1;
dma_cfg->src_bsize = HAL_DMA_BSIZE_1;
dma_cfg->try_burst = 0;
} else {
dma_cfg->dst_bsize = HAL_DMA_BSIZE_4;
#ifndef CHIP_BEST1000
// If channel num > 1, burst size should be set to 1 for:
// 1) all playback streams with 2D DMA enabled; or
// 2) internal codec capture streams with 2D DMA disabled.
if (cfg->channel_num > AUD_CHANNEL_NUM_1 &&
((stream == AUD_STREAM_PLAYBACK && cfg->chan_sep_buf) ||
(device == AUD_STREAM_USE_INT_CODEC && stream == AUD_STREAM_CAPTURE &&
!cfg->chan_sep_buf))) {
dma_cfg->src_bsize = HAL_DMA_BSIZE_1;
} else
#endif
{
dma_cfg->src_bsize = HAL_DMA_BSIZE_4;
}
dma_cfg->try_burst = 1;
}
dma_cfg->handler = af_dma_irq_handler;
if (stream == AUD_STREAM_PLAYBACK) {
AF_TRACE_DEBUG();
dma_cfg->src_periph = (enum HAL_DMA_PERIPH_T)0;
dma_cfg->type = HAL_DMA_FLOW_M2P_DMA;
// open device and stream
if (0) {
}
#ifdef AF_DEVICE_EXT_CODEC
else if (device == AUD_STREAM_USE_EXT_CODEC) {
AF_TRACE_DEBUG();
tlv32aic32_open();
tlv32aic32_stream_open(stream);
dma_cfg->dst_periph = HAL_AUDMA_I2S0_TX;
}
#endif
#ifdef AF_DEVICE_I2S
else if (device == AUD_STREAM_USE_I2S0_MASTER) {
AF_TRACE_DEBUG();
hal_i2s_open(HAL_I2S_ID_0, stream, HAL_I2S_MODE_MASTER);
dma_cfg->dst_periph = HAL_AUDMA_I2S0_TX;
} else if (device == AUD_STREAM_USE_I2S0_SLAVE) {
AF_TRACE_DEBUG();
hal_i2s_open(HAL_I2S_ID_0, stream, HAL_I2S_MODE_SLAVE);
dma_cfg->dst_periph = HAL_AUDMA_I2S0_TX;
}
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
else if (device == AUD_STREAM_USE_I2S1_MASTER) {
AF_TRACE_DEBUG();
hal_i2s_open(HAL_I2S_ID_1, stream, HAL_I2S_MODE_MASTER);
dma_cfg->dst_periph = HAL_AUDMA_I2S1_TX;
} else if (device == AUD_STREAM_USE_I2S1_SLAVE) {
AF_TRACE_DEBUG();
hal_i2s_open(HAL_I2S_ID_1, stream, HAL_I2S_MODE_SLAVE);
dma_cfg->dst_periph = HAL_AUDMA_I2S1_TX;
}
#endif
#endif
#ifdef AF_DEVICE_TDM
else if (device == AUD_STREAM_USE_TDM0_MASTER) {
AF_TRACE_DEBUG();
hal_tdm_open(HAL_I2S_ID_0, stream, HAL_I2S_MODE_MASTER);
dma_cfg->dst_periph = HAL_AUDMA_I2S0_TX;
} else if (device == AUD_STREAM_USE_TDM0_SLAVE) {
AF_TRACE_DEBUG();
hal_tdm_open(HAL_I2S_ID_0, stream, HAL_I2S_MODE_SLAVE);
dma_cfg->dst_periph = HAL_AUDMA_I2S0_TX;
}
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
else if (device == AUD_STREAM_USE_TDM1_MASTER) {
AF_TRACE_DEBUG();
hal_tdm_open(HAL_I2S_ID_1, stream, HAL_I2S_MODE_MASTER);
dma_cfg->dst_periph = HAL_AUDMA_I2S1_TX;
} else if (device == AUD_STREAM_USE_TDM1_SLAVE) {
AF_TRACE_DEBUG();
hal_tdm_open(HAL_I2S_ID_1, stream, HAL_I2S_MODE_SLAVE);
dma_cfg->dst_periph = HAL_AUDMA_I2S1_TX;
}
#endif
#endif
#ifdef AF_DEVICE_INT_CODEC
else if (device == AUD_STREAM_USE_INT_CODEC) {
AF_TRACE_DEBUG();
codec_int_open();
codec_int_stream_open(stream);
#ifdef AUDIO_OUTPUT_SW_GAIN
#ifdef AUDIO_OUTPUT_SW_LIMITER
FLOATLIMITER_ERROR limiter_err;
if (FloatLimiterP == NULL) {
FloatLimiterP = CreateFloatLimiter(
FL_ATTACK_DEFAULT_MS, FL_RELEASE_DEFAULT_MS, FL_THRESHOLD,
MAX_CHANEL, MAX_SAMPLERATE, MAX_SAMPLEBIT);
}
limiter_err = SetFloatLimiterNChannels(FloatLimiterP, cfg->channel_num);
if (limiter_err != FLOATLIMIT_OK) {
goto _exit;
}
limiter_err = SetFloatLimiterSampleRate(FloatLimiterP, cfg->sample_rate);
if (limiter_err != FLOATLIMIT_OK) {
goto _exit;
}
limiter_err = SetFloatLimiterSampleBit(FloatLimiterP, cfg->bits);
if (limiter_err != FLOATLIMIT_OK) {
goto _exit;
}
#else
sw_gain_iir.history_x[0] = 0.0f;
sw_gain_iir.history_x[1] = 0.0f;
sw_gain_iir.history_y[0] = 0.0f;
sw_gain_iir.history_y[1] = 0.0f;
#endif
#endif
#ifdef CODEC_DSD
if (af_dsd_enabled) {
dma_cfg->dst_periph = HAL_AUDMA_DSD_TX;
dma_cfg->dst_bsize = HAL_DMA_BSIZE_1;
} else
#endif
{
dma_cfg->dst_periph = HAL_AUDMA_CODEC_TX;
}
}
#endif
#ifdef AF_DEVICE_SPDIF
else if (device == AUD_STREAM_USE_INT_SPDIF) {
AF_TRACE_DEBUG();
hal_spdif_open(AF_SPDIF_INST, stream);
dma_cfg->dst_periph = HAL_AUDMA_SPDIF0_TX;
}
#endif
#ifdef AF_DEVICE_BT_PCM
else if (device == AUD_STREAM_USE_BT_PCM) {
AF_TRACE_DEBUG();
hal_btpcm_open(AF_BTPCM_INST, stream);
dma_cfg->dst_periph = HAL_AUDMA_BTPCM_TX;
}
#endif
#ifdef AUDIO_ANC_FB_MC
else if (device == AUD_STREAM_USE_MC) {
AF_TRACE_DEBUG();
dma_cfg->dst_periph = HAL_AUDMA_MC_RX;
}
#endif
else {
ASSERT(0, "[%s] ERROR: device %d is not defined!", __func__, device);
}
dma_cfg->ch = hal_audma_get_chan(dma_cfg->dst_periph, HAL_DMA_HIGH_PRIO);
} else {
AF_TRACE_DEBUG();
dma_cfg->dst_periph = (enum HAL_DMA_PERIPH_T)0;
dma_cfg->type = HAL_DMA_FLOW_P2M_DMA;
// open device and stream
if (0) {
}
#ifdef AF_DEVICE_EXT_CODEC
else if (device == AUD_STREAM_USE_EXT_CODEC) {
AF_TRACE_DEBUG();
tlv32aic32_open();
tlv32aic32_stream_open(stream);
dma_cfg->src_periph = HAL_AUDMA_I2S0_RX;
}
#endif
#ifdef AF_DEVICE_I2S
else if (device == AUD_STREAM_USE_I2S0_MASTER) {
AF_TRACE_DEBUG();
hal_i2s_open(HAL_I2S_ID_0, stream, HAL_I2S_MODE_MASTER);
dma_cfg->src_periph = HAL_AUDMA_I2S0_RX;
} else if (device == AUD_STREAM_USE_I2S0_SLAVE) {
AF_TRACE_DEBUG();
hal_i2s_open(HAL_I2S_ID_0, stream, HAL_I2S_MODE_SLAVE);
dma_cfg->src_periph = HAL_AUDMA_I2S0_RX;
}
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
else if (device == AUD_STREAM_USE_I2S1_MASTER) {
AF_TRACE_DEBUG();
hal_i2s_open(HAL_I2S_ID_1, stream, HAL_I2S_MODE_MASTER);
dma_cfg->src_periph = HAL_AUDMA_I2S1_RX;
} else if (device == AUD_STREAM_USE_I2S1_SLAVE) {
AF_TRACE_DEBUG();
hal_i2s_open(HAL_I2S_ID_1, stream, HAL_I2S_MODE_SLAVE);
dma_cfg->src_periph = HAL_AUDMA_I2S1_RX;
}
#endif
#endif
#ifdef AF_DEVICE_TDM
else if (device == AUD_STREAM_USE_TDM0_MASTER) {
AF_TRACE_DEBUG();
hal_tdm_open(HAL_I2S_ID_0, stream, HAL_I2S_MODE_MASTER);
dma_cfg->src_periph = HAL_AUDMA_I2S0_RX;
AF_TRACE_DEBUG();
} else if (device == AUD_STREAM_USE_TDM0_SLAVE) {
AF_TRACE_DEBUG();
hal_tdm_open(HAL_I2S_ID_0, stream, HAL_I2S_MODE_SLAVE);
dma_cfg->src_periph = HAL_AUDMA_I2S0_RX;
}
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
else if (device == AUD_STREAM_USE_TDM1_MASTER) {
AF_TRACE_DEBUG();
hal_tdm_open(HAL_I2S_ID_1, stream, HAL_I2S_MODE_MASTER);
dma_cfg->src_periph = HAL_AUDMA_I2S1_RX;
} else if (device == AUD_STREAM_USE_TDM1_SLAVE) {
AF_TRACE_DEBUG();
hal_tdm_open(HAL_I2S_ID_1, stream, HAL_I2S_MODE_SLAVE);
dma_cfg->src_periph = HAL_AUDMA_I2S1_RX;
}
#endif
#endif
#ifdef AF_DEVICE_INT_CODEC
else if (device == AUD_STREAM_USE_INT_CODEC) {
AF_TRACE_DEBUG();
codec_int_open();
codec_int_stream_open(stream);
dma_cfg->src_periph = HAL_AUDMA_CODEC_RX;
}
#endif
#ifdef AF_DEVICE_SPDIF
else if (device == AUD_STREAM_USE_INT_SPDIF) {
AF_TRACE_DEBUG();
hal_spdif_open(AF_SPDIF_INST, stream);
dma_cfg->src_periph = HAL_AUDMA_SPDIF0_RX;
}
#endif
#ifdef AF_DEVICE_BT_PCM
else if (device == AUD_STREAM_USE_BT_PCM) {
AF_TRACE_DEBUG();
hal_btpcm_open(AF_BTPCM_INST, stream);
dma_cfg->src_periph = HAL_AUDMA_BTPCM_RX;
}
#endif
#ifdef AF_DEVICE_DPD_RX
else if (device == AUD_STREAM_USE_DPD_RX) {
AF_TRACE_DEBUG();
dma_cfg->src_periph = HAL_AUDMA_DPD_RX;
}
#endif
else {
ASSERT(0, "[%s] ERROR: device %d is not defined!", __func__, device);
}
dma_cfg->ch = hal_audma_get_chan(dma_cfg->src_periph, HAL_DMA_HIGH_PRIO);
}
af_stream_update_dma_buffer(stream, role, cfg);
role->handler = cfg->handler;
af_set_status(id, stream, AF_STATUS_STREAM_OPEN_CLOSE);
#ifndef RTOS
af_clear_flag(&af_flag_signal, 1 << (id * 2 + stream));
af_set_flag(&af_flag_open, 1 << (id * 2 + stream));
#endif
AF_TRACE_DEBUG();
ret = AF_RES_SUCCESS;
_exit:
af_unlock_thread();
if (ret == AF_RES_SUCCESS) {
af_stream_setup(id, stream, &role->cfg);
}
return ret;
}
// volume, path, sample rate, channel num ...
uint32_t af_stream_setup(enum AUD_STREAM_ID_T id, enum AUD_STREAM_T stream,
const struct AF_STREAM_CONFIG_T *cfg) {
AF_TRACE_DEBUG();
struct af_stream_cfg_t *role;
enum AF_RESULT_T ret;
enum AUD_STREAM_USE_DEVICE_T device;
role = af_get_stream_role(id, stream);
TRACE(3, "[%s] id = %d, stream = %d", __func__, id, stream);
ret = AF_RES_FAILD;
af_lock_thread();
// check stream is open
if (!(role->ctl.status & AF_STATUS_STREAM_OPEN_CLOSE)) {
TRACE(2, "[%s] ERROR: status = %d", __func__, role->ctl.status);
goto _exit;
}
device = role->ctl.use_device;
if (&role->cfg != cfg) {
bool update_dma = false;
if (role->cfg.bits != cfg->bits) {
TRACE(4, "[%s] Change bits from %d to %d for stream %d", __func__,
role->cfg.bits, cfg->bits, stream);
update_dma = true;
}
if (role->cfg.data_ptr != cfg->data_ptr) {
TRACE(4, "[%s] Change data_ptr from %p to %p for stream %d", __func__,
role->cfg.data_ptr, cfg->data_ptr, stream);
update_dma = true;
}
if (role->cfg.data_size != cfg->data_size) {
TRACE(4, "[%s] Change data_size from %d to %d for stream %d", __func__,
role->cfg.data_size, cfg->data_size, stream);
update_dma = true;
}
if (update_dma) {
// To avoid FIFO corruption, streams must be stopped before changing
// sample size
ASSERT((role->ctl.status & AF_STATUS_STREAM_START_STOP) == 0,
"[%s] ERROR: Update dma while stream %d started", __func__,
stream);
af_stream_update_dma_buffer(stream, role, cfg);
}
if (role->cfg.sample_rate != cfg->sample_rate) {
TRACE(4, "[%s] Change sample rate from %d to %d for stream %d", __func__,
role->cfg.sample_rate, cfg->sample_rate, stream);
// To avoid L/R sample misalignment, streams must be stopped before
// changing sample rate
ASSERT((role->ctl.status & AF_STATUS_STREAM_START_STOP) == 0,
"[%s] ERROR: Change sample rate from %d to %d while stream %d "
"started",
__func__, role->cfg.sample_rate, cfg->sample_rate, stream);
}
role->cfg = *cfg;
}
AF_TRACE_DEBUG();
if (0) {
}
#ifdef AF_DEVICE_EXT_CODEC
else if (device == AUD_STREAM_USE_EXT_CODEC) {
AF_TRACE_DEBUG();
struct tlv32aic32_config_t tlv32aic32_cfg;
memset(&tlv32aic32_cfg, 0, sizeof(tlv32aic32_cfg));
tlv32aic32_cfg.bits = cfg->bits;
tlv32aic32_cfg.channel_num = cfg->channel_num;
tlv32aic32_cfg.channel_map = cfg->channel_map;
tlv32aic32_cfg.sample_rate = cfg->sample_rate;
tlv32aic32_cfg.use_dma = AF_TRUE;
tlv32aic32_cfg.chan_sep_buf = cfg->chan_sep_buf;
tlv32aic32_cfg.sync_start = cfg->sync_start;
tlv32aic32_cfg.slot_cycles = cfg->slot_cycles;
tlv32aic32_stream_setup(stream, &tlv32aic32_cfg);
}
#endif
#ifdef AF_DEVICE_I2S
else if (device == AUD_STREAM_USE_I2S0_MASTER ||
device == AUD_STREAM_USE_I2S0_SLAVE
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
|| device == AUD_STREAM_USE_I2S1_MASTER ||
device == AUD_STREAM_USE_I2S1_SLAVE
#endif
) {
AF_TRACE_DEBUG();
struct HAL_I2S_CONFIG_T i2s_cfg;
enum HAL_I2S_ID_T i2s_id;
i2s_id = HAL_I2S_ID_0;
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
if (device == AUD_STREAM_USE_I2S1_MASTER ||
device == AUD_STREAM_USE_I2S1_SLAVE) {
i2s_id = HAL_I2S_ID_1;
}
#endif
memset(&i2s_cfg, 0, sizeof(i2s_cfg));
i2s_cfg.use_dma = AF_TRUE;
i2s_cfg.chan_sep_buf = cfg->chan_sep_buf;
i2s_cfg.sync_start = cfg->sync_start;
i2s_cfg.cycles = cfg->slot_cycles;
i2s_cfg.bits = cfg->bits;
i2s_cfg.channel_num = cfg->channel_num;
i2s_cfg.channel_map = cfg->channel_map;
i2s_cfg.sample_rate = cfg->sample_rate;
hal_i2s_setup_stream(i2s_id, stream, &i2s_cfg);
}
#endif
#ifdef AF_DEVICE_TDM
else if (device == AUD_STREAM_USE_TDM0_MASTER ||
device == AUD_STREAM_USE_TDM0_SLAVE
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
|| device == AUD_STREAM_USE_TDM1_MASTER ||
device == AUD_STREAM_USE_TDM1_SLAVE
#endif
) {
AF_TRACE_DEBUG();
struct HAL_TDM_CONFIG_T tdm_cfg;
enum HAL_I2S_ID_T i2s_id;
i2s_id = HAL_I2S_ID_0;
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
if (device == AUD_STREAM_USE_TDM1_MASTER ||
device == AUD_STREAM_USE_TDM1_SLAVE) {
i2s_id = HAL_I2S_ID_1;
}
#endif
memset(&tdm_cfg, 0, sizeof(tdm_cfg));
tdm_cfg.mode = HAL_TDM_MODE_FS_ASSERTED_AT_FIRST;
tdm_cfg.edge = HAL_TDM_FS_EDGE_POSEDGE;
tdm_cfg.cycles = (cfg->channel_num * cfg->slot_cycles);
tdm_cfg.fs_cycles = cfg->fs_cycles;
tdm_cfg.slot_cycles = cfg->slot_cycles;
tdm_cfg.data_offset = 0;
tdm_cfg.sync_start = cfg->sync_start;
TRACE(5, "%s: cycle = %d, fs_cycles = %d, slot_cycles = %d,wait = %d.",
__func__, tdm_cfg.cycles, tdm_cfg.fs_cycles, tdm_cfg.slot_cycles,
tdm_cfg.sync_start);
hal_tdm_setup_stream(i2s_id, stream, cfg->sample_rate, &tdm_cfg);
}
#endif
#ifdef AF_DEVICE_INT_CODEC
else if (device == AUD_STREAM_USE_INT_CODEC) {
AF_TRACE_DEBUG();
struct HAL_CODEC_CONFIG_T codec_cfg;
memset(&codec_cfg, 0, sizeof(codec_cfg));
codec_cfg.bits = cfg->bits;
codec_cfg.sample_rate = cfg->sample_rate;
codec_cfg.channel_num = cfg->channel_num;
codec_cfg.channel_map = cfg->channel_map;
codec_cfg.use_dma = AF_TRUE;
codec_cfg.vol = cfg->vol;
codec_cfg.io_path = cfg->io_path;
AF_TRACE_DEBUG();
codec_int_stream_setup(stream, &codec_cfg);
}
#endif
#ifdef AF_DEVICE_SPDIF
else if (device == AUD_STREAM_USE_INT_SPDIF) {
AF_TRACE_DEBUG();
struct HAL_SPDIF_CONFIG_T spdif_cfg;
memset(&spdif_cfg, 0, sizeof(spdif_cfg));
spdif_cfg.use_dma = AF_TRUE;
spdif_cfg.bits = cfg->bits;
spdif_cfg.channel_num = cfg->channel_num;
spdif_cfg.sample_rate = cfg->sample_rate;
hal_spdif_setup_stream(AF_SPDIF_INST, stream, &spdif_cfg);
}
#endif
#ifdef AF_DEVICE_BT_PCM
else if (device == AUD_STREAM_USE_BT_PCM) {
AF_TRACE_DEBUG();
struct HAL_BTPCM_CONFIG_T btpcm_cfg;
memset(&btpcm_cfg, 0, sizeof(btpcm_cfg));
btpcm_cfg.use_dma = AF_TRUE;
btpcm_cfg.bits = cfg->bits;
btpcm_cfg.channel_num = cfg->channel_num;
btpcm_cfg.sample_rate = cfg->sample_rate;
hal_btpcm_setup_stream(AF_BTPCM_INST, stream, &btpcm_cfg);
}
#endif
#ifdef AF_DEVICE_DPD_RX
else if (device == AUD_STREAM_USE_DPD_RX) {
AF_TRACE_DEBUG();
}
#endif
#ifdef AUDIO_ANC_FB_MC
else if (device == AUD_STREAM_USE_MC) {
AF_TRACE_DEBUG();
hal_codec_setup_mc(cfg->channel_num, cfg->bits);
}
#endif
else {
ASSERT(0, "[%s] ERROR: device %d is not defined!", __func__, device);
}
AF_TRACE_DEBUG();
ret = AF_RES_SUCCESS;
_exit:
af_unlock_thread();
return ret;
}
uint32_t af_stream_mute(enum AUD_STREAM_ID_T id, enum AUD_STREAM_T stream,
bool mute) {
AF_TRACE_DEBUG();
struct af_stream_cfg_t *role;
enum AF_RESULT_T ret;
enum AUD_STREAM_USE_DEVICE_T device;
ret = AF_RES_FAILD;
role = af_get_stream_role(id, stream);
af_lock_thread();
if ((role->ctl.status & AF_STATUS_STREAM_OPEN_CLOSE) == 0) {
TRACE(2, "[%s] ERROR: status = %d", __func__, role->ctl.status);
goto _exit;
}
device = role->ctl.use_device;
if (device == AUD_STREAM_USE_INT_CODEC) {
codec_int_stream_mute(stream, mute);
ret = AF_RES_SUCCESS;
}
_exit:
af_unlock_thread();
return ret;
}
uint32_t af_stream_set_chan_vol(enum AUD_STREAM_ID_T id,
enum AUD_STREAM_T stream,
enum AUD_CHANNEL_MAP_T ch_map, uint8_t vol) {
AF_TRACE_DEBUG();
struct af_stream_cfg_t *role;
enum AF_RESULT_T ret;
enum AUD_STREAM_USE_DEVICE_T device;
ret = AF_RES_FAILD;
role = af_get_stream_role(id, stream);
af_lock_thread();
if ((role->ctl.status & AF_STATUS_STREAM_OPEN_CLOSE) == 0) {
TRACE(2, "[%s] ERROR: status = %d", __func__, role->ctl.status);
goto _exit;
}
device = role->ctl.use_device;
if (device == AUD_STREAM_USE_INT_CODEC) {
codec_int_stream_set_chan_vol(stream, ch_map, vol);
ret = AF_RES_SUCCESS;
}
_exit:
af_unlock_thread();
return ret;
}
uint32_t af_stream_restore_chan_vol(enum AUD_STREAM_ID_T id,
enum AUD_STREAM_T stream) {
AF_TRACE_DEBUG();
struct af_stream_cfg_t *role;
enum AF_RESULT_T ret;
enum AUD_STREAM_USE_DEVICE_T device;
ret = AF_RES_FAILD;
role = af_get_stream_role(id, stream);
af_lock_thread();
if ((role->ctl.status & AF_STATUS_STREAM_OPEN_CLOSE) == 0) {
TRACE(2, "[%s] ERROR: status = %d", __func__, role->ctl.status);
goto _exit;
}
device = role->ctl.use_device;
if (device == AUD_STREAM_USE_INT_CODEC) {
codec_int_stream_restore_chan_vol(stream);
ret = AF_RES_SUCCESS;
}
_exit:
af_unlock_thread();
return ret;
}
#ifdef CODEC_PLAY_BEFORE_CAPTURE
static struct af_stream_cfg_t *codec_capture_role;
static void af_codec_stream_pre_start(enum AUD_STREAM_T stream) {
struct af_stream_cfg_t *role = NULL;
if (stream == AUD_STREAM_CAPTURE) {
return;
}
for (uint8_t id = 0; id < AUD_STREAM_ID_NUM; id++) {
role = af_get_stream_role((enum AUD_STREAM_ID_T)id, AUD_STREAM_CAPTURE);
if (role->cfg.device == AUD_STREAM_USE_INT_CODEC &&
role->ctl.status ==
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE |
AF_STATUS_STREAM_START_STOP)) {
hal_audma_stop(role->dma_cfg.ch);
codec_int_stream_stop(AUD_STREAM_CAPTURE);
codec_capture_role = role;
return;
}
}
}
static void af_codec_stream_post_start(enum AUD_STREAM_T stream) {
if (stream == AUD_STREAM_CAPTURE) {
return;
}
if (codec_capture_role) {
hal_audma_sg_start(&codec_capture_role->dma_desc[0],
&codec_capture_role->dma_cfg);
codec_int_stream_start(AUD_STREAM_CAPTURE);
codec_capture_role = NULL;
}
}
static void af_codec_stream_pre_stop(enum AUD_STREAM_T stream) {
struct af_stream_cfg_t *role = NULL;
if (stream == AUD_STREAM_CAPTURE) {
return;
}
for (uint8_t id = 0; id < AUD_STREAM_ID_NUM; id++) {
role = af_get_stream_role((enum AUD_STREAM_ID_T)id, AUD_STREAM_CAPTURE);
if (role->cfg.device == AUD_STREAM_USE_INT_CODEC &&
role->ctl.status ==
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE |
AF_STATUS_STREAM_START_STOP)) {
hal_audma_stop(role->dma_cfg.ch);
codec_int_stream_stop(AUD_STREAM_CAPTURE);
codec_capture_role = role;
return;
}
}
}
static void af_codec_stream_post_stop(enum AUD_STREAM_T stream) {
if (stream == AUD_STREAM_CAPTURE) {
return;
}
if (codec_capture_role) {
hal_audma_sg_start(&codec_capture_role->dma_desc[0],
&codec_capture_role->dma_cfg);
codec_int_stream_start(AUD_STREAM_CAPTURE);
codec_capture_role = NULL;
}
}
#endif
uint32_t af_stream_start(enum AUD_STREAM_ID_T id, enum AUD_STREAM_T stream) {
struct af_stream_cfg_t *role;
enum AF_RESULT_T ret;
enum AUD_STREAM_USE_DEVICE_T device;
enum HAL_DMA_RET_T dma_ret;
role = af_get_stream_role(id, stream);
TRACE(3, "[%s] id = %d, stream = %d", __func__, id, stream);
af_lock_thread();
// check stream is open and not start.
if (role->ctl.status !=
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE)) {
TRACE(2, "[%s] ERROR: status = %d", __func__, role->ctl.status);
ret = AF_RES_FAILD;
goto _exit;
}
device = role->ctl.use_device;
role->ctl.pp_index = PP_PING;
role->ctl.pp_cnt = 0;
#ifndef RTOS
af_clear_flag(&af_flag_signal, 1 << (id * 2 + stream));
#endif
if (device == AUD_STREAM_USE_INT_CODEC && stream == AUD_STREAM_PLAYBACK) {
#ifdef AUDIO_OUTPUT_PA_ON_FADE_IN
dac_pa_state = AF_DAC_PA_ON_TRIGGER;
// Has the buffer been zero-ed out?
af_zero_mem(role->dma_buf_ptr, role->dma_buf_size);
#ifdef AUDIO_OUTPUT_DC_CALIB_SW
af_codec_playback_sw_dc_calib(role->dma_buf_ptr, role->dma_buf_size,
role->cfg.bits, role->cfg.channel_num);
#endif
dac_dc_start_time = hal_sys_timer_get();
#endif
}
#ifndef CHIP_BEST1000
if (role->cfg.chan_sep_buf && role->cfg.channel_num > AUD_CHANNEL_NUM_1) {
struct HAL_DMA_2D_CFG_T *src, *dst;
struct HAL_DMA_2D_CFG_T dma_2d_cfg;
uint8_t burst_size = 1;
uint32_t chan_xfer_cnt;
src = NULL;
dst = NULL;
if (stream == AUD_STREAM_PLAYBACK) {
if (role->cfg.channel_num == AUD_CHANNEL_NUM_2) {
ASSERT(role->dma_cfg.src_bsize == HAL_DMA_BSIZE_1,
"Play 2D DMA: Bad src burst size: %d", role->dma_cfg.src_bsize);
burst_size = 1;
src = &dma_2d_cfg;
}
} else {
if (role->cfg.channel_num > AUD_CHANNEL_NUM_1) {
ASSERT(role->dma_cfg.src_bsize == role->dma_cfg.dst_bsize,
"Cap 2D DMA: src burst size (%d) != dst (%d)",
role->dma_cfg.src_bsize, role->dma_cfg.dst_bsize);
if (role->dma_cfg.dst_bsize == HAL_DMA_BSIZE_1) {
burst_size = 1;
} else if (role->dma_cfg.dst_bsize == HAL_DMA_BSIZE_4) {
burst_size = 4;
} else if (role->dma_cfg.dst_bsize == HAL_DMA_BSIZE_8) {
burst_size = 8;
} else {
ASSERT(false, "Cap 2D DMA: Bad dst burst size: %d",
role->dma_cfg.dst_bsize);
}
dst = &dma_2d_cfg;
}
}
if (src || dst) {
chan_xfer_cnt =
role->dma_cfg.src_tsize * AUDIO_BUFFER_COUNT / role->cfg.channel_num;
dma_2d_cfg.xcount = role->cfg.channel_num;
dma_2d_cfg.xmodify = chan_xfer_cnt - burst_size;
dma_2d_cfg.ycount = chan_xfer_cnt / burst_size;
dma_2d_cfg.ymodify = -chan_xfer_cnt * (role->cfg.channel_num - 1);
}
dma_ret = hal_dma_sg_2d_start(&role->dma_desc[0], &role->dma_cfg, src, dst);
} else
#endif
{
dma_ret = hal_dma_sg_start(&role->dma_desc[0], &role->dma_cfg);
}
ASSERT(dma_ret == HAL_DMA_OK,
"[%s] Failed to start dma for stream %d: ret=%d", __func__, stream,
dma_ret);
AF_TRACE_DEBUG();
if (0) {
}
#ifdef AF_DEVICE_EXT_CODEC
else if (device == AUD_STREAM_USE_EXT_CODEC) {
AF_TRACE_DEBUG();
tlv32aic32_stream_start(stream);
}
#endif
#ifdef AF_DEVICE_I2S
else if (device == AUD_STREAM_USE_I2S0_MASTER ||
device == AUD_STREAM_USE_I2S0_SLAVE) {
hal_i2s_start_stream(HAL_I2S_ID_0, stream);
}
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
else if (device == AUD_STREAM_USE_I2S1_MASTER ||
device == AUD_STREAM_USE_I2S1_SLAVE) {
hal_i2s_start_stream(HAL_I2S_ID_1, stream);
}
#endif
#endif
#ifdef AF_DEVICE_TDM
else if (device == AUD_STREAM_USE_TDM0_MASTER ||
device == AUD_STREAM_USE_TDM0_SLAVE) {
hal_tdm_start_stream(HAL_I2S_ID_0, stream);
}
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
else if (device == AUD_STREAM_USE_TDM1_MASTER ||
device == AUD_STREAM_USE_TDM1_SLAVE) {
hal_tdm_start_stream(HAL_I2S_ID_1, stream);
}
#endif
#endif
#ifdef AF_DEVICE_INT_CODEC
else if (device == AUD_STREAM_USE_INT_CODEC) {
AF_TRACE_DEBUG();
#ifdef CODEC_PLAY_BEFORE_CAPTURE
af_codec_stream_pre_start(stream);
#endif
codec_int_stream_start(stream);
#ifdef CODEC_PLAY_BEFORE_CAPTURE
af_codec_stream_post_start(stream);
#endif
}
#endif
#ifdef AF_DEVICE_SPDIF
else if (device == AUD_STREAM_USE_INT_SPDIF) {
AF_TRACE_DEBUG();
hal_spdif_start_stream(AF_SPDIF_INST, stream);
}
#endif
#ifdef AF_DEVICE_BT_PCM
else if (device == AUD_STREAM_USE_BT_PCM) {
AF_TRACE_DEBUG();
hal_btpcm_start_stream(AF_BTPCM_INST, stream);
}
#endif
#ifdef AF_DEVICE_DPD_RX
else if (device == AUD_STREAM_USE_DPD_RX) {
AF_TRACE_DEBUG();
hal_btpcm_start_stream(AF_BTPCM_INST, stream);
}
#endif
#ifdef AUDIO_ANC_FB_MC
else if (device == AUD_STREAM_USE_MC) {
AF_TRACE_DEBUG();
}
#endif
else {
ASSERT(0, "[%s] ERROR: device %d is not defined!", __func__, device);
}
AF_TRACE_DEBUG();
af_set_status(id, stream, AF_STATUS_STREAM_START_STOP);
ret = AF_RES_SUCCESS;
_exit:
af_unlock_thread();
return ret;
}
uint32_t af_stream_stop(enum AUD_STREAM_ID_T id, enum AUD_STREAM_T stream) {
struct af_stream_cfg_t *role;
enum AF_RESULT_T ret;
enum AUD_STREAM_USE_DEVICE_T device;
role = af_get_stream_role(id, stream);
TRACE(3, "[%s] id = %d, stream = %d", __func__, id, stream);
af_lock_thread();
device = role->ctl.use_device;
if (device == AUD_STREAM_USE_INT_CODEC &&
role->ctl.status ==
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE |
AF_STATUS_STREAM_START_STOP | AF_STATUS_STREAM_PAUSE_RESTART)) {
af_clear_status(id, stream, AF_STATUS_STREAM_PAUSE_RESTART);
goto _pause_stop;
}
// check stream is start and not stop
if (role->ctl.status != (AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE |
AF_STATUS_STREAM_START_STOP)) {
TRACE(2, "[%s] ERROR: status = %d", __func__, role->ctl.status);
ret = AF_RES_FAILD;
goto _exit;
}
#if defined(RTOS) && defined(AF_STREAM_ID_0_PLAYBACK_FADEOUT)
if (id == AUD_STREAM_ID_0 && stream == AUD_STREAM_PLAYBACK) {
af_stream_fadeout_start(512);
af_stream_stop_wait_finish();
}
#endif
if (device == AUD_STREAM_USE_INT_CODEC && stream == AUD_STREAM_PLAYBACK) {
#ifdef AUDIO_OUTPUT_PA_OFF_FADE_OUT
dac_pa_state = AF_DAC_PA_OFF_TRIGGER;
af_unlock_thread();
while (dac_pa_state != AF_DAC_PA_NULL) {
#ifdef RTOS
osSignalWait((1 << AF_FADE_OUT_SIGNAL_ID), 300);
osSignalClear(fade_thread_id, (1 << AF_FADE_OUT_SIGNAL_ID));
#else
af_thread(NULL);
#endif
}
af_lock_thread();
#elif defined(AUDIO_OUTPUT_PA_ON_FADE_IN)
dac_pa_state = AF_DAC_PA_NULL;
analog_aud_codec_speaker_enable(false);
dac_pa_stop_time = hal_sys_timer_get();
#endif // !AUDIO_OUTPUT_PA_OFF_FADE_OUT && AUDIO_OUTPUT_PA_ON_FADE_IN
}
hal_audma_stop(role->dma_cfg.ch);
#if defined(RTOS) && defined(AF_STREAM_ID_0_PLAYBACK_FADEOUT)
if (id == AUD_STREAM_ID_0 && stream == AUD_STREAM_PLAYBACK) {
af_stream_fadeout_stop();
}
#endif
if (0) {
}
#ifdef AF_DEVICE_EXT_CODEC
else if (device == AUD_STREAM_USE_EXT_CODEC) {
AF_TRACE_DEBUG();
tlv32aic32_stream_stop(stream);
}
#endif
#ifdef AF_DEVICE_I2S
else if (device == AUD_STREAM_USE_I2S0_MASTER ||
device == AUD_STREAM_USE_I2S0_SLAVE) {
AF_TRACE_DEBUG();
hal_i2s_stop_stream(HAL_I2S_ID_0, stream);
}
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
else if (device == AUD_STREAM_USE_I2S1_MASTER ||
device == AUD_STREAM_USE_I2S1_SLAVE) {
AF_TRACE_DEBUG();
hal_i2s_stop_stream(HAL_I2S_ID_1, stream);
}
#endif
#endif
#ifdef AF_DEVICE_TDM
else if (device == AUD_STREAM_USE_TDM0_MASTER ||
device == AUD_STREAM_USE_TDM0_SLAVE) {
AF_TRACE_DEBUG();
hal_tdm_stop_stream(HAL_I2S_ID_0, stream);
}
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
else if (device == AUD_STREAM_USE_TDM1_MASTER ||
device == AUD_STREAM_USE_TDM1_SLAVE) {
AF_TRACE_DEBUG();
hal_tdm_stop_stream(HAL_I2S_ID_1, stream);
}
#endif
#endif
#ifdef AF_DEVICE_INT_CODEC
else if (device == AUD_STREAM_USE_INT_CODEC) {
AF_TRACE_DEBUG();
#ifdef CODEC_PLAY_BEFORE_CAPTURE
af_codec_stream_pre_stop(stream);
#endif
codec_int_stream_stop(stream);
#ifdef CODEC_PLAY_BEFORE_CAPTURE
af_codec_stream_post_stop(stream);
#endif
}
#endif
#ifdef AF_DEVICE_SPDIF
else if (device == AUD_STREAM_USE_INT_SPDIF) {
AF_TRACE_DEBUG();
hal_spdif_stop_stream(AF_SPDIF_INST, stream);
}
#endif
#ifdef AF_DEVICE_BT_PCM
else if (device == AUD_STREAM_USE_BT_PCM) {
AF_TRACE_DEBUG();
hal_btpcm_stop_stream(AF_BTPCM_INST, stream);
}
#endif
#ifdef AF_DEVICE_DPD_RX
else if (device == AUD_STREAM_USE_DPD_RX) {
AF_TRACE_DEBUG();
hal_btpcm_stop_stream(AF_BTPCM_INST, stream);
}
#endif
#ifdef AUDIO_ANC_FB_MC
else if (device == AUD_STREAM_USE_MC) {
AF_TRACE_DEBUG();
}
#endif
else {
ASSERT(0, "[%s] ERROR: device %d is not defined!", __func__, device);
}
_pause_stop:
AF_TRACE_DEBUG();
af_clear_status(id, stream, AF_STATUS_STREAM_START_STOP);
#ifndef RTOS
af_clear_flag(&af_flag_signal, 1 << (id * 2 + stream));
#endif
ret = AF_RES_SUCCESS;
_exit:
af_unlock_thread();
return ret;
}
uint32_t af_stream_pause(enum AUD_STREAM_ID_T id, enum AUD_STREAM_T stream) {
#ifdef CHIP_BEST1000
struct af_stream_cfg_t *role = NULL;
enum AF_RESULT_T ret;
role = af_get_stream_role(id, stream);
TRACE(3, "[%s] id = %d, stream = %d", __func__, id, stream);
af_lock_thread();
if (role->cfg.device != AUD_STREAM_USE_INT_CODEC) {
ret = AF_RES_FAILD;
goto _exit;
}
if (role->ctl.status != (AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE |
AF_STATUS_STREAM_START_STOP)) {
TRACE(2, "[%s] ERROR: status = %d", __func__, role->ctl.status);
ret = AF_RES_FAILD;
goto _exit;
}
#if defined(AUDIO_OUTPUT_PA_ON_FADE_IN) || defined(AUDIO_OUTPUT_PA_OFF_FADE_OUT)
if (AUD_STREAM_PLAYBACK == stream) {
dac_pa_state = AF_DAC_PA_NULL;
analog_aud_codec_speaker_enable(false);
dac_pa_stop_time = hal_sys_timer_get();
}
#endif
hal_audma_stop(role->dma_cfg.ch);
codec_int_stream_stop(stream);
af_set_status(id, stream, AF_STATUS_STREAM_PAUSE_RESTART);
ret = AF_RES_SUCCESS;
_exit:
af_unlock_thread();
return ret;
#else
return af_stream_stop(id, stream);
#endif
}
uint32_t af_stream_restart(enum AUD_STREAM_ID_T id, enum AUD_STREAM_T stream) {
#ifdef CHIP_BEST1000
struct af_stream_cfg_t *role = NULL;
enum AF_RESULT_T ret;
role = af_get_stream_role(id, stream);
TRACE(3, "[%s] id = %d, stream = %d", __func__, id, stream);
af_lock_thread();
if (role->cfg.device != AUD_STREAM_USE_INT_CODEC) {
ret = AF_RES_FAILD;
goto _exit;
}
if (role->ctl.status !=
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE |
AF_STATUS_STREAM_START_STOP | AF_STATUS_STREAM_PAUSE_RESTART)) {
TRACE(2, "[%s] ERROR: status = %d", __func__, role->ctl.status);
ret = AF_RES_FAILD;
goto _exit;
}
role->ctl.pp_index = PP_PING;
role->ctl.pp_cnt = 0;
#ifdef AUDIO_OUTPUT_PA_ON_FADE_IN
if (AUD_STREAM_PLAYBACK == stream) {
dac_pa_state = AF_DAC_PA_ON_TRIGGER;
af_zero_mem(role->dma_buf_ptr, role->dma_buf_size);
#ifdef AUDIO_OUTPUT_DC_CALIB_SW
af_codec_playback_sw_dc_calib(role->dma_buf_ptr, role->dma_buf_size,
role->cfg.bits, role->cfg.channel_num);
#endif
dac_dc_start_time = hal_sys_timer_get();
}
#endif
hal_audma_sg_start(&role->dma_desc[0], &role->dma_cfg);
codec_int_stream_start(stream);
af_clear_status(id, stream, AF_STATUS_STREAM_PAUSE_RESTART);
ret = AF_RES_SUCCESS;
_exit:
af_unlock_thread();
return ret;
#else
return af_stream_start(id, stream);
#endif
}
uint32_t af_stream_close(enum AUD_STREAM_ID_T id, enum AUD_STREAM_T stream) {
struct af_stream_cfg_t *role;
enum AF_RESULT_T ret;
enum AUD_STREAM_USE_DEVICE_T device;
role = af_get_stream_role(id, stream);
TRACE(3, "[%s] id = %d, stream = %d", __func__, id, stream);
af_lock_thread();
// check stream is stop and not close.
if (role->ctl.status !=
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE)) {
TRACE(2, "[%s] ERROR: status = %d", __func__, role->ctl.status);
ret = AF_RES_FAILD;
goto _exit;
}
device = role->ctl.use_device;
memset(role->dma_buf_ptr, 0, role->dma_buf_size);
hal_audma_free_chan(role->dma_cfg.ch);
// TODO: more parameter should be set!!!
// memset(role, 0xff, sizeof(struct af_stream_cfg_t));
role->handler = NULL;
role->ctl.pp_index = PP_PING;
role->ctl.use_device = AUD_STREAM_USE_DEVICE_NULL;
role->dma_buf_ptr = NULL;
role->dma_buf_size = 0;
role->dma_cfg.ch = HAL_DMA_CHAN_NONE;
if (0) {
}
#ifdef AF_DEVICE_EXT_CODEC
else if (device == AUD_STREAM_USE_EXT_CODEC) {
AF_TRACE_DEBUG();
tlv32aic32_stream_close(stream);
}
#endif
#ifdef AF_DEVICE_I2S
else if (device == AUD_STREAM_USE_I2S0_MASTER ||
device == AUD_STREAM_USE_I2S0_SLAVE) {
AF_TRACE_DEBUG();
hal_i2s_close(HAL_I2S_ID_0, stream);
}
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
else if (device == AUD_STREAM_USE_I2S1_MASTER ||
device == AUD_STREAM_USE_I2S1_SLAVE) {
AF_TRACE_DEBUG();
hal_i2s_close(HAL_I2S_ID_1, stream);
}
#endif
#endif
#ifdef AF_DEVICE_TDM
else if (device == AUD_STREAM_USE_TDM0_MASTER ||
device == AUD_STREAM_USE_TDM0_SLAVE) {
AF_TRACE_DEBUG();
hal_tdm_close(HAL_I2S_ID_0, stream);
}
#if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1)
else if (device == AUD_STREAM_USE_TDM1_MASTER ||
device == AUD_STREAM_USE_TDM1_SLAVE) {
AF_TRACE_DEBUG();
hal_tdm_close(HAL_I2S_ID_1, stream);
}
#endif
#endif
#ifdef AF_DEVICE_INT_CODEC
else if (device == AUD_STREAM_USE_INT_CODEC) {
AF_TRACE_DEBUG();
codec_int_stream_close(stream);
codec_int_close(CODEC_CLOSE_NORMAL);
}
#endif
#ifdef AF_DEVICE_SPDIF
else if (device == AUD_STREAM_USE_INT_SPDIF) {
AF_TRACE_DEBUG();
hal_spdif_close(AF_SPDIF_INST, stream);
}
#endif
#ifdef AF_DEVICE_BT_PCM
else if (device == AUD_STREAM_USE_BT_PCM) {
AF_TRACE_DEBUG();
hal_btpcm_close(AF_BTPCM_INST, stream);
}
#endif
#ifdef AF_DEVICE_DPD_RX
else if (device == AUD_STREAM_USE_DPD_RX) {
AF_TRACE_DEBUG();
}
#endif
#ifdef AUDIO_ANC_FB_MC
else if (device == AUD_STREAM_USE_MC) {
AF_TRACE_DEBUG();
}
#endif
else {
ASSERT(0, "[%s] ERROR: device %d is not defined!", __func__, device);
}
AF_TRACE_DEBUG();
af_clear_status(id, stream, AF_STATUS_STREAM_OPEN_CLOSE);
#ifndef RTOS
af_clear_flag(&af_flag_open, 1 << (id * 2 + stream));
if (af_flag_open == 0) {
hal_cpu_wake_unlock(AF_CPU_WAKE_USER);
}
#endif
ret = AF_RES_SUCCESS;
_exit:
af_unlock_thread();
return ret;
}
uint32_t af_close(void) {
struct af_stream_cfg_t *role;
// Avoid blocking shutdown process
// af_lock_thread();
for (uint8_t id = 0; id < AUD_STREAM_ID_NUM; id++) {
for (uint8_t stream = 0; stream < AUD_STREAM_NUM; stream++) {
role = af_get_stream_role((enum AUD_STREAM_ID_T)id,
(enum AUD_STREAM_T)stream);
role->ctl.status = AF_STATUS_NULL;
}
}
codec_int_close(CODEC_CLOSE_FORCED);
// af_unlock_thread();
return AF_RES_SUCCESS;
}
uint32_t af_stream_get_cur_dma_addr(enum AUD_STREAM_ID_T id,
enum AUD_STREAM_T stream) {
struct af_stream_cfg_t *role;
int i;
uint32_t addr = 0;
role = af_get_stream_role(id, stream);
// check stream is start and not stop
if (role->ctl.status == (AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE |
AF_STATUS_STREAM_START_STOP)) {
if (role->dma_cfg.ch != HAL_DMA_CHAN_NONE) {
for (i = 0; i < 2; i++) {
if (stream == AUD_STREAM_PLAYBACK) {
addr = hal_audma_get_cur_src_addr(role->dma_cfg.ch);
} else {
addr = hal_audma_get_cur_dst_addr(role->dma_cfg.ch);
}
if (addr) {
break;
}
// Previous link list item was just finished. Read current DMA address
// again.
}
}
}
return addr;
}
int af_stream_get_cur_dma_pos(enum AUD_STREAM_ID_T id,
enum AUD_STREAM_T stream) {
struct af_stream_cfg_t *role;
uint32_t addr;
int pos;
role = af_get_stream_role(id, stream);
addr = af_stream_get_cur_dma_addr(id, stream);
pos = addr - (uint32_t)role->dma_buf_ptr;
if (pos < 0 || pos > role->dma_buf_size) {
return -1;
}
#ifndef CHIP_BEST1000
if (role->cfg.chan_sep_buf && role->cfg.channel_num > AUD_CHANNEL_NUM_1) {
uint32_t chan_size;
uint8_t chan_idx;
uint8_t desc_idx;
uint16_t chan_desc_offset;
uint16_t chan_desc_xfer_size;
uint32_t chan_offset;
chan_size = role->dma_buf_size / role->cfg.channel_num;
chan_desc_xfer_size = chan_size / AUDIO_BUFFER_COUNT;
chan_idx = pos / chan_size;
chan_offset = pos % chan_size;
desc_idx = chan_offset / chan_desc_xfer_size;
chan_desc_offset = chan_offset % chan_desc_xfer_size;
pos = desc_idx * (role->dma_buf_size / AUDIO_BUFFER_COUNT) +
chan_idx * chan_desc_xfer_size + chan_desc_offset;
}
#endif
return pos;
}
int af_stream_buffer_error(enum AUD_STREAM_ID_T id, enum AUD_STREAM_T stream) {
return af_sig_lost_cnt[id][stream];
}
uint32_t af_stream_dma_tc_irq_enable(enum AUD_STREAM_ID_T id,
enum AUD_STREAM_T stream) {
struct af_stream_cfg_t *role;
role = af_get_stream_role(id, stream);
// Check if opened
if ((role->ctl.status &
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE)) ==
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE)) {
hal_dma_tc_irq_enable(role->dma_cfg.ch);
return AF_RES_SUCCESS;
}
return AF_RES_FAILD;
}
uint32_t af_stream_dma_tc_irq_disable(enum AUD_STREAM_ID_T id,
enum AUD_STREAM_T stream) {
struct af_stream_cfg_t *role;
role = af_get_stream_role(id, stream);
// Check if opened
if ((role->ctl.status &
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE)) ==
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE)) {
hal_dma_tc_irq_disable(role->dma_cfg.ch);
return AF_RES_SUCCESS;
}
return AF_RES_FAILD;
}
#ifdef RTOS
void af_set_irq_notification(AF_IRQ_NOTIFICATION_T notif) { irq_notif = notif; }
static int af_priority[AF_USER_NUM];
void af_set_priority(AF_USER_E user, int priority) {
uint8_t i = 0;
int max_priority = 0;
af_priority[user] = priority;
for (i = 0; i < AF_USER_NUM; i++) {
if (max_priority < af_priority[i]) {
max_priority = af_priority[i];
}
}
if (max_priority != af_get_priority()) {
osThreadSetPriority(af_thread_tid, max_priority);
}
}
int af_get_priority(void) { return (int)osThreadGetPriority(af_thread_tid); }
int af_get_default_priority(void) { return af_default_priority; }
void af_reset_priority(void) {
osThreadSetPriority(af_thread_tid, af_default_priority);
}
#endif
void af_codec_tune_resample_rate(enum AUD_STREAM_T stream, float ratio) {
af_lock_thread();
af_codec_direct_tune_resample_rate(stream, ratio);
af_unlock_thread();
}
void af_codec_direct_tune_resample_rate(enum AUD_STREAM_T stream, float ratio) {
ASSERT(stream < AUD_STREAM_NUM, "[%s] Bad stream=%d", __func__, stream);
hal_codec_tune_resample_rate(stream, ratio);
}
void af_codec_tune_both_resample_rate(float ratio) {
af_lock_thread();
hal_codec_tune_both_resample_rate(ratio);
af_unlock_thread();
}
void af_codec_tune_pll(float ratio) {
af_lock_thread();
analog_aud_pll_tune(ratio);
af_unlock_thread();
}
void af_codec_tune_xtal(float ratio) {
af_lock_thread();
analog_aud_xtal_tune(ratio);
af_unlock_thread();
}
void af_codec_tune(enum AUD_STREAM_T stream, float ratio) {
af_lock_thread();
af_codec_direct_tune(stream, ratio);
af_unlock_thread();
}
void af_codec_direct_tune(enum AUD_STREAM_T stream, float ratio) {
ASSERT(stream <= AUD_STREAM_NUM, "[%s] Bad stream=%d", __func__, stream);
#ifdef __AUDIO_RESAMPLE__
if (hal_cmu_get_audio_resample_status()) {
if (stream < AUD_STREAM_NUM) {
hal_codec_tune_resample_rate(stream, ratio);
} else {
hal_codec_tune_both_resample_rate(ratio);
}
} else
#endif
{
analog_aud_pll_tune(ratio);
}
}
void af_codec_set_perf_test_power(int type) {
af_lock_thread();
hal_codec_dac_gain_m60db_check((enum HAL_CODEC_PERF_TEST_POWER_T)type);
af_unlock_thread();
}
void af_codec_set_noise_reduction(bool enable) {
af_lock_thread();
hal_codec_set_noise_reduction(enable);
af_unlock_thread();
}
void af_codec_bt_trigger_config(bool en,
AF_CODEC_BT_TRIGGER_CALLBACK callback) {
if (en) {
hal_codec_set_bt_trigger_callback(callback);
hal_codec_bt_trigger_start();
} else {
hal_codec_bt_trigger_stop();
}
}
void af_codec_sync_config(enum AUD_STREAM_T stream,
enum AF_CODEC_SYNC_TYPE_T type, bool enable) {
#ifndef CHIP_BEST1000
af_lock_thread();
if (stream == AUD_STREAM_PLAYBACK) {
if (enable) {
hal_codec_sync_dac_enable((enum HAL_CODEC_SYNC_TYPE_T)type);
} else {
hal_codec_sync_dac_disable();
}
} else {
if (enable) {
hal_codec_sync_adc_enable((enum HAL_CODEC_SYNC_TYPE_T)type);
} else {
hal_codec_sync_adc_disable();
}
}
af_unlock_thread();
#endif
}
void af_i2s_sync_config(enum AUD_STREAM_T stream, enum AF_I2S_SYNC_TYPE_T type,
bool enable) {
#ifdef CHIP_BEST2300A
af_lock_thread();
if (stream == AUD_STREAM_PLAYBACK) {
if (enable) {
hal_i2s_clk_sync_enable((enum HAL_I2S_SYNC_TYPE_T)type);
} else {
hal_i2s_clk_sync_disable();
}
} else {
if (enable) {
hal_i2s_clk_sync_enable((enum HAL_I2S_SYNC_TYPE_T)type);
} else {
hal_i2s_clk_sync_disable();
}
}
af_unlock_thread();
#endif
}
void af_codec_sync_resample_rate_config(enum AUD_STREAM_T stream,
enum AF_CODEC_SYNC_TYPE_T type,
bool enable) {
#ifndef CHIP_BEST1000
af_lock_thread();
if (stream == AUD_STREAM_PLAYBACK) {
if (enable) {
hal_codec_sync_dac_resample_rate_enable((enum HAL_CODEC_SYNC_TYPE_T)type);
} else {
hal_codec_sync_dac_resample_rate_disable();
}
} else {
if (enable) {
hal_codec_sync_adc_resample_rate_enable((enum HAL_CODEC_SYNC_TYPE_T)type);
} else {
hal_codec_sync_adc_resample_rate_disable();
}
}
af_unlock_thread();
#endif
}
void af_codec_sync_gain_config(enum AUD_STREAM_T stream,
enum AF_CODEC_SYNC_TYPE_T type, bool enable) {
#ifndef CHIP_BEST1000
af_lock_thread();
if (stream == AUD_STREAM_PLAYBACK) {
if (enable) {
hal_codec_sync_dac_gain_enable((enum HAL_CODEC_SYNC_TYPE_T)type);
} else {
hal_codec_sync_dac_gain_disable();
}
} else {
if (enable) {
hal_codec_sync_adc_gain_enable((enum HAL_CODEC_SYNC_TYPE_T)type);
} else {
hal_codec_sync_adc_gain_disable();
}
}
af_unlock_thread();
#endif
}
void af_codec_swap_output(bool swap) {
af_lock_thread();
hal_codec_swap_output(swap);
af_unlock_thread();
}
void af_codec_set_playback_post_handler(AF_CODEC_PLAYBACK_POST_HANDLER_T hdlr) {
codec_play_post_hdlr = hdlr;
}
int af_anc_open(enum ANC_TYPE_T type, enum AUD_SAMPRATE_T play_rate,
enum AUD_SAMPRATE_T capture_rate, AF_ANC_HANDLER handler) {
FUNC_ENTRY_TRACE();
af_lock_thread();
codec_anc_open(type, play_rate, capture_rate, handler);
af_unlock_thread();
return AF_RES_SUCCESS;
}
int af_anc_close(enum ANC_TYPE_T type) {
FUNC_ENTRY_TRACE();
af_lock_thread();
codec_anc_close(type);
af_unlock_thread();
return AF_RES_SUCCESS;
}
#ifdef VOICE_DETECTOR_EN
int af_vad_open(const struct AUD_VAD_CONFIG_T *cfg) {
FUNC_ENTRY_TRACE();
af_lock_thread();
codec_vad_open(cfg);
af_unlock_thread();
return AF_RES_SUCCESS;
}
int af_vad_close(void) {
FUNC_ENTRY_TRACE();
af_lock_thread();
codec_vad_close();
af_unlock_thread();
return AF_RES_SUCCESS;
}
int af_vad_start(void) {
FUNC_ENTRY_TRACE();
af_lock_thread();
hal_codec_vad_start();
af_unlock_thread();
return AF_RES_SUCCESS;
}
int af_vad_stop(void) {
FUNC_ENTRY_TRACE();
af_lock_thread();
hal_codec_vad_stop();
af_unlock_thread();
return AF_RES_SUCCESS;
}
uint32_t af_vad_get_data(uint8_t *buf, uint32_t len) {
return hal_codec_vad_recv_data(buf, len);
}
void af_vad_get_data_info(struct CODEC_VAD_BUF_INFO_T *vad_buf_info) {
hal_codec_get_vad_data_info(vad_buf_info);
}
#endif
#ifdef CODEC_DSD
void af_dsd_enable(void) {
enum AUD_STREAM_ID_T id;
struct af_stream_cfg_t *role;
bool opened = false;
af_lock_thread();
for (id = AUD_STREAM_ID_0; id < AUD_STREAM_ID_NUM; id++) {
role = af_get_stream_role(id, AUD_STREAM_PLAYBACK);
if (role->ctl.status & AF_STATUS_STREAM_OPEN_CLOSE) {
if (role->cfg.device == AUD_STREAM_USE_INT_CODEC &&
role->dma_cfg.dst_periph == HAL_AUDMA_CODEC_TX) {
ASSERT(role->ctl.status ==
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE),
"Bad stream status when DSD enabled: 0x%X", role->ctl.status);
role->dma_cfg.dst_periph = HAL_AUDMA_DSD_TX;
af_stream_update_dma_buffer(AUD_STREAM_PLAYBACK, role, &role->cfg);
opened = true;
break;
}
}
}
hal_codec_dsd_enable();
af_dsd_enabled = true;
af_unlock_thread();
if (opened) {
// Enable DSD sample rate handling
af_stream_setup(id, AUD_STREAM_PLAYBACK, &role->cfg);
}
}
void af_dsd_disable(void) {
enum AUD_STREAM_ID_T id;
struct af_stream_cfg_t *role;
bool opened = false;
af_lock_thread();
for (id = AUD_STREAM_ID_0; id < AUD_STREAM_ID_NUM; id++) {
role = af_get_stream_role(id, AUD_STREAM_PLAYBACK);
if (role->ctl.status & AF_STATUS_STREAM_OPEN_CLOSE) {
if (role->cfg.device == AUD_STREAM_USE_INT_CODEC &&
role->dma_cfg.dst_periph == HAL_AUDMA_DSD_TX) {
ASSERT(role->ctl.status ==
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE),
"Bad stream status when DSD disabled: 0x%X", role->ctl.status);
role->dma_cfg.dst_periph = HAL_AUDMA_CODEC_TX;
af_stream_update_dma_buffer(AUD_STREAM_PLAYBACK, role, &role->cfg);
opened = true;
break;
}
}
}
hal_codec_dsd_disable();
af_dsd_enabled = false;
af_unlock_thread();
if (opened) {
// Disable DSD sample rate handling
af_stream_setup(id, AUD_STREAM_PLAYBACK, &role->cfg);
}
}
#endif
#ifdef __RAND_FROM_MIC__
uint8_t random_mic_is_on(uint8_t *deviceId) {
struct af_stream_cfg_t *role = NULL;
*deviceId = 0;
for (uint8_t id = 0; id < AUD_STREAM_ID_NUM; id++) {
role = af_get_stream_role((enum AUD_STREAM_ID_T)id, AUD_STREAM_CAPTURE);
if (role->cfg.device == AUD_STREAM_USE_INT_CODEC &&
role->ctl.status ==
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE |
AF_STATUS_STREAM_START_STOP)) {
return RAND_STATUS_MIC_STARTED;
} else if (role->cfg.device == AUD_STREAM_USE_INT_CODEC &&
role->ctl.status ==
(AF_STATUS_OPEN_CLOSE | AF_STATUS_STREAM_OPEN_CLOSE)) {
*deviceId = id;
return RAND_STATUS_MIC_OPENED;
}
}
return RAND_STATUS_CLOSE;
}
#endif