dca92cf01f
As we will never get their FGPA source code. Zero loss.
3140 lines
84 KiB
C
3140 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
|