add first commit

This commit is contained in:
dylancaowugang 2022-08-15 17:20:27 +08:00
commit 235a402c8c
2046 changed files with 901681 additions and 0 deletions

99
.gitignore vendored Normal file
View file

@ -0,0 +1,99 @@
#
# NOTE! Don't add files that are generated in specific
# subdirectories here. Add them in the ".gitignore" file
# in that subdirectory instead.
#
# NOTE! Please use 'git ls-files -i --exclude-standard'
# command after changing this file, to see if there are
# any tracked files which get ignored after the change.
#
# ('git ls-files -i --exclude-standard -ocs --directory'
# command can show all the tracked and untracked files
# which get ignored after the change.)
#
# Hidden files
.*
# Except for these hidden files
!.gitignore
!.gitattributes
!.mailmap
# Backup files
*~
*.bak
*.BAK
*.orig
\#*#
# Tag files
/tags
/TAGS
/cscope.*
/ncscope.*
/compile_commands.json
# Object files
*.o
*.o.*
*.ko
*.obj
*.lo
*.slo
*.py[co]
# List files
*.i
*.lst
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lai
*.pyd
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.elf
*.i*86
*.x86_64
*.hex
# Source insight project files
/[sS][iI]/
# Generated project files
*.ncb
*.idb
*.pdb
*.sdf
*.suo
*.opensdf
#/Debug/
#/Release/
Debug/
Release/
/ipch/
# Library dir
#lib/
# Build dir
/out/
*.pre
# configuration file
# *.ini

1043
Makefile Normal file

File diff suppressed because it is too large Load diff

52
apps/Makefile Normal file
View file

@ -0,0 +1,52 @@
obj-y := audioplayers/ common/ main/ key/ pwl/ battery/ factory/
ifeq ($(APP_TEST_AUDIO),1)
obj-y += apptester/
endif
ifeq ($(BTUSB_AUDIO_MODE),1)
obj-y += usbaudio/
endif
ifeq ($(BT_USB_AUDIO_DUAL_MODE),1)
obj-y += btusbaudio/
obj-y += usbaudio/
endif
ifeq ($(APP_TEST_SDMMC),1)
obj-y += sdmmc/
endif
ifeq ($(ANC_APP),1)
obj-y += anc/
endif
ifeq ($(VOICE_DETECTOR_EN),1)
obj-y += voice_detector/
endif
ifeq ($(PC_CMD_UART),1)
obj-y += cmd/
endif
subdir-ccflags-y += -Iapps/apptester \
-Iapps/audioplayers \
-Iapps/common \
-Iapps/sdmmc \
-Iapps/main \
-Iapps/cmd \
-Iapps/key \
-Iapps/pwl \
-Iapps/battery \
-Iservices/voicepath \
-Iservices/ble_app/app_datapath \
-Iutils/list \
-Iutils/heap \
-Iservices/multimedia/audio/process/filters/include
ifeq ($(BT_USB_AUDIO_DUAL_MODE),1)
subdir-ccflags-y += -Iapps/btusbaudio
endif
ifeq ($(A2DP_LDAC_ON),1)
subdir-ccflags-y += -Ithirdparty/audio_codec_lib/ldac/inc
endif

105
apps/anc/Makefile Normal file
View file

@ -0,0 +1,105 @@
cur_dir := $(dir $(lastword $(MAKEFILE_LIST)))
obj_s := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)src/*.s))
obj_c := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)src/*.c))
obj_cpp := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)src/*.cpp))
ifeq ($(ANC_APP),1)
CFLAGS_app_anc.o += -DANC_APP
endif
ifeq ($(ANC_FF_ENABLED),1)
CFLAGS_app_anc.o += -DANC_FF_ENABLED
endif
ifeq ($(ANC_FB_ENABLED),1)
CFLAGS_app_anc.o += -DANC_FB_ENABLED
endif
ifeq ($(ANC_WNR_ENABLED),1)
CFLAGS_app_anc.o += -DANC_WNR_ENABLED
endif
ifeq ($(ANC_ASSIST_ENABLED),1)
CFLAGS_app_anc.o += -DANC_ASSIST_ENABLED
ifeq ($(ANC_ASSIST_WNR_ENABLED),1)
CFLAGS_anc_assist.o += -DANC_ASSIST_WNR_ENABLED
endif
ifeq ($(ANC_ASSIST_PILOT_ENABLED),1)
CFLAGS_anc_assist.o += -DANC_ASSIST_PILOT_ENABLED
endif
ifeq ($(ANC_ASSIST_NOISE_ADAPTIVE_ENABLED),1)
CFLAGS_anc_assist.o += -DANC_ASSIST_NOISE_ADAPTIVE_ENABLED
endif
ifeq ($(ANC_ASSIST_HESS_ENABLED),1)
CFLAGS_anc_assist.o += -DANC_ASSIST_HESS_ENABLED
endif
ifeq ($(ANC_ASSIST_PNC_ENABLED),1)
CFLAGS_anc_assist.o += -DANC_ASSIST_PNC_ENABLED
endif
ifeq ($(ANC_ASSIST_DEHOWLING_ENABLED),1)
CFLAGS_anc_assist.o += -DANC_ASSIST_DEHOWLING_ENABLED
endif
else
obj_c := $(filter-out src/anc_assist.c ,$(obj_c))
endif
ifeq ($(AUDIO_RESAMPLE),1)
CFLAGS_app_anc.o += -D__AUDIO_RESAMPLE__
endif
ifeq ($(SW_PLAYBACK_RESAMPLE),1)
CFLAGS_app_anc.o += -DSW_PLAYBACK_RESAMPLE
endif
ifeq ($(SW_CAPTURE_RESAMPLE),1)
CFLAGS_app_anc.o += -DSW_CAPTURE_RESAMPLE
endif
ifeq ($(AUDIO_SECTION_SUPPT),1)
CFLAGS_app_anc.o += -D__AUDIO_SECTION_SUPPT__
endif
obj-y := $(obj_c:.c=.o) $(obj_s:.S=.o) $(obj_cpp:.cpp=.o)
subdir-ccflags-y += \
-Iservices/fs/fat \
-Iservices/fs/sd \
-Iservices/fs/fat/ChaN \
-Iservices/overlay \
-Iservices/nvrecord \
-Iservices/resources \
-Iservices/multimedia/audio/process/resample/include \
-Iservices/multimedia/audio/process/anc/include \
-Iservices/multimedia/speech/inc \
-Iplatform/drivers/uarthci \
-Iplatform/drivers/ana \
-Iplatform/drivers/bt \
-Iutils/cqueue \
-Iservices/audioflinger \
-Iutils/lockcqueue \
-Iutils/intersyshci \
-Iapps/anc/inc \
-Iapps/key \
-Iapps/main \
-Iapps/common \
-Iapps/audioplayers \
-Iapps/factory \
-Iservices/ble_app \
-Iservices/bt_app \
-Iservices/anc/inc \
-Iservices/multimedia/audio/codec/sbc/inc \
-Iservices/nv_section/aud_section \
-Iservices/nv_section/include \
-Iutils/hwtimer_list \
-Iservices/ibrt_core/inc \
-Iservices/tota \
$(BT_IF_INCLUDES) \
-Iservices/app_ibrt/inc \
-Iservices/ble_stack/common/api \
-Iservices/ble_stack/ble_ip \
-Iservices/ibrt_ui/inc \
-Iservices/audio_dump/include

70
apps/anc/inc/anc_assist.h Normal file
View file

@ -0,0 +1,70 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __ANC_ASSIT_H__
#define __ANC_ASSIT_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "plat_types.h"
//#define AF_ANC_DUMP_DATA
#if defined(_24BITS_ENABLE)
#define _SAMPLE_BITS (24)
typedef int ASSIST_PCM_T;
#else
#define _SAMPLE_BITS (16)
typedef short ASSIST_PCM_T;
#endif
#define ANC_ASSIST_FF1_MIC (1<<2)
#define ANC_ASSIST_FF2_MIC (1<<1)
#define ANC_ASSIST_FB_MIC (1<<0)
typedef enum{
ANC_ASSIST_STANDALONE = 0,
ANC_ASSIST_MUSIC,
ANC_ASSIST_PHONE_8K,
ANC_ASSIST_PHONE_16K,
ANC_ASSIST_MODE_QTY
}ANC_ASSIST_MODE_T;
void anc_assist_open(ANC_ASSIST_MODE_T mode);
void anc_assist_process(uint8_t * buf, int len);
void anc_assist_close();
#ifdef __cplusplus
}
#endif
#endif

56
apps/anc/inc/anc_wnr.h Normal file
View file

@ -0,0 +1,56 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __ANC_WNR_H__
#define __ANC_WNR_H__
// #include "plat_types.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum
{
ANC_WNR_OPEN_MODE_STANDALONE = 0,
ANC_WNR_OPEN_MODE_CONFIGURE,
ANC_WNR_OPEN_MODE_QTY
} anc_wnr_open_mode_t;
void anc_release_gain(void);
typedef enum
{
APP_WNR_NOTIFY_DETECT_RESULT,
APP_WNR_REQUEST_DETECT_RESULT,
APP_WNR_RESPONSE_DETECT_RESULT,
APP_WNR_PROCESS_DETECT_RESULT,
APP_WNR_SET_TRIGGER,
APP_WNR_EXCUTE_TRIGGER,
APP_WNR_SHARE_MODULE_INFO,
} anc_wnr_sync_ctrl_internal_event_e;
int32_t anc_wnr_ctrl(int32_t sample_rate, int32_t frame_len);
int32_t anc_wnr_open(anc_wnr_open_mode_t mode);
int32_t anc_wnr_close(void);
int32_t anc_wnr_process(void *pcm_buf, uint32_t pcm_len);
void app_wnr_sync_state(void);
void app_wnr_cmd_receive_process(uint8_t *p_buff, uint16_t length);
#ifdef __cplusplus
}
#endif
#endif

72
apps/anc/inc/app_anc.h Normal file
View file

@ -0,0 +1,72 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __APP_ANC_H__
#define __APP_ANC_H__
#include "hal_aud.h"
#include "app_key.h"
#ifdef __cplusplus
extern "C" {
#endif
void app_anc_set_playback_samplerate(enum AUD_SAMPRATE_T sample_rate);
void app_anc_init(enum AUD_IO_PATH_T input_path, enum AUD_SAMPRATE_T playback_rate, enum AUD_SAMPRATE_T capture_rate);
void app_anc_close(void);
void app_anc_enable(void);
void app_anc_disable(void);
bool anc_enabled(void);
void test_anc(void);
void app_anc_resample(uint32_t res_ratio, uint32_t *in, uint32_t *out, uint32_t samples);
#ifdef __BT_ANC_KEY__
void app_anc_key(APP_KEY_STATUS *status, void *param);
#endif
int app_anc_open_module(void);
int app_anc_close_module(void);
enum AUD_SAMPRATE_T app_anc_get_play_rate(void);
bool app_anc_work_status(void);
void app_anc_send_howl_evt(uint32_t howl);
uint32_t app_anc_get_anc_status(void);
bool app_pwr_key_monitor_get_val(void);
bool app_anc_switch_get_val(void);
void app_anc_ios_init(void);
void app_anc_set_init_done(void);
bool app_anc_set_reboot(void);
void app_anc_status_post(uint8_t status);
bool app_anc_is_on(void);
uint32_t app_anc_get_sample_rate(void);
void app_anc_set_coef_idx(uint8_t idx);
uint8_t app_anc_get_coef_idx(void);
#if defined(IBRT)
void app_anc_cmd_receive_process(uint8_t *buf, uint16_t len);
void app_anc_set_peer_coef_idx(uint8_t idx);
uint8_t app_anc_get_peer_coef_idx(void);
void app_anc_set_status_sync_flag(bool status);
bool app_anc_get_status_sync_flag(void);
#endif
#ifndef __BT_ANC_KEY__
int app_anc_start(void);
int app_anc_switch_coef(uint8_t index);
int app_anc_stop(void);
#endif
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,41 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __PEAK_DETECTOR_H__
#define __PEAK_DETECTOR_H__
#include "plat_types.h"
#include "hal_aud.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
enum AUD_SAMPRATE_T fs;
enum AUD_BITS_T bits;
float factor_up;
float factor_down;
float reduce_dB;
} PEAK_DETECTOR_CFG_T;
void peak_detector_init(void);
void peak_detector_setup(PEAK_DETECTOR_CFG_T *cfg);
void peak_detector_run(uint8_t *buf, uint32_t len, float vol_multiple);
#ifdef __cplusplus
}
#endif
#endif

445
apps/anc/src/anc_assist.c Normal file
View file

@ -0,0 +1,445 @@
/***************************************************************************
*
* 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 "anc_assist.h"
#include "hal_trace.h"
#include "arm_math.h"
#include "audio_dump.h"
#include "speech_cfg.h"
#include "anc_process.h"
#include "audioflinger.h"
#include "anc_assist_algo.h"
#include "hal_codec.h"
#include "audioflinger.h"
#include "hal_timer.h"
#include "hal_aud.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "hal_aud.h"
#include "anc_process.h"
#include "anc_assist_algo.h"
#include "speech_memory.h"
#include "speech_ssat.h"
#if defined(ANC_ASSIST_NOISE_ADAPTIVE_ENABLED)
#include "main_classify.h"
#endif
static void _close_mic_anc_assist();
static void _open_mic_anc_assist();
#define _SAMPLE_RATE (16000)
#if defined(ANC_ASSIST_NOISE_ADAPTIVE_ENABLED)
#define _FRAME_LEN (128)
#else
#define _FRAME_LEN (160)
#endif
#define _CHANNEL_NUM_MAX (3)
#define SAMPLE_BYTES (sizeof(ASSIST_PCM_T))
#define AF_STREAM_BUFF_SIZE (_FRAME_LEN * SAMPLE_BYTES * _CHANNEL_NUM_MAX * 2)
#define ANC_ADPT_STREAM_ID AUD_STREAM_ID_3
#define _FRAME_LEN_MAX (160)
#define _SAMPLE_BITS_MAX (32)
static uint8_t __attribute__((aligned(4))) af_stream_buff[AF_STREAM_BUFF_SIZE];
static ASSIST_PCM_T af_stream_mic1[_FRAME_LEN_MAX * (_SAMPLE_BITS_MAX / 8)];
static ASSIST_PCM_T af_stream_mic2[_FRAME_LEN_MAX * (_SAMPLE_BITS_MAX / 8)];
static ASSIST_PCM_T af_stream_mic3[_FRAME_LEN_MAX * (_SAMPLE_BITS_MAX / 8)];
int MIC_NUM = 0;
int MIC_MAP = 0;
#if defined(ANC_ASSIST_PILOT_ENABLED)
#define _PLAY_SAMPLE_RATE (8000)
#define _PLAY_FRAME_LEN (80)
#define AF_PLAY_STREAM_BUFF_SIZE (_PLAY_FRAME_LEN * SAMPLE_BYTES * 1 * 2)
static uint8_t __attribute__((aligned(4))) af_play_stream_buff[AF_PLAY_STREAM_BUFF_SIZE];
#endif
#if defined(ANC_ASSIST_NOISE_ADAPTIVE_ENABLED)
ClassifyState * NoiseClassify_st = NULL;
#endif
#if defined(ANC_ASSIST_PILOT_ENABLED) || defined(ANC_ASSIST_HESS_ENABLED) || defined(ANC_ASSIST_PNC_ENABLED) || defined(ANC_ASSIST_DEHOWLING_ENABLED) || defined(ANC_ASSIST_WNR_ENABLED) || defined(ANC_ASSIST_NOISE_ADAPTIVE_ENABLED)
extern const struct_anc_cfg * anc_coef_list_48k[1];
void anc_assist_change_curve(int curve_id){
TRACE(2,"[%s] change anc curve %d",__func__,curve_id);
anc_set_cfg(anc_coef_list_48k[0],ANC_FEEDFORWARD,ANC_GAIN_NO_DELAY);
anc_set_cfg(anc_coef_list_48k[0],ANC_FEEDBACK,ANC_GAIN_NO_DELAY);
}
bool audio_engine_tt_is_on(){
return 1;
}
#define _tgt_ff_gain (512)
void anc_assist_set_anc_gain(float gain_ch_l, float gain_ch_r,enum ANC_TYPE_T anc_type){
TRACE(2,"[%s] set anc gain %d",__func__,(int)(100*gain_ch_l));
uint32_t tgt_ff_gain_l,tgt_ff_gain_r;
tgt_ff_gain_l = (uint32_t)(_tgt_ff_gain*gain_ch_l);
tgt_ff_gain_r = (uint32_t)(_tgt_ff_gain*gain_ch_r);
anc_set_gain(tgt_ff_gain_l,tgt_ff_gain_r,anc_type);
}
#endif
#if defined(ANC_ASSIST_PILOT_ENABLED)
static LeakageDetectionState * pilot_st = NULL;
#endif
#if defined(ANC_ASSIST_HESS_ENABLED) || defined(ANC_ASSIST_PNC_ENABLED) || defined(ANC_ASSIST_DEHOWLING_ENABLED) || defined(ANC_ASSIST_WNR_ENABLED)
static ANCAssistMultiState * anc_assist_multi_st = NULL;
#endif
ANC_ASSIST_MODE_T g_anc_assist_mode = ANC_ASSIST_MODE_QTY;
void anc_assist_open(ANC_ASSIST_MODE_T mode){
g_anc_assist_mode = mode;
//normal init
#if defined(ANC_ASSIST_PILOT_ENABLED)
pilot_st = LeakageDetection_create(160,0);
#endif
#if defined(ANC_ASSIST_HESS_ENABLED) || defined(ANC_ASSIST_PNC_ENABLED) || defined(ANC_ASSIST_DEHOWLING_ENABLED) || defined(ANC_ASSIST_WNR_ENABLED)
anc_assist_multi_st = ANCAssistMulti_create(_SAMPLE_RATE,_FRAME_LEN,128);
#endif
#if defined(ANC_ASSIST_NOISE_ADAPTIVE_ENABLED)
NoiseClassify_st = classify_create(_SAMPLE_RATE, _FRAME_LEN);
#endif
// audio_dump_init(160,sizeof(short),3);
if( mode == ANC_ASSIST_MODE_QTY){
return;
}
else{
if(mode == ANC_ASSIST_STANDALONE || mode == ANC_ASSIST_MUSIC ){
_open_mic_anc_assist();
}
if(mode == ANC_ASSIST_PHONE_8K){
// normal init 8k
}
else if(mode == ANC_ASSIST_PHONE_16K){
// normal init 16k
}
}
}
void anc_assist_close(){
#if defined(ANC_ASSIST_PILOT_ENABLED)
LeakageDetection_destroy(pilot_st);
#endif
#if defined(ANC_ASSIST_HESS_ENABLED) || defined(ANC_ASSIST_PNC_ENABLED) || defined(ANC_ASSIST_DEHOWLING_ENABLED) || defined(ANC_ASSIST_WNR_ENABLED)
ANCAssistMulti_destroy(anc_assist_multi_st);
#endif
#if defined(ANC_ASSIST_NOISE_ADAPTIVE_ENABLED)
classify_destroy(NoiseClassify_st);
#endif
// ext_heap_deinit();
if( g_anc_assist_mode == ANC_ASSIST_MODE_QTY){
return;
}
else{
if(g_anc_assist_mode == ANC_ASSIST_STANDALONE || g_anc_assist_mode == ANC_ASSIST_MUSIC ){
_close_mic_anc_assist();
}
if(g_anc_assist_mode == ANC_ASSIST_PHONE_8K){
// normal init 8k
}
else if(g_anc_assist_mode == ANC_ASSIST_PHONE_16K){
// normal init 16k
}
}
}
extern ASSIST_PCM_T ref_buf_data[80];
void anc_assist_process(uint8_t * buf, int len){
int32_t frame_len = len / SAMPLE_BYTES / MIC_NUM;
ASSERT(frame_len == _FRAME_LEN, "[%s] frame len(%d) is invalid.", __func__, frame_len);
ASSIST_PCM_T *pcm_buf = (ASSIST_PCM_T *)buf;
ASSIST_PCM_T *mic1 = (ASSIST_PCM_T *)af_stream_mic1;
ASSIST_PCM_T *mic2 = (ASSIST_PCM_T *)af_stream_mic2;
ASSIST_PCM_T *mic3 = (ASSIST_PCM_T *)af_stream_mic3;
for (int32_t i=0; i<frame_len; i++) {
mic1[i] = pcm_buf[MIC_NUM*i + 0];
mic2[i] = pcm_buf[MIC_NUM*i + 1];
mic3[i] = pcm_buf[MIC_NUM*i + 2];
}
// audio_dump_clear_up();
// audio_dump_add_channel_data(0,mic1,160);
// audio_dump_add_channel_data(1,mic2,160);
// audio_dump_add_channel_data(2,mic3,160);
// audio_dump_run();
// TRACE(2,"in callback");
#if defined(ANC_ASSIST_PILOT_ENABLED)
LeakageDetection_process(pilot_st,AF_ANC_OFF,mic3,ref_buf_data,frame_len);
#endif
#if defined(ANC_ASSIST_HESS_ENABLED) || defined(ANC_ASSIST_PNC_ENABLED) || defined(ANC_ASSIST_DEHOWLING_ENABLED) || defined(ANC_ASSIST_WNR_ENABLED)
ANCAssistMulti_process(anc_assist_multi_st,mic1,mic2,mic3,frame_len);
#endif
#if defined(ANC_ASSIST_NOISE_ADAPTIVE_ENABLED)
static int last_classify_res = -1;
classify_process(NoiseClassify_st, mic1, last_classify_res);
#endif
if(g_anc_assist_mode == ANC_ASSIST_PHONE_16K){
//down sample
}
//process fft
// wnr
// pnc
// hess
// pilot adpt
}
static uint32_t anc_assist_callback(uint8_t *buf, uint32_t len){
#ifdef TEST_MIPS
start_ticks = hal_fast_sys_timer_get();
#endif
anc_assist_process(buf,len);
#ifdef TEST_MIPS
end_ticks = hal_fast_sys_timer_get();
used_mips = (end_ticks - start_ticks) * 1000 / (start_ticks - pre_ticks);
TRACE(2,"[%s] Usage: %d in a thousand (MIPS).", __func__, used_mips);
//wnr_ticks = start_ticks;
//TRACE(2,"[%s] WNR frame takes %d ms.", __func__, FAST_TICKS_TO_MS((start_ticks - pre_ticks)*100));
pre_ticks = start_ticks;
#endif
return 0;
}
#if defined(ANC_ASSIST_PILOT_ENABLED)
static uint32_t anc_assist_playback_callback(uint8_t *buf, uint32_t len){
get_pilot_data(buf,len);
// TRACE(2,"playing data %d",len);
return 0;
}
#endif
static void _open_mic_anc_assist(void)
{
int anc_assist_mic_num = 0;
#if defined(ANC_ASSIST_PILOT_ENABLED)
anc_assist_mic_num = anc_assist_mic_num | ANC_ASSIST_FB_MIC;
#endif
#if defined(ANC_ASSIST_HESS_ENABLED) || defined(ANC_ASSIST_NOISE_ADAPTIVE_ENABLED)
anc_assist_mic_num = anc_assist_mic_num | ANC_ASSIST_FF1_MIC;
#endif
#if defined(ANC_ASSIST_PNC_ENABLED)
anc_assist_mic_num = anc_assist_mic_num | ANC_ASSIST_FF1_MIC | ANC_ASSIST_FB_MIC;
#endif
#if defined(ANC_ASSIST_DEHOWLING_ENABLED)
anc_assist_mic_num = anc_assist_mic_num | ANC_ASSIST_FF1_MIC | ANC_ASSIST_FB_MIC;
#endif
#if defined(ANC_ASSIST_WNR_ENABLED)
anc_assist_mic_num = anc_assist_mic_num | ANC_ASSIST_FF1_MIC | ANC_ASSIST_FF2_MIC;
#endif
switch(anc_assist_mic_num){
case(0):
{
TRACE(2,"[%s] no mic is used",__func__);
return;
}
break;
case(1):
{
TRACE(2,"[%s] use fb mic only",__func__);
MIC_NUM = 3;
MIC_MAP = AUD_INPUT_PATH_AF_ANC;
}
break;
case(4):
{
TRACE(2,"[%s] use ff mic only",__func__);
MIC_NUM = 3;
MIC_MAP = AUD_INPUT_PATH_ANC_WNR;
}
break;
case(5):
{
TRACE(2,"[%s] use ff mic and fb mic",__func__);
MIC_NUM = 3;
MIC_MAP = AUD_INPUT_PATH_ANC_WNR;
}
break;
case(6):
{
TRACE(2,"[%s] use ff1 mic and ff2 mic",__func__);
MIC_NUM = 2;
MIC_MAP = AUD_INPUT_PATH_AF_ANC;
}
break;
case(7):
{
TRACE(2,"[%s] use ff1 mic and ff2 mic and fb mic",__func__);
MIC_NUM = 2;
MIC_MAP = AUD_INPUT_PATH_AF_ANC;
}
break;
default:
{
TRACE(2,"[%s] invalid mic order is used",__func__);
}
break;
}
MIC_NUM = 3;
MIC_MAP = AUD_INPUT_PATH_AF_ANC;
struct AF_STREAM_CONFIG_T stream_cfg;
TRACE(1,"[%s] ...", __func__);
memset(&stream_cfg, 0, sizeof(stream_cfg));
stream_cfg.channel_num = (enum AUD_CHANNEL_NUM_T)MIC_NUM;
stream_cfg.sample_rate = (enum AUD_SAMPRATE_T)_SAMPLE_RATE;
stream_cfg.bits = (enum AUD_BITS_T)_SAMPLE_BITS;
stream_cfg.vol = 12;
stream_cfg.chan_sep_buf = false;
stream_cfg.device = AUD_STREAM_USE_INT_CODEC;
stream_cfg.io_path = (enum AUD_IO_PATH_T)MIC_MAP;
stream_cfg.handler = anc_assist_callback;
stream_cfg.data_size = _FRAME_LEN * SAMPLE_BYTES * 2 * MIC_NUM;
stream_cfg.data_ptr = af_stream_buff;
ASSERT(stream_cfg.channel_num == MIC_NUM, "[%s] channel number(%d) is invalid.", __func__, stream_cfg.channel_num);
TRACE(2,"[%s] sample_rate:%d, data_size:%d", __func__, stream_cfg.sample_rate, stream_cfg.data_size);
TRACE(2,"[%s] af_stream_buff = %p", __func__, af_stream_buff);
af_stream_open(ANC_ADPT_STREAM_ID, AUD_STREAM_CAPTURE, &stream_cfg);
af_stream_start(ANC_ADPT_STREAM_ID, AUD_STREAM_CAPTURE);
#if defined(ANC_ASSIST_PILOT_ENABLED)
// struct AF_STREAM_CONFIG_T stream_cfg;
TRACE(1,"[%s] set play ...", __func__);
memset(&stream_cfg, 0, sizeof(stream_cfg));
stream_cfg.bits = (enum AUD_BITS_T)_SAMPLE_BITS;
stream_cfg.channel_num = AUD_CHANNEL_NUM_1;
stream_cfg.sample_rate = (enum AUD_SAMPRATE_T)_PLAY_SAMPLE_RATE;
stream_cfg.device = AUD_STREAM_USE_INT_CODEC;
stream_cfg.io_path = AUD_OUTPUT_PATH_SPEAKER;
stream_cfg.vol = 15;
stream_cfg.handler = anc_assist_playback_callback;
stream_cfg.data_ptr = af_play_stream_buff;
stream_cfg.data_size = sizeof(af_play_stream_buff);
af_stream_open(ANC_ADPT_STREAM_ID, AUD_STREAM_PLAYBACK, &stream_cfg);
af_stream_start(ANC_ADPT_STREAM_ID, AUD_STREAM_PLAYBACK);
#endif
}
static void _close_mic_anc_assist(){
TRACE(1,"[%s] ...", __func__);
af_stream_stop(ANC_ADPT_STREAM_ID, AUD_STREAM_CAPTURE);
af_stream_close(ANC_ADPT_STREAM_ID, AUD_STREAM_CAPTURE);
if(g_anc_assist_mode == ANC_ASSIST_STANDALONE || g_anc_assist_mode == ANC_ASSIST_MUSIC ){
// close capture
}
// destroy
}

1371
apps/anc/src/anc_wnr.c Normal file

File diff suppressed because it is too large Load diff

1956
apps/anc/src/app_anc.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,196 @@
/***************************************************************************
*
* 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 "math.h"
#include "peak_detector.h"
// #define PKD_FACTOR_UP (0.6)
// #define PKD_FACTOR_DOWN (2.0)
// #define PKD_REDUCE_RATE (0.0335) // -30dB
static enum AUD_BITS_T pkd_samp_bits;
static float pkd_alphaR = 0.0f;
static float pkd_alphaA = 0.0f;
static float pkd_factor1 = 0.0f;
static float pkd_factor2 = 0.0f;
static float pkd_reduce_rate = 1.0f;
#define FABS(x) ( (x) >= 0.f ? (x) : -(x) )
#define Max(a,b) ((a)>(b) ? (a):(b))
// Depend on codec_dac_vol
// const float pkd_vol_multiple[18] = {0.089125, 0.0, 0.005623, 0.007943, 0.011220, 0.015849, 0.022387, 0.031623, 0.044668, 0.063096, 0.089125, 0.125893, 0.177828, 0.251189, 0.354813, 0.501187, 0.707946, 1.000000};
// static uint32_t test_num = 0;
// int app_bt_stream_local_volume_get(void);
// y = 20log(x)
static inline float convert_multiple_to_db(float multiple)
{
return 20*(float)log10(multiple);
}
// x = 10^(y/20)
static inline float convert_db_to_multiple(float db)
{
return (float)pow(10, db/20);
}
void peak_detector_init(void)
{
pkd_alphaR = 0.0f;
pkd_alphaA = 0.0f;
pkd_factor1 = 0.0f;
pkd_factor2 = 0.0f;
pkd_reduce_rate = 1.0f;
// TRACE(3,"[%s] pkd_alphaR = %f, pkd_alphaA = %f", __func__, (double)pkd_alphaR, (double)pkd_alphaA);
}
void peak_detector_setup(PEAK_DETECTOR_CFG_T *cfg)
{
pkd_samp_bits = cfg->bits;
pkd_alphaR = (float)exp(-1/(cfg->factor_down * cfg->fs));
pkd_alphaA = (float)exp(-1/(cfg->factor_up * cfg->fs));
pkd_reduce_rate = convert_db_to_multiple(cfg->reduce_dB);
}
static void peak_detector_run_16bits(int16_t *buf, uint32_t len, float vol_multiple)
{
float normal_rate = 1.0;
float tgt_rate = 1.0;
for(uint32_t i = 0; i < len; i++)
{
pkd_factor1 = Max(buf[i], pkd_alphaR * pkd_factor1);
pkd_factor2 = pkd_alphaA * pkd_factor2 + (1 - pkd_alphaA) * pkd_factor1;
normal_rate = pkd_factor2/32768;
tgt_rate = pkd_reduce_rate / normal_rate / vol_multiple;
if(tgt_rate > 1.0)
{
tgt_rate = 1.0;
}
// rate += (tgt_rate - rate) / 10000.0;
// if(pkd_factor2>)
// {
// normal_rate = 0.25;
// }
// else
// {
// normal_rate = 0.25;
// }
// normal_rate *= 1.0 - pkd_factor2/32768;
buf[i] = (int16_t)(buf[i] * tgt_rate);
// buf[i] = 0;
//
// TRACE(2,"%d, %d", buf[i], pkd_factor2);
}
// if(test_num == 500)
// {
// test_num = 0;
// TRACE(0,"START>>>");
// TRACE(2,"vol_level = %d, pkd_vol_multiple = %f", vol_level, pkd_vol_multiple[vol_level]);
// TRACE(3,"buf = %d, pkd_alphaR = %f, pkd_alphaA = %f", buf[len-1], pkd_alphaR, pkd_alphaA);
// TRACE(4,"pkd_factor1 = %f, pkd_factor2 = %f, normal_rate = %f, tgt_rate = %f", pkd_factor1, pkd_factor2, normal_rate, tgt_rate);
// TRACE(0,"END<<<");
// // TRACE(7,"[%s] buf = %d, pkd_alphaR = %f, pkd_alphaA = %f, pkd_factor1 = %f, pkd_factor2 = %f, normal_rate = %f", __func__, buf[len-1], pkd_alphaR, pkd_alphaA, pkd_factor1, pkd_factor2, (1.0 - pkd_factor2/32768));
// }
#if 0
short sample;
short sample_max = 0;
short sample_min = 0;
for (uint32_t i = 0; i < len; i++)
{
sample = buf[i];
if(sample > sample_max)
{
sample_max = sample;
}
if(sample < sample_min)
{
sample_min = sample;
}
}
TRACE(2,"Max = %10d, Min = %10d",sample_max, sample_min);
#endif
}
static void peak_detector_run_24bits(int32_t *buf, uint32_t len, float vol_multiple)
{
float normal_rate = 1.0;
float tgt_rate = 1.0;
for(uint32_t i = 0; i < len; i++)
{
pkd_factor1 = Max(buf[i], pkd_alphaR * pkd_factor1);
pkd_factor2 = pkd_alphaA * pkd_factor2 + (1 - pkd_alphaA) * pkd_factor1;
normal_rate = pkd_factor2/32768;
tgt_rate = pkd_reduce_rate / normal_rate / vol_multiple;
if(tgt_rate > 1.0)
{
tgt_rate = 1.0;
}
// rate += (tgt_rate - rate) / 10000.0;
// if(pkd_factor2>)
// {
// normal_rate = 0.25;
// }
// else
// {
// normal_rate = 0.25;
// }
// normal_rate *= 1.0 - pkd_factor2/32768;
buf[i] = (int32_t)(buf[i] * tgt_rate);
// buf[i] = 0;
//
// TRACE(2,"%d, %d", buf[i], pkd_factor2);
}
}
void peak_detector_run(uint8_t *buf, uint32_t len, float vol_multiple)
{
// int vol_level = 0;
if (pkd_samp_bits <= AUD_BITS_16) {
len = len / sizeof(int16_t);
peak_detector_run_16bits((int16_t *)buf, len, vol_multiple);
} else {
len = len / sizeof(int32_t);
peak_detector_run_24bits((int32_t *)buf, len, vol_multiple);
}
// test_num++;
// vol_level = app_bt_stream_local_volume_get();
}

176
apps/apptester/Makefile Normal file
View file

@ -0,0 +1,176 @@
cur_dir := $(dir $(lastword $(MAKEFILE_LIST)))
obj-y := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)*.c $(cur_dir)*.cpp $(cur_dir)*.S))
ifeq ($(ANC_APP),1)
obj-y += ../../tests/anc_usb/anc_usb_app.c
endif
obj-y += ../../tests/anc_usb/usb_audio_app.c
obj-y += ../../tests/anc_usb/safe_queue.c
obj-y += ../../tests/anc_usb/memutils.c
obj-y += ../../tests/anc_usb/speech_process.c
obj-y := $(obj-y:.c=.o)
obj-y := $(obj-y:.cpp=.o)
obj-y := $(obj-y:.S=.o)
subdir-ccflags-y += \
-Iutils/cqueue \
-Iplatform/drivers/ana \
-Iservices/audio_process \
-Iservices/multimedia/rbcodec/inc \
-Iservices/multimedia/audio/process/anc/include \
-Iservices/multimedia/audio/process/filters/include \
-Iservices/multimedia/audio/process/resample/include \
-Iservices/multimedia/speech/inc \
-Iservices/nv_section/include \
-Iservices/nv_section/aud_section \
-Iplatform/drivers/usb/usb_dev/inc \
-Itests/anc_usb \
-Iutils/hwtimer_list
CFLAGS_usb_audio_app.o += -DAUDIO_OUTPUT_VOLUME_DEFAULT=$(AUDIO_OUTPUT_VOLUME_DEFAULT)
CFLAGS_adda_loop_app.o += -DAUDIO_OUTPUT_VOLUME_DEFAULT=$(AUDIO_OUTPUT_VOLUME_DEFAULT)
ifeq ($(APP_TEST_AUDIO),1)
ccflags-y += -DAPP_TEST_AUDIO
endif
ANC_USB_CFG_FLAGS :=
# ANC option
ifeq ($(ANC_APP),1)
ANC_USB_CFG_FLAGS += -DANC_APP
endif
# USB audio option
ifeq ($(USB_AUDIO_APP),1)
ANC_USB_CFG_FLAGS += -DUSB_AUDIO_APP
endif
ifeq ($(USB_HIGH_SPEED),1)
ANC_USB_CFG_FLAGS += -DUSB_HIGH_SPEED
endif
ifeq ($(AUDIO_RESAMPLE),1)
ANC_USB_CFG_FLAGS += -D__AUDIO_RESAMPLE__
endif
ifeq ($(ADC_CH_SEP_BUFF),1)
ANC_USB_CFG_FLAGS += -DADC_CH_SEP_BUFF
endif
include platform/drivers/usb/usb_dev/uaud_cfg_flags.mk
platform/drivers/usb/usb_dev/uaud_cfg_flags.mk: ;
ANC_USB_CFG_FLAGS += $(UAUD_CFG_FLAGS)
# USB audio configuration
ifeq ($(USB_AUDIO_DYN_CFG),1)
ifneq ($(AUDIO_RESAMPLE),1)
SW_CAPTURE_RESAMPLE ?= 1
endif
endif
ifeq ($(AUDIO_PLAYBACK_24BIT),1)
ANC_USB_CFG_FLAGS += -DAUDIO_PLAYBACK_24BIT
endif
# DSD configuration
ifeq ($(HW_FIR_DSD_PROCESS),1)
ANC_USB_CFG_FLAGS += -D__HW_FIR_DSD_PROCESS__
endif
# EQ configuration
ifeq ($(HW_FIR_EQ_PROCESS),1)
ANC_USB_CFG_FLAGS += -D__HW_FIR_EQ_PROCESS__
endif
ifeq ($(HW_IIR_EQ_PROCESS),1)
ANC_USB_CFG_FLAGS += -D__HW_IIR_EQ_PROCESS__
endif
ifeq ($(SW_IIR_EQ_PROCESS),1)
ANC_USB_CFG_FLAGS += -D__SW_IIR_EQ_PROCESS__
endif
ifeq ($(SW_CAPTURE_RESAMPLE),1)
ANC_USB_CFG_FLAGS += -DSW_CAPTURE_RESAMPLE
endif
CFLAGS_app_audtest.o += $(ANC_USB_CFG_FLAGS)
CFLAGS_usb_audio_app.o += $(ANC_USB_CFG_FLAGS)
CFLAGS_anc_usb_app.o += $(ANC_USB_CFG_FLAGS)
ifeq ($(ANC_KEY_DOUBLE_CLICK_ON_OFF),1)
CFLAGS_anc_usb_app.o += -DANC_KEY_DOUBLE_CLICK_ON_OFF
endif
ifeq ($(ANC_FF_ENABLED),1)
CFLAGS_anc_usb_app.o += -DANC_FF_ENABLED
endif
ifeq ($(ANC_FB_ENABLED),1)
CFLAGS_anc_usb_app.o += -DANC_FB_ENABLED
endif
ifeq ($(AUDIO_SECTION_SUPPT),1)
CFLAGS_anc_usb_app.o += -D__AUDIO_SECTION_SUPPT__
endif
ifeq ($(ANC_INIT_OFF),1)
CFLAGS_anc_usb_app.o += -DANC_INIT_OFF
endif
ifeq ($(PC_CMD_UART),1)
CFLAGS_app_audtest.o += -D__PC_CMD_UART__
endif
ifeq ($(DELAY_STREAM_OPEN),1)
CFLAGS_usb_audio_app.o += -DDELAY_STREAM_OPEN
endif
ifeq ($(NOISE_GATING),1)
CFLAGS_usb_audio_app.o += -DNOISE_GATING
endif
ifeq ($(NOISE_REDUCTION),1)
CFLAGS_usb_audio_app.o += -DNOISE_REDUCTION
endif
ifeq ($(ANC_L_R_MISALIGN_WORKAROUND),1)
CFLAGS_usb_audio_app.o += -DANC_L_R_MISALIGN_WORKAROUND
endif
ifeq ($(ANDROID_ACCESSORY_SPEC),1)
CFLAGS_usb_audio_app.o += -DANDROID_ACCESSORY_SPEC
ifeq ($(ANDROID_VOICE_CMD_KEY),1)
CFLAGS_usb_audio_app.o += -DANDROID_VOICE_CMD_KEY
endif
endif
ifeq ($(DUAL_AUX_MIC_MORE_FILTER),1)
CFLAGS_usb_audio_app.o += -DDUAL_AUX_MIC_MORE_FILTER
endif
ifeq ($(FREQ_RESP_EQ),1)
CFLAGS_usb_audio_app.o += -DFREQ_RESP_EQ
endif
ifeq ($(KEEP_SAME_LATENCY),1)
CFLAGS_usb_audio_app.o += -DKEEP_SAME_LATENCY
endif
ifeq ($(USB_AUDIO_PWRKEY_TEST),1)
CFLAGS_usb_audio_app.o += -DUSB_AUDIO_PWRKEY_TEST
endif
ifeq ($(AUDIO_RESAMPLE),1)
# If neither best1000 nor best2000
ifeq ($(filter best1000 best2000,$(CHIP)),)
PLL_TUNE_SAMPLE_RATE ?= 1
endif
ifeq ($(PLL_TUNE_SAMPLE_RATE),1)
CFLAGS_usb_audio_app.o += -DPLL_TUNE_SAMPLE_RATE
endif
endif

View file

@ -0,0 +1,307 @@
/***************************************************************************
*
* 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 "cmsis_os.h"
#include "hal_trace.h"
#include "app_thread.h"
#include "hal_timer.h"
#include "app_audtest_pattern.h"
#include "hal_aud.h"
#include "audioflinger.h"
#include "audiobuffer.h"
#include "stdbool.h"
#include <string.h>
#include "eq_export.h"
#include "app_utils.h"
#if defined(APP_TEST_AUDIO) && defined(ANC_APP)
#include "anc_usb_app.h"
#include "usb_audio_app.h"
#include "usb_audio_frm_defs.h"
//#include "dualadc_audio_app.h"
#endif
#define USB_AUDIO_PLAYBACK_BUFF_SIZE (FRAME_SIZE_PLAYBACK * 4)
#define USB_AUDIO_CAPTURE_BUFF_SIZE (FRAME_SIZE_CAPTURE * 4)
#define USB_AUDIO_RECV_BUFF_SIZE (FRAME_SIZE_RECV * 8)
#define USB_AUDIO_SEND_BUFF_SIZE (FRAME_SIZE_SEND * 8)
#define APP_TEST_PLAYBACK_BUFF_SIZE (128 * 20)
#define APP_TEST_CAPTURE_BUFF_SIZE (128 * 20)
#if (USB_AUDIO_PLAYBACK_BUFF_SIZE > APP_TEST_PLAYBACK_BUFF_SIZE)
#define REAL_PLAYBACK_BUFF_SIZE USB_AUDIO_PLAYBACK_BUFF_SIZE
#else
#define REAL_PLAYBACK_BUFF_SIZE APP_TEST_PLAYBACK_BUFF_SIZE
#endif
#if (USB_AUDIO_CAPTURE_BUFF_SIZE > APP_TEST_CAPTURE_BUFF_SIZE)
#define REAL_CAPTURE_BUFF_SIZE USB_AUDIO_CAPTURE_BUFF_SIZE
#else
#define REAL_CAPTURE_BUFF_SIZE APP_TEST_CAPTURE_BUFF_SIZE
#endif
#define ALIGNED4 ALIGNED(4)
static uint8_t ALIGNED4 app_test_playback_buff[REAL_PLAYBACK_BUFF_SIZE];
static uint8_t ALIGNED4 app_test_capture_buff[REAL_CAPTURE_BUFF_SIZE];
#if defined(APP_TEST_AUDIO) && defined(ANC_APP)
static uint8_t ALIGNED4 app_test_recv_buff[USB_AUDIO_RECV_BUFF_SIZE];
static uint8_t ALIGNED4 app_test_send_buff[USB_AUDIO_SEND_BUFF_SIZE];
#endif
uint32_t pcm_1ksin_more_data(uint8_t *buf, uint32_t len)
{
static uint32_t nextPbufIdx = 0;
uint32_t remain_size = len;
uint32_t curr_size = 0;
static uint32_t pcm_preIrqTime = 0;;
uint32_t stime = 0;
stime = hal_sys_timer_get();
TRACE(3,"pcm_1ksin_more_data irqDur:%d readbuff:0x%08x %d\n ", TICKS_TO_MS(stime - pcm_preIrqTime), buf, len);
pcm_preIrqTime = stime;
// TRACE(2,"[pcm_1ksin_more_data] len=%d nextBuf:%d\n", len, nextPbufIdx);
if (remain_size > sizeof(sinwave))
{
do{
if (nextPbufIdx)
{
curr_size = sizeof(sinwave)-nextPbufIdx;
memcpy(buf,&sinwave[nextPbufIdx/2], curr_size);
remain_size -= curr_size;
nextPbufIdx = 0;
}
else if (remain_size>sizeof(sinwave))
{
memcpy(buf+curr_size,sinwave,sizeof(sinwave));
curr_size += sizeof(sinwave);
remain_size -= sizeof(sinwave);
}
else
{
memcpy(buf+curr_size,sinwave,remain_size);
nextPbufIdx = remain_size;
remain_size = 0;
}
}while(remain_size);
}
else
{
if ((sizeof(sinwave) - nextPbufIdx) >= len)
{
memcpy(buf, &sinwave[nextPbufIdx/2],len);
nextPbufIdx += len;
}
else
{
curr_size = sizeof(sinwave)-nextPbufIdx;
memcpy(buf, &sinwave[nextPbufIdx/2],curr_size);
nextPbufIdx = len - curr_size;
memcpy(buf+curr_size,sinwave, nextPbufIdx);
}
}
return 0;
}
uint32_t pcm_mute_more_data(uint8_t *buf, uint32_t len)
{
memset(buf, 0 , len);
return 0;
}
void da_output_sin1k(bool on)
{
static bool isRun = false;
struct AF_STREAM_CONFIG_T stream_cfg;
memset(&stream_cfg, 0, sizeof(stream_cfg));
if (isRun==on)
return;
else
isRun=on;
TRACE(2,"%s %d\n", __func__, on);
if (on){
stream_cfg.bits = AUD_BITS_16;
stream_cfg.channel_num = AUD_CHANNEL_NUM_2;
stream_cfg.sample_rate = AUD_SAMPRATE_44100;
stream_cfg.device = AUD_STREAM_USE_INT_CODEC;
stream_cfg.io_path = AUD_OUTPUT_PATH_SPEAKER;
stream_cfg.vol = 16;
stream_cfg.handler = pcm_1ksin_more_data;
stream_cfg.data_ptr = app_test_playback_buff;
stream_cfg.data_size = APP_TEST_PLAYBACK_BUFF_SIZE;
af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg);
af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
}else{
af_stream_stop(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
af_stream_close(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
}
}
void da_tester(uint8_t on)
{
da_output_sin1k(on);
}
extern int voicecvsd_audio_init(void);
extern uint32_t voicecvsd_audio_more_data(uint8_t *buf, uint32_t len);
extern int get_voicecvsd_buffer_size(void);
extern int store_voice_pcm2cvsd(unsigned char *buf, unsigned int len);
static uint32_t pcm_data_capture(uint8_t *buf, uint32_t len)
{
uint32_t stime, etime;
static uint32_t preIrqTime = 0;
stime = hal_sys_timer_get();
// audio_buffer_set_stereo2mono_16bits(buf, len, 1);
audio_buffer_set(buf, len);
etime = hal_sys_timer_get();
TRACE(4,"%s irqDur:%d fsSpend:%d, Len:%d", __func__, TICKS_TO_MS(stime - preIrqTime), TICKS_TO_MS(etime - stime), len);
preIrqTime = stime;
return 0;
}
static uint32_t pcm_data_playback(uint8_t *buf, uint32_t len)
{
uint32_t stime, etime;
static uint32_t preIrqTime = 0;
stime = hal_sys_timer_get();
// audio_buffer_get_mono2stereo_16bits(buf, len);
audio_buffer_get(buf, len);
etime = hal_sys_timer_get();
TRACE(4,"%s irqDur:%d fsSpend:%d, Len:%d", __func__, TICKS_TO_MS(stime - preIrqTime), TICKS_TO_MS(etime - stime), len);
preIrqTime = stime;
return 0;
}
uint32_t pcm_cvsd_data_capture(uint8_t *buf, uint32_t len)
{
uint32_t stime, etime;
static uint32_t preIrqTime = 0;
//TRACE(1,"%s enter", __func__);
stime = hal_sys_timer_get();
len >>= 1;
audio_stereo2mono_16bits(0, (uint16_t *)buf, (uint16_t *)buf, len);
store_voice_pcm2cvsd(buf, len);
etime = hal_sys_timer_get();
TRACE(4,"%s exit irqDur:%d fsSpend:%d, add:%d", __func__, TICKS_TO_MS(stime - preIrqTime), TICKS_TO_MS(etime - stime), len);
preIrqTime = stime;
return 0;
}
uint32_t pcm_cvsd_data_playback(uint8_t *buf, uint32_t len)
{
int n;
uint32_t stime, etime;
static uint32_t preIrqTime = 0;
//TRACE(1,"%s enter", __func__);
stime = hal_sys_timer_get();
pcm_1ksin_more_data(buf, len);
voicecvsd_audio_more_data(buf, len);
n = get_voicecvsd_buffer_size();
etime = hal_sys_timer_get();
TRACE(5,"%s exit irqDur:%d fsSpend:%d, get:%d remain:%d", __func__, TICKS_TO_MS(stime - preIrqTime), TICKS_TO_MS(etime - stime), len, n);
preIrqTime = stime;
return 0;
}
void adc_looptester(bool on, enum AUD_IO_PATH_T input_path, enum AUD_SAMPRATE_T sample_rate)
{
struct AF_STREAM_CONFIG_T stream_cfg;
static bool isRun = false;
if (isRun==on)
return;
else
isRun=on;
if (on){
audio_buffer_init();
memset(&stream_cfg, 0, sizeof(stream_cfg));
stream_cfg.bits = AUD_BITS_16;
stream_cfg.channel_num = AUD_CHANNEL_NUM_2;
stream_cfg.sample_rate = sample_rate;
stream_cfg.device = AUD_STREAM_USE_INT_CODEC;
stream_cfg.io_path = input_path;
stream_cfg.vol = 0x03;
stream_cfg.handler = pcm_data_capture;
stream_cfg.data_ptr = app_test_capture_buff;
stream_cfg.data_size = APP_TEST_CAPTURE_BUFF_SIZE;
af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE, &stream_cfg);
stream_cfg.handler = pcm_data_playback;
stream_cfg.io_path = AUD_OUTPUT_PATH_SPEAKER;
stream_cfg.data_ptr = app_test_playback_buff;
stream_cfg.data_size = APP_TEST_PLAYBACK_BUFF_SIZE;
af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg);
af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
}else{
af_stream_stop(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
af_stream_stop(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
af_stream_close(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
af_stream_close(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
}
}
#if defined(APP_TEST_AUDIO) && defined(ANC_APP)
void app_anc_usb_init(void)
{
app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_52M);
anc_usb_app_init(AUD_INPUT_PATH_MAINMIC, AUD_SAMPRATE_96000, AUD_SAMPRATE_192000);
struct USB_AUDIO_BUF_CFG cfg;
memset(&cfg, 0, sizeof(cfg));
cfg.play_buf = app_test_playback_buff;
cfg.play_size = USB_AUDIO_PLAYBACK_BUFF_SIZE;
cfg.cap_buf = app_test_capture_buff;
cfg.cap_size = USB_AUDIO_CAPTURE_BUFF_SIZE;
cfg.recv_buf = app_test_recv_buff;
cfg.recv_size = USB_AUDIO_RECV_BUFF_SIZE;
cfg.send_buf = app_test_send_buff;
cfg.send_size = USB_AUDIO_SEND_BUFF_SIZE;
usb_audio_app_init(&cfg);
//dualadc_audio_app_init(app_test_playback_buff, USB_AUDIO_PLAYBACK_BUFF_SIZE,
//app_test_capture_buff, USB_AUDIO_CAPTURE_BUFF_SIZE);
}
#endif

View file

@ -0,0 +1,23 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __APP_AUDTEST_H__
#define __APP_AUDTEST_H__
#include "audioflinger.h"
void da_output_sin1k(bool on);
void adc_looptester(bool on, uint8_t mode, enum AUD_SAMPRATE_T sample_rate);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,146 @@
/***************************************************************************
*
* 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 "cmsis_os.h"
#include "cqueue.h"
#include "string.h"
#include "audiobuffer.h"
#ifndef _AUDIO_NO_THREAD_
static osMutexId g_audio_queue_mutex_id = NULL;
osMutexDef(g_audio_queue_mutex);
#endif
static CQueue audio_queue;
static unsigned char audio_queue_buf[AUDIO_BUFFER_FRAME_SIZE*AUDIO_BUFFER_FRAME_NUM];
void audio_mono2stereo_16bits(uint16_t *dst_buf, uint16_t *src_buf, uint32_t src_len)
{
uint32_t i = 0;
for (i = 0; i < src_len; ++i) {
dst_buf[i*2 + 0] = dst_buf[i*2 + 1] = src_buf[i];
}
}
void audio_stereo2mono_16bits(uint8_t chnlsel, uint16_t *dst_buf, uint16_t *src_buf, uint32_t src_len)
{
uint32_t i = 0;
for (i = 0; i < src_len; i+=2) {
dst_buf[i/2] = src_buf[i + chnlsel];
}
}
void audio_buffer_init(void)
{
#ifndef _AUDIO_NO_THREAD_
if (g_audio_queue_mutex_id == NULL)
g_audio_queue_mutex_id = osMutexCreate((osMutex(g_audio_queue_mutex)));
#endif
InitCQueue(&audio_queue, sizeof(audio_queue_buf), (unsigned char *)&audio_queue_buf);
memset(&audio_queue_buf, 0x00, sizeof(audio_queue_buf));
}
int audio_buffer_length(void)
{
int len;
#ifndef _AUDIO_NO_THREAD_
osMutexWait(g_audio_queue_mutex_id, osWaitForever);
#endif
len = LengthOfCQueue(&audio_queue);
#ifndef _AUDIO_NO_THREAD_
osMutexRelease(g_audio_queue_mutex_id);
#endif
return len;
}
int audio_buffer_set(uint8_t *buff, uint16_t len)
{
int status;
#ifndef _AUDIO_NO_THREAD_
osMutexWait(g_audio_queue_mutex_id, osWaitForever);
#endif
status = EnCQueue(&audio_queue, buff, len);
#ifndef _AUDIO_NO_THREAD_
osMutexRelease(g_audio_queue_mutex_id);
#endif
return status;
}
int audio_buffer_get(uint8_t *buff, uint16_t len)
{
uint8_t *e1 = NULL, *e2 = NULL;
unsigned int len1 = 0, len2 = 0;
int status;
#ifndef _AUDIO_NO_THREAD_
osMutexWait(g_audio_queue_mutex_id, osWaitForever);
#endif
status = PeekCQueue(&audio_queue, len, &e1, &len1, &e2, &len2);
if (len==(len1+len2)){
memcpy(buff,e1,len1);
memcpy(buff+len1,e2,len2);
DeCQueue(&audio_queue, 0, len);
DeCQueue(&audio_queue, 0, len2);
}else{
memset(buff, 0x00, len);
status = -1;
}
#ifndef _AUDIO_NO_THREAD_
osMutexRelease(g_audio_queue_mutex_id);
#endif
return status;
}
int audio_buffer_set_stereo2mono_16bits(uint8_t *buff, uint16_t len, uint8_t chnlsel)
{
int status;
#ifndef _AUDIO_NO_THREAD_
osMutexWait(g_audio_queue_mutex_id, osWaitForever);
#endif
audio_stereo2mono_16bits(chnlsel, (uint16_t *)buff, (uint16_t *)buff, len>>1);
status = EnCQueue(&audio_queue, buff, len>>1);
#ifndef _AUDIO_NO_THREAD_
osMutexRelease(g_audio_queue_mutex_id);
#endif
return status;
}
int audio_buffer_get_mono2stereo_16bits(uint8_t *buff, uint16_t len)
{
uint8_t *e1 = NULL, *e2 = NULL;
unsigned int len1 = 0, len2 = 0;
int status;
#ifndef _AUDIO_NO_THREAD_
osMutexWait(g_audio_queue_mutex_id, osWaitForever);
#endif
status = PeekCQueue(&audio_queue, len>>1, &e1, &len1, &e2, &len2);
if (len>>1== len1+len2){
audio_mono2stereo_16bits((uint16_t *)buff, (uint16_t *)e1, len1>>1);
audio_mono2stereo_16bits((uint16_t *)(buff+(len1<<1)), (uint16_t *)e2, len2>>1);
DeCQueue(&audio_queue, 0, len1);
DeCQueue(&audio_queue, 0, len2);
status = len;
}else{
memset(buff, 0x00, len);
status = -1;
}
#ifndef _AUDIO_NO_THREAD_
osMutexRelease(g_audio_queue_mutex_id);
#endif
return status;
}

View file

@ -0,0 +1,47 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __AUDIOBUFFER_H__
#define __AUDIOBUFFER_H__
#ifdef __cplusplus
extern "C" {
#endif
#define AUDIO_BUFFER_FRAME_SIZE (4*1024)
#define AUDIO_BUFFER_FRAME_NUM (1)
#define AUDIO_BUFFER_TOTAL_SIZE (AUDIO_BUFFER_FRAME_SIZE*AUDIO_BUFFER_FRAME_NUM)
void audio_mono2stereo_16bits(uint16_t *dst_buf, uint16_t *src_buf, uint32_t src_len);
void audio_stereo2mono_16bits(uint8_t chnlsel, uint16_t *dst_buf, uint16_t *src_buf, uint32_t src_len);
void audio_buffer_init(void);
int audio_buffer_length(void);
int audio_buffer_set(uint8_t *buff, uint16_t len);
int audio_buffer_get(uint8_t *buff, uint16_t len);
int audio_buffer_set_stereo2mono_16bits(uint8_t *buff, uint16_t len, uint8_t chnlsel);
int audio_buffer_get_mono2stereo_16bits(uint8_t *buff, uint16_t len);
#ifdef __cplusplus
}
#endif
#endif//__FMDEC_H__

180
apps/audioplayers/Makefile Normal file
View file

@ -0,0 +1,180 @@
cur_dir := $(dir $(lastword $(MAKEFILE_LIST)))
obj_s := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)*.s))
obj_c := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)*.c))
obj_cpp := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)*.cpp))
ifeq ($(A2DP_DECODER_VER),2)
obj_cpp := $(filter-out a2dpplay.cpp,$(obj_cpp))
obj_cpp += a2dp_decoder/
endif
bt_sco_chain_obj = bt_sco_chain.c bt_sco_chain_thirdparty.c bt_sco_chain_thirdparty_alango.c
obj_c := $(filter-out $(bt_sco_chain_obj),$(obj_c))
ifeq ($(SPEECH_TX_THIRDPARTY_ALANGO),1)
obj_c += bt_sco_chain_thirdparty_alango.c
else ifeq ($(SPEECH_TX_THIRDPARTY),1)
obj_c += bt_sco_chain_thirdparty.c
else
obj_c += bt_sco_chain.c
endif
ifeq ($(SCO_DMA_SNAPSHOT),1)
obj_cpp := $(filter-out voicebtpcmplay.cpp,$(obj_cpp))
else
obj_cpp := $(filter-out voicebtpcmplay_sco_dma_snapshot.cpp,$(obj_cpp))
endif
ifeq ($(RB_CODEC),1)
obj_cpp += $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)rbplay/*.cpp))
endif
obj-y := $(obj_c:.c=.o) $(obj_s:.S=.o) $(obj_cpp:.cpp=.o)
CFLAGS_a2dpplay.o += -O3
ifeq ($(A2DP_AAC_ON),1)
AAC_INCLUDES = \
-Iservices/multimedia/audio/codec/fdkaac_codec/libAACdec/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libAACenc/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libFDK/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libMpegTPDec/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libMpegTPEnc/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libPCMutils/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libSBRdec/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libSBRenc/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libSYS/include
else
AAC_INCLUDES =
endif
ccflags-y := \
$(AAC_INCLUDES) \
-Iservices/osif \
-Iservices/audio_process \
-Iservices/fs/fat \
-Iservices/fs/sd \
-Iservices/resources \
-Iservices/fs/fat/ChaN \
-Iservices/bt_app \
$(BT_IF_INCLUDES) \
-Iplatform/drivers/uarthci \
-Iutils/cqueue \
-Iservices/audio_dump/include \
-Iservices/multimedia/speech/inc \
-Iservices/multimedia/rbcodec/inc \
-Iservices/multimedia/audio/process/eq/include \
-Iservices/multimedia/audio/process/resample/include \
-Iservices/multimedia/audio/process/filters/include \
-Iservices/multimedia/fm/inc \
-Iservices/nv_section/aud_section \
-Iservices/nv_section/include \
-Iservices/overlay \
-Iservices/norflash_api \
-Iservices/nvrecord \
-Iservices/nv_section/log_section \
-Iapps/main \
-Iapps/audioplayers/rbplay/ \
-Iapps/audioplayers/a2dp_decoder \
-Iutils/list \
-Iutils/heap \
-Iutils/intersyshci \
-Irtos/rtos \
-Iplatform/drivers/ana \
-Ithirdparty/audio_codec_lib/scalable/ \
-Ithirdparty/audio_codec_lib/liblhdc-dec/inc \
-Iapps/apptester \
-Iapps/key \
-Iplatform/drivers/bt \
-Iapps/anc/inc \
-Iservices/multimedia/audio/codec/sbc/inc \
-Iservices/multimedia/audio/codec/sbc/src/inc \
-Iservices/bt_app/a2dp_codecs/include \
-Iservices/bt_profiles_enhanced/inc \
-Iservices/app_ai/inc
ifeq ($(IBRT),1)
ccflags-y += -Iservices/ibrt_ui/inc
ccflags-y += -Iservices/ibrt_core/inc
ccflags-y += -Iservices/app_ibrt/inc
endif
ifeq ($(A2DP_LDAC_ON),1)
ccflags-y += -Ithirdparty/audio_codec_lib/ldac/inc
endif
ifeq ($(A2DP_CP_ACCEL),1)
ccflags-y += -Iservices/cp_accel
else ifeq ($(SCO_CP_ACCEL),1)
ccflags-y += -Iservices/cp_accel
endif
ifeq ($(APP_TEST_AUDIO),1)
CFLAGS_app_audio.o += -DAPP_TEST_AUDIO
endif
ifeq ($(AUDIO_RESAMPLE),1)
CFLAGS_a2dpplay.o += -D__AUDIO_RESAMPLE__
CFLAGS_voicebtpcmplay.o += -D__AUDIO_RESAMPLE__
CFLAGS_voicebtpcmplay_sco_dma_snapshot.o += -D__AUDIO_RESAMPLE__
endif
ifeq ($(SW_PLAYBACK_RESAMPLE),1)
CFLAGS_a2dpplay.o += -DSW_PLAYBACK_RESAMPLE
endif
ifeq ($(RESAMPLE_ANY_SAMPLE_RATE),1)
CFLAGS_a2dpplay.o += -DRESAMPLE_ANY_SAMPLE_RATE
endif
ifeq ($(SW_SCO_RESAMPLE),1)
CFLAGS_voicebtpcmplay.o += -DSW_SCO_RESAMPLE
CFLAGS_voicebtpcmplay_sco_dma_snapshot.o += -DSW_SCO_RESAMPLE
endif
ifeq ($(SPEECH_TX_THIRDPARTY_ALANGO),1)
CFLAGS_bt_sco_chain_thirdparty_alango.o += -Ithirdparty/alango_lib/include
endif
ifeq ($(VOICE_PROMPT),1)
CFLAGS_app_audio.o += -DMEDIA_PLAYER_SUPPORT
endif
ifeq ($(AUDIO_QUEUE_SUPPORT),1)
CFLAGS_app_audio.o += -D__AUDIO_QUEUE_SUPPORT__
endif
ifeq ($(ANC_APP),1)
CFLAGS_app_audio.o += -DANC_APP
endif
ifeq ($(A2DP_EQ_24BIT),1)
CFLAGS_app_audio.o += -DA2DP_EQ_24BIT
CFLAGS_a2dpplay.o += -DA2DP_EQ_24BIT
endif
ifeq ($(A2DP_TRACE_CP_ACCEL),1)
CFLAGS_a2dpplay.o += -DA2DP_TRACE_CP_ACCEL
endif
ifeq ($(A2DP_TRACE_DEC_TIME),1)
CFLAGS_a2dpplay.o += -DA2DP_TRACE_DEC_TIME
endif
ifeq ($(A2DP_TRACE_CP_DEC_TIME),1)
CFLAGS_a2dpplay.o += -DA2DP_TRACE_CP_DEC_TIME
endif
ifeq ($(SPEECH_TX_AEC_CODEC_REF),1)
CFLAGS_voicebtpcmplay.o += -DSPEECH_TX_AEC_CODEC_REF
CFLAGS_voicebtpcmplay_sco_dma_snapshot.o += -DSPEECH_TX_AEC_CODEC_REF
endif
ifeq ($(SPEECH_RX_24BIT),1)
CFLAGS_bt_sco_chain.o += -DSPEECH_RX_24BIT
CFLAGS_voicebtpcmplay.o += -DSPEECH_RX_24BIT
CFLAGS_voicebtpcmplay_sco_dma_snapshot.o += -DSPEECH_RX_24BIT
endif

View file

@ -0,0 +1,120 @@
cur_dir := $(dir $(lastword $(MAKEFILE_LIST)))
obj-y := a2dp_decoder.o
obj-y += a2dp_decoder_sbc.o
CFLAGS_a2dp_decoder_sbc.o += -O3
ifeq ($(A2DP_AAC_ON),1)
obj-y += a2dp_decoder_aac_lc.o
CFLAGS_a2dp_decoder_aac_lc.o += -O3
AAC_INCLUDES = \
-Iservices/multimedia/audio/codec/fdkaac_codec/libAACdec/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libAACenc/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libFDK/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libMpegTPDec/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libMpegTPEnc/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libPCMutils/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libSBRdec/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libSBRenc/include \
-Iservices/multimedia/audio/codec/fdkaac_codec/libSYS/include
else
AAC_INCLUDES =
endif
ifeq ($(A2DP_SCALABLE_ON),1)
obj-y += a2dp_decoder_scalable.o
CFLAGS_a2dp_decoder_scalable.o += -O3
SCALABLE_INCLUDES = \
-Ithirdparty/audio_codec_lib/scalable
else
SCALABLE_INCLUDES =
endif
ifeq ($(A2DP_LHDC_ON),1)
obj-y += a2dp_decoder_lhdc.o
CFLAGS_a2dp_decoder_lhdc.o += -O3
LHDC_INCLUDES = \
-Ithirdparty/audio_codec_lib/liblhdc-dec/inc
else
LHDC_INCLUDES =
endif
ifeq ($(A2DP_LDAC_ON),1)
obj-y += a2dp_decoder_ldac.o
CFLAGS_a2dp_decoder_ldac.o += -O3
LDAC_INCLUDES = \
-Ithirdparty/audio_codec_lib/ldac/inc
else
LDAC_INCLUDES =
endif
ccflags-y := \
$(AAC_INCLUDES) \
$(SCALABLE_INCLUDES) \
$(LHDC_INCLUDES) \
$(LDAC_INCLUDES) \
-Iservices/audio_process \
-Iservices/app_ai/inc \
-Iservices/fs/fat \
-Iservices/fs/sd \
-Iservices/resources \
-Iservices/fs/fat/ChaN \
-Iservices/bt_app \
-Iservices/bt_app/a2dp_codecs/include \
$(BT_IF_INCLUDES) \
-Iplatform/drivers/uarthci \
-Iutils/cqueue \
-Iservices/audio_dump/include \
-Iservices/multimedia/speech/inc \
-Iservices/multimedia/rbcodec/inc \
-Iservices/multimedia/audio/process/eq/include \
-Iservices/multimedia/audio/process/resample/include \
-Iservices/multimedia/audio/process/filters/include \
-Iservices/multimedia/fm/inc \
-Iservices/nv_section/aud_section \
-Iservices/nv_section/include \
-Iservices/overlay \
-Iservices/norflash_api \
-Iservices/nvrecord \
-Iservices/nv_section/log_section \
-Iapps/main \
-Iapps/audioplayers/rbplay/ \
-Iapps/audioplayers/a2dp_decoder \
-Iutils/list \
-Iutils/heap \
-Iplatform/drivers/ana \
-Iapps/apptester \
-Iapps/key \
-Iservices/multimedia/audio/codec/sbc/inc \
-Iservices/multimedia/audio/codec/sbc/src/inc \
-Iplatform/drivers/bt \
-Iutils/crc32
ifeq ($(A2DP_LHDC_ON),1)
ccflags-y += -Iservices/bt_if_enhanced/lhdc_license
endif
ifeq ($(IBRT),1)
ccflags-y += -Iservices/ibrt_core/inc
ccflags-y += -Iservices/ibrt_ui/inc
ccflags-y += -Iservices/app_ibrt/inc
endif
ifeq ($(A2DP_CP_ACCEL),1)
obj-y += a2dp_decoder_cp.o
ccflags-y += -Iservices/cp_accel
endif
ifeq ($(A2DP_TRACE_CP_ACCEL),1)
ccflags-y += -DA2DP_TRACE_CP_ACCEL
endif
ifeq ($(A2DP_TRACE_DEC_TIME),1)
ccflags-y += -DA2DP_TRACE_DEC_TIME
endif
ifeq ($(A2DP_TRACE_CP_DEC_TIME),1)
ccflags-y += -DA2DP_TRACE_CP_DEC_TIME
endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,155 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __A2DPPLAY_H__
#define __A2DPPLAY_H__
#include "app_utils.h"
#include "avdtp_api.h"
#define A2DP_DECODER_HISTORY_SEQ_SAVE (25)
//#define A2DP_DECODER_HISTORY_LOCTIME_SAVE (1)
//#define A2DP_DECODER_HISTORY_CHECK_SUM_SAVE (1)
typedef uint16_t A2DP_AUDIO_CODEC_TYPE;
#define A2DP_AUDIO_CODEC_TYPE_SBC (1u<<0)
#define A2DP_AUDIO_CODEC_TYPE_MPEG2_4_AAC (1u<<1)
#define A2DP_AUDIO_CODEC_TYPE_OPUS (1u<<2)
#define A2DP_AUDIO_CODEC_TYPE_SCALABL (1u<<3)
#define A2DP_AUDIO_CODEC_TYPE_LHDC (1u<<4)
#define A2DP_AUDIO_CODEC_TYPE_LDAC (1u<<5)
#define A2DP_AUDIO_SYNCFRAME_MASK_SEQ (1u<<0)
#define A2DP_AUDIO_SYNCFRAME_MASK_TIMESTAMP (1u<<1)
#define A2DP_AUDIO_SYNCFRAME_MASK_CURRSUBSEQ (1u<<2)
#define A2DP_AUDIO_SYNCFRAME_MASK_TOTALSUBSEQ (1u<<3)
#define A2DP_AUDIO_SYNCFRAME_MASK_ALL (A2DP_AUDIO_SYNCFRAME_MASK_SEQ | \
A2DP_AUDIO_SYNCFRAME_MASK_TIMESTAMP | \
A2DP_AUDIO_SYNCFRAME_MASK_CURRSUBSEQ | \
A2DP_AUDIO_SYNCFRAME_MASK_TOTALSUBSEQ)
#define A2DP_AUDIO_SYNCFRAME_CHK(equ, mask_val, mask) (((equ)|!(mask_val&mask)))
typedef enum {
A2DP_AUDIO_LATENCY_STATUS_LOW,
A2DP_AUDIO_LATENCY_STATUS_HIGH,
} A2DP_AUDIO_LATENCY_STATUS_E;
typedef struct {
uint32_t sample_rate;
uint8_t num_channels;
uint8_t bits_depth;
uint8_t curr_bits;
uint32_t frame_samples;
float factor_reference;
} A2DP_AUDIO_OUTPUT_CONFIG_T;
typedef enum {
A2DP_AUDIO_CHANNEL_SELECT_STEREO,
A2DP_AUDIO_CHANNEL_SELECT_LRMERGE,
A2DP_AUDIO_CHANNEL_SELECT_LCHNL,
A2DP_AUDIO_CHANNEL_SELECT_RCHNL,
} A2DP_AUDIO_CHANNEL_SELECT_E;
typedef struct {
uint16_t sequenceNumber;
uint32_t timestamp;
uint16_t curSubSequenceNumber;
uint16_t totalSubSequenceNumber;
uint32_t frame_samples;
uint32_t list_samples;
uint32_t decoded_frames;
uint32_t undecode_frames;
uint32_t undecode_min_frames;
uint32_t undecode_max_frames;
uint32_t average_frames;
uint32_t check_sum;
A2DP_AUDIO_OUTPUT_CONFIG_T stream_info;
} A2DP_AUDIO_LASTFRAME_INFO_T;
typedef struct {
uint16_t sequenceNumber;
uint32_t timestamp;
uint16_t curSubSequenceNumber;
uint16_t totalSubSequenceNumber;
} A2DP_AUDIO_HEADFRAME_INFO_T;
typedef struct{
float proportiongain;
float integralgain;
float derivativegain;
float error[3];
float result;
}A2DP_AUDIO_SYNC_PID_T;
typedef A2DP_AUDIO_LASTFRAME_INFO_T A2DP_AUDIO_SYNCFRAME_INFO_T;
typedef int(*A2DP_AUDIO_DETECT_NEXT_PACKET_CALLBACK)(btif_media_header_t *, unsigned char *, unsigned int len);
#ifdef __cplusplus
extern "C" {
#endif
uint32_t a2dp_audio_playback_handler(uint8_t *buffer, uint32_t buffer_bytes);
float a2dp_audio_sync_pid_calc(A2DP_AUDIO_SYNC_PID_T *pid, float diff);
int a2dp_audio_sync_init(double ratio);
int a2dp_audio_sync_reset_data(void);
int a2dp_audio_sync_tune_sample_rate(double ratio);
int a2dp_audio_sync_direct_tune_sample_rate(double ratio);
int a2dp_audio_sync_tune_cancel(void);
int a2dp_audio_sysfreq_boost_start(uint32_t boost_cnt);
int a2dp_audio_sysfreq_boost_running(void);
int a2dp_audio_init(uint32_t sysfreq, A2DP_AUDIO_CODEC_TYPE codec_type, A2DP_AUDIO_OUTPUT_CONFIG_T *config,
A2DP_AUDIO_CHANNEL_SELECT_E chnl_sel, uint16_t dest_packet_mut);
int a2dp_audio_deinit(void);
int a2dp_audio_start(void);
int a2dp_audio_stop(void);
int a2dp_audio_detect_next_packet_callback_register(A2DP_AUDIO_DETECT_NEXT_PACKET_CALLBACK callback);
int a2dp_audio_detect_store_packet_callback_register(A2DP_AUDIO_DETECT_NEXT_PACKET_CALLBACK callback);
int a2dp_audio_detect_first_packet(void);
int a2dp_audio_detect_first_packet_clear(void);
int a2dp_audio_store_packet(btif_media_header_t * header, unsigned char *buf, unsigned int len);
int a2dp_audio_discards_packet(uint32_t packets);
int a2dp_audio_synchronize_dest_packet_mut(uint32_t mtu);
int a2dp_audio_discards_samples(uint32_t samples);
int a2dp_audio_convert_list_to_samples(uint32_t *samples);
int a2dp_audio_synchronize_packet(A2DP_AUDIO_SYNCFRAME_INFO_T *sync_info, uint32_t mask);
int a2dp_audio_decoder_headframe_info_get(A2DP_AUDIO_HEADFRAME_INFO_T *headframe_info);
int a2dp_audio_get_packet_samples(void);
int a2dp_audio_lastframe_info_get(A2DP_AUDIO_LASTFRAME_INFO_T *lastframe_info);
int a2dp_audio_lastframe_info_reset_undecodeframe(void);
void a2dp_audio_clear_input_raw_packet_list(void);
int a2dp_audio_refill_packet(void);
bool a2dp_audio_auto_synchronize_support(void);
A2DP_AUDIO_OUTPUT_CONFIG_T *a2dp_audio_get_output_config(void);
int a2dp_audio_latency_factor_setlow(void);
int a2dp_audio_latency_factor_sethigh(void);
float a2dp_audio_latency_factor_get(void);
int a2dp_audio_latency_factor_set(float factor);
int a2dp_audio_frame_delay_get(void);
int a2dp_audio_dest_packet_mut_get(void);
int a2dp_audio_latency_factor_status_get(A2DP_AUDIO_LATENCY_STATUS_E *latency_status, float *more_latency_factor);
#if A2DP_DECODER_HISTORY_SEQ_SAVE
int a2dp_audio_show_history_seq(void);
#endif
int a2dp_audio_set_channel_select(A2DP_AUDIO_CHANNEL_SELECT_E chnl_sel);
#ifdef __cplusplus
}
#endif
#endif//__A2DPPLAY_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,618 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifdef A2DP_CP_ACCEL
#include "a2dp_decoder_internal.h"
#include "a2dp_decoder_cp.h"
#include "cp_accel.h"
#include "hal_location.h"
#include "hal_timer.h"
#include "hal_trace.h"
#include "heap_api.h"
#include "norflash_api.h"
#define CP_IN_FRAME_CNT 100
#define CP_OUT_FRAME_CNT 3
#define CP_IN_CACHE_SIZE (1024 * 10)
#if defined(A2DP_LHDC_V3)
#define CP_HEAP_SIZE (1024 * 64)
#else
#define CP_HEAP_SIZE (1024 * 32)
#endif
enum CP_DEC_STATE_T {
CP_DEC_STATE_IDLE,
CP_DEC_STATE_WORKING,
CP_DEC_STATE_DONE,
CP_DEC_STATE_INIT_DONE,
};
struct CP_IN_FRAME_INFO_T {
uint32_t pos;
uint32_t len;
};
struct CP_OUT_FRAME_INFO_T {
enum CP_DEC_STATE_T state;
uint32_t pos;
uint32_t len;
};
static CP_BSS_LOC uint32_t cp_heap_buf[CP_HEAP_SIZE / 4];
static CP_BSS_LOC heap_handle_t cp_heap;
static CP_BSS_LOC uint16_t cp_in_widx;
static CP_BSS_LOC uint16_t cp_in_ridx;
static CP_BSS_LOC uint8_t cp_out_widx;
static CP_BSS_LOC uint8_t cp_out_ridx;
static CP_BSS_LOC struct CP_IN_FRAME_INFO_T *in_frames;
static CP_BSS_LOC struct CP_OUT_FRAME_INFO_T *out_frames;
static CP_BSS_LOC uint8_t *cp_in_cache;
static CP_BSS_LOC uint8_t *cp_out_cache;
static CP_BSS_LOC bool reset_frames;
#ifdef A2DP_TRACE_CP_DEC_TIME
static CP_BSS_LOC uint32_t cp_last_dec_time;
#endif
static uint8_t max_buffer_frames = 2;
static bool mcu_dec_inited;
static A2DP_CP_DECODE_T decode_frame;
static enum CP_PROC_DELAY_T proc_delay;
static bool cp_need_reset;
CP_TEXT_SRAM_LOC
unsigned int set_cp_reset_flag(uint8_t evt)
{
cp_need_reset = true;
return 0;
}
bool is_cp_need_reset(void)
{
bool ret = cp_need_reset;
cp_need_reset = false;
return ret;
}
bool is_cp_init_done(void)
{
return cp_accel_init_done();
}
CP_TEXT_SRAM_LOC
static void reset_frame_info(void)
{
uint32_t idle_cnt;
int i;
if (proc_delay == CP_PROC_DELAY_0_FRAME) {
idle_cnt = CP_OUT_FRAME_CNT;
} else if (proc_delay == CP_PROC_DELAY_1_FRAME) {
idle_cnt = CP_OUT_FRAME_CNT - 1;
} else {
idle_cnt = CP_OUT_FRAME_CNT - 2;
}
for (i = 0; i < CP_OUT_FRAME_CNT; i++) {
if (i < idle_cnt) {
out_frames[i].state = CP_DEC_STATE_IDLE;
} else {
out_frames[i].state = CP_DEC_STATE_INIT_DONE;
}
}
cp_in_widx = 0;
cp_in_ridx = 0;
cp_out_widx = 0;
cp_out_ridx = idle_cnt;
reset_frames = false;
}
CP_TEXT_SRAM_LOC
static unsigned int cp_a2dp_main(uint8_t event)
{
int ret;
#ifdef A2DP_TRACE_CP_DEC_TIME
uint32_t stime;
uint32_t etime;
#endif
if (!mcu_dec_inited) {
return 0;
}
if (decode_frame) {
do {
#ifdef A2DP_TRACE_CP_DEC_TIME
stime = hal_fast_sys_timer_get();
#endif
ret = decode_frame();
#ifdef A2DP_TRACE_CP_DEC_TIME
etime = hal_fast_sys_timer_get();
TRACE_A2DP_DECODER_I("cp_decode: %5u us in %5u us", FAST_TICKS_TO_US(etime - stime), FAST_TICKS_TO_US(etime - cp_last_dec_time));
cp_last_dec_time = etime;
#endif
} while (ret == 0);
}
if (reset_frames) {
reset_frame_info();
#ifdef A2DP_TRACE_CP_ACCEL
TRACE_A2DP_DECODER_I("%s: Reset frames", __func__);
#endif
}
return 0;
}
static struct cp_task_desc TASK_DESC_A2DP = {CP_ACCEL_STATE_CLOSED, cp_a2dp_main, NULL, NULL, set_cp_reset_flag};
int a2dp_cp_init(A2DP_CP_DECODE_T decode_func, enum CP_PROC_DELAY_T delay)
{
if (delay >= CP_PROC_DELAY_QTY) {
return 1;
}
mcu_dec_inited = false;
decode_frame = decode_func;
proc_delay = delay;
#ifdef A2DP_TRACE_CP_DEC_TIME
cp_last_dec_time = hal_fast_sys_timer_get();
#endif
norflash_api_flush_disable(NORFLASH_API_USER_CP,(uint32_t)cp_accel_init_done);
cp_accel_open(CP_TASK_A2DP_DECODE, &TASK_DESC_A2DP);
while(cp_accel_init_done() == false) {
hal_sys_timer_delay_us(100);
}
norflash_api_flush_enable(NORFLASH_API_USER_CP);
return 0;
}
int a2dp_cp_deinit(void)
{
cp_accel_close(CP_TASK_A2DP_DECODE);
return 0;
}
SRAM_TEXT_LOC
int a2dp_cp_decoder_init(uint32_t out_frame_len, uint8_t max_frames)
{
uint32_t i;
max_buffer_frames = max_frames;
if (!mcu_dec_inited) {
#ifdef A2DP_TRACE_CP_ACCEL
TRACE_A2DP_DECODER_I("%s: Decoder init", __func__);
#endif
if(cp_accel_init_done() == false){
TRACE_A2DP_DECODER_I("%s: CP ACCEL not init yet", __func__);
return 6;
}
cp_heap = heap_register(cp_heap_buf, sizeof(cp_heap_buf));
if (cp_heap == NULL) {
return 1;
}
in_frames = heap_malloc(cp_heap, sizeof(in_frames[0]) * CP_IN_FRAME_CNT);
if (in_frames == NULL) {
return 2;
}
out_frames = heap_malloc(cp_heap, sizeof(out_frames[0]) * CP_OUT_FRAME_CNT);
if (out_frames == NULL) {
return 3;
}
cp_in_cache = heap_malloc(cp_heap, CP_IN_CACHE_SIZE);
if (cp_in_cache == NULL) {
return 4;
}
cp_out_cache = heap_malloc(cp_heap, out_frame_len * CP_OUT_FRAME_CNT);
if (cp_out_cache == NULL) {
return 5;
}
for (i = 0; i < CP_OUT_FRAME_CNT; i++) {
out_frames[i].pos = out_frame_len * i;
out_frames[i].len = out_frame_len;
}
reset_frame_info();
mcu_dec_inited = true;
}
return 0;
}
CP_TEXT_SRAM_LOC
static uint32_t get_in_frame_cnt(uint32_t in_widx, uint32_t in_ridx)
{
uint32_t cnt;
if (in_widx >= in_ridx) {
cnt = in_widx - in_ridx;
} else {
cnt = CP_IN_FRAME_CNT - in_ridx + in_widx;
}
return cnt;
}
uint32_t get_in_cp_frame_cnt(void)
{
return get_in_frame_cnt(cp_in_widx, cp_in_ridx);
}
uint32_t get_in_cp_frame_delay(void)
{
return proc_delay;
}
SRAM_TEXT_LOC
static uint32_t get_in_frame_free_cnt(uint32_t in_widx, uint32_t in_ridx)
{
uint32_t free_cnt;
if (in_widx >= in_ridx) {
free_cnt = CP_IN_FRAME_CNT - in_widx + in_ridx;
} else {
free_cnt = in_ridx - in_widx;
}
free_cnt -= 1;
return free_cnt;
}
SRAM_TEXT_LOC
int a2dp_cp_put_in_frame(const void *buf1, uint32_t len1, const void *buf2, uint32_t len2)
{
uint16_t free_cnt;
uint16_t in_widx;
uint16_t in_ridx;
uint16_t prev_in_widx;
uint32_t free_len;
uint32_t in_wpos;
uint32_t in_rpos;
uint32_t aligned_len;
if (reset_frames) {
return -1;
}
in_widx = cp_in_widx;
in_ridx = cp_in_ridx;
if (max_buffer_frames < get_in_cp_frame_cnt()){
return 1;
}
free_cnt = get_in_frame_free_cnt(in_widx, in_ridx);
if (free_cnt == 0) {
return 1;
}
if (in_widx == in_ridx) {
in_wpos = 0;
in_rpos = 0;
} else {
if (in_widx == 0) {
prev_in_widx = CP_IN_FRAME_CNT - 1;
} else {
prev_in_widx = in_widx - 1;
}
in_wpos = in_frames[prev_in_widx].pos + in_frames[prev_in_widx].len;
if (in_wpos >= CP_IN_CACHE_SIZE) {
in_wpos -= CP_IN_CACHE_SIZE;
}
in_rpos = in_frames[in_ridx].pos;
}
// Align to word boundary
in_wpos = (in_wpos + 3) & ~3;
if (in_wpos >= CP_IN_CACHE_SIZE) {
in_wpos -= CP_IN_CACHE_SIZE;
}
aligned_len = (len1 + len2 + 3) & ~3;
if (in_wpos >= in_rpos) {
free_len = CP_IN_CACHE_SIZE - in_wpos;
if (in_rpos == 0) {
free_len -= 1;
}
if (free_len < aligned_len) {
free_len = (in_rpos > 0) ? (in_rpos - 1) : 0;
if (free_len < aligned_len) {
return 2;
}
in_wpos = 0;
}
} else {
free_len = in_rpos - in_wpos - 1;
if (free_len < aligned_len) {
return 3;
}
}
in_frames[in_widx].pos = in_wpos;
in_frames[in_widx].len = len1 + len2;
if (len1) {
memcpy(&cp_in_cache[in_wpos], buf1, len1);
in_wpos += len1;
}
if (len2) {
memcpy(&cp_in_cache[in_wpos], buf2, len2);
in_wpos += len2;
}
in_widx += 1;
if (in_widx >= CP_IN_FRAME_CNT) {
in_widx -= CP_IN_FRAME_CNT;
}
cp_in_widx = in_widx;
return 0;
}
CP_TEXT_SRAM_LOC
int a2dp_cp_get_in_frame(void **p_buf, uint32_t *p_len)
{
uint16_t in_widx;
uint16_t in_ridx;
uint32_t in_rpos;
if (reset_frames) {
return -1;
}
in_widx = cp_in_widx;
in_ridx = cp_in_ridx;
if (in_widx == in_ridx) {
return 1;
}
in_rpos = in_frames[in_ridx].pos;
if (p_buf) {
*p_buf = &cp_in_cache[in_rpos];
}
if (p_len) {
*p_len = in_frames[in_ridx].len;
}
return 0;
}
CP_TEXT_SRAM_LOC
int a2dp_cp_consume_in_frame(void)
{
uint16_t in_widx;
uint16_t in_ridx;
if (reset_frames) {
return 0;
}
in_widx = cp_in_widx;
in_ridx = cp_in_ridx;
if (in_widx == in_ridx) {
return 1;
}
in_ridx += 1;
if (in_ridx >= CP_IN_FRAME_CNT) {
in_ridx -= CP_IN_FRAME_CNT;
}
cp_in_ridx = in_ridx;
return 0;
}
CP_TEXT_SRAM_LOC
uint32_t a2dp_cp_get_in_frame_index(void)
{
return cp_in_ridx;
}
SRAM_TEXT_LOC
uint32_t a2dp_cp_get_in_frame_cnt_by_index(uint32_t ridx)
{
return get_in_frame_cnt(cp_in_widx, ridx);
}
SRAM_TEXT_LOC
void a2dp_cp_reset_frame(void)
{
#ifdef A2DP_TRACE_CP_ACCEL
TRACE_A2DP_DECODER_I("%s: Reset frames", __func__);
#endif
reset_frames = true;
// Notify CP to work again
cp_accel_send_event_mcu2cp(1);
}
SRAM_TEXT_LOC
bool a2dp_cp_get_frame_reset_status(void)
{
return reset_frames;
}
CP_TEXT_SRAM_LOC
enum CP_EMPTY_OUT_FRM_T a2dp_cp_get_emtpy_out_frame(void **p_buf, uint32_t *p_len)
{
enum CP_EMPTY_OUT_FRM_T ret;
uint8_t out_widx;
uint32_t out_wpos;
enum CP_DEC_STATE_T state ;
if (reset_frames) {
return CP_EMPTY_OUT_FRM_ERR;
}
out_widx = cp_out_widx;
state = out_frames[out_widx].state;
if (state != CP_DEC_STATE_IDLE && state != CP_DEC_STATE_WORKING) {
return CP_EMPTY_OUT_FRM_ERR;
}
if (state == CP_DEC_STATE_WORKING) {
ret = CP_EMPTY_OUT_FRM_WORKING;
} else {
out_frames[out_widx].state = CP_DEC_STATE_WORKING;
ret = CP_EMPTY_OUT_FRM_OK;
}
out_wpos = out_frames[out_widx].pos;
if (p_buf) {
*p_buf = &cp_out_cache[out_wpos];
}
if (p_len) {
*p_len = out_frames[out_widx].len;
}
return ret;
}
CP_TEXT_SRAM_LOC
int a2dp_cp_consume_emtpy_out_frame(void)
{
uint8_t out_widx;
if (reset_frames) {
return 0;
}
out_widx = cp_out_widx;
if (out_frames[out_widx].state != CP_DEC_STATE_WORKING) {
return 1;
}
out_frames[out_widx].state = CP_DEC_STATE_DONE;
#ifdef A2DP_TRACE_CP_ACCEL
TRACE_A2DP_DECODER_I("AD2P-CP out frame W[%d]", out_widx);
#endif
out_widx += 1;
if (out_widx >= CP_OUT_FRAME_CNT) {
out_widx -= CP_OUT_FRAME_CNT;
}
cp_out_widx = out_widx;
return 0;
}
SRAM_TEXT_LOC
int a2dp_cp_get_full_out_frame(void **p_buf, uint32_t *p_len)
{
uint8_t out_ridx;
uint32_t out_rpos;
enum CP_DEC_STATE_T state ;
if (reset_frames) {
return -1;
}
out_ridx = cp_out_ridx;
state = out_frames[out_ridx].state;
if (state != CP_DEC_STATE_DONE && state != CP_DEC_STATE_INIT_DONE) {
// Notify CP to work again
cp_accel_send_event_mcu2cp(CP_BUILD_ID(CP_TASK_A2DP_DECODE, CP_EVENT_A2DP_DECODE));
if (state == CP_DEC_STATE_WORKING){
return CP_EMPTY_OUT_FRM_WORKING;
}else{
return (10 + state);
}
}
out_rpos = out_frames[out_ridx].pos;
if (state == CP_DEC_STATE_DONE) {
if (p_buf) {
*p_buf = &cp_out_cache[out_rpos];
}
if (p_len) {
*p_len = out_frames[out_ridx].len;
}
} else {
if (p_buf) {
*p_buf = NULL;
}
if (p_len) {
*p_len = 0;
}
}
return 0;
}
SRAM_TEXT_LOC
int a2dp_cp_consume_full_out_frame(void)
{
uint8_t out_ridx;
enum CP_DEC_STATE_T state ;
if (reset_frames) {
return 0;
}
out_ridx = cp_out_ridx;
state = out_frames[out_ridx].state;
if (state != CP_DEC_STATE_DONE && state != CP_DEC_STATE_INIT_DONE) {
return 1;
}
#ifdef A2DP_TRACE_CP_ACCEL
TRACE_A2DP_DECODER_I("AD2P-CP out frame R[%d]", out_ridx);
#endif
out_frames[out_ridx].state = CP_DEC_STATE_IDLE;
out_ridx += 1;
if (out_ridx >= CP_OUT_FRAME_CNT) {
out_ridx -= CP_OUT_FRAME_CNT;
}
cp_out_ridx = out_ridx;
// Notify CP to work again
cp_accel_send_event_mcu2cp(CP_BUILD_ID(CP_TASK_A2DP_DECODE, CP_EVENT_A2DP_DECODE));
return 0;
}
#endif

View file

@ -0,0 +1,82 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __A2DP_DECODER_CP_H__
#define __A2DP_DECODER_CP_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
#include "stdbool.h"
enum CP_PROC_DELAY_T {
CP_PROC_DELAY_0_FRAME = 0,
CP_PROC_DELAY_1_FRAME,
CP_PROC_DELAY_2_FRAMES,
CP_PROC_DELAY_3_FRAMES,
CP_PROC_DELAY_QTY,
};
enum CP_EMPTY_OUT_FRM_T {
CP_EMPTY_OUT_FRM_OK,
CP_EMPTY_OUT_FRM_WORKING,
CP_EMPTY_OUT_FRM_ERR,
};
typedef int (*A2DP_CP_DECODE_T)(void);
int a2dp_cp_init(A2DP_CP_DECODE_T decode_func, enum CP_PROC_DELAY_T delay);
int a2dp_cp_deinit(void);
int a2dp_cp_decoder_init(uint32_t out_frame_len, uint8_t max_frames);
int a2dp_cp_put_in_frame(const void *buf1, uint32_t len1, const void *buf2, uint32_t len2);
int a2dp_cp_get_in_frame(void **p_buf, uint32_t *p_len);
int a2dp_cp_consume_in_frame(void);
uint32_t a2dp_cp_get_in_frame_index(void);
uint32_t a2dp_cp_get_in_frame_cnt_by_index(uint32_t ridx);
void a2dp_cp_reset_frame(void);
bool a2dp_cp_get_in_frame_reset_status(void);
enum CP_EMPTY_OUT_FRM_T a2dp_cp_get_emtpy_out_frame(void **p_buf, uint32_t *p_len);
int a2dp_cp_consume_emtpy_out_frame(void);
int a2dp_cp_get_full_out_frame(void **p_buf, uint32_t *p_len);
int a2dp_cp_consume_full_out_frame(void);
unsigned int set_cp_reset_flag(uint8_t evt);
bool is_cp_need_reset(void);
bool is_cp_init_done(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,137 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
// Standard C Included Files
#include "cmsis.h"
#include "plat_types.h"
#include <string.h>
#include "heap_api.h"
#include "hal_location.h"
#include "a2dp_decoder_internal.h"
static A2DP_AUDIO_CONTEXT_T *a2dp_audio_context_p = NULL;
static A2DP_AUDIO_DECODER_LASTFRAME_INFO_T a2dp_audio_ldac_example_info;
static A2DP_AUDIO_OUTPUT_CONFIG_T a2dp_audio_example_output_config;
typedef struct {
uint16_t sequenceNumber;
uint32_t timestamp;
uint8_t *buffer;
uint32_t buffer_len;
} a2dp_audio_example_decoder_frame_t;
int a2dp_audio_example_decode_frame(uint8_t *buffer, uint32_t buffer_bytes)
{
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_example_preparse_packet(btif_media_header_t * header, uint8_t *buffer, uint32_t buffer_bytes)
{
return A2DP_DECODER_NO_ERROR;
}
static void *a2dp_audio_example_frame_malloc(uint32_t packet_len)
{
a2dp_audio_example_decoder_frame_t *decoder_frame_p = NULL;
uint8_t *buffer = NULL;
buffer = (uint8_t *)a2dp_audio_heap_malloc(packet_len);
decoder_frame_p = (a2dp_audio_example_decoder_frame_t *)a2dp_audio_heap_malloc(sizeof(a2dp_audio_example_decoder_frame_t));
decoder_frame_p->buffer = buffer;
decoder_frame_p->buffer_len = packet_len;
return (void *)decoder_frame_p;
}
void a2dp_audio_example_free(void *packet)
{
a2dp_audio_example_decoder_frame_t *decoder_frame_p = (a2dp_audio_example_decoder_frame_t *)packet;
a2dp_audio_heap_free(decoder_frame_p->buffer);
a2dp_audio_heap_free(decoder_frame_p);
}
int a2dp_audio_example_store_packet(btif_media_header_t * header, uint8_t *buffer, uint32_t buffer_bytes)
{
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
a2dp_audio_example_decoder_frame_t *decoder_frame_p = (a2dp_audio_example_decoder_frame_t *)a2dp_audio_example_frame_malloc(buffer_bytes);
decoder_frame_p->sequenceNumber = header->sequenceNumber;
decoder_frame_p->timestamp = header->timestamp;
memcpy(decoder_frame_p->buffer, buffer, buffer_bytes);
decoder_frame_p->buffer_len = buffer_bytes;
a2dp_audio_list_append(list, decoder_frame_p);
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_example_discards_packet(uint32_t packets)
{
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_example_headframe_info_get(A2DP_AUDIO_HEADFRAME_INFO_T* headframe_info)
{
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_example_info_get(void *info)
{
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_example_init(A2DP_AUDIO_OUTPUT_CONFIG_T *config, void *context)
{
TRACE_A2DP_DECODER_D("%s", __func__);
a2dp_audio_context_p = (A2DP_AUDIO_CONTEXT_T *)context;
memset(&a2dp_audio_ldac_example_info, 0, sizeof(A2DP_AUDIO_DECODER_LASTFRAME_INFO_T));
memcpy(&a2dp_audio_example_output_config, config, sizeof(A2DP_AUDIO_OUTPUT_CONFIG_T));
a2dp_audio_ldac_example_info.stream_info = &a2dp_audio_example_output_config;
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_example_deinit(void)
{
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_example_synchronize_packet(A2DP_AUDIO_SYNCFRAME_INFO_T *sync_info, uint32_t mask)
{
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_example_synchronize_dest_packet_mut(uint16_t packet_mut)
{
return A2DP_DECODER_NO_ERROR;
}
A2DP_AUDIO_DECODER_T a2dp_audio_example_decoder_config = {
{44100, 2, 16},
0,
a2dp_audio_example_init,
a2dp_audio_example_deinit,
a2dp_audio_example_decode_frame,
a2dp_audio_example_preparse_packet,
a2dp_audio_example_store_packet,
a2dp_audio_example_discards_packet,
a2dp_audio_example_synchronize_packet,
a2dp_audio_example_synchronize_dest_packet_mut,
a2dp_audio_example_headframe_info_get,
a2dp_audio_example_info_get,
a2dp_audio_example_free,
} ;

View file

@ -0,0 +1,201 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __A2DP_DECODER_INTERNAL_H__
#define __A2DP_DECODER_INTERNAL_H__
#include "list.h"
#include "a2dp_decoder.h"
#ifdef A2DP_CP_ACCEL
#include "a2dp_decoder_cp.h"
#include "hal_location.h"
#endif
#include "a2dp_decoder_trace.h"
#define TEXT_A2DP_LOC_A(n, l) __attribute__((section(#n "." #l)))
#define TEXT_A2DP_LOC(n, l) TEXT_A2DP_LOC_A(n, l)
#define TEXT_SBC_LOC TEXT_A2DP_LOC(.overlay_a2dp_sbc, __LINE__)
#define TEXT_AAC_LOC TEXT_A2DP_LOC(.overlay_a2dp_aac, __LINE__)
#define TEXT_SSC_LOC TEXT_A2DP_LOC(.overlay_a2dp_ssc, __LINE__)
#define TEXT_LDAC_LOC TEXT_A2DP_LOC(.overlay_a2dp_ldac, __LINE__)
#define TEXT_LHDC_LOC TEXT_A2DP_LOC(.overlay_a2dp_lhdc, __LINE__)
#define A2DP_DECODER_NO_ERROR (0)
#define A2DP_DECODER_DECODE_ERROR (-1)
#define A2DP_DECODER_BUSY_ERROR (-2)
#define A2DP_DECODER_MEMORY_ERROR (-3)
#define A2DP_DECODER_MTU_LIMTER_ERROR (-4)
#define A2DP_DECODER_CACHE_UNDERFLOW_ERROR (-5)
#define A2DP_DECODER_SYNC_ERROR (-6)
#define A2DP_DECODER_NOT_SUPPORT (-128)
#ifdef MIN
#undef MIN
#endif
#define MIN(a,b) ((a)<(b) ? (a):(b))
#ifdef MAX
#undef MAX
#endif
#define MAX(a,b) ((a)>(b) ? (a):(b))
typedef A2DP_AUDIO_OUTPUT_CONFIG_T AUDIO_DECODER_STREAM_INFO_T;
typedef int (*AUDIO_DECODER_INIT)(A2DP_AUDIO_OUTPUT_CONFIG_T *, void *);
typedef int (*AUDIO_DECODER_DEINIT)(void);
typedef int (*AUDIO_DECODER_DECODE_FRAME)(uint8_t *, uint32_t);
typedef int (*AUDIO_DECODER_PREPARSE_PACKET)(btif_media_header_t *, uint8_t *, uint32_t);
typedef int (*AUDIO_DECODER_STORE_PACKET)(btif_media_header_t *, uint8_t *, uint32_t);
typedef int (*AUDIO_DECODER_DISCARDS_PACKET)(uint32_t);
typedef int (*AUDIO_DECODER_SYNCHRONIZE_PACKET)(A2DP_AUDIO_SYNCFRAME_INFO_T *, uint32_t);
typedef int (*AUDIO_DECODER_SYNCHRONIZE_DEST_PACKET_MUT)(uint16_t);
typedef int (*AUDIO_DECODER_HEADFRAME_INFO_GET)(A2DP_AUDIO_HEADFRAME_INFO_T*);
typedef int (*AUDIO_DECODER_INFO_GET)(void *);
typedef void(*AUDIO_DECODER_PACKET_FREE)(void *);
typedef int (*AUDIO_DECODER_SYNCHRONIZE_CONVERT_LIST_TO_SAMPLES)(uint32_t *);
typedef int (*AUDIO_DECODER_SYNCHRONIZE_DISCARDS_SAMPLES)(uint32_t);
typedef int (*AUDIO_DECODER_CHANNEL_SELECT)(A2DP_AUDIO_CHANNEL_SELECT_E);
typedef struct {
AUDIO_DECODER_STREAM_INFO_T stream_info;
uint32_t auto_synchronize_support;
AUDIO_DECODER_INIT audio_decoder_init;
AUDIO_DECODER_DEINIT audio_decoder_deinit;
AUDIO_DECODER_DECODE_FRAME audio_decoder_decode_frame;
AUDIO_DECODER_PREPARSE_PACKET audio_decoder_preparse_packet;
AUDIO_DECODER_STORE_PACKET audio_decoder_store_packet;
AUDIO_DECODER_DISCARDS_PACKET audio_decoder_discards_packet;
AUDIO_DECODER_SYNCHRONIZE_PACKET audio_decoder_synchronize_packet;
AUDIO_DECODER_SYNCHRONIZE_DEST_PACKET_MUT audio_decoder_synchronize_dest_packet_mut;
AUDIO_DECODER_SYNCHRONIZE_CONVERT_LIST_TO_SAMPLES a2dp_audio_convert_list_to_samples;
AUDIO_DECODER_SYNCHRONIZE_DISCARDS_SAMPLES a2dp_audio_discards_samples;
AUDIO_DECODER_HEADFRAME_INFO_GET audio_decoder_headframe_info_get;
AUDIO_DECODER_INFO_GET audio_decoder_info_get;
AUDIO_DECODER_PACKET_FREE audio_decoder_packet_free;
AUDIO_DECODER_CHANNEL_SELECT audio_decoder_channel_select;
} A2DP_AUDIO_DECODER_T;
typedef struct {
list_t *input_raw_packet_list;
list_t *output_pcm_packet_list;
} A2DP_AUDIO_DATAPATH_T;
typedef struct {
bool enalbe;
void *semaphore;
} AUDIO_BUFFER_SEMAPHORE_T;
enum A2DP_AUDIO_DECODER_STATUS {
A2DP_AUDIO_DECODER_STATUS_NULL,
A2DP_AUDIO_DECODER_STATUS_READY,
A2DP_AUDIO_DECODER_STATUS_START,
A2DP_AUDIO_DECODER_STATUS_STOP
};
enum A2DP_AUDIO_DECODER_STORE_PACKET_STATUS {
A2DP_AUDIO_DECODER_STORE_PACKET_STATUS_IDLE,
A2DP_AUDIO_DECODER_STORE_PACKET_STATUS_BUSY,
};
enum A2DP_AUDIO_DECODER_PLAYBACK_STATUS {
A2DP_AUDIO_DECODER_PLAYBACK_STATUS_IDLE,
A2DP_AUDIO_DECODER_PLAYBACK_STATUS_BUSY,
};
typedef struct {
uint16_t sequenceNumber;
uint32_t timestamp;
uint16_t curSubSequenceNumber;
uint16_t totalSubSequenceNumber;
uint32_t frame_samples;
uint32_t list_samples;
uint32_t decoded_frames;
uint32_t undecode_frames;
uint32_t check_sum;
A2DP_AUDIO_OUTPUT_CONFIG_T stream_info;
} A2DP_AUDIO_DECODER_LASTFRAME_INFO_T;
typedef struct {
A2DP_AUDIO_SYNC_PID_T pid;
uint32_t tick;
uint32_t cnt;
} A2DP_AUDIO_SYNC_T;
typedef struct {
A2DP_AUDIO_OUTPUT_CONFIG_T output_cfg;
float init_factor_reference;
A2DP_AUDIO_CHANNEL_SELECT_E chnl_sel;
uint16_t dest_packet_mut;
float average_packet_mut;
A2DP_AUDIO_DECODER_T audio_decoder;
A2DP_AUDIO_DATAPATH_T audio_datapath;
list_t *input_raw_packet_list;
list_t *output_pcm_packet_list;
bool need_detect_first_packet;
bool underflow_onporcess;
uint32_t skip_frame_cnt_after_no_cache;
uint32_t mute_frame_cnt_after_no_cache;
AUDIO_BUFFER_SEMAPHORE_T audio_semaphore;
void *audio_buffer_mutex;
void *audio_status_mutex;
void *audio_stop_mutex;
enum A2DP_AUDIO_DECODER_STATUS audio_decoder_status;
enum A2DP_AUDIO_DECODER_STORE_PACKET_STATUS store_packet_status;
enum A2DP_AUDIO_DECODER_PLAYBACK_STATUS playback_status;
A2DP_AUDIO_SYNC_T audio_sync;
#if A2DP_DECODER_HISTORY_SEQ_SAVE
uint16_t historySeq[A2DP_DECODER_HISTORY_SEQ_SAVE];
#ifdef A2DP_DECODER_HISTORY_LOCTIME_SAVE
uint32_t historyLoctime[A2DP_DECODER_HISTORY_SEQ_SAVE];
#endif
#ifdef A2DP_DECODER_HISTORY_CHECK_SUM_SAVE
uint32_t historyChecksum[A2DP_DECODER_HISTORY_SEQ_SAVE];
#endif
uint8_t historySeq_idx;
#endif
} A2DP_AUDIO_CONTEXT_T;
#ifdef __cplusplus
extern "C" {
#endif
void *a2dp_audio_heap_malloc(uint32_t size);
void *a2dp_audio_heap_cmalloc(uint32_t size);
void *a2dp_audio_heap_realloc(void *rmem, uint32_t newsize);
void a2dp_audio_heap_free(void *rmem);
list_node_t *a2dp_audio_list_begin(const list_t *list);
list_node_t *a2dp_audio_list_end(const list_t *list);
uint32_t a2dp_audio_list_length(const list_t *list);
void *a2dp_audio_list_node(const list_node_t *node);
list_node_t *a2dp_audio_list_next(const list_node_t *node);
bool a2dp_audio_list_remove(list_t *list, void *data);
bool a2dp_audio_list_append(list_t *list, void *data);
void a2dp_audio_list_clear(list_t *list);
void a2dp_audio_list_free(list_t *list);
list_t *a2dp_audio_list_new(list_free_cb callback, list_mempool_zmalloc zmalloc, list_mempool_free free);
int a2dp_audio_semaphore_wait(uint32_t timeout_ms);
int a2dp_audio_semaphore_release(void);
int a2dp_audio_decoder_internal_lastframe_info_set(A2DP_AUDIO_DECODER_LASTFRAME_INFO_T *lastframe_info);
uint32_t a2dp_audio_get_passed(uint32_t curr_ticks, uint32_t prev_ticks, uint32_t max_ticks);
uint32_t a2dp_audio_decoder_internal_check_sum_generate(const uint8_t *buf, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif//__A2DPPLAY_H__

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,969 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
// Standard C Included Files
#include "cmsis.h"
#include "plat_types.h"
#include <string.h>
#include "heap_api.h"
#include "hal_location.h"
#include "codec_sbc.h"
#include "a2dp_decoder_internal.h"
#include "hal_timer.h"
#include "cmsis_os.h"
#ifndef SBC_MTU_LIMITER
#define SBC_MTU_LIMITER (250) /*must <= 332*/
#endif
#define SBC_PCMLEN_DEFAULT (512)
#define SBC_LIST_SAMPLES (128)
static A2DP_AUDIO_CONTEXT_T *a2dp_audio_context_p = NULL;
extern A2DP_AUDIO_DECODER_T a2dp_audio_sbc_decoder_config;
typedef struct {
btif_sbc_decoder_t *sbc_decoder;
btif_sbc_pcm_data_t *pcm_data;
} a2dp_audio_sbc_decoder_t;
typedef struct {
uint16_t sequenceNumber;
uint32_t timestamp;
uint16_t curSubSequenceNumber;
uint16_t totalSubSequenceNumber;
uint8_t *sbc_buffer;
uint32_t sbc_buffer_len;
} a2dp_audio_sbc_decoder_frame_t;
static a2dp_audio_sbc_decoder_t a2dp_audio_sbc_decoder;
static btif_sbc_decoder_t *a2dp_audio_sbc_decoder_preparse = NULL;
static A2DP_AUDIO_DECODER_LASTFRAME_INFO_T a2dp_audio_sbc_lastframe_info;
static uint16_t sbc_mtu_limiter = SBC_MTU_LIMITER;
static btif_media_header_t sbc_decoder_last_valid_frame = {0,};
static bool sbc_decoder_last_valid_frame_ready = false;
static bool sbc_chnl_mode_mono = false;
static int a2dp_audio_sbc_header_parser_init(void);
static void *a2dp_audio_sbc_subframe_malloc(uint32_t sbc_len)
{
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame_p = NULL;
uint8_t *sbc_buffer = NULL;
sbc_buffer = (uint8_t *)a2dp_audio_heap_malloc(sbc_len);
sbc_decoder_frame_p = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_heap_malloc(sizeof(a2dp_audio_sbc_decoder_frame_t));
sbc_decoder_frame_p->sbc_buffer = sbc_buffer;
sbc_decoder_frame_p->sbc_buffer_len = sbc_len;
return (void *)sbc_decoder_frame_p;
}
static void a2dp_audio_sbc_subframe_free(void *packet)
{
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame_p = (a2dp_audio_sbc_decoder_frame_t *)packet;
a2dp_audio_heap_free(sbc_decoder_frame_p->sbc_buffer);
a2dp_audio_heap_free(sbc_decoder_frame_p);
}
static void sbc_codec_init(void)
{
btif_sbc_init_decoder(a2dp_audio_sbc_decoder.sbc_decoder);
a2dp_audio_sbc_decoder.sbc_decoder->maxPcmLen = SBC_PCMLEN_DEFAULT;
a2dp_audio_sbc_decoder.pcm_data->data = NULL;
a2dp_audio_sbc_decoder.pcm_data->dataLen = 0;
}
#ifdef A2DP_CP_ACCEL
struct A2DP_CP_SBC_IN_FRM_INFO_T {
uint16_t sequenceNumber;
uint32_t timestamp;
uint16_t curSubSequenceNumber;
uint16_t totalSubSequenceNumber;
};
struct A2DP_CP_SBC_OUT_FRM_INFO_T {
struct A2DP_CP_SBC_IN_FRM_INFO_T in_info;
uint16_t frame_samples;
uint16_t decoded_frames;
uint16_t frame_idx;
uint16_t pcm_len;
};
static bool cp_codec_reset;
extern "C" uint32_t get_in_cp_frame_cnt(void);
extern "C" unsigned int set_cp_reset_flag(uint8_t evt);
int a2dp_cp_sbc_cp_decode(void);
extern uint32_t app_bt_stream_get_dma_buffer_samples(void);
static int TEXT_SBC_LOC a2dp_cp_sbc_after_cache_underflow(void)
{
#ifdef A2DP_CP_ACCEL
cp_codec_reset = true;
#endif
return 0;
}
static int a2dp_cp_sbc_mcu_decode(uint8_t *buffer, uint32_t buffer_bytes)
{
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
list_node_t *node = NULL;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
int ret, dec_ret;
struct A2DP_CP_SBC_IN_FRM_INFO_T in_info;
struct A2DP_CP_SBC_OUT_FRM_INFO_T *p_out_info = NULL;
uint8_t *out = NULL;
uint32_t out_len;
uint32_t out_frame_len;
uint32_t cp_buffer_frames_max = 0;
uint32_t check_sum = 0;
cp_buffer_frames_max = app_bt_stream_get_dma_buffer_samples()/2;
if (cp_buffer_frames_max %(a2dp_audio_sbc_lastframe_info.frame_samples) ){
cp_buffer_frames_max = cp_buffer_frames_max /(a2dp_audio_sbc_lastframe_info.frame_samples) +1 ;
}else{
cp_buffer_frames_max = cp_buffer_frames_max /(a2dp_audio_sbc_lastframe_info.frame_samples) ;
}
out_frame_len = sizeof(*p_out_info) + buffer_bytes;
ret = a2dp_cp_decoder_init(out_frame_len, cp_buffer_frames_max * 2);
if (ret){
TRACE_A2DP_DECODER_W("[SBC][INIT] cp_decoder_init() failed: ret=%d", ret);
set_cp_reset_flag(true);
return A2DP_DECODER_DECODE_ERROR;
}
while ((node = a2dp_audio_list_begin(list)) != NULL) {
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
in_info.sequenceNumber = sbc_decoder_frame->sequenceNumber;
in_info.timestamp = sbc_decoder_frame->timestamp;
in_info.curSubSequenceNumber = sbc_decoder_frame->curSubSequenceNumber;
in_info.totalSubSequenceNumber = sbc_decoder_frame->totalSubSequenceNumber;
ret = a2dp_cp_put_in_frame(&in_info, sizeof(in_info), sbc_decoder_frame->sbc_buffer, sbc_decoder_frame->sbc_buffer_len);
if (ret) {
TRACE_A2DP_DECODER_D("[MCU][SBC] piff !!!!!!ret: %d ", ret);
break;
}
check_sum = a2dp_audio_decoder_internal_check_sum_generate(sbc_decoder_frame->sbc_buffer, sbc_decoder_frame->sbc_buffer_len);
a2dp_audio_list_remove(list, sbc_decoder_frame);
}
ret = a2dp_cp_get_full_out_frame((void **)&out, &out_len);
if (ret) {
if (!get_in_cp_frame_cnt()){
TRACE_A2DP_DECODER_I("[MCU][SBC] cp cache underflow list:%d in_cp:%d",a2dp_audio_list_length(list), get_in_cp_frame_cnt());
return A2DP_DECODER_CACHE_UNDERFLOW_ERROR;
}
if (!a2dp_audio_sysfreq_boost_running()){
a2dp_audio_sysfreq_boost_start(1);
}
osDelay(8);
ret = a2dp_cp_get_full_out_frame((void **)&out, &out_len);
if (ret) {
TRACE_A2DP_DECODER_I("[MCU][SBC] cp cache underflow list:%d in_cp:%d",a2dp_audio_list_length(list), get_in_cp_frame_cnt());
a2dp_cp_sbc_after_cache_underflow();
return A2DP_DECODER_CACHE_UNDERFLOW_ERROR;
}
}
if (out_len == 0) {
TRACE_A2DP_DECODER_I("[MCU][SBC] olz!!!%d ",__LINE__);
memset(buffer, 0, buffer_bytes);
a2dp_cp_consume_full_out_frame();
return A2DP_DECODER_NO_ERROR;
}
if(out_len != out_frame_len){
TRACE_A2DP_DECODER_I("[MCU][SBC] Bad out len %u (should be %u)", out_len, out_frame_len);
set_cp_reset_flag(true);
return A2DP_DECODER_DECODE_ERROR;
}
p_out_info = (struct A2DP_CP_SBC_OUT_FRM_INFO_T *)out;
if (p_out_info->pcm_len) {
a2dp_audio_sbc_lastframe_info.sequenceNumber = p_out_info->in_info.sequenceNumber;
a2dp_audio_sbc_lastframe_info.timestamp = p_out_info->in_info.timestamp;
a2dp_audio_sbc_lastframe_info.curSubSequenceNumber = p_out_info->in_info.curSubSequenceNumber;
a2dp_audio_sbc_lastframe_info.totalSubSequenceNumber = p_out_info->in_info.totalSubSequenceNumber;
a2dp_audio_sbc_lastframe_info.frame_samples = p_out_info->frame_samples;
a2dp_audio_sbc_lastframe_info.decoded_frames += p_out_info->decoded_frames;
a2dp_audio_sbc_lastframe_info.undecode_frames =
a2dp_audio_list_length(list) + a2dp_cp_get_in_frame_cnt_by_index(p_out_info->frame_idx) - 1;
a2dp_audio_sbc_lastframe_info.check_sum= check_sum?check_sum:a2dp_audio_sbc_lastframe_info.check_sum;
a2dp_audio_decoder_internal_lastframe_info_set(&a2dp_audio_sbc_lastframe_info);
}
if (p_out_info->pcm_len == buffer_bytes) {
memcpy(buffer, p_out_info + 1, p_out_info->pcm_len);
dec_ret = A2DP_DECODER_NO_ERROR;
} else {
TRACE_A2DP_DECODER_I("[MCU][SBC] line:%d cp decoder error !!!!!!", __LINE__);
set_cp_reset_flag(true);
return A2DP_DECODER_DECODE_ERROR;
}
ret = a2dp_cp_consume_full_out_frame();
if(ret){
TRACE_A2DP_DECODER_I("[MCU][SBC] cp_consume_full_out_frame failed: ret=%d", ret);
set_cp_reset_flag(true);
return A2DP_DECODER_DECODE_ERROR;
}
return dec_ret;
}
#ifdef __CP_EXCEPTION_TEST__
static bool _cp_assert = false;
int cp_assert_sbc(void)
{
_cp_assert = true;
return 0;
}
#endif
TEXT_SBC_LOC
int a2dp_cp_sbc_cp_decode(void)
{
int ret = 0;
enum CP_EMPTY_OUT_FRM_T out_frm_st;
uint8_t *out = NULL;
uint32_t out_len = 0;
uint8_t *dec_start = NULL;
uint32_t dec_len = 0;
struct A2DP_CP_SBC_IN_FRM_INFO_T *p_in_info = NULL;
struct A2DP_CP_SBC_OUT_FRM_INFO_T *p_out_info = NULL;
uint8_t *in_buf = NULL;
uint32_t in_len = 0;
uint16_t bytes_parsed = 0;
float sbc_subbands_gain[8]={1,1,1,1,1,1,1,1};
btif_sbc_decoder_t *sbc_decoder = NULL;
btif_sbc_pcm_data_t *pcm_data = NULL;
bt_status_t decoder_err = 0;
int error = 0;
if (cp_codec_reset) {
cp_codec_reset = false;
sbc_codec_init();
}
#ifdef __CP_EXCEPTION_TEST__
if (_cp_assert){
_cp_assert = false;
*(int*) 0 = 1;
//ASSERT_A2DP_DECODER(0, "ASSERT_A2DP_DECODER %s %d", __func__, __LINE__);
}
#endif
sbc_decoder = a2dp_audio_sbc_decoder.sbc_decoder;
pcm_data = a2dp_audio_sbc_decoder.pcm_data;
out_frm_st = a2dp_cp_get_emtpy_out_frame((void **)&out, &out_len);
if (out_frm_st != CP_EMPTY_OUT_FRM_OK && out_frm_st != CP_EMPTY_OUT_FRM_WORKING) {
return 1;
}
ASSERT_A2DP_DECODER(out_len > sizeof(*p_out_info), "[CP][SBC] Bad out_len %u (should > %u)", out_len, sizeof(*p_out_info));
p_out_info = (struct A2DP_CP_SBC_OUT_FRM_INFO_T *)out;
if (out_frm_st == CP_EMPTY_OUT_FRM_OK) {
p_out_info->pcm_len = 0;
p_out_info->decoded_frames = 0;
}
ASSERT_A2DP_DECODER(out_len > sizeof(*p_out_info) + p_out_info->pcm_len, "[CP][SBC] Bad out_len %u (should > %u + %u)", out_len, sizeof(*p_out_info), p_out_info->pcm_len);
dec_start = (uint8_t *)(p_out_info + 1) + p_out_info->pcm_len;
dec_len = out_len - (dec_start - (uint8_t *)out);
pcm_data->data = dec_start;
pcm_data->dataLen = 0;
error = 0;
while (pcm_data->dataLen < dec_len && error == 0) {
ret = a2dp_cp_get_in_frame((void **)&in_buf, &in_len);
if (ret) {
p_out_info->pcm_len += pcm_data->dataLen;
return 4;
}
ASSERT_A2DP_DECODER(in_len > sizeof(*p_in_info), "%s: Bad in_len %u (should > %u)", __func__, in_len, sizeof(*p_in_info));
p_in_info = (struct A2DP_CP_SBC_IN_FRM_INFO_T *)in_buf;
in_buf += sizeof(*p_in_info);
in_len -= sizeof(*p_in_info);
decoder_err = btif_sbc_decode_frames(sbc_decoder, in_buf, in_len,
&bytes_parsed,
pcm_data,
dec_len,
sbc_subbands_gain);
switch (decoder_err)
{
case BT_STS_SUCCESS:
case BT_STS_CONTINUE:
break;
case BT_STS_NO_RESOURCES:
error = 1;
ASSERT_A2DP_DECODER(0, "sbc_decode BT_STS_NO_RESOURCES pcm has no more buffer, i think can't reach here");
break;
case BT_STS_FAILED:
default:
error = 1;
sbc_codec_init();
break;
}
memcpy(&p_out_info->in_info, p_in_info, sizeof(*p_in_info));
p_out_info->decoded_frames++;
p_out_info->frame_samples = sbc_decoder->maxPcmLen/4;
p_out_info->frame_idx = a2dp_cp_get_in_frame_index();
ret = a2dp_cp_consume_in_frame();
ASSERT_A2DP_DECODER(ret == 0, "%s: a2dp_cp_consume_in_frame() failed: ret=%d", __func__, ret);
}
p_out_info->pcm_len += pcm_data->dataLen;
if (error || out_len <= sizeof(*p_out_info) + p_out_info->pcm_len) {
ret = a2dp_cp_consume_emtpy_out_frame();
ASSERT_A2DP_DECODER(ret == 0, "%s: a2dp_cp_consume_emtpy_out_frame() failed: ret=%d", __func__, ret);
}
return error;
}
#endif
static int a2dp_audio_sbc_list_checker(void)
{
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_node_t *node = NULL;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
int cnt = 0;
do {
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_sbc_subframe_malloc(SBC_LIST_SAMPLES);
if (sbc_decoder_frame){
a2dp_audio_list_append(list, sbc_decoder_frame);
}
cnt++;
}while(sbc_decoder_frame && cnt < SBC_MTU_LIMITER);
do {
node = a2dp_audio_list_begin(list);
if (node){
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, sbc_decoder_frame);
}
}while(node);
TRACE_A2DP_DECODER_I("[SBC][INIT] cnt:%d list:%d", cnt, a2dp_audio_list_length(list));
return 0;
}
int a2dp_audio_sbc_init(A2DP_AUDIO_OUTPUT_CONFIG_T *config, void *context)
{
TRACE_A2DP_DECODER_I("[SBC][INIT]");
a2dp_audio_context_p = (A2DP_AUDIO_CONTEXT_T *)context;
a2dp_audio_sbc_header_parser_init();
memset(&a2dp_audio_sbc_lastframe_info, 0, sizeof(A2DP_AUDIO_DECODER_LASTFRAME_INFO_T));
a2dp_audio_sbc_lastframe_info.stream_info = *config;
a2dp_audio_sbc_lastframe_info.frame_samples= SBC_LIST_SAMPLES;
a2dp_audio_sbc_lastframe_info.list_samples = SBC_LIST_SAMPLES;
a2dp_audio_decoder_internal_lastframe_info_set(&a2dp_audio_sbc_lastframe_info);
ASSERT_A2DP_DECODER(a2dp_audio_context_p->dest_packet_mut < SBC_MTU_LIMITER, "%s MTU OVERFLOW:%u/%u", __func__, a2dp_audio_context_p->dest_packet_mut, SBC_MTU_LIMITER);
a2dp_audio_sbc_decoder.sbc_decoder = (btif_sbc_decoder_t *)a2dp_audio_heap_malloc(sizeof(btif_sbc_decoder_t));
a2dp_audio_sbc_decoder.pcm_data = (btif_sbc_pcm_data_t *)a2dp_audio_heap_malloc(sizeof(btif_sbc_pcm_data_t));
a2dp_audio_sbc_decoder_preparse = (btif_sbc_decoder_t *)a2dp_audio_heap_malloc(sizeof(btif_sbc_decoder_t));
#ifdef A2DP_CP_ACCEL
int ret;
cp_codec_reset = true;
ret = a2dp_cp_init(a2dp_cp_sbc_cp_decode, CP_PROC_DELAY_2_FRAMES);
ASSERT_A2DP_DECODER(ret == 0, "%s: a2dp_cp_init() failed: ret=%d", __func__, ret);
#else
sbc_codec_init();
#endif
a2dp_audio_sbc_list_checker();
sbc_chnl_mode_mono = false;
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_sbc_deinit(void)
{
#ifdef A2DP_CP_ACCEL
a2dp_cp_deinit();
#endif
a2dp_audio_heap_free(a2dp_audio_sbc_decoder_preparse);
a2dp_audio_heap_free(a2dp_audio_sbc_decoder.sbc_decoder);
a2dp_audio_heap_free(a2dp_audio_sbc_decoder.pcm_data);
TRACE_A2DP_DECODER_I("[SBC][DEINIT]");
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_sbc_mcu_decode_frame(uint8_t *buffer, uint32_t buffer_bytes)
{
bt_status_t ret = BT_STS_SUCCESS;
uint16_t bytes_parsed = 0;
float sbc_subbands_gain[8]={1,1,1,1,1,1,1,1};
btif_sbc_decoder_t *sbc_decoder = NULL;
btif_sbc_pcm_data_t *pcm_data = NULL;
uint16_t frame_pcmbyte = 0;
uint16_t pcm_output_byte = 0;
bool cache_underflow = false;
sbc_decoder = a2dp_audio_sbc_decoder.sbc_decoder;
pcm_data = a2dp_audio_sbc_decoder.pcm_data;
frame_pcmbyte = sbc_decoder->maxPcmLen;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
list_node_t *node = NULL;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
pcm_data->data = buffer;
pcm_data->dataLen = 0;
TRACE_A2DP_DECODER_D("[MCU][SBC] size:%d", a2dp_audio_list_length(list));
for (pcm_output_byte = 0; pcm_output_byte<buffer_bytes; pcm_output_byte += frame_pcmbyte){
node = a2dp_audio_list_begin(list);
if (node){
uint32_t lock;
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
lock = int_lock();
ret = btif_sbc_decode_frames(sbc_decoder, sbc_decoder_frame->sbc_buffer, sbc_decoder_frame->sbc_buffer_len,
&bytes_parsed,
pcm_data,
buffer_bytes,
sbc_subbands_gain);
int_unlock(lock);
TRACE_A2DP_DECODER_D("[MCU][SBC] seq:%d/%d/%d len:%d ret:%d used:%d",
sbc_decoder_frame->curSubSequenceNumber,
sbc_decoder_frame->totalSubSequenceNumber,
sbc_decoder_frame->sequenceNumber,
sbc_decoder_frame->sbc_buffer_len,
ret,
bytes_parsed);
a2dp_audio_sbc_lastframe_info.sequenceNumber = sbc_decoder_frame->sequenceNumber;
a2dp_audio_sbc_lastframe_info.timestamp = sbc_decoder_frame->timestamp;
a2dp_audio_sbc_lastframe_info.curSubSequenceNumber = sbc_decoder_frame->curSubSequenceNumber;
a2dp_audio_sbc_lastframe_info.totalSubSequenceNumber = sbc_decoder_frame->totalSubSequenceNumber;
a2dp_audio_sbc_lastframe_info.frame_samples = sbc_decoder->maxPcmLen/4;
a2dp_audio_sbc_lastframe_info.decoded_frames++;
a2dp_audio_sbc_lastframe_info.undecode_frames = a2dp_audio_list_length(list)-1;
a2dp_audio_sbc_lastframe_info.check_sum = a2dp_audio_decoder_internal_check_sum_generate(sbc_decoder_frame->sbc_buffer, sbc_decoder_frame->sbc_buffer_len);
a2dp_audio_decoder_internal_lastframe_info_set(&a2dp_audio_sbc_lastframe_info);
a2dp_audio_list_remove(list, sbc_decoder_frame);
switch (ret)
{
case BT_STS_SUCCESS:
if (pcm_data->dataLen != buffer_bytes){
TRACE_A2DP_DECODER_W("[MCU][SBC] WARNING pcm buff mismatch %d/%d", pcm_data->dataLen, buffer_bytes);
}
if (pcm_data->dataLen == buffer_bytes){
if (pcm_output_byte+frame_pcmbyte != buffer_bytes){
TRACE_A2DP_DECODER_W("[MCU][SBC]WARNING loop not break %d/%d frame_pcm:%d", pcm_output_byte, buffer_bytes, frame_pcmbyte);
goto exit;
}
}
break;
case BT_STS_CONTINUE:
continue;
break;
case BT_STS_NO_RESOURCES:
ASSERT_A2DP_DECODER(0, "sbc_decode BT_STS_NO_RESOURCES pcm has no more buffer, i think can't reach here");
break;
case BT_STS_FAILED:
default:
sbc_codec_init();
goto exit;
}
}else{
TRACE_A2DP_DECODER_W("[MCU][SBC] A2DP PACKET CACHE UNDERFLOW");
ret = BT_STS_FAILED;
cache_underflow = true;
goto exit;
}
}
exit:
if (cache_underflow){
TRACE_A2DP_DECODER_W("[MCU][SBC] A2DP PACKET CACHE UNDERFLOW need add some process");
a2dp_audio_sbc_lastframe_info.undecode_frames = 0;
a2dp_audio_sbc_lastframe_info.check_sum = 0;
a2dp_audio_decoder_internal_lastframe_info_set(&a2dp_audio_sbc_lastframe_info);
ret = A2DP_DECODER_CACHE_UNDERFLOW_ERROR;
}
return ret;
}
int a2dp_audio_sbc_decode_frame(uint8_t *buffer, uint32_t buffer_bytes)
{
int nRet = 0;
if (sbc_chnl_mode_mono){
int i = 0;
int16_t *src = NULL,*dest = NULL;
#ifdef A2DP_CP_ACCEL
nRet = a2dp_cp_sbc_mcu_decode(buffer, buffer_bytes/2);
#else
nRet = a2dp_audio_sbc_mcu_decode_frame(buffer, buffer_bytes/2);
#endif
i = buffer_bytes / 2;
dest = (int16_t *)buffer + i - 1;
i = i / 2;
src = (int16_t *)buffer + i - 1;
for (; i>=0; i--){
*dest = *src;
dest--;
*dest = *src;
dest--;
src--;
}
}else{
#ifdef A2DP_CP_ACCEL
nRet = a2dp_cp_sbc_mcu_decode(buffer, buffer_bytes);
#else
nRet = a2dp_audio_sbc_mcu_decode_frame(buffer, buffer_bytes);
#endif
}
return nRet;
}
int a2dp_audio_sbc_preparse_packet(btif_media_header_t * header, uint8_t *buffer, uint32_t buffer_bytes)
{
uint16_t bytes_parsed = 0;
uint32_t frame_num = 0;
uint8_t *parser_p = buffer;
frame_num = *parser_p;
parser_p++;
buffer_bytes--;
// TODO: Remove the following sbc init and decode codes. They might conflict with the calls
// during CP process. CP process is triggered by audioflinger PCM callback.
if (*parser_p != 0x9c){
TRACE_A2DP_DECODER_I("[SBC][PRE] ERROR SBC FRAME !!! frame_num:%d", frame_num);
DUMP8("%02x ", parser_p, 12);
}else{
btif_sbc_decode_frames_parser(a2dp_audio_sbc_decoder_preparse,parser_p, buffer_bytes, &bytes_parsed);
TRACE_A2DP_DECODER_I("[SBC][PRE] seq:%d tStmp:%08x smpR:%d ch:%d len:%d",
header->sequenceNumber,
header->timestamp,
a2dp_audio_sbc_decoder_preparse->streamInfo.sampleFreq,
a2dp_audio_sbc_decoder_preparse->streamInfo.channelMode,
a2dp_audio_sbc_decoder_preparse->maxPcmLen);
TRACE_A2DP_DECODER_I("[SBC][PRE] frmN:%d par:%d/%d", frame_num, buffer_bytes, bytes_parsed);
a2dp_audio_sbc_lastframe_info.sequenceNumber = header->sequenceNumber;
a2dp_audio_sbc_lastframe_info.timestamp = header->timestamp;
a2dp_audio_sbc_lastframe_info.curSubSequenceNumber = 0;
a2dp_audio_sbc_lastframe_info.totalSubSequenceNumber = frame_num;
a2dp_audio_sbc_lastframe_info.frame_samples = a2dp_audio_sbc_decoder_preparse->maxPcmLen/4;
a2dp_audio_sbc_lastframe_info.list_samples = SBC_LIST_SAMPLES;
a2dp_audio_sbc_lastframe_info.decoded_frames = 0;
a2dp_audio_sbc_lastframe_info.undecode_frames = 0;
a2dp_audio_decoder_internal_lastframe_info_set(&a2dp_audio_sbc_lastframe_info);
}
if (a2dp_audio_sbc_decoder_preparse->streamInfo.channelMode == BTIF_SBC_CHNL_MODE_MONO){
sbc_chnl_mode_mono = true;
}
return A2DP_DECODER_NO_ERROR;
}
static int a2dp_audio_sbc_header_parser_init(void)
{
a2dp_audio_sbc_decoder_config.auto_synchronize_support = true;
sbc_decoder_last_valid_frame_ready = false;
memset(&sbc_decoder_last_valid_frame, 0, sizeof(sbc_decoder_last_valid_frame));
return 0;
}
static int a2dp_audio_sbc_packet_recover_save_last(btif_media_header_t *sbc_decoder_frame)
{
sbc_decoder_last_valid_frame = *sbc_decoder_frame;
sbc_decoder_last_valid_frame_ready = true;
return 0;
}
static int a2dp_audio_sbc_packet_recover_find_missing(btif_media_header_t *sbc_decoder_frame, uint8_t frame_cnt)
{
uint16_t diff_seq = 0;
uint32_t diff_timestamp = 0;
uint32_t diff = 0;
uint32_t need_recover_pkt = 0;
if (!sbc_decoder_last_valid_frame_ready){
return need_recover_pkt;
}
diff_seq = a2dp_audio_get_passed(sbc_decoder_frame->sequenceNumber, sbc_decoder_last_valid_frame.sequenceNumber, UINT16_MAX);
diff_timestamp = a2dp_audio_get_passed(sbc_decoder_frame->timestamp, sbc_decoder_last_valid_frame.timestamp, UINT32_MAX);
if (diff_seq > 1){
diff = diff_timestamp/diff_seq;
if (diff%SBC_LIST_SAMPLES == 0){
need_recover_pkt = diff_timestamp/SBC_LIST_SAMPLES;
if (need_recover_pkt > frame_cnt){
need_recover_pkt -= frame_cnt;
}
}else{
diff_seq--;
need_recover_pkt = diff_seq * frame_cnt;
}
TRACE_A2DP_DECODER_W("[SBC][INPUT][PLC] seq:%d/%d stmp:%d/%d", sbc_decoder_frame->sequenceNumber, sbc_decoder_last_valid_frame.sequenceNumber,
sbc_decoder_frame->timestamp, sbc_decoder_last_valid_frame.timestamp);
TRACE_A2DP_DECODER_W("[SBC][INPUT][PLC] diff_seq:%d diff_stmp:%d diff:%d missing:%d", diff_seq, diff_timestamp, diff, need_recover_pkt);
}
return need_recover_pkt;
}
static int a2dp_audio_sbc_packet_recover_proc(btif_media_header_t *sbc_decoder_frame, a2dp_audio_sbc_decoder_frame_t *sbc_raw_frame, uint8_t frame_cnt)
{
int nRet = A2DP_DECODER_NO_ERROR;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
int missing_pkt_cnt = 0;
missing_pkt_cnt = a2dp_audio_sbc_packet_recover_find_missing(sbc_decoder_frame, frame_cnt);
if (missing_pkt_cnt && sbc_raw_frame &&
(a2dp_audio_list_length(list)+missing_pkt_cnt) < sbc_mtu_limiter){
for (uint8_t i =0; i<missing_pkt_cnt; i++){
a2dp_audio_sbc_decoder_frame_t *frame_p = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_sbc_subframe_malloc(sbc_raw_frame->sbc_buffer_len);
if (!frame_p){
nRet = A2DP_DECODER_MEMORY_ERROR;
goto exit;
}
frame_p->sequenceNumber = UINT16_MAX;
frame_p->timestamp = UINT32_MAX;
memcpy(frame_p->sbc_buffer, sbc_raw_frame->sbc_buffer, sbc_raw_frame->sbc_buffer_len);
frame_p->sbc_buffer_len = sbc_raw_frame->sbc_buffer_len;
a2dp_audio_list_append(list, frame_p);
}
}
exit:
return nRet;
}
#define FRAME_LIST_MAX (20)
int a2dp_audio_sbc_store_packet(btif_media_header_t * header, uint8_t *buffer, uint32_t buffer_bytes)
{
int nRet = A2DP_DECODER_NO_ERROR;
uint32_t frame_cnt = 0;
uint32_t frame_num = 0;
uint32_t frame_len = 0;
uint8_t *parser_p = buffer;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
uint16_t bytes_parsed = 0;
a2dp_audio_sbc_decoder_frame_t *frame_list[FRAME_LIST_MAX] = {0,};
uint8_t frame_list_idx = 0;
bool find_err = false;
uint32_t i = 0;
frame_num = *parser_p;
if (!frame_num){
TRACE_A2DP_DECODER_W("[SBC][INPUT] ERROR SBC FRAME !!! frame_num:%d", frame_num);
DUMP8("%02x ", parser_p, 12);
return A2DP_DECODER_DECODE_ERROR;
}
parser_p++;
buffer_bytes--;
frame_len = buffer_bytes/frame_num;
if ((a2dp_audio_list_length(list)+frame_num) < sbc_mtu_limiter){
for (i=0; i<buffer_bytes; i+=bytes_parsed, frame_cnt++){
bytes_parsed = 0;
if (*(parser_p+i) == 0x9c){
if (btif_sbc_decode_frames_parser(a2dp_audio_sbc_decoder_preparse, parser_p+i, buffer_bytes, &bytes_parsed) != BT_STS_SUCCESS){
bytes_parsed = frame_len;
TRACE_A2DP_DECODER_W("[SBC][INPUT] ERROR SBC FRAME PARSER !!!");
DUMP8("%02x ", parser_p+i, 12);
find_err = true;
break;
}
a2dp_audio_sbc_decoder_frame_t *frame_p = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_sbc_subframe_malloc(bytes_parsed);
if (!frame_p){
nRet = A2DP_DECODER_MEMORY_ERROR;
find_err = true;
break;
}
frame_p->sequenceNumber = header->sequenceNumber;
frame_p->timestamp = header->timestamp;
frame_p->curSubSequenceNumber = frame_cnt;
frame_p->totalSubSequenceNumber = frame_num;
memcpy(frame_p->sbc_buffer, (parser_p+i), bytes_parsed);
frame_p->sbc_buffer_len = bytes_parsed;
frame_list[frame_list_idx++] = frame_p;
if (frame_list_idx >= FRAME_LIST_MAX){
find_err = true;
break;
}
}else{
TRACE_A2DP_DECODER_W("[SBC][INPUT] ERROR SBC FRAME !!!");
DUMP8("%02x ", parser_p+i, 12);
find_err = true;
break;
}
}
if (find_err){
TRACE_A2DP_DECODER_W("[SBC][INPUT] FIND ERR !!!");
for (i = 0; i<frame_list_idx; i++){
a2dp_audio_sbc_subframe_free(frame_list[i]);
}
nRet = A2DP_DECODER_DECODE_ERROR;
}else{
a2dp_audio_sbc_packet_recover_proc(header, frame_list[0], frame_num);
a2dp_audio_sbc_packet_recover_save_last(header);
for (i = 0; i<frame_list_idx; i++){
a2dp_audio_list_append(list, frame_list[i]);
}
nRet = A2DP_DECODER_NO_ERROR;
}
}else{
TRACE_A2DP_DECODER_W("[SBC][INPUT] OVERFLOW list:%d", a2dp_audio_list_length(list));
nRet = A2DP_DECODER_MTU_LIMTER_ERROR;
}
return nRet;
}
int a2dp_audio_sbc_discards_packet(uint32_t packets)
{
int nRet = A2DP_DECODER_MEMORY_ERROR;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_node_t *node = NULL;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
uint16_t totalSubSequenceNumber;
uint8_t j = 0;
#ifdef A2DP_CP_ACCEL
a2dp_cp_reset_frame();
#endif
node = a2dp_audio_list_begin(list);
if (!node){
goto exit;
}
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
for (j=0; j<a2dp_audio_list_length(list); j++){
node = a2dp_audio_list_begin(list);
if (!node){
goto exit;
}
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
if (sbc_decoder_frame->curSubSequenceNumber != 0){
a2dp_audio_list_remove(list, sbc_decoder_frame);
}else{
break;
}
}
node = a2dp_audio_list_begin(list);
if (!node){
goto exit;
}
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
ASSERT_A2DP_DECODER(sbc_decoder_frame->curSubSequenceNumber == 0, "sbc_discards_packet not align curSubSequenceNumber:%d",
sbc_decoder_frame->curSubSequenceNumber);
totalSubSequenceNumber = sbc_decoder_frame->totalSubSequenceNumber;
if (packets <= a2dp_audio_list_length(list)/totalSubSequenceNumber){
for (uint8_t i=0; i<packets; i++){
for (j=0; j<totalSubSequenceNumber; j++){
node = a2dp_audio_list_begin(list);
if (!node){
goto exit;
}
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, sbc_decoder_frame);
}
}
nRet = A2DP_DECODER_NO_ERROR;
}
exit:
TRACE_A2DP_DECODER_I("[SBC][DISCARDS] packets:%d nRet:%d", packets, nRet);
return nRet;
}
int a2dp_audio_sbc_headframe_info_get(A2DP_AUDIO_HEADFRAME_INFO_T *headframe_info)
{
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_node_t *node = NULL;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
if (a2dp_audio_list_length(list) && ((node = a2dp_audio_list_begin(list)) != NULL)){
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
headframe_info->sequenceNumber = sbc_decoder_frame->sequenceNumber;
headframe_info->timestamp = sbc_decoder_frame->timestamp;
headframe_info->curSubSequenceNumber = sbc_decoder_frame->curSubSequenceNumber;
headframe_info->totalSubSequenceNumber = sbc_decoder_frame->totalSubSequenceNumber;
}else{
memset(headframe_info, 0, sizeof(A2DP_AUDIO_HEADFRAME_INFO_T));
}
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_sbc_info_get(void *info)
{
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_sbc_synchronize_packet(A2DP_AUDIO_SYNCFRAME_INFO_T *sync_info, uint32_t mask)
{
int nRet = A2DP_DECODER_SYNC_ERROR;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_node_t *node = NULL;
int list_len;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
#ifdef A2DP_CP_ACCEL
a2dp_cp_reset_frame();
#endif
list_len = a2dp_audio_list_length(list);
for (uint16_t i=0; i<list_len; i++){
node = a2dp_audio_list_begin(list);
if (node){
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
if (A2DP_AUDIO_SYNCFRAME_CHK(sbc_decoder_frame->sequenceNumber == sync_info->sequenceNumber, A2DP_AUDIO_SYNCFRAME_MASK_SEQ, mask)&&
A2DP_AUDIO_SYNCFRAME_CHK(sbc_decoder_frame->curSubSequenceNumber == sync_info->curSubSequenceNumber, A2DP_AUDIO_SYNCFRAME_MASK_CURRSUBSEQ, mask)&&
A2DP_AUDIO_SYNCFRAME_CHK(sbc_decoder_frame->totalSubSequenceNumber == sync_info->totalSubSequenceNumber,A2DP_AUDIO_SYNCFRAME_MASK_TOTALSUBSEQ,mask)){
nRet = A2DP_DECODER_NO_ERROR;
break;
}
a2dp_audio_list_remove(list, sbc_decoder_frame);
}
}
node = a2dp_audio_list_begin(list);
if (node){
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
TRACE_A2DP_DECODER_I("[MCU][SYNC][SBC] sync pkt nRet:%d SEQ:%d timestamp:%d %d/%d",
nRet, sbc_decoder_frame->sequenceNumber, sbc_decoder_frame->timestamp,
sbc_decoder_frame->curSubSequenceNumber, sbc_decoder_frame->totalSubSequenceNumber);
}else{
TRACE_A2DP_DECODER_I("[MCU][SYNC][SBC] sync pkt nRet:%d", nRet);
}
return nRet;
}
int a2dp_audio_sbc_synchronize_dest_packet_mut(uint16_t packet_mut)
{
list_node_t *node = NULL;
uint32_t list_len = 0;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
list_len = a2dp_audio_list_length(list);
if (list_len > packet_mut){
do{
node = a2dp_audio_list_begin(list);
if (node){
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, sbc_decoder_frame);
}
}while(a2dp_audio_list_length(list) > packet_mut);
}
TRACE_A2DP_DECODER_I("[MCU][SYNC][SBC] dest pkt list:%d", a2dp_audio_list_length(list));
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_sbc_convert_list_to_samples(uint32_t *samples)
{
uint32_t list_len = 0;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_len = a2dp_audio_list_length(list);
*samples = SBC_LIST_SAMPLES*list_len;
TRACE_A2DP_DECODER_I("[MCU][SBC] list:%d samples:%d", list_len, *samples);
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_sbc_discards_samples(uint32_t samples)
{
int nRet = A2DP_DECODER_SYNC_ERROR;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
a2dp_audio_sbc_decoder_frame_t *sbc_decoder_frame = NULL;
list_node_t *node = NULL;
int need_remove_list = 0;
uint32_t list_samples = 0;
ASSERT_A2DP_DECODER(!(samples%SBC_LIST_SAMPLES), "%s samples err:%d", __func__, samples);
a2dp_audio_sbc_convert_list_to_samples(&list_samples);
if (list_samples >= samples){
need_remove_list = samples/SBC_LIST_SAMPLES;
for (int i=0; i<need_remove_list; i++){
node = a2dp_audio_list_begin(list);
if (node){
sbc_decoder_frame = (a2dp_audio_sbc_decoder_frame_t *)a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, sbc_decoder_frame);
}
}
nRet = A2DP_DECODER_NO_ERROR;
}
return nRet;
}
int a2dp_audio_sbc_channel_select(A2DP_AUDIO_CHANNEL_SELECT_E chnl_sel)
{
return A2DP_DECODER_NO_ERROR;
}
A2DP_AUDIO_DECODER_T a2dp_audio_sbc_decoder_config = {
{44100, 2, 16},
1,
a2dp_audio_sbc_init,
a2dp_audio_sbc_deinit,
a2dp_audio_sbc_decode_frame,
a2dp_audio_sbc_preparse_packet,
a2dp_audio_sbc_store_packet,
a2dp_audio_sbc_discards_packet,
a2dp_audio_sbc_synchronize_packet,
a2dp_audio_sbc_synchronize_dest_packet_mut,
a2dp_audio_sbc_convert_list_to_samples,
a2dp_audio_sbc_discards_samples,
a2dp_audio_sbc_headframe_info_get,
a2dp_audio_sbc_info_get,
a2dp_audio_sbc_subframe_free,
a2dp_audio_sbc_channel_select,
} ;

View file

@ -0,0 +1,739 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
// Standard C Included Files
#include "cmsis.h"
#include "plat_types.h"
#include <string.h>
#include "heap_api.h"
#include "hal_location.h"
#include "a2dp_decoder_internal.h"
#include "app_audio.h"
#if defined(A2DP_SCALABLE_ON)
#include "heap_api.h"
#include "ssc.h"
#define SCALABLE_MTU_LIMITER (32)
#define SCALABLE_MEMPOOL_SIZE 1024
#define SCALABLE_OUTPUT_FRAME_SAMPLES (SCALABLE_FRAME_SIZE)
typedef void *HANDLE_DECODER;
static A2DP_AUDIO_CONTEXT_T *a2dp_audio_context_p = NULL;
static A2DP_AUDIO_OUTPUT_CONFIG_T output_config;
static unsigned char *scalable_decoder_place = NULL;
static unsigned char *scalable_decoder_temp_buf = NULL;
static short ss_pcm_buff[SCALABLE_FRAME_SIZE*4];
static int scalable_uhq_flag __attribute__((unused)) = 0;
static HANDLE_DECODER scalableDec_handle = NULL;
static A2DP_AUDIO_DECODER_LASTFRAME_INFO_T lastframe_info;
typedef struct {
uint16_t sequenceNumber;
uint32_t timestamp;
uint8_t *buffer;
int buffer_len;
} a2dp_audio_scalable_decoder_frame_t;
static void ss_to_24bit_buf(int32_t * out, int32_t * in, int size)
{
for (int i = 0; i < size; i++) {
out[i] = in[i];
}
}
static void a2dp_audio_scalable_decoder_init(void)
{
if (scalableDec_handle == NULL) {
scalableDec_handle = scalable_decoder_place;
ssc_decoder_init(scalableDec_handle, output_config.num_channels, output_config.sample_rate);
}
}
static int scalableDecoder_Close(HANDLE_DECODER handle)
{
if (handle) {
a2dp_audio_heap_free(handle);
a2dp_audio_heap_free(scalable_decoder_temp_buf);
}
return 0;
}
static void a2dp_audio_scalable_decoder_deinit(void)
{
if (scalableDec_handle) {
scalableDecoder_Close(scalableDec_handle);
scalableDec_handle = NULL;
}
}
static void a2dp_audio_scalable_decoder_reinit(void)
{
if (scalableDec_handle) {
a2dp_audio_scalable_decoder_deinit();
}
a2dp_audio_scalable_decoder_init();
}
static bool is_valid_frame(a2dp_audio_scalable_decoder_frame_t * decoder_frame_p)
{
int hw_tmp, len, bitrate_bps, frame_len, frame_size;
int sampling_rate = 44100;
unsigned char *input_buf = decoder_frame_p->buffer;
if (decoder_frame_p->buffer_len < SCALABLE_HEAD_SIZE) {
TRACE_A2DP_DECODER_E("invalid scalable a2dp frame, length < SCALABLE_HEAD_SIZE !!!!!!!");
return false;
}
scalable_uhq_flag = 0;
switch ((input_buf[3]&0xf7)) {
case 0xF0:
bitrate_bps = 88000;
break;
case 0xF1:
bitrate_bps = 96000;
break;
case 0xF2:
bitrate_bps = 128000;
break;
case 0xF3:
bitrate_bps = 192000;
break;
case 0xF4:
bitrate_bps = 229000;
break;
case 0xF5:
scalable_uhq_flag = 1;
bitrate_bps = 328000;
sampling_rate = 96000;
break;
default:
bitrate_bps = 192000;
break;
}
frame_size = SCALABLE_FRAME_SIZE;
len = bitrate_bps * frame_size / sampling_rate / 8;
if (scalable_uhq_flag == 0) {
hw_tmp = (len * 3) >> 7;
len = hw_tmp + len;
len = len + ((len & 1) ^ 1);
} else {
len = 369; //744/2-4+1
}
TRACE_A2DP_DECODER_D
("scalable a2dp frame, length:%d bitrate:%d sampling_rate:%d",
decoder_frame_p->buffer_len, bitrate_bps, sampling_rate);
frame_len = SCALABLE_HEAD_SIZE + len - 1;
if (decoder_frame_p->buffer_len < frame_len) {
TRACE_A2DP_DECODER_E
("invalid scalable a2dp frame, length:%d < %d !!!!!!!", decoder_frame_p->buffer_len, frame_len);
return false;
}
return true;
}
#ifdef A2DP_CP_ACCEL
struct A2DP_CP_scalable_IN_FRM_INFO_T {
uint16_t sequenceNumber;
uint32_t timestamp;
};
struct A2DP_CP_scalable_OUT_FRM_INFO_T {
struct A2DP_CP_scalable_IN_FRM_INFO_T in_info;
uint16_t frame_samples;
uint16_t decoded_frames;
uint16_t frame_idx;
uint16_t pcm_len;
};
static bool cp_codec_reset;
extern uint32_t app_bt_stream_get_dma_buffer_samples(void);
TEXT_SSC_LOC static int a2dp_cp_scalable_mcu_decode(uint8_t * buffer, uint32_t buffer_bytes)
{
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p = NULL;
list_node_t *node = NULL;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
int ret, dec_ret;
struct A2DP_CP_scalable_IN_FRM_INFO_T in_info;
struct A2DP_CP_scalable_OUT_FRM_INFO_T *p_out_info;
uint8_t *out;
uint32_t out_len;
uint32_t out_frame_len;
uint32_t cp_buffer_frames_max = 0;
cp_buffer_frames_max = app_bt_stream_get_dma_buffer_samples()/2;
if (cp_buffer_frames_max %(lastframe_info.frame_samples) ){
cp_buffer_frames_max = cp_buffer_frames_max /(lastframe_info.frame_samples) +1;
}else{
cp_buffer_frames_max = cp_buffer_frames_max /(lastframe_info.frame_samples);
}
out_frame_len = sizeof(*p_out_info) + buffer_bytes;
ret = a2dp_cp_decoder_init(out_frame_len, cp_buffer_frames_max * 2);
ASSERT(ret == 0, "%s: a2dp_cp_decoder_init() failed: ret=%d", __func__, ret);
while ((node = a2dp_audio_list_begin(list)) != NULL) {
decoder_frame_p = (a2dp_audio_scalable_decoder_frame_t *)
a2dp_audio_list_node(node);
if (false == is_valid_frame(decoder_frame_p)) {
return A2DP_DECODER_DECODE_ERROR;
}
in_info.sequenceNumber = decoder_frame_p->sequenceNumber;
in_info.timestamp = decoder_frame_p->timestamp;
ret = a2dp_cp_put_in_frame(&in_info, sizeof(in_info), decoder_frame_p->buffer, decoder_frame_p->buffer_len);
if (ret) {
break;
}
a2dp_audio_list_remove(list, decoder_frame_p);
}
ret = a2dp_cp_get_full_out_frame((void **)&out, &out_len);
if (ret) {
return A2DP_DECODER_DECODE_ERROR;
}
if (out_len == 0) {
memset(buffer, 0, buffer_bytes);
a2dp_cp_consume_full_out_frame();
return A2DP_DECODER_NO_ERROR;
}
ASSERT(out_len == out_frame_len, "%s: Bad out len %u (should be %u)", __func__, out_len, out_frame_len);
p_out_info = (struct A2DP_CP_scalable_OUT_FRM_INFO_T *)out;
if (p_out_info->pcm_len) {
lastframe_info.sequenceNumber = p_out_info->in_info.sequenceNumber;
lastframe_info.timestamp = p_out_info->in_info.timestamp;
lastframe_info.curSubSequenceNumber = 0;
lastframe_info.totalSubSequenceNumber = 0;
lastframe_info.frame_samples = p_out_info->frame_samples;
lastframe_info.decoded_frames += p_out_info->decoded_frames;
lastframe_info.undecode_frames =
a2dp_audio_list_length(list) + a2dp_cp_get_in_frame_cnt_by_index(p_out_info->frame_idx) - 1;
a2dp_audio_decoder_internal_lastframe_info_set(&lastframe_info);
}
if (p_out_info->pcm_len == buffer_bytes) {
memcpy(buffer, p_out_info + 1, p_out_info->pcm_len);
dec_ret = A2DP_DECODER_NO_ERROR;
} else {
dec_ret = A2DP_DECODER_DECODE_ERROR;
}
ret = a2dp_cp_consume_full_out_frame();
ASSERT(ret == 0, "%s: a2dp_cp_consume_full_out_frame() failed: ret=%d", __func__, ret);
return dec_ret;
}
TEXT_SSC_LOC int a2dp_cp_scalable_cp_decode(void)
{
int ret;
enum CP_EMPTY_OUT_FRM_T out_frm_st;
uint8_t *out;
uint32_t out_len;
uint8_t *dec_start;
uint32_t dec_len;
struct A2DP_CP_scalable_IN_FRM_INFO_T *p_in_info;
struct A2DP_CP_scalable_OUT_FRM_INFO_T *p_out_info;
uint8_t *in_buf;
uint32_t in_len;
uint32_t dec_sum;
int error, output_samples = 0,output_byte = 0;
if (cp_codec_reset)
{
cp_codec_reset = false;
a2dp_audio_scalable_decoder_init();
}
out_frm_st = a2dp_cp_get_emtpy_out_frame((void **)&out, &out_len);
if (out_frm_st != CP_EMPTY_OUT_FRM_OK && out_frm_st != CP_EMPTY_OUT_FRM_WORKING)
{
return 1;
}
ASSERT(out_len > sizeof(*p_out_info), "%s: Bad out_len %u (should > %u)", __func__, out_len, sizeof(*p_out_info));
p_out_info = (struct A2DP_CP_scalable_OUT_FRM_INFO_T *)out;
if (out_frm_st == CP_EMPTY_OUT_FRM_OK)
{
p_out_info->pcm_len = 0;
p_out_info->decoded_frames = 0;
}
ASSERT(out_len > sizeof(*p_out_info) + p_out_info->pcm_len,
"%s: Bad out_len %u (should > %u + %u)", __func__, out_len, sizeof(*p_out_info), p_out_info->pcm_len);
dec_start = (uint8_t *) (p_out_info + 1) + p_out_info->pcm_len;
dec_len = out_len - (dec_start - (uint8_t *) out);
if (!scalableDec_handle) {
TRACE(0,"scalable_decode not ready");
return 3;
}
dec_sum = 0;
error = 0;
while (dec_sum < dec_len && error == 0)
{
ret = a2dp_cp_get_in_frame((void * *) &in_buf, &in_len);
if (ret)
{
break;
}
ASSERT(in_len > sizeof(*p_in_info), "%s: Bad in_len %u (should > %u)", __func__, in_len, sizeof(*p_in_info));
p_in_info = (struct A2DP_CP_scalable_IN_FRM_INFO_T *)in_buf;
in_buf += sizeof(*p_in_info);
in_len -= sizeof(*p_in_info);
/* decode one SSC frame */
output_samples = ssc_decode(scalableDec_handle,(const unsigned char*)in_buf, ss_pcm_buff, SCALABLE_FRAME_SIZE, 0, 2);
if (0 == output_samples)
{
a2dp_audio_scalable_decoder_reinit();
TRACE(0, "scalable_decode reinin codec \n");
error = A2DP_DECODER_DECODE_ERROR;
goto exit;
}
ss_to_24bit_buf((int32_t *) (dec_start+dec_sum), (int32_t *) ss_pcm_buff, output_samples);
output_byte = output_samples * 4;
dec_sum += output_byte;
exit:
memcpy(&p_out_info->in_info, ss_pcm_buff, sizeof(*p_in_info));
p_out_info->decoded_frames++;
p_out_info->frame_samples = SCALABLE_OUTPUT_FRAME_SAMPLES;
p_out_info->frame_idx = a2dp_cp_get_in_frame_index();
ret = a2dp_cp_consume_in_frame();
ASSERT(ret == 0, "%s: a2dp_cp_consume_in_frame() failed: ret=%d", __func__, ret);
}
p_out_info->pcm_len += dec_sum;
if (error || out_len <= sizeof(*p_out_info) + p_out_info->pcm_len) {
ret = a2dp_cp_consume_emtpy_out_frame();
ASSERT(ret == 0, "%s: a2dp_cp_consume_emtpy_out_frame() failed: ret=%d", __func__, ret);
}
return error;
}
#endif
static int a2dp_audio_scalable_init(A2DP_AUDIO_OUTPUT_CONFIG_T * config, void *context)
{
TRACE_A2DP_DECODER_D("%s", __func__);
TRACE(0,"\n\nA2DP SSC-LC INIT\n");
a2dp_audio_context_p = (A2DP_AUDIO_CONTEXT_T *) context;
memcpy(&output_config, config, sizeof(A2DP_AUDIO_OUTPUT_CONFIG_T));
memset(&lastframe_info, 0, sizeof(A2DP_AUDIO_DECODER_LASTFRAME_INFO_T));
lastframe_info.stream_info = output_config;
lastframe_info.frame_samples = SCALABLE_FRAME_SIZE;
lastframe_info.list_samples = SCALABLE_FRAME_SIZE;
a2dp_audio_decoder_internal_lastframe_info_set(&lastframe_info);
ASSERT(a2dp_audio_context_p->dest_packet_mut < SCALABLE_MTU_LIMITER,
"%s MTU OVERFLOW:%u/%u", __func__, a2dp_audio_context_p->dest_packet_mut, SCALABLE_MTU_LIMITER);
int decoder_size;
decoder_size = ssc_decoder_get_size(output_config.num_channels); //todo: get size with codec capability
TRACE(0, "decoder size %d", decoder_size);
scalable_decoder_place = (unsigned char *)a2dp_audio_heap_malloc(decoder_size);
ASSERT_A2DP_DECODER(scalable_decoder_place, "no memory resource for scalable_decoder_place");
scalable_decoder_temp_buf = (unsigned char *)a2dp_audio_heap_malloc(SCALABLE_FRAME_SIZE * 16);
ASSERT_A2DP_DECODER(scalable_decoder_temp_buf, "no memory resource for scalable_decoder_temp_buf");
#ifdef A2DP_CP_ACCEL
int ret;
cp_codec_reset = true;
ret = a2dp_cp_init(a2dp_cp_scalable_cp_decode, CP_PROC_DELAY_1_FRAME);
ASSERT(ret == 0, "%s: a2dp_cp_init() failed: ret=%d", __func__, ret);
#else
a2dp_audio_scalable_decoder_init();
#endif
return A2DP_DECODER_NO_ERROR;
}
static int a2dp_audio_scalable_deinit(void)
{
#ifdef A2DP_CP_ACCEL
a2dp_cp_deinit();
#endif
a2dp_audio_scalable_decoder_deinit();
TRACE(0,"\n\nA2DP SCALABLE DEINIT\n");
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_scalable_mcu_decode_frame(uint8_t * buffer, uint32_t buffer_bytes)
{
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_node_t *node = NULL;
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p = NULL;
int ret = A2DP_DECODER_NO_ERROR;
bool cache_underflow = false;
int output_byte = 0, output_samples = 0;
uint8_t *output = buffer;
// TRACE(1,"bbd %d",buffer_bytes );
if (buffer_bytes < (SCALABLE_FRAME_SIZE * output_config.num_channels * output_config.bits_depth / 8)) {
TRACE(1,"scalable_decode pcm_len = %d \n", buffer_bytes);
return A2DP_DECODER_NO_ERROR;
}
if (!scalableDec_handle) {
TRACE(0,"scalable_decode not ready");
return A2DP_DECODER_NO_ERROR;
}
while (output < buffer + buffer_bytes) {
node = a2dp_audio_list_begin(list);
if (!node) {
TRACE(0,"scalable_decode cache underflow");
cache_underflow = true;
goto exit;
} else {
decoder_frame_p = (a2dp_audio_scalable_decoder_frame_t *)
a2dp_audio_list_node(node);
if (false == is_valid_frame(decoder_frame_p)) {
TRACE_A2DP_DECODER_E("%s %d invalid a2dp frame", __func__, __LINE__);
ret = A2DP_DECODER_DECODE_ERROR;
goto exit;
}
/* decode one SSC frame */
output_samples =
ssc_decode(scalableDec_handle,
decoder_frame_p->buffer, ss_pcm_buff, SCALABLE_FRAME_SIZE,0,2);
TRACE_A2DP_DECODER_D
("scalable_decode seq:%d len:%d output_samples:%d",
decoder_frame_p->sequenceNumber, decoder_frame_p->buffer_len, output_samples);
if (0 == output_samples) {
TRACE(0,"scalable_decode failed !!!!!!");
//if failed reopen it again
a2dp_audio_scalable_decoder_reinit();
TRACE(0,"scalable_decode reinin codec \n");
ret = A2DP_DECODER_DECODE_ERROR;
goto exit;
}
ss_to_24bit_buf((int32_t *) output, (int32_t *) ss_pcm_buff, output_samples * 2);
output_byte = output_samples * 8;
output += output_byte;
ASSERT(SCALABLE_FRAME_SIZE == output_samples, "scalable_decode output mismatch samples:%d", output_samples);
lastframe_info.sequenceNumber = decoder_frame_p->sequenceNumber;
lastframe_info.timestamp = decoder_frame_p->timestamp;
lastframe_info.curSubSequenceNumber = 0;
lastframe_info.totalSubSequenceNumber = 0;
lastframe_info.frame_samples = SCALABLE_FRAME_SIZE;
lastframe_info.decoded_frames++;
lastframe_info.undecode_frames = a2dp_audio_list_length(list) - 1;
a2dp_audio_decoder_internal_lastframe_info_set(&lastframe_info);
a2dp_audio_list_remove(list, decoder_frame_p);
}
}
exit:
if (cache_underflow) {
lastframe_info.undecode_frames = 0;
a2dp_audio_decoder_internal_lastframe_info_set(&lastframe_info);
ret = A2DP_DECODER_CACHE_UNDERFLOW_ERROR;
}
//TRACE(0,"abd");
return ret;
}
static int a2dp_audio_scalable_decode_frame(uint8_t * buffer, uint32_t buffer_bytes)
{
#ifdef A2DP_CP_ACCEL
return a2dp_cp_scalable_mcu_decode(buffer, buffer_bytes);
#else
return a2dp_audio_scalable_mcu_decode_frame(buffer, buffer_bytes);
#endif
}
static int a2dp_audio_scalable_preparse_packet(btif_media_header_t * header, uint8_t * buffer, uint32_t buffer_bytes)
{
lastframe_info.sequenceNumber = header->sequenceNumber;
lastframe_info.timestamp = header->timestamp;
lastframe_info.curSubSequenceNumber = 0;
lastframe_info.totalSubSequenceNumber = 0;
lastframe_info.frame_samples = SCALABLE_FRAME_SIZE;
lastframe_info.list_samples = SCALABLE_FRAME_SIZE;
lastframe_info.decoded_frames = 0;
lastframe_info.undecode_frames = 0;
a2dp_audio_decoder_internal_lastframe_info_set(&lastframe_info);
TRACE(3,"%s seq:%d timestamp:%08x", __func__, header->sequenceNumber, header->timestamp);
return A2DP_DECODER_NO_ERROR;
}
static void *a2dp_audio_scalable_frame_malloc(uint32_t packet_len)
{
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p = NULL;
uint8_t *buffer = NULL;
buffer = (uint8_t *) a2dp_audio_heap_malloc(SCALABLE_READBUF_SIZE);
decoder_frame_p = (a2dp_audio_scalable_decoder_frame_t *)
a2dp_audio_heap_malloc(sizeof(a2dp_audio_scalable_decoder_frame_t));
decoder_frame_p->buffer = buffer;
decoder_frame_p->buffer_len = packet_len;
return (void *)decoder_frame_p;
}
static void a2dp_audio_scalable_free(void *packet)
{
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p = (a2dp_audio_scalable_decoder_frame_t *) packet;
a2dp_audio_heap_free(decoder_frame_p->buffer);
a2dp_audio_heap_free(decoder_frame_p);
}
static int a2dp_audio_scalable_store_packet(btif_media_header_t * header, uint8_t * buffer, uint32_t buffer_bytes)
{
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
int nRet = A2DP_DECODER_NO_ERROR;
if (a2dp_audio_list_length(list) < SCALABLE_MTU_LIMITER) {
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p = (a2dp_audio_scalable_decoder_frame_t *)
a2dp_audio_scalable_frame_malloc(buffer_bytes);
TRACE_A2DP_DECODER_D("%s seq:%d len:%d", __func__, header->sequenceNumber, buffer_bytes);
decoder_frame_p->sequenceNumber = header->sequenceNumber;
decoder_frame_p->timestamp = header->timestamp;
memcpy(decoder_frame_p->buffer, buffer, buffer_bytes);
decoder_frame_p->buffer_len = buffer_bytes;
a2dp_audio_list_append(list, decoder_frame_p);
nRet = A2DP_DECODER_NO_ERROR;
} else {
TRACE(2,"%s list full current len:%d", __func__, a2dp_audio_list_length(list));
nRet = A2DP_DECODER_MTU_LIMTER_ERROR;
}
return nRet;
}
static int a2dp_audio_scalable_discards_packet(uint32_t packets)
{
int nRet = A2DP_DECODER_MEMORY_ERROR;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_node_t *node = NULL;
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p = NULL;
#ifdef A2DP_CP_ACCEL
a2dp_cp_reset_frame();
#endif
if (packets <= a2dp_audio_list_length(list)) {
for (uint8_t i = 0; i < packets; i++) {
if ((node = a2dp_audio_list_begin(list)) != NULL){
decoder_frame_p = (a2dp_audio_scalable_decoder_frame_t *)
a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, decoder_frame_p);
}
}
nRet = A2DP_DECODER_NO_ERROR;
}
TRACE(3,"%s packets:%d nRet:%d", __func__, packets, nRet);
return nRet;
}
static int a2dp_audio_scalable_headframe_info_get(A2DP_AUDIO_HEADFRAME_INFO_T* headframe_info)
{
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_node_t *node = NULL;
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p = NULL;
if (a2dp_audio_list_length(list)){
if ((node = a2dp_audio_list_begin(list)) != NULL){
decoder_frame_p = (a2dp_audio_scalable_decoder_frame_t *)a2dp_audio_list_node(node);
headframe_info->sequenceNumber = decoder_frame_p->sequenceNumber;
headframe_info->timestamp = decoder_frame_p->timestamp;
headframe_info->curSubSequenceNumber = 0;
headframe_info->totalSubSequenceNumber = 0;
}
}else{
memset(headframe_info, 0, sizeof(A2DP_AUDIO_HEADFRAME_INFO_T));
}
return A2DP_DECODER_NO_ERROR;
}
static int a2dp_audio_scalable_info_get(void *info)
{
return A2DP_DECODER_NO_ERROR;
}
static int a2dp_audio_scalable_synchronize_packet(A2DP_AUDIO_SYNCFRAME_INFO_T * sync_info, uint32_t mask)
{
int nRet = A2DP_DECODER_SYNC_ERROR;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_node_t *node = NULL;
int list_len;
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p = NULL;
#ifdef A2DP_CP_ACCEL
a2dp_cp_reset_frame();
#endif
list_len = a2dp_audio_list_length(list);
for (uint16_t i = 0; i < list_len; i++) {
if ((node = a2dp_audio_list_begin(list)) != NULL){
decoder_frame_p = (a2dp_audio_scalable_decoder_frame_t *)
a2dp_audio_list_node(node);
if (A2DP_AUDIO_SYNCFRAME_CHK(decoder_frame_p->sequenceNumber == sync_info->sequenceNumber, A2DP_AUDIO_SYNCFRAME_MASK_SEQ, mask)&&
A2DP_AUDIO_SYNCFRAME_CHK(decoder_frame_p->timestamp == sync_info->timestamp, A2DP_AUDIO_SYNCFRAME_MASK_TIMESTAMP, mask)) {
nRet = A2DP_DECODER_NO_ERROR;
break;
}
a2dp_audio_list_remove(list, decoder_frame_p);
}
}
node = a2dp_audio_list_begin(list);
if (node) {
decoder_frame_p = (a2dp_audio_scalable_decoder_frame_t *)
a2dp_audio_list_node(node);
TRACE(4,"%s nRet:%d SEQ:%d timestamp:%d", __func__, nRet,
decoder_frame_p->sequenceNumber, decoder_frame_p->timestamp);
} else {
TRACE(2,"%s nRet:%d", __func__, nRet);
}
return nRet;
}
static int a2dp_audio_scalable_synchronize_dest_packet_mut(uint16_t packet_mut)
{
list_node_t *node = NULL;
uint32_t list_len = 0;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
a2dp_audio_scalable_decoder_frame_t *decoder_frame_p = NULL;
list_len = a2dp_audio_list_length(list);
if (list_len > packet_mut) {
do {
node = a2dp_audio_list_begin(list);
if (node)
{
decoder_frame_p = (a2dp_audio_scalable_decoder_frame_t *)
a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, decoder_frame_p);
}
} while (a2dp_audio_list_length(list) > packet_mut);
}
TRACE(2,"%s list:%d", __func__, a2dp_audio_list_length(list));
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_scalable_convert_list_to_samples(uint32_t *samples)
{
uint32_t list_len = 0;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
list_len = a2dp_audio_list_length(list);
*samples = SCALABLE_FRAME_SIZE*list_len;
TRACE(3, "%s list:%d samples:%d", __func__, list_len, *samples);
return A2DP_DECODER_NO_ERROR;
}
int a2dp_audio_scalable_discards_samples(uint32_t samples)
{
int nRet = A2DP_DECODER_SYNC_ERROR;
list_t *list = a2dp_audio_context_p->audio_datapath.input_raw_packet_list;
a2dp_audio_scalable_decoder_frame_t *scalable_decoder_frame = NULL;
list_node_t *node = NULL;
int need_remove_list = 0;
uint32_t list_samples = 0;
ASSERT(!(samples%SCALABLE_FRAME_SIZE), "%s samples err:%d", __func__, samples);
a2dp_audio_scalable_convert_list_to_samples(&list_samples);
if (list_samples >= samples){
need_remove_list = samples/SCALABLE_FRAME_SIZE;
for (int i=0; i<need_remove_list; i++){
node = a2dp_audio_list_begin(list);
if (node)
{
scalable_decoder_frame = (a2dp_audio_scalable_decoder_frame_t *)a2dp_audio_list_node(node);
a2dp_audio_list_remove(list, scalable_decoder_frame);
}
}
nRet = A2DP_DECODER_NO_ERROR;
}
return nRet;
}
A2DP_AUDIO_DECODER_T a2dp_audio_scalable_decoder_config = {
{44100, 2, 16},
1,
a2dp_audio_scalable_init,
a2dp_audio_scalable_deinit,
a2dp_audio_scalable_decode_frame,
a2dp_audio_scalable_preparse_packet,
a2dp_audio_scalable_store_packet,
a2dp_audio_scalable_discards_packet,
a2dp_audio_scalable_synchronize_packet,
a2dp_audio_scalable_synchronize_dest_packet_mut,
a2dp_audio_scalable_convert_list_to_samples,
a2dp_audio_scalable_discards_samples,
a2dp_audio_scalable_headframe_info_get,
a2dp_audio_scalable_info_get,
a2dp_audio_scalable_free,
};
#else
A2DP_AUDIO_DECODER_T a2dp_audio_scalable_decoder_config = { 0, };
#endif

View file

@ -0,0 +1,37 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __A2DP_DECODER_TRACE_H__
#define __A2DP_DECODER_TRACE_H__
#include "hal_trace.h"
#ifdef ENABLE_COMPRESS_LOG
#define TRACE_A2DP_DECODER_D(str, ...) hal_trace_dummy(str, ##__VA_ARGS__)
//LOG_DEBUG(LOG_ATTR_ARG_NUM(COUNT_ARG_NUM(unused, ##__VA_ARGS__)), "[AUD][DECODER][DBG]"str, ##__VA_ARGS__)
#define TRACE_A2DP_DECODER_I(str, ...) LOG_INFO(LOG_ATTR_ARG_NUM(COUNT_ARG_NUM(unused, ##__VA_ARGS__)), "[AUD][DECODER]"str, ##__VA_ARGS__)
#define TRACE_A2DP_DECODER_W(str, ...) LOG_WARN(LOG_ATTR_ARG_NUM(COUNT_ARG_NUM(unused, ##__VA_ARGS__)), "[AUD][DECODER][WARN]"str, ##__VA_ARGS__)
#define TRACE_A2DP_DECODER_E(str, ...) LOG_ERROR(LOG_ATTR_ARG_NUM(COUNT_ARG_NUM(unused, ##__VA_ARGS__)), "[AUD][DECODER][ERR]"str, ##__VA_ARGS__)
#else
#define TRACE_A2DP_DECODER_D(str, ...) hal_trace_dummy(str, ##__VA_ARGS__)
//LOG_DEBUG(LOG_MOD(AUDFLG), "[AUD][DECODER][DBG]"str, ##__VA_ARGS__)
#define TRACE_A2DP_DECODER_I(str, ...) LOG_INFO(LOG_MOD(AUDFLG), "[AUD][DECODER]"str, ##__VA_ARGS__)
#define TRACE_A2DP_DECODER_W(str, ...) LOG_WARN(LOG_MOD(AUDFLG), "[AUD][DECODER][WARN]"str, ##__VA_ARGS__)
#define TRACE_A2DP_DECODER_E(str, ...) LOG_ERROR(LOG_MOD(AUDFLG), "[AUD][DECODER][ERR]"str, ##__VA_ARGS__)
#endif
#define ASSERT_A2DP_DECODER(cond, str, ...) ASSERT(cond, str, ##__VA_ARGS__)
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,791 @@
/***************************************************************************
*
* 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 "cmsis_os.h"
#include "app_bt_trace.h"
#include "string.h"
#include "cqueue.h"
#include "list.h"
#include "hal_aud.h"
#include "resources.h"
#include "app_thread.h"
#include "app_audio.h"
#include "app_media_player.h"
#include "app_ring_merge.h"
#include "nvrecord.h"
#include <assert.h>
#include "a2dp_api.h"
#include "btapp.h"
#include "app_bt_media_manager.h"
extern uint8_t __StackLimit[];
extern uint8_t __HeapLimit[];
static const size_t heap_size = __StackLimit - __HeapLimit - 512;
static bool app_audio_init = false;
static uint32_t capture_audio_buff_size_used;
// from the bottom of the system available memory pool, size is APP_CAPTURE_AUDIO_BUFFER_SIZE
// can be overlayed with the sco used audio buffer
static uint8_t* capture_audio_buffer = __HeapLimit + heap_size - APP_CAPTURE_AUDIO_BUFFER_SIZE;
int app_capture_audio_mempool_init(void)
{
TRACE_AUD_HDL_I("[CAPMEM][INIT] size %d.", APP_CAPTURE_AUDIO_BUFFER_SIZE);
capture_audio_buff_size_used = 0;
memset((uint8_t *)capture_audio_buffer, 0, APP_CAPTURE_AUDIO_BUFFER_SIZE);
return 0;
}
uint32_t app_capture_audio_mempool_free_buff_size()
{
return APP_CAPTURE_AUDIO_BUFFER_SIZE - capture_audio_buff_size_used;
}
int app_capture_audio_mempool_get_buff(uint8_t **buff, uint32_t size)
{
uint32_t buff_size_free;
uint8_t* capture_buf_addr = (uint8_t *)capture_audio_buffer;
buff_size_free = app_capture_audio_mempool_free_buff_size();
if (size % 4){
size = size + (4 - size % 4);
}
TRACE_AUD_HDL_I("[CAPMEM][GET] current free %d to allocate %d", buff_size_free, size);
ASSERT(size <= buff_size_free, "[%s] size = %d > free size = %d", __func__, size, buff_size_free);
*buff = capture_buf_addr + capture_audio_buff_size_used;
capture_audio_buff_size_used += size;
TRACE_AUD_HDL_I("[CAPMEM][GET] %d, now used %d left %d",
size, capture_audio_buff_size_used, app_capture_audio_mempool_free_buff_size());
return 0;
}
osPoolDef (app_audio_status_mempool, 20, APP_AUDIO_STATUS);
osPoolId app_audio_status_mempool = NULL;
// control queue access
osMutexId g_app_audio_queue_mutex_id = NULL;
osMutexDef(g_app_audio_queue_mutex);
// control pcmbuff access
static CQueue app_audio_pcm_queue;
static osMutexId app_audio_pcmbuff_mutex_id = NULL;
osMutexDef(app_audio_pcmbuff_mutex);
#ifdef __AUDIO_QUEUE_SUPPORT__
typedef struct {
list_t *audio_list;
}APP_AUDIO_CONFIG;
APP_AUDIO_CONFIG app_audio_conifg = {
.audio_list = NULL
};
#endif
void LOCK_APP_AUDIO_QUEUE()
{
osMutexWait(g_app_audio_queue_mutex_id, osWaitForever);
}
void UNLOCK_APP_AUDIO_QUEUE()
{
osMutexRelease(g_app_audio_queue_mutex_id);
}
uint32_t app_audio_lr_balance(uint8_t *buf, uint32_t len, int8_t balance)
{
short *balance_buf=(short *)buf;
uint32_t balance_len = len/2;
float factor;
ASSERT((balance >= -100) && (balance <= 100), "balance = %d is invalid!", balance);
if(balance > 0)
{
//reduce L channel
factor = 1 - 0.01 * balance;
for(uint32_t i=0; i<balance_len;i+=2)
{
balance_buf[i] = (short) (factor * balance_buf[i]);
}
}
else if(balance < 0)
{
//reduce R channel
factor = 1 + 0.01 * balance;
for(uint32_t i=0; i<balance_len;i+=2)
{
balance_buf[i+1] = (short) (factor * balance_buf[i+1]);
}
}
return 0;
}
void app_audio_mempool_init_with_specific_size(uint32_t size)
{
syspool_init_specific_size(size);
}
int app_audio_pcmbuff_init(uint8_t *buff, uint16_t len)
{
if (app_audio_pcmbuff_mutex_id == NULL)
app_audio_pcmbuff_mutex_id = osMutexCreate((osMutex(app_audio_pcmbuff_mutex)));
if ((buff == NULL)||(app_audio_pcmbuff_mutex_id == NULL))
return -1;
osMutexWait(app_audio_pcmbuff_mutex_id, osWaitForever);
InitCQueue(&app_audio_pcm_queue, len, buff);
memset(buff, 0x00, len);
osMutexRelease(app_audio_pcmbuff_mutex_id);
return 0;
}
int app_audio_pcmbuff_length(void)
{
int len;
osMutexWait(app_audio_pcmbuff_mutex_id, osWaitForever);
len = LengthOfCQueue(&app_audio_pcm_queue);
osMutexRelease(app_audio_pcmbuff_mutex_id);
return len;
}
int app_audio_pcmbuff_put(uint8_t *buff, uint16_t len)
{
int status;
osMutexWait(app_audio_pcmbuff_mutex_id, osWaitForever);
status = EnCQueue(&app_audio_pcm_queue, buff, len);
osMutexRelease(app_audio_pcmbuff_mutex_id);
return status;
}
int app_audio_pcmbuff_get(uint8_t *buff, uint16_t len)
{
unsigned char *e1 = NULL, *e2 = NULL;
unsigned int len1 = 0, len2 = 0;
int status;
osMutexWait(app_audio_pcmbuff_mutex_id, osWaitForever);
status = PeekCQueue(&app_audio_pcm_queue, len, &e1, &len1, &e2, &len2);
if (len==(len1+len2)){
memcpy(buff,e1,len1);
memcpy(buff+len1,e2,len2);
DeCQueue(&app_audio_pcm_queue, 0, len1);
DeCQueue(&app_audio_pcm_queue, 0, len2);
}else{
memset(buff, 0x00, len);
status = -1;
}
osMutexRelease(app_audio_pcmbuff_mutex_id);
return status;
}
int app_audio_pcmbuff_discard(uint16_t len)
{
int status;
osMutexWait(app_audio_pcmbuff_mutex_id, osWaitForever);
status = DeCQueue(&app_audio_pcm_queue, 0, len);
osMutexRelease(app_audio_pcmbuff_mutex_id);
return status;
}
void __attribute__((section(".fast_text_sram"))) app_audio_memcpy_16bit(int16_t *des, int16_t *src, int len)
{
// Check input
for(int i=0; i<len; i++)
{
des[i] = src[i];
}
}
void __attribute__((section(".fast_text_sram"))) app_audio_memset_16bit(int16_t *des, int16_t val, int len)
{
// Check input
for(int i=0; i<len; i++)
{
des[i] = val;
}
}
#ifdef __AUDIO_QUEUE_SUPPORT__
int app_audio_sendrequest_param(uint16_t id, uint8_t status, uint32_t ptr, uint32_t param)
{
uint32_t audevt;
APP_MESSAGE_BLOCK msg;
if(app_audio_init == false)
return -1;
msg.mod_id = APP_MODUAL_AUDIO;
APP_AUDIO_SET_MESSAGE(audevt, id, status);
msg.msg_body.message_id = audevt;
msg.msg_body.message_ptr = ptr;
msg.msg_body.message_Param0 = param;
app_mailbox_put(&msg);
return 0;
}
int app_audio_sendrequest(uint16_t id, uint8_t status, uint32_t ptr)
{
return app_audio_sendrequest_param(id, status, ptr, 0);
}
extern bool app_audio_list_playback_exist(void);
#ifdef MEDIA_PLAYER_SUPPORT
static uint8_t app_audio_get_list_playback_num(void)
{
APP_AUDIO_STATUS *audio_handle = NULL;
list_node_t *node = NULL;
uint8_t num=0;
for (node = list_begin(app_audio_conifg.audio_list); node != list_end(app_audio_conifg.audio_list); node = list_next(node))
{
audio_handle = (APP_AUDIO_STATUS *)list_node(node);
if(audio_handle == NULL)
{
return num;
}
if (audio_handle->id == APP_PLAY_BACK_AUDIO)
num++;
}
return num;
}
#endif
#endif
static bool need_flush_flash_switch_audio = false;
void app_audio_switch_flash_flush_req(void)
{
uint32_t lock;
lock = int_lock();
need_flush_flash_switch_audio = true;
int_unlock(lock);
}
static void app_audio_switch_flash_proc(void)
{
// no need to do this across the audio switch,
// will use suspend flash erase to assure that no audio
// irq is missing for handling caused by long time global irq disabling
// during flash erase.
// Just flash the nvrecord flash periodically
return;
uint32_t lock;
bool need_flush_flash = false;
lock = int_lock();
if (need_flush_flash_switch_audio){
need_flush_flash_switch_audio = false;
need_flush_flash = true;
}
int_unlock(lock);
if (need_flush_flash){
#ifndef FPGA
nv_record_flash_flush();
#endif
}
}
#ifdef VOICE_DATAPATH
static bool app_audio_handle_pre_processing(APP_MESSAGE_BODY *msg_body)
{
uint16_t stream_type;
APP_AUDIO_GET_AUD_ID(msg_body->message_ptr, stream_type);
bool isToResetCaptureStream = false;
if ((BT_STREAM_SBC == stream_type) || (BT_STREAM_MEDIA == stream_type))
{
if (app_audio_manager_capture_is_active())
{
isToResetCaptureStream = true;
}
}
if (isToResetCaptureStream)
{
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_STOP,
BT_STREAM_CAPTURE, 0, 0);
APP_MESSAGE_BLOCK msg;
msg.msg_body = *msg_body;
msg.mod_id = APP_MODUAL_AUDIO_MANAGE;
app_mailbox_put(&msg);
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_START,
BT_STREAM_CAPTURE, 0, 0);
return false;
}
else
{
return true;
}
}
#endif
static int app_audio_handle_process(APP_MESSAGE_BODY *msg_body)
{
int nRet = -1;
APP_AUDIO_STATUS aud_status;
if (app_audio_init == false)
return -1;
#ifdef VOICE_DATAPATH
bool isContinue = app_audio_handle_pre_processing(msg_body);
if (!isContinue)
{
return -1;
}
#endif
APP_AUDIO_GET_ID(msg_body->message_id, aud_status.id);
APP_AUDIO_GET_STATUS(msg_body->message_id, aud_status.status);
APP_AUDIO_GET_AUD_ID(msg_body->message_ptr, aud_status.aud_id);
APP_AUDIO_GET_FREQ(msg_body->message_Param0, aud_status.freq);
switch (aud_status.status)
{
case APP_BT_SETTING_OPEN:
#ifdef __AUDIO_QUEUE_SUPPORT__
TRACE_AUD_HDL_I(
"[OPEN] before status_id: 0x%x%s, aud_id: %d, len = %d",
aud_status.id,
player2str(aud_status.id),
aud_status.aud_id,
list_length(app_audio_conifg.audio_list));
if (app_audio_list_append(&aud_status))
{
app_bt_stream_open(&aud_status);
TRACE_AUD_HDL_I(
"[OPEN] after status_id: 0x%x%s, len = %d",
aud_status.id,
player2str(aud_status.id),
list_length(app_audio_conifg.audio_list));
}
#else
app_bt_stream_open(&aud_status);
#endif
break;
case APP_BT_SETTING_CLOSE:
app_audio_switch_flash_proc();
#ifdef __AUDIO_QUEUE_SUPPORT__
APP_AUDIO_STATUS next_status;
TRACE_AUD_HDL_I(
"[CLOSE] current id: 0x%x%s",
aud_status.id,
player2str(aud_status.id));
app_bt_stream_close(aud_status.id);
app_audio_switch_flash_proc();
#ifdef MEDIA_PLAYER_SUPPORT
if (aud_status.id == APP_PLAY_BACK_AUDIO)
{
TRACE_AUD_HDL_I("[CLOSE] list: %d", app_audio_get_list_playback_num());
if (app_audio_get_list_playback_num() == 1)
{
TRACE_AUD_HDL_I("=======>APP_BT_SETTING_CLOSE MEDIA");
bt_media_stop(BT_STREAM_MEDIA, BT_DEVICE_ID_1);
}
}
#endif
if (app_audio_list_rmv_callback(&aud_status, &next_status, APP_BT_SETTING_Q_POS_HEAD, false))
{
TRACE_AUD_HDL_I(
"[CLOSE] %p, next id: 0x%x%s, status %d",
&next_status,
next_status.id,
player2str(next_status.id),
next_status.status);
app_bt_stream_open(&next_status);
}
#else
app_bt_stream_close(aud_status.id);
app_audio_switch_flash_proc();
#endif
break;
case APP_BT_SETTING_SETUP:
app_bt_stream_setup(aud_status.id, msg_body->message_ptr);
break;
case APP_BT_SETTING_RESTART:
app_bt_stream_restart(&aud_status);
break;
case APP_BT_SETTING_CLOSEALL:
app_bt_stream_closeall();
#ifdef __AUDIO_QUEUE_SUPPORT__
app_audio_list_clear();
#endif
app_audio_switch_flash_proc();
break;
default:
break;
}
return nRet;
}
#ifdef __AUDIO_QUEUE_SUPPORT__
static void app_audio_handle_free(void* data)
{
#ifdef MEDIA_PLAYER_SUPPORT
APP_AUDIO_STATUS * status = (APP_AUDIO_STATUS * )data;
if(status->id == APP_PLAY_BACK_AUDIO)
{
TRACE_AUD_HDL_I("[HANDLE_FREE] , aud_id: 0x%x, type = 0x%x", status->aud_id, status->aud_type);
}
#endif
osPoolFree (app_audio_status_mempool, data);
}
void app_audio_list_create()
{
if (app_audio_conifg.audio_list == NULL)
{
app_audio_conifg.audio_list = list_new(app_audio_handle_free, NULL, NULL);
}
}
bool app_audio_list_stream_exist()
{
APP_AUDIO_STATUS *audio_handle = NULL;
list_node_t *node = NULL;
for (node = list_begin(app_audio_conifg.audio_list); node != list_end(app_audio_conifg.audio_list); node = list_next(node)) {
audio_handle = (APP_AUDIO_STATUS *)list_node(node);
if(audio_handle == NULL)
{
return false;
}
if (audio_handle->id == APP_BT_STREAM_HFP_PCM ||
audio_handle->id == APP_BT_STREAM_HFP_CVSD ||
audio_handle->id == APP_BT_STREAM_HFP_VENDOR ||
audio_handle->id == APP_BT_STREAM_A2DP_SBC ||
audio_handle->id == APP_BT_STREAM_A2DP_AAC ||
#ifdef VOICE_DATAPATH
audio_handle->id == APP_BT_STREAM_VOICEPATH ||
#endif
#ifdef __AI_VOICE__
audio_handle->id == APP_BT_STREAM_AI_VOICE ||
#endif
#ifdef __THIRDPARTY
audio_handle->id == APP_BT_STREAM_THIRDPARTY_VOICE ||
#endif
audio_handle->id == APP_BT_STREAM_A2DP_VENDOR
) {
TRACE_AUD_HDL_I("[STREAM_LIST][EXIST] id 0x%x", audio_handle->id);
return true;
}
}
return false;
}
bool app_audio_list_filter_exist(APP_AUDIO_STATUS* aud_status)
{
#ifdef MEDIA_PLAYER_SUPPORT
APP_AUDIO_STATUS *audio_handle = NULL;
list_node_t *node = NULL;
uint8_t cnt = 0;
if (aud_status->id == APP_PLAY_BACK_AUDIO){
if(aud_status->aud_id == AUD_ID_BT_CALL_INCOMING_CALL) {
for (node = list_begin(app_audio_conifg.audio_list); node != list_end(app_audio_conifg.audio_list); node = list_next(node)) {
audio_handle = (APP_AUDIO_STATUS *)list_node(node);
if(audio_handle == NULL)
{
return false;
}
if (audio_handle->id == APP_PLAY_BACK_AUDIO && audio_handle->aud_id == AUD_ID_BT_CALL_INCOMING_CALL) {
TRACE_AUD_HDL_I("[STREAM_LIST][FILTER] id 0x%x", audio_handle->id);
return true;
}
}
} else {
for (node = list_begin(app_audio_conifg.audio_list); node != list_end(app_audio_conifg.audio_list); node = list_next(node)) {
audio_handle = (APP_AUDIO_STATUS *)list_node(node);
if (cnt++ > 1) {
TRACE_AUD_HDL_I("[STREAM_LIST][FILTER] cnt %d", cnt);
return true;
}
}
}
}
#endif
return false;
}
bool app_audio_list_playback_exist(void)
{
#ifdef MEDIA_PLAYER_SUPPORT
APP_AUDIO_STATUS *audio_handle = NULL;
list_node_t *node = NULL;
for (node = list_begin(app_audio_conifg.audio_list); node != list_end(app_audio_conifg.audio_list); node = list_next(node)) {
audio_handle = (APP_AUDIO_STATUS *)list_node(node);
if(audio_handle == NULL)
{
return false;
}
if (audio_handle->id == APP_PLAY_BACK_AUDIO) {
TRACE_AUD_HDL_I("[STREAM_LIST][PLAYBACK_EXIST]");
return true;
}
}
#endif
return false;
}
void app_audio_list_playback_clear(void)
{
#ifdef MEDIA_PLAYER_SUPPORT
APP_AUDIO_STATUS *audio_handle = NULL;
list_node_t *node = NULL;
for (node = list_begin(app_audio_conifg.audio_list); node != list_end(app_audio_conifg.audio_list); node = list_next(node)) {
audio_handle = (APP_AUDIO_STATUS *)list_node(node);
if(audio_handle == NULL)
{
TRACE_AUD_HDL_I("[STREAM_LIST][CLR] find null\n ");
return;
}
if (audio_handle->id == APP_PLAY_BACK_AUDIO){
list_remove(app_audio_conifg.audio_list, list_node(node));
}
}
#endif
}
bool app_audio_list_append(APP_AUDIO_STATUS* aud_status)
{
APP_AUDIO_STATUS *data_to_append = NULL;
bool add_data_to_head_of_list = false;
bool ret = true;
TRACE_AUD_HDL_I("[STREAM_LIST][APPEND] id 0x%x%s", aud_status->id, player2str(aud_status->id));
#ifdef MEDIA_PLAYER_SUPPORT
if (aud_status->id == APP_PLAY_BACK_AUDIO)
{
//ignore redundant ring ind from hfp...
if (app_audio_list_filter_exist(aud_status))
{
return false;
}
if (app_audio_list_playback_exist())
{
if (list_length(app_audio_conifg.audio_list) >= MAX_AUDIO_BUF_LIST)
{
if (app_audio_list_stream_exist())
{
data_to_append = (APP_AUDIO_STATUS *)osPoolCAlloc (app_audio_status_mempool);
if(data_to_append == NULL)
{
return false;
}
memcpy(data_to_append, (const void *)list_front(app_audio_conifg.audio_list), sizeof(APP_AUDIO_STATUS));
add_data_to_head_of_list = true;
}
app_audio_list_clear();
TRACE_AUD_HDL_E("[STREAM_LIST][APPEND] FIXME!!!!\n ");
}
else
{
ret = false;
}
}
}
else
#endif
{
add_data_to_head_of_list = true;
}
if (data_to_append == NULL)
{
data_to_append = (APP_AUDIO_STATUS *)osPoolCAlloc (app_audio_status_mempool);
if(data_to_append == NULL)
{
return false;
}
memcpy(data_to_append, aud_status, sizeof(APP_AUDIO_STATUS));
}
if (add_data_to_head_of_list)
{
list_prepend(app_audio_conifg.audio_list, (void*)data_to_append);
}
else
{
list_append(app_audio_conifg.audio_list, (void*)data_to_append);
}
TRACE_AUD_HDL_I("[STREAM_LIST][APPEND] id 0x%x%s status %d len %d ret %d", data_to_append->id, player2str(data_to_append->id), \
data_to_append->status, list_length(app_audio_conifg.audio_list), ret);
return ret;
}
bool app_audio_list_rmv_callback(APP_AUDIO_STATUS *status_close, APP_AUDIO_STATUS *status_next, enum APP_BT_AUDIO_Q_POS pos, bool pop_next)
{
void *data_to_remove = NULL;
bool ret = false;
//for status: first bt_a2dp->APP_BT_SETTING_CLOSE,then ring-> APP_BT_SETTING_CLOSE
TRACE_AUD_HDL_I("[STREAM_LIST][RMV] audio list len %d close_id 0x%x%s", list_length(app_audio_conifg.audio_list), \
status_close->id, player2str(status_close->id));
if(list_length(app_audio_conifg.audio_list) == 0)
{
return false;
}
#ifdef MEDIA_PLAYER_SUPPORT
APP_AUDIO_STATUS *audio_handle = NULL;
list_node_t *node = NULL;
if (status_close->id == APP_PLAY_BACK_AUDIO)
{
for (node = list_begin(app_audio_conifg.audio_list); node != list_end(app_audio_conifg.audio_list); node = list_next(node))
{
audio_handle = (APP_AUDIO_STATUS *)list_node(node);
if(audio_handle == NULL)
{
return ret;
}
if (audio_handle->id == APP_PLAY_BACK_AUDIO)
{
list_node_t *nod_next = list_next(node);
data_to_remove = list_node(node);
if (pop_next)
{
memcpy(status_next, list_node(node), sizeof(APP_AUDIO_STATUS));
ret = true;
break;
}
if (nod_next != NULL)
{
memcpy(status_next, list_node(nod_next), sizeof(APP_AUDIO_STATUS));
ASSERT(status_next->id == APP_PLAY_BACK_AUDIO, "[%s] 111ERROR: status_next->id != APP_PLAY_BACK_AUDIO", __func__);
ret = true;
}
else if (app_audio_list_stream_exist())
{
void *indata = list_front(app_audio_conifg.audio_list);
if(indata == NULL)
{
return ret;
}
memcpy(status_next, indata, sizeof(APP_AUDIO_STATUS));
ASSERT(status_next->id != APP_PLAY_BACK_AUDIO, "[%s] 222ERROR: status_next->id != APP_PLAY_BACK_AUDIO", __func__);
ret = true;
}
break;
}
}
}
else //maybe...a2dp send >> APP_BT_SETTING_CLOSE, when ring
#endif
{
if (app_audio_list_stream_exist())
{
if(pos == APP_BT_SETTING_Q_POS_HEAD)
{
data_to_remove = list_front(app_audio_conifg.audio_list);
}
else if (pos == APP_BT_SETTING_Q_POS_TAIL)
{
data_to_remove = list_back(app_audio_conifg.audio_list);
}
}
}
if (data_to_remove)
{
list_remove(app_audio_conifg.audio_list, data_to_remove);
}
TRACE_AUD_HDL_I("[STREAM_LIST][RMV] end len:%d ret %d data %p", list_length(app_audio_conifg.audio_list), ret, data_to_remove);
return ret;
}
void app_audio_list_clear()
{
list_clear(app_audio_conifg.audio_list);
}
#endif
void app_audio_open(void)
{
if(app_audio_init)
{
return;
}
if (g_app_audio_queue_mutex_id == NULL)
{
g_app_audio_queue_mutex_id = osMutexCreate((osMutex(g_app_audio_queue_mutex)));
}
else
{
ASSERT(0, "[%s] ERROR: g_app_audio_queue_mutex_id != NULL", __func__);
}
if (app_audio_status_mempool == NULL)
app_audio_status_mempool = osPoolCreate(osPool(app_audio_status_mempool));
ASSERT(app_audio_status_mempool, "[%s] ERROR: app_audio_status_mempool != NULL", __func__);
#ifdef __AUDIO_QUEUE_SUPPORT__
app_audio_list_create();
#endif
app_ring_merge_init();
app_set_threadhandle(APP_MODUAL_AUDIO, app_audio_handle_process);
app_bt_stream_init();
app_audio_init = true;
}
void app_audio_close(void)
{
app_set_threadhandle(APP_MODUAL_AUDIO, NULL);
app_audio_init = false;
}

View file

@ -0,0 +1,224 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __APP_AUDIO_H__
#define __APP_AUDIO_H__
#include "app_bt_stream.h"
#include "heap_api.h"
//should solve this problem
//#include "./../../utils/cqueue/cqueue.h"
//#include "cqueue.h"
#ifdef __cplusplus
extern "C" {
#endif
//This buff is used as queue
#ifndef APP_AUDIO_BUFFER_SIZE
#if (RAM_SIZE >= 0x48000)
#if defined(AUDIO_ANC_FB_MC) && defined(ANC_APP) && !defined(__AUDIO_RESAMPLE__)
#if defined(A2DP_EQ_24BIT)
#define APP_AUDIO_BUFFER_SIZE (1024 * 210)
#else
#define APP_AUDIO_BUFFER_SIZE (1024 * 140)
#endif
#else
#define APP_AUDIO_BUFFER_SIZE (1024 * 100)
#endif
#elif (RAM_SIZE >= 0x40000)
#ifdef NEW_NV_RECORD_ENABLED
#define APP_AUDIO_BUFFER_SIZE (1024 * 62)
#else
#define APP_AUDIO_BUFFER_SIZE (1024 * 59)
#endif
#else // RAM_SIZE < 0x40000
#ifdef APP_TEST_AUDIO
#define APP_AUDIO_BUFFER_SIZE (1024 * 10)
#elif defined(SPEECH_RX_NS)
#define APP_AUDIO_BUFFER_SIZE (1024 * 37)
#else
#define APP_AUDIO_BUFFER_SIZE (1024 * 32)
#endif
#endif // RAM_SIZE < 0x40000
#endif
#if defined(VOB_ENCODING_ALGORITHM) && (VOB_ENCODING_ALGORITHM == ENCODING_ALGORITHM_OPUS)
#ifdef __ALEXA_WWE
#ifdef __ALEXA_WWE_LITE
#define APP_CAPTURE_AUDIO_BUFFER_SIZE (63*1024)
#else
#define APP_CAPTURE_AUDIO_BUFFER_SIZE (305*1024)
#endif
#elif defined(SPEECH_CAPTURE_TWO_CHANNEL)
#define APP_CAPTURE_AUDIO_BUFFER_SIZE (76*1024)
#elif defined(__DUAL_MIC_RECORDING__)
#define APP_CAPTURE_AUDIO_BUFFER_SIZE (79*1024)
#else
#define APP_CAPTURE_AUDIO_BUFFER_SIZE (67*1024)
#endif
#elif defined(__AMA_VOICE__) && (VOB_ENCODING_ALGORITHM == ENCODING_ALGORITHM_SBC)
#if defined(CHIP_BEST1400) && defined(__AI_VOICE__)
#define APP_CAPTURE_AUDIO_BUFFER_SIZE (13*1024)
#else
#define APP_CAPTURE_AUDIO_BUFFER_SIZE (17*1024)
#endif
#elif defined(__KWS_ALEXA__)
#define APP_CAPTURE_AUDIO_BUFFER_SIZE (160*1024)
#elif defined(AI_CAPTURE_DATA_AEC)
#define APP_CAPTURE_AUDIO_BUFFER_SIZE (19*1024-512)
#elif defined(GSOUND_HOTWORD_EXTERNAL)
/// gsound_external_hotword_configuration
#ifdef VOICE_DETECTOR_EN
/// VAD_enabled_configuration
#ifdef VAD_USE_8K_SAMPLE_RATE
/// vad_use_8K_sample_rate_configuration
#define APP_CAPTURE_AUDIO_BUFFER_SIZE ((32 + 16 + 32)*1024-512)
/// vad_use_8K_sample_rate_configuration
#else
/// vad_use_16K_sample_rate_configuration
#define APP_CAPTURE_AUDIO_BUFFER_SIZE ((32 + 32)*1024-512)
/// vad_use_16K_sample_rate_configuration
#endif
/// VAD_enabled_configuration
#else
/// VAD_disabled_configuration
#define APP_CAPTURE_AUDIO_BUFFER_SIZE (32*1024-512)
/// VAD_disabled_configuration
#endif
/// gsound_external_hotword_configuration
#else
#ifdef VOICE_DETECTOR_EN
/// VAD_enabled_configuration
#define APP_CAPTURE_AUDIO_BUFFER_SIZE ((13 + 32)*1024-512)
/// VAD_enabled_configuration
#else
/// VAD_disabled_configuration
#define APP_CAPTURE_AUDIO_BUFFER_SIZE (13*1024-512)
/// VAD_disabled_configuration
#endif
#endif
#if defined(A2DP_SCALABLE_ON)
#define SCALABLE_FRAME_SIZE (864)
#define SCALABLE_HEAD_SIZE (4) /* pick something big enough to hold a bunch of frames */
#define SCALABLE_READBUF_SIZE (500) /* pick something big enough to hold a bunch of frames */
#define SCALABLE_DECODER_SIZE (17456) /* pick something big enough to hold a bunch of frames */
#define SBM_FAST_SPEED 67380 // 840 2.76%
#define SBM_SLOW_SPEED 63730 // 888 2.76%
#define SBM_NUM_NORMAL 100
#endif
#define MAX_AUDIO_BUF_LIST 20
enum APP_AUDIO_CACHE_T {
APP_AUDIO_CACHE_CACHEING= 0,
APP_AUDIO_CACHE_OK,
APP_AUDIO_CACHE_QTY,
};
#define APP_AUDIO_SET_MESSAGE(appevt, id, status) (appevt = (((uint32_t)id&0xffff)<<16)|(status&0xffff))
#define APP_AUDIO_GET_ID(appevt, id) (id = (appevt>>16)&0xffff)
#define APP_AUDIO_GET_STATUS(appevt, status) (status = appevt&0xffff)
#define APP_AUDIO_GET_AUD_ID(appevt, aud_id) (aud_id = appevt)
#define APP_AUDIO_GET_FREQ(appevt, freq) (freq = appevt)
#define APP_AUDIO_InitCQueue(a, b, c) InitCQueue(a, b, c)
#define APP_AUDIO_AvailableOfCQueue(a) AvailableOfCQueue(a)
#define APP_AUDIO_LengthOfCQueue(a) LengthOfCQueue(a)
#define APP_AUDIO_PeekCQueue(a, b, c, d, e, f) PeekCQueue(a, b, c, d, e, f)
#define APP_AUDIO_EnCQueue(a, b, c) EnCQueue(a, b, c)
#define APP_AUDIO_DeCQueue(a, b, c) DeCQueue(a, b, c)
#define app_audio_mempool_init syspool_init
#define app_audio_mempool_noclr_init syspool_init
#define app_audio_mempool_use_mempoolsection_init syspool_init
#define app_audio_mempool_free_buff_size syspool_free_size
#define app_audio_mempool_get_buff syspool_get_buff
#if defined(A2DP_LDAC_ON)
#define app_audio_mempool_total_buf syspool_total_size
#define app_audio_mempool_force_set_buff_used syspool_force_used_size
#endif
void UNLOCK_APP_AUDIO_QUEUE();
void LOCK_APP_AUDIO_QUEUE();
uint32_t app_audio_lr_balance(uint8_t *buf, uint32_t len, int8_t balance);
void app_audio_mempool_init_with_specific_size(uint32_t size);
int app_audio_pcmbuff_init(uint8_t *buff, uint16_t len);
int app_audio_pcmbuff_length(void);
int app_audio_pcmbuff_put(uint8_t *buff, uint16_t len);
int app_audio_pcmbuff_get(uint8_t *buff, uint16_t len);
int app_audio_pcmbuff_discard(uint16_t len);
void app_audio_memcpy_16bit(int16_t *des, int16_t *src, int len);
void app_audio_memset_16bit(int16_t *des, int16_t val, int len);
int app_audio_sendrequest(uint16_t id, uint8_t status, uint32_t ptr);
int app_audio_sendrequest_param(uint16_t id, uint8_t status, uint32_t ptr, uint32_t param);
void app_audio_open(void);
void app_audio_close(void);
bool app_audio_list_append(APP_AUDIO_STATUS* aud_status);
bool app_audio_list_playback_exist(void);
void app_audio_list_playback_clear(void);
bool app_audio_list_rmv_callback(APP_AUDIO_STATUS *status_close, APP_AUDIO_STATUS *status_next, enum APP_BT_AUDIO_Q_POS pos, bool pop_next);
void app_audio_list_clear();
int app_capture_audio_mempool_init(void);
uint32_t app_capture_audio_mempool_free_buff_size();
int app_capture_audio_mempool_get_buff(uint8_t **buff, uint32_t size);
#ifdef __cplusplus
}
#endif
#endif//__FMDEC_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,76 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __BT_SCO_CHAIN_H__
#define __BT_SCO_CHAIN_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Init speech algorithm, init all related states and memory
* Input:
* tx_sample_rate: capture sample rate
* rx_sample_rate: playback sample rate
* tx_frame_ms: capture frame size in ms
* rx_frame_ms: playback frame size in ms
* sco_frame_ms: sco frame size in ms(must be multiply of 7.5)
* buf: buffer to be used for algorithms
* len: buffer size
*/
int speech_init(int tx_sample_rate, int rx_sample_rate,
int tx_frame_ms, int rx_frame_ms,
int sco_frame_ms,
uint8_t *buf, int len);
/*
* Deinit speech algorithm, free all related states and memory
*/
int speech_deinit(void);
/*
* Uplink process
* Input:
* pcm_buf: captured buffer by microphone, multi-channel is interleaved.
* ref_buf: reference buffer for acoustic echo canceller.
* buffee sample num should be tx_sample_rate * tx_frame_ms
* pcm_len: capture buffer sample num, should be tx_sample_rate * sco_frame_ms * ch_num
* Output:
* pcm_buf: output buffer of speech algorithm, should be single channel
* pcm_len: output buffer sample num, should be tx_sample_rate * sco_frame_ms
*/
int speech_tx_process(void *pcm_buf, void *ref_buf, int *pcm_len);
/*
* Downlink process
* Input:
* pcm_buf: input buffer to be processed
* pcm_len: input buffer sample num, should be rx_sample_rate * sco_frame_ms
* Output:
* pcm_buf: output buffer
* pcm_len: output buffer sample num, should be rx_sample_rate * sco_frame_ms
*/
int speech_rx_process(void *pcm_buf, int *pcm_len);
void *speech_get_ext_buff(int size);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,146 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __BT_SCO_CHAIN_CFG_H__
#define __BT_SCO_CHAIN_CFG_H__
#include "speech_cfg.h"
typedef struct {
#if defined(SPEECH_TX_DC_FILTER)
SpeechDcFilterConfig tx_dc_filter;
#endif
#if defined(SPEECH_TX_AEC)
SpeechAecConfig tx_aec;
#endif
#if defined(SPEECH_TX_AEC2)
SpeechAec2Config tx_aec2;
#endif
#if defined(SPEECH_TX_AEC2FLOAT)
Ec2FloatConfig tx_aec2float;
#endif
#if defined(SPEECH_TX_AEC3)
SubBandAecConfig tx_aec3;
#endif
#if defined(SPEECH_TX_2MIC_NS)
DUAL_MIC_DENOISE_CFG_T tx_2mic_ns;
#endif
#if defined(SPEECH_TX_2MIC_NS2)
Speech2MicNs2Config tx_2mic_ns2;
#endif
#if defined(SPEECH_TX_2MIC_NS4)
SensorMicDenoiseConfig tx_2mic_ns4;
#endif
#if defined(SPEECH_TX_2MIC_NS5)
LeftRightDenoiseConfig tx_2mic_ns5;
#endif
#if defined(SPEECH_TX_3MIC_NS)
Speech3MicNsConfig tx_3mic_ns;
#endif
#if defined(SPEECH_TX_3MIC_NS3)
TripleMicDenoise3Config tx_3mic_ns3;
#endif
#if defined(SPEECH_TX_NS)
SpeechNsConfig tx_ns;
#endif
#if defined(SPEECH_TX_NS2)
SpeechNs2Config tx_ns2;
#endif
#if defined(SPEECH_TX_NS2FLOAT)
SpeechNs2FloatConfig tx_ns2float;
#endif
#if defined(SPEECH_TX_NS3)
Ns3Config tx_ns3;
#endif
#if defined(SPEECH_TX_WNR)
WnrConfig tx_wnr;
#endif
#if defined(SPEECH_TX_NOISE_GATE)
NoisegateConfig tx_noise_gate;
#endif
#if defined(SPEECH_TX_COMPEXP)
CompexpConfig tx_compexp;
#endif
#if defined(SPEECH_TX_AGC)
AgcConfig tx_agc;
#endif
#if defined(SPEECH_TX_EQ)
EqConfig tx_eq;
#endif
#if defined(SPEECH_TX_POST_GAIN)
SpeechGainConfig tx_post_gain;
#endif
// #if defined(SPEECH_CS_VAD)
// VADConfig cs_vad;
// #endif
#if defined(SPEECH_RX_NS)
SpeechNsConfig rx_ns;
#endif
#if defined(SPEECH_RX_NS2)
SpeechNs2Config rx_ns2;
#endif
#if defined(SPEECH_RX_NS2FLOAT)
SpeechNs2FloatConfig rx_ns2float;
#endif
#if defined(SPEECH_RX_NS3)
Ns3Config rx_ns3;
#endif
#if defined(SPEECH_RX_NOISE_GATE)
NoisegateConfig rx_noise_gate;
#endif
#if defined(SPEECH_RX_COMPEXP)
CompexpConfig rx_compexp;
#endif
#if defined(SPEECH_RX_AGC)
AgcConfig rx_agc;
#endif
#if defined(SPEECH_RX_EQ)
EqConfig rx_eq;
#endif
#if defined(SPEECH_RX_POST_GAIN)
SpeechGainConfig rx_post_gain;
#endif
// Add more process
} SpeechConfig;
#endif

View file

@ -0,0 +1,796 @@
/***************************************************************************
*
* 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 "plat_types.h"
#include "bt_sco_chain_cfg.h"
#if defined(SPEECH_TX_2MIC_NS4)
static float ff_fb_h[256] = {1.f, };
#endif
#if defined(SPEECH_TX_MIC_CALIBRATION)
/****************************************************************************************************
* Describtion:
* Mic Calibration Equalizer, implementation with 2 order iir filters
* Parameters:
* bypass(0/1): bypass enable or disable.
* mic_num(1~4): the number of microphones. The filter num is (mic_num - 1)
* calib: {bypass, gain, num, {type, frequency, gain, q}}. Please refer to SPEECH_TX_EQ section
* in this file
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz, 0.5M/section;
* Note:
* None
****************************************************************************************************/
const SpeechIirCalibConfig WEAK speech_tx_mic_calib_cfg =
{
.bypass = 0,
.mic_num = 2,
.calib = {
{
.bypass = 0,
.gain = 0.f,
.num = 0,
.params = {
{IIR_BIQUARD_LOWSHELF, 150, -2.5, 0.707},
}
},
},
};
#endif
#if defined(SPEECH_TX_MIC_FIR_CALIBRATION)
/****************************************************************************************************
* Describtion:
* Mic Calibration Equalizer, implementation with fir filter
* Parameters:
* bypass(0/1): bypass enable or disable.
* mic_num(1~4): the number of microphones. The filter num is (mic_num - 1)
* calib: {filter, filter_length, nfft}.
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz, 0.5M/section;
* Note:
* None
****************************************************************************************************/
float mic2_ft_caliration[256] = {1.f, };
const SpeechFirCalibConfig WEAK speech_tx_mic_fir_calib_cfg =
{
.bypass = 0,
.mic_num = SPEECH_CODEC_CAPTURE_CHANNEL_NUM,
.delay = 0,
.calib = {
{
.filter = mic2_ft_caliration,
.filter_length = ARRAY_SIZE(mic2_ft_caliration),
},
},
};
#endif
const SpeechConfig WEAK speech_cfg_default = {
#if defined(SPEECH_TX_DC_FILTER)
.tx_dc_filter = {
.bypass = 0,
.gain = 0,
},
#endif
#if defined(SPEECH_TX_AEC)
/****************************************************************************************************
* Describtion:
* Acoustic Echo Cancellation
* Parameters:
* bypass(0/1): bypass enable or disable.
* delay(>0): delay samples from mic to speak, unit(sample).
* leak_estimate(0~32767): echo supression value. This is a fixed mode. It has relatively large
* echo supression and large damage to speech signal.
* leak_estimate_shift(0~8): echo supression value. if leak_estimate == 0, then leak_estimate_shift
* can take effect. This is a adaptive mode. It has relatively small echo supression and also
* small damage to speech signal.
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz, 40M;
* Note:
* If possible, use SPEECH_TX_AEC2FLOAT
****************************************************************************************************/
.tx_aec = {
.bypass = 0,
.delay = 60,
.leak_estimate = 16383,
.leak_estimate_shift = 4,
},
#endif
#if defined(SPEECH_TX_AEC2)
/****************************************************************************************************
* Describtion:
* Acoustic Echo Cancellation
* Parameters:
* bypass(0/1): bypass enable or disable.
* .
* .
* .
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz, enNlpEnable = 1, 39M;
* Note:
* If possible, use SPEECH_TX_AEC2FLOAT
****************************************************************************************************/
.tx_aec2 = {
.bypass = 0,
.enEAecEnable = 1,
.enHpfEnable = 1,
.enAfEnable = 0,
.enNsEnable = 0,
.enNlpEnable = 1,
.enCngEnable = 0,
.shwDelayLength = 0,
.shwNlpBandSortIdx = 0.75f,
.shwNlpBandSortIdxLow = 0.5f,
.shwNlpTargetSupp = 3.0f,
.shwNlpMinOvrd = 1.0f,
},
#endif
#if defined(SPEECH_TX_AEC2FLOAT)
/****************************************************************************************************
* Describtion:
* Acoustic Echo Cancellation
* Parameters:
* bypass(0/1): bypass enable or disable.
* hpf_enabled(0/1): high pass filter enable or disable. Used to remove DC for Near and Ref signals.
* af_enabled(0/1): adaptive filter enable or disable. If the echo signal is very large, enable this
* nlp_enabled(0/1): non-linear process enable or disable. Enable this by default.
* ns_enabled(0/1): noise supression enable or disable. Enable this by default.
* cng_enabled(0/1): comfort noise generator enable or disable.
* blocks(1~8): the length of adaptive filter = blocks * frame length
* delay(>0): delay samples from mic to speak, unit(sample).
* min_ovrd(1~6): supression factor, min_ovrd becomes larger and echo suppression becomes larger.
* target_supp(<0): target echo suppression, unit(dB)
* noise_supp(-30~0): noise suppression, unit(dB)
* cng_type(0/1): noise type(0: White noise; 1: Pink noise)
* cng_level(<0): noise gain, unit(dB)
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz;
* Note:
* This is the recommended AEC
****************************************************************************************************/
.tx_aec2float = {
.bypass = 0,
.hpf_enabled = false,
.af_enabled = false,
.nlp_enabled = true,
.clip_enabled = false,
.stsupp_enabled = false,
.ns_enabled = true,
.cng_enabled = false,
.blocks = 1,
.delay = 70,
.min_ovrd = 2,
.target_supp = -40,
.noise_supp = -15,
.cng_type = 1,
.cng_level = -60,
.clip_threshold = -20.f,
.banks = 64,
},
#endif
#if defined(SPEECH_TX_AEC3)
.tx_aec3 = {
.bypass = 0,
.filter_size = 16,
},
#endif
#if defined(SPEECH_TX_2MIC_NS)
/****************************************************************************************************
* Describtion:
* 2 MICs Noise Suppression
* Parameters:
* bypass(0/1): bypass enable or disable.
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz;
* Note:
* None
****************************************************************************************************/
.tx_2mic_ns = {
.bypass = 0,
.alpha_h = 0.8,
.alpha_slow = 0.9,
.alpha_fast = 0.6,
.thegma = 0.01,
.thre_corr = 0.2,
.thre_filter_diff = 0.2,
.cal_left_gain = 1.0,
.cal_right_gain = 1.0,
.delay_mono_sample = 6,
.wnr_enable = 0,
},
#endif
#if defined(SPEECH_TX_2MIC_NS2)
/****************************************************************************************************
* Describtion:
* 2 MICs Noise Suppression
* Parameters:
* bypass(0/1): bypass enable or disable.
* delay_taps(0~4): ceil{[d(MIC1~mouth) - d(MIC2~mouth)] / 2}.
* ceil: Returns the largest integer less than or equal to the specified data
* d(MIC~mouth): The dinstance from MIC to mouth
* e.g. 0: 0~2cm; 1: 2~4; 2: 5~6...
* freq_smooth_enable(1): Must enable
* wnr_enable(0/1): wind noise reduction enable or disable. This is also useful for improving
* noise suppression, but it also has some damage to speech signal.
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz, 32M;
* Note:
* None
****************************************************************************************************/
.tx_2mic_ns2 = {
.bypass = 0,
.delay_taps = 0.f,
.freq_smooth_enable = 1,
.wnr_enable = 1,
},
#endif
#if defined(SPEECH_TX_2MIC_NS5)
/****************************************************************************************************
* Describtion:
* 2 MICs Noise Suppression
* Parameters:
* bypass(0/1): bypass enable or disable.
* delay_taps(0~4): ceil{[d(MIC1~mouth) - d(MIC2~mouth)] / 2}. Default as 0
* ceil: Returns the largest integer less than or equal to the specified data
* d(MIC~mouth): The dinstance from MIC to mouth
* e.g. 0: 0~2cm; 1: 2~4; 2: 5~6...
* freq_smooth_enable(1): Must enable
* wnr_enable(0/1): wind noise reduction enable or disable. This is also useful for improving
* noise suppression, but it also has some damage to speech signal.
* delay_enable(0/1): enable the delay_taps or not. Ideally, never need to enable the delay and
* delay_taps will be a useless parameter.
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz, 32M;
* Note:
* None
****************************************************************************************************/
.tx_2mic_ns5 = {
.bypass = 0,
.delay_taps = 0.0f,
.freq_smooth_enable = 1,
.wnr_enable = 0,
.delay_enable = 0,
},
#endif
#if defined(SPEECH_TX_2MIC_NS4)
/****************************************************************************************************
* Describtion:
* 2 MICs Noise Suppression
* Parameters:
* bypass(0/1): bypass enable or disable.
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz;
* Note:
* None
****************************************************************************************************/
.tx_2mic_ns4 = {
.bypass = 0,
.blend_en = 1,
// .left_gain = 1.0f,
// .right_gain = 1.0f,
.delay_tapsM = 0,
.delay_tapsS = 0,
// .delay_tapsC = 32,
//////////////////////////{{a0,a1,a2,a3,a4},{b0,b1,b2,b3,b4}}///////////////////////////
// .coefH[0] = {1.0, -1.88561808316413, 1.55555555555556, -0.628539361054709, 0.111111111111111},
// .coefH[1] = {0.323801506930344, -1.29520602772138, 1.94280904158206, -1.29520602772138, 0.323801506930344},
// .coefL[0] = {1.0, -1.88561808316413, 1.55555555555556, -0.628539361054709, 0.111111111111111},
// .coefL[1] = {0.00953182640298944, 0.0381273056119578, 0.0571909584179366, 0.0381273056119578, 0.00953182640298944},
.crossover_freq = 1000,
.ff_fb_coeff = ff_fb_h,
.ff_fb_coeff_len = ARRAY_SIZE(ff_fb_h),
},
#endif
#if defined(SPEECH_TX_3MIC_NS)
/****************************************************************************************************
* Describtion:
* 3 MICs Noise Suppression
* Parameters:
* bypass(0/1): bypass enable or disable.
* delay_tapsM(0~4): MIC L/R delay samples. Refer to SPEECH_TX_2MIC_NS2 delay_taps
* delay_tapsS(0~4): MIC L/S delay samples. Refer to SPEECH_TX_2MIC_NS2 delay_taps
* freq_smooth_enable(1): Must enable
* wnr_enable(0/1): wind noise reduction enable or disable. This is also useful for improving
* noise suppression, but it also has some damage to speech signal.
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz;
* Note:
* None
****************************************************************************************************/
.tx_3mic_ns = {
.bypass = 0,
.blend_en = 1,
.authen_en = 1,
.delay_tapsM = 0.65f,
.delay_tapsS = 2,
.denoise_dB = -15.0f,
// .coefH[0] = {1.0,-3.3384,4.2195,-2.3924,0.5136},
// .coefH[1] = {0.7165,-2.8660,4.2990,-2.8660,0.7165},
// .coefL[0] = {1.0,-3.3384,4.2195,-2.3924,0.5136},
// .coefL[1] = {0.00014,0.00056,0.00084,0.00056,0.00014},
.crossover_freq = 1000,
.freq_smooth_enable = 1,
.wnr_enable = 0,
},
#endif
#if defined(SPEECH_TX_3MIC_NS3)
/****************************************************************************************************
* Describtion:
* 3 MICs Noise Suppression
* Parameters:
* bypass(0/1): bypass enable or disable.
* delay_taps(0~4): ceil{[d(MIC1~mouth) - d(MIC2~mouth)] / 2}.
* ceil: Returns the largest integer less than or equal to the specified data
* d(MIC~mouth): The dinstance from MIC to mouth
* e.g. 0: 0~2cm; 1: 2~4; 2: 5~6...
* freq_smooth_enable(1): Must enable
* wnr_enable(0/1): wind noise reduction enable or disable. This is also useful for improving
* noise suppression, but it also has some damage to speech signal.
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz, 32M;
* Note:
* None
****************************************************************************************************/
.tx_3mic_ns3 = {
.bypass = 0,
.endfire_enable = 1,
.broadside_enable = 1,
.delay_taps = 0.7f,
.freq_smooth_enable = 1,
.wnr_enable = 0,
},
#endif
#if defined(SPEECH_TX_NS)
/****************************************************************************************************
* Describtion:
* Noise Suppression
* Parameters:
* bypass(0/1): bypass enable or disable.
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz, 30M;
* Note:
* If possible, use SPEECH_TX_NS2 or SPEECH_TX_NS2FLOAT
****************************************************************************************************/
.tx_ns = {
.bypass = 0,
.denoise_dB = -12,
},
#endif
#if defined(SPEECH_TX_NS2)
/****************************************************************************************************
* Describtion:
* Noise Suppression
* Parameters:
* bypass(0/1): bypass enable or disable.
* denoise_dB(-30~0): noise suppression, unit(dB).
* e.g. -15: Can reduce 15dB of stationary noise.
* Resource consumption:
* RAM: fs = 16k: RAM = 8k;
* fs = 8k: RAM = 4k;
* RAM = frame_size * 30
* FLASE: None
* MIPS: fs = 16kHz, 16M;
* Note:
* None
****************************************************************************************************/
.tx_ns2 = {
.bypass = 0,
.denoise_dB = -15,
},
#endif
#if defined(SPEECH_TX_NS2FLOAT)
/****************************************************************************************************
* Describtion:
* Noise Suppression
* Parameters:
* bypass(0/1): bypass enable or disable.
* denoise_dB(-30~0): noise suppression, unit(dB).
* e.g. -15: Can reduce 15dB of stationary noise.
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz;
* Note:
* This is a 'float' version for SPEECH_TX_NS2.
* It needs more MIPS and RAM, but can redece quantization noise.
****************************************************************************************************/
.tx_ns2float = {
.bypass = 0,
.denoise_dB = -15,
.banks = 64,
},
#endif
#if defined(SPEECH_TX_NS3)
/****************************************************************************************************
* Describtion:
* Noise Suppression
* Parameters:
* bypass(0/1): bypass enable or disable.
* mode: None
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz;
* Note:
* None
****************************************************************************************************/
.tx_ns3 = {
.bypass = 0,
.mode = NS3_SUPPRESSION_HIGH,
},
#endif
#if defined(SPEECH_TX_WNR)
/****************************************************************************************************
* Describtion:
* Wind Noise Suppression
* Parameters:
* bypass(0/1): bypass enable or disable.
* lpf_cutoff: lowpass filter for wind noise detection
* hpf_cutoff: highpass filter for wind noise suppression
* power_ratio_thr: ratio of the power spectrum of the lower frequencies over the total power
spectrum for all frequencies
* power_thr: normalized power of the low frequencies
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz;
* Note:
* None
****************************************************************************************************/
.tx_wnr = {
.bypass = 0,
.lpf_cutoff = 1000,
.hpf_cutoff = 400,
.power_ratio_thr = 0.9f,
.power_thr = 1.f,
},
#endif
#if defined(SPEECH_TX_NOISE_GATE)
/****************************************************************************************************
* Describtion:
* Noise Gate
* Parameters:
* bypass(0/1): bypass enable or disable.
* data_threshold(0~32767): distinguish between noise and speech, unit(sample).
* data_shift(1~3): 1: -6dB; 2: -12dB; 3: -18dB
* factor_up(float): attack time, unit(s)
* factor_down(float): release time, unit(s)
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz;
* Note:
* None
****************************************************************************************************/
.tx_noise_gate = {
.bypass = 0,
.data_threshold = 640,
.data_shift = 1,
.factor_up = 0.001f,
.factor_down = 0.5f,
},
#endif
#if defined(SPEECH_TX_COMPEXP)
/****************************************************************************************************
* Describtion:
* Compressor and expander
* Parameters:
* bypass(0/1): bypass enable or disable.
* ...
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz;
* Note:
* None
****************************************************************************************************/
.tx_compexp = {
.bypass = 0,
.comp_threshold = -10.f,
.comp_ratio = 2.f,
.expand_threshold = -45.f,
.expand_ratio = 0.5556f,
.attack_time = 0.001f,
.release_time = 0.6f,
.makeup_gain = 6,
.delay = 128,
},
#endif
#if defined(SPEECH_TX_AGC)
/****************************************************************************************************
* Describtion:
* Automatic Gain Control
* Parameters:
* bypass(0/1): bypass enable or disable.
* target_level(>0): signal can not exceed (-1 * target_level)dB.
* compression_gain(>0): excepted gain.
* limiter_enable(0/1): 0: target_level does not take effect; 1: target_level takes effect.
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz, 3M;
* Note:
* None
****************************************************************************************************/
.tx_agc = {
.bypass = 0,
.target_level = 3,
.compression_gain = 6,
.limiter_enable = 1,
},
#endif
#if defined(SPEECH_TX_EQ)
/****************************************************************************************************
* Describtion:
* Equalizer, implementation with 2 order iir filters
* Parameters:
* bypass(0/1): bypass enable or disable.
* gain(float): normalized gain. It is usually less than or equal to 0
* num(0~6): the number of EQs
* params: {type, frequency, gain, q}. It supports a lot of types, please refer to iirfilt.h file
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz, 0.5M/section;
* Note:
* None
****************************************************************************************************/
.tx_eq = {
.bypass = 0,
.gain = 0.f,
.num = 1,
.params = {
{IIR_BIQUARD_HPF, {{60, 0, 0.707f}}},
},
},
#endif
#if defined(SPEECH_TX_POST_GAIN)
/****************************************************************************************************
* Describtion:
* Linear Gain
* Parameters:
* bypass(0/1): bypass enable or disable.
* Resource consumption:
* RAM: None
* FLASE: None
* MIPS: fs = 16kHz;
* Note:
* None
****************************************************************************************************/
.tx_post_gain = {
.bypass = 0,
.gain_dB = 6.0f,
},
#endif
// #if defined(SPEECH_CS_VAD)
// /****************************************************************************************************
// * Describtion:
// * Voice Activity Detector
// * Parameters:
// * bypass(0/1): bypass enable or disable.
// * Resource consumption:
// * RAM: None
// * FLASE: None
// * MIPS: fs = 16kHz;
// * Note:
// * None
// ****************************************************************************************************/
// .tx_vad = {
// .snrthd = 5.f,
// .energythd = 100.f,
// },
// #endif
#if defined(SPEECH_RX_NS)
/****************************************************************************************************
* Describtion:
* Acoustic Echo Cancellation
* Parameters:
* Refer to SPEECH_TX_NS
* Note:
* None
****************************************************************************************************/
.rx_ns = {
.bypass = 0,
.denoise_dB = -12,
},
#endif
#if defined(SPEECH_RX_NS2)
/****************************************************************************************************
* Describtion:
* Acoustic Echo Cancellation
* Parameters:
* Refer to SPEECH_TX_NS2
* Note:
* None
****************************************************************************************************/
.rx_ns2 = {
.bypass = 0,
.denoise_dB = -15,
},
#endif
#if defined(SPEECH_RX_NS2FLOAT)
/****************************************************************************************************
* Describtion:
* Acoustic Echo Cancellation
* Parameters:
* Refer to SPEECH_TX_NS2FLOAT
* Note:
* None
****************************************************************************************************/
.rx_ns2float = {
.bypass = 0,
.denoise_dB = -15,
.banks = 64,
},
#endif
#if defined(SPEECH_RX_NS3)
/****************************************************************************************************
* Describtion:
* Acoustic Echo Cancellation
* Parameters:
* Refer to SPEECH_TX_NS3
* Note:
* None
****************************************************************************************************/
.rx_ns3 = {
.bypass = 0,
.mode = NS3_SUPPRESSION_HIGH,
},
#endif
#if defined(SPEECH_RX_NOISE_GATE)
/****************************************************************************************************
* Describtion:
* Noise Gate
* Parameters:
* Refer to SPEECH_TX_NOISE_GATE
* Note:
* None
****************************************************************************************************/
.rx_noise_gate = {
.bypass = 0,
.data_threshold = 640,
.data_shift = 1,
.factor_up = 0.001f,
.factor_down = 0.5f,
},
#endif
#if defined(SPEECH_RX_COMPEXP)
/****************************************************************************************************
* Describtion:
* Compressor and expander
* Parameters:
* Refer to SPEECH_TX_COMPEXP
* Note:
* None
****************************************************************************************************/
.rx_compexp = {
.bypass = 0,
.comp_threshold = -10.f,
.comp_slope = 0.5f,
.expand_threshold = -40.f,
.expand_slope = -0.5f,
.attack_time = 0.01f,
.release_time = 0.6f,
.makeup_gain = 6,
.delay = 128,
},
#endif
#if defined(SPEECH_RX_AGC)
/****************************************************************************************************
* Describtion:
* Automatic Gain Control
* Parameters:
* Refer to SPEECH_TX_AGC
* Note:
* None
****************************************************************************************************/
.rx_agc = {
.bypass = 0,
.target_level = 3,
.compression_gain = 6,
.limiter_enable = 1,
},
#endif
#if defined(SPEECH_RX_EQ)
/****************************************************************************************************
* Describtion:
* Equalizer, implementation with 2 order iir filters
* Parameters:
* Refer to SPEECH_TX_EQ
* Note:
* None
****************************************************************************************************/
.rx_eq = {
.bypass = 0,
.gain = 0.f,
.num = 1,
.params = {
{IIR_BIQUARD_HPF, {{60, 0, 0.707f}}},
},
},
#endif
#if defined(SPEECH_RX_POST_GAIN)
/****************************************************************************************************
* Describtion:
* Linear Gain
* Parameters:
* Refer to SPEECH_TX_POST_GAIN
* Note:
* None
****************************************************************************************************/
.rx_post_gain = {
.bypass = 0,
.gain_dB = 6.0f,
},
#endif
};

View file

@ -0,0 +1,228 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
/**
* Usage:
* 1. Enable SCO_CP_ACCEL ?= 1 to enable dual core in sco
* 2. Enable SCO_TRACE_CP_ACCEL ?= 1 to see debug log.
* 3. Change channel number if the algo(run in cp) input is more than one channel: sco_cp_init(speech_tx_frame_len, 1);
* 4. The code between SCO_CP_ACCEL_ALGO_START(); and SCO_CP_ACCEL_ALGO_END(); will run in CP core.
* 5. These algorithms will work in AP. Need to move this algorithms from overlay to fast ram.
*
* NOTE:
* 1. spx fft and hw fft will share buffer, so just one core can use these fft.
* 2. audio_dump_add_channel_data function can not work correctly in CP core, because
* audio_dump_add_channel_data is possible called after audio_dump_run();
* 3. AP and CP just can use 85%
*
*
*
* TODO:
* 1. FFT, RAM, CODE overlay
**/
#if defined(SCO_CP_ACCEL)
#include "cp_accel.h"
#include "hal_location.h"
#include "hal_trace.h"
#include "hal_timer.h"
#include "cmsis_os.h"
#include "speech_cfg.h"
#include "math.h"
#include "norflash_api.h"
// malloc data from pool in init function
#define FRAME_LEN_MAX (256)
#define CHANNEL_NUM_MAX (2)
enum CP_SCO_STATE_T {
CP_SCO_STATE_NONE = 0,
CP_SCO_STATE_IDLE,
CP_SCO_STATE_WORKING,
};
enum SCO_CP_CMD_T {
SCO_CP_CMD_PRO = 0,
SCO_CP_CMD_OTHER,
SCO_CP_CMD_QTY,
};
static CP_DATA_LOC enum CP_SCO_STATE_T g_cp_state = CP_SCO_STATE_NONE;
// TODO: Use malloc to replace array
// static CP_BSS_LOC char g_cp_heap_buf[1024 * 100];
static CP_BSS_LOC short g_in_pcm_buf[FRAME_LEN_MAX * CHANNEL_NUM_MAX];
static CP_BSS_LOC short g_out_pcm_buf[FRAME_LEN_MAX * CHANNEL_NUM_MAX];
static CP_BSS_LOC short g_in_ref_buf[FRAME_LEN_MAX];
static CP_BSS_LOC int g_pcm_len;
static CP_BSS_LOC int g_frame_len;
static CP_BSS_LOC int g_channel_num;
static int g_require_cnt = 0;
static int g_run_cnt = 0;
int sco_cp_process(short *pcm_buf, short *ref_buf, int *_pcm_len)
{
int32_t pcm_len = *_pcm_len;
uint32_t wait_cnt = 0;
ASSERT(g_frame_len * g_channel_num == pcm_len, "[%s] g_frame_len(%d) * g_channel_num(%d) != pcm_len(%d)", __func__, g_frame_len, g_channel_num, pcm_len);
// Check CP has new data to get and can get data from buffer
#if defined(SCO_TRACE_CP_ACCEL)
TRACE(4,"[%s] g_require_cnt: %d, status: %d, pcm_len: %d", __func__, g_require_cnt, g_cp_state, pcm_len);
#endif
while (g_cp_state == CP_SCO_STATE_WORKING)
{
hal_sys_timer_delay_us(10);
if (wait_cnt++ > 300000) { // 3s
ASSERT(0, "cp is hung %d", g_cp_state);
}
}
if (g_cp_state == CP_SCO_STATE_IDLE)
{
speech_copy_int16(g_in_pcm_buf, pcm_buf, pcm_len);
if (ref_buf)
{
speech_copy_int16(g_in_ref_buf, ref_buf, pcm_len / g_channel_num);
}
speech_copy_int16(pcm_buf, g_out_pcm_buf, g_pcm_len);
*_pcm_len = g_pcm_len;
g_pcm_len = pcm_len;
g_require_cnt++;
g_cp_state = CP_SCO_STATE_WORKING;
cp_accel_send_event_mcu2cp(CP_BUILD_ID(CP_TASK_SCO, CP_EVENT_SCO_PROCESSING));
}
else
{
// Multi channels to one channel
#if 0
for (int i = 0; i < pcm_len / g_channel_num; i++)
{
pcm_buf[i] = pcm_buf[2*i];
}
*_pcm_len = pcm_len / g_channel_num;
#endif
// Check abs(g_require_cnt - g_run_cnt) > threshold, reset or assert
TRACE(2,"[%s] ERROR: status = %d", __func__, g_cp_state);
}
return 0;
}
extern int sco_cp_algo(short *pcm_buf, short *ref_buf, int *_pcm_len);
CP_TEXT_SRAM_LOC
static unsigned int sco_cp_main(uint8_t event)
{
#if defined(SCO_TRACE_CP_ACCEL)
TRACE(2,"[%s] g_run_cnt: %d", __func__, g_run_cnt);
#endif
// LOCK BUFFER
// process pcm
#if 0
// speech_copy_int16(g_out_pcm_buf, g_in_pcm_buf, g_pcm_len);
for (int i = 0; i < g_pcm_len; i++)
{
g_out_pcm_buf[i] = (short)(sinf(2 * 3.1415926 * i / 16 ) * 10000);
}
#else
sco_cp_algo(g_in_pcm_buf, g_in_ref_buf, &g_pcm_len);
speech_copy_int16(g_out_pcm_buf, g_in_pcm_buf, g_pcm_len);
#endif
// set status
g_run_cnt++;
g_cp_state = CP_SCO_STATE_IDLE;
#if defined(SCO_TRACE_CP_ACCEL)
TRACE(1,"[%s] CP_SCO_STATE_IDLE", __func__);
#endif
// UNLOCK BUFFER
return 0;
}
static struct cp_task_desc TASK_DESC_SCO = {CP_ACCEL_STATE_CLOSED, sco_cp_main, NULL, NULL, NULL};
int sco_cp_init(int frame_len, int channel_num)
{
TRACE(3,"[%s] frame_len: %d, channel_num: %d", __func__, frame_len, channel_num);
ASSERT(frame_len <= FRAME_LEN_MAX, "[%s] frame_len(%d) > FRAME_LEN_MAX", __func__, frame_len);
ASSERT(channel_num <= CHANNEL_NUM_MAX, "[%s] channel_num(%d) > CHANNEL_NUM_MAX", __func__, channel_num);
g_require_cnt = 0;
g_run_cnt = 0;
norflash_api_flush_disable(NORFLASH_API_USER_CP,(uint32_t)cp_accel_init_done);
cp_accel_open(CP_TASK_SCO, &TASK_DESC_SCO);
uint32_t cnt=0;
while(cp_accel_init_done() == false) {
hal_sys_timer_delay_us(100);
cnt++;
if (cnt % 10 == 0) {
if (cnt == 10 * 200) { // 200ms
ASSERT(0, "[%s] ERROR: Can not init cp!!!", __func__);
} else {
TRACE(1, "[%s] Wait CP init done...%d(ms)", __func__, cnt/10);
}
}
}
norflash_api_flush_enable(NORFLASH_API_USER_CP);
#if 0
speech_heap_cp_start();
speech_heap_add_block(g_cp_heap_buf, sizeof(g_cp_heap_buf));
speech_heap_cp_end();
#endif
g_frame_len = frame_len;
g_channel_num = channel_num;
g_pcm_len = frame_len; // Initialize output pcm_len
speech_set_int16(g_in_pcm_buf, 0, g_frame_len * g_channel_num);
speech_set_int16(g_out_pcm_buf, 0, g_frame_len * g_channel_num);
speech_set_int16(g_in_ref_buf, 0, g_frame_len);
g_cp_state = CP_SCO_STATE_IDLE;
TRACE(2,"[%s] status = %d", __func__, g_cp_state);
return 0;
}
int sco_cp_deinit(void)
{
TRACE(1,"[%s] ...", __func__);
cp_accel_close(CP_TASK_SCO);
g_cp_state = CP_SCO_STATE_NONE;
return 0;
}
#endif

View file

@ -0,0 +1,49 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __BT_SCO_CHAIN_CP_H__
#define __BT_SCO_CHAIN_CP_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
#include "stdbool.h"
// enum CP_EMPTY_OUT_FRM_T {
// CP_EMPTY_OUT_FRM_OK,
// CP_EMPTY_OUT_FRM_WORKING,
// CP_EMPTY_OUT_FRM_ERR,
// };
// typedef int (*A2DP_CP_DECODE_T)(void);
int sco_cp_init(int frame_len, int channel_num);
int sco_cp_deinit(void);
// int sco_cp_set_pcm(short *pcm_buf, int pcm_len);
// int sco_cp_get_pcm(short *pcm_buf, int pcm_len);
int sco_cp_process(short *pcm_buf, short *ref_buf, int *_pcm_len);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,155 @@
#include "bt_sco_chain.h"
#include "speech_memory.h"
#include "speech_utils.h"
#include "hal_trace.h"
#include "audio_dump.h"
#include "speech_cfg.h"
#if defined(SPEECH_TX_24BIT)
int32_t *aec_echo_buf = NULL;
// Use to free buffer
static int32_t *aec_echo_buf_ptr = NULL;
#else
short *aec_echo_buf = NULL;
// Use to free buffer
static short *aec_echo_buf_ptr;
#endif
#if defined(MSBC_8K_SAMPLE_RATE)
#define SPEECH_HEAP_RESERVE_SIZE (1024 * 4)
#else
#define SPEECH_HEAP_RESERVE_SIZE (1024 * 4)
#endif
#if defined(SPEECH_TX_DC_FILTER)
SpeechDcFilterState *speech_tx_dc_filter_st = NULL;
#endif
int speech_init(int tx_sample_rate, int rx_sample_rate,
int tx_frame_ms, int rx_frame_ms,
int sco_frame_ms,
uint8_t *buf, int len)
{
// we shoule keep a minmum buffer for speech heap
// MSBC_16K_SAMPLE_RATE = 0, 560 bytes
// MSBC_16K_SAMPLE_RATE = 1, 2568 bytes
speech_heap_init(buf, SPEECH_HEAP_RESERVE_SIZE);
uint8_t *free_buf = buf + SPEECH_HEAP_RESERVE_SIZE;
int free_len = len - SPEECH_HEAP_RESERVE_SIZE;
// use free_buf for your algorithm
memset(free_buf, 0, free_len);
int frame_len = SPEECH_FRAME_MS_TO_LEN(tx_sample_rate, tx_frame_ms);
#if defined(SPEECH_TX_24BIT)
aec_echo_buf = (int32_t *)speech_calloc(frame_len, sizeof(int32_t));
#else
aec_echo_buf = (short *)speech_calloc(frame_len, sizeof(short));
#endif
aec_echo_buf_ptr = aec_echo_buf;
#if defined(SPEECH_TX_DC_FILTER)
int channel_num = SPEECH_CODEC_CAPTURE_CHANNEL_NUM;
int data_separation = 0;
SpeechDcFilterConfig dc_filter_cfg = {
.bypass = 0,
.gain = 0.f,
};
speech_tx_dc_filter_st = speech_dc_filter_create(tx_sample_rate, frame_len, &dc_filter_cfg);
speech_dc_filter_ctl(speech_tx_dc_filter_st, SPEECH_DC_FILTER_SET_CHANNEL_NUM, &channel_num);
speech_dc_filter_ctl(speech_tx_dc_filter_st, SPEECH_DC_FILTER_SET_DATA_SEPARATION, &data_separation);
#endif
audio_dump_init(frame_len, sizeof(int16_t), 3);
return 0;
}
int speech_deinit(void)
{
#if defined(SPEECH_TX_DC_FILTER)
speech_dc_filter_destroy(speech_tx_dc_filter_st);
#endif
speech_free(aec_echo_buf_ptr);
size_t total = 0, used = 0, max_used = 0;
speech_memory_info(&total, &used, &max_used);
TRACE(3,"SPEECH MALLOC MEM: total - %d, used - %d, max_used - %d.", total, used, max_used);
ASSERT(used == 0, "[%s] used != 0", __func__);
return 0;
}
#if defined(BONE_SENSOR_TDM)
extern void bt_sco_get_tdm_buffer(uint8_t **buf, uint32_t *len);
#endif
int speech_tx_process(void *_pcm_buf, void *_ref_buf, int *_pcm_len)
{
#if defined(SPEECH_TX_24BIT)
int32_t *pcm_buf = (int32_t *)_pcm_buf;
int32_t *ref_buf = (int32_t *)_ref_buf;
#else
int16_t *pcm_buf = (int16_t *)_pcm_buf;
int16_t *ref_buf = (int16_t *)_ref_buf;
#endif
int pcm_len = *_pcm_len;
#if defined(BONE_SENSOR_TDM)
uint8_t *bone_buf = NULL;
uint32_t bone_len = 0;
bt_sco_get_tdm_buffer(&bone_buf, &bone_len);
#endif
audio_dump_clear_up();
audio_dump_add_channel_data(0, ref_buf, pcm_len / SPEECH_CODEC_CAPTURE_CHANNEL_NUM);
audio_dump_add_channel_data_from_multi_channels(1, pcm_buf, pcm_len / SPEECH_CODEC_CAPTURE_CHANNEL_NUM, SPEECH_CODEC_CAPTURE_CHANNEL_NUM, 0);
audio_dump_add_channel_data_from_multi_channels(2, pcm_buf, pcm_len / SPEECH_CODEC_CAPTURE_CHANNEL_NUM, SPEECH_CODEC_CAPTURE_CHANNEL_NUM, 1);
#if defined(BONE_SENSOR_TDM)
audio_dump_add_channel_data(3, bone_buf, pcm16_len/SPEECH_CODEC_CAPTURE_CHANNEL_NUM);
#endif
audio_dump_run();
#if defined(SPEECH_TX_DC_FILTER)
#if defined(SPEECH_TX_24BIT)
speech_dc_filter_process_int24(speech_tx_dc_filter_st, pcm_buf, pcm_len);
#else
speech_dc_filter_process(speech_tx_dc_filter_st, pcm_buf, pcm_len);
#endif
#endif
// Add your algrithm here and disable #if macro
#if 1
for (int i = 0, j = 0; i < pcm_len; i += SPEECH_CODEC_CAPTURE_CHANNEL_NUM, j++) {
// choose main microphone data
pcm_buf[j] = pcm_buf[i];
// choose reference data, i.e. loopback
//pcm16_buf[j] = ref16_buf[j];
}
pcm_len /= SPEECH_CODEC_CAPTURE_CHANNEL_NUM;
#endif
#if defined(BONE_SENSOR_TDM)
memcpy(pcm_buf, bone_buf, bone_len);
#endif
*_pcm_len = pcm_len;
return 0;
}
int speech_rx_process(void *pcm_buf, int *pcm_len)
{
// Add your algorithm here
return 0;
}

View file

@ -0,0 +1,192 @@
#include "bt_sco_chain.h"
#include "speech_memory.h"
#include "speech_utils.h"
#include "hal_trace.h"
#include "audio_dump.h"
#include "vcp-api.h"
#include "spf-postapi.h"
#define ALANGO_TRACE(s, ...) TRACE(1,"%s: " s, __FUNCTION__, ## __VA_ARGS__)
short *aec_echo_buf = NULL;
// Use to free buffer
static short *aec_echo_buf_ptr;
static void *mem;
extern void *voicebtpcm_get_ext_buff(int size);
extern char* vcp_errorv(err_t err);
extern PROFILE_TYPE(t) alango_profile;
static vcp_profile_t *curr_profile = NULL;
mem_reg_t reg[NUM_MEM_REGIONS];
#if SPEECH_CODEC_CAPTURE_CHANNEL_NUM >= 2
static int16_t *deinterleaved_buf = NULL;
static void deinterleave_audio(int16_t *dst, int16_t *src, uint32_t len, uint32_t ch_num)
{
uint32_t samples_per_channel = len / ch_num;
for (uint32_t i = 0; i < samples_per_channel; i++) {
for (uint32_t j = 0; j < ch_num; j++) {
dst[samples_per_channel * j + i] = src[ch_num * i + j];
}
}
}
#endif
int speech_init(int tx_sample_rate, int rx_sample_rate,
int tx_frame_ms, int rx_frame_ms,
int sco_frame_ms,
uint8_t *buf, int len)
{
speech_heap_init(buf, len);
int frame_len = SPEECH_FRAME_MS_TO_LEN(tx_sample_rate, tx_frame_ms);
aec_echo_buf = (short *)speech_calloc(frame_len, sizeof(short));
aec_echo_buf_ptr = aec_echo_buf;
// init alango
// check profile
curr_profile = &alango_profile;
err_t err = vcp_check_profile(curr_profile);
if (err.err) {
if (err.err == ERR_INVALID_CRC)
ALANGO_TRACE(0,"Profile error: Invalid CRC!");
else
ALANGO_TRACE(1,"Profile error: %d", err.err);
}
ASSERT(frame_len % curr_profile->p_gen->frlen == 0, "Profile error: frame_len(%d) should be divided by frlen(%d)", frame_len, curr_profile->p_gen->frlen);
unsigned int smem = vcp_get_hook_size();
mem = speech_malloc(smem);
vcp_get_mem_size(curr_profile, reg, mem);
ALANGO_TRACE(0,"Hello, I am VCP8!");
for (int i = 0; i < NUM_MEM_REGIONS; i++) {
reg[i].mem = (void *)speech_malloc(reg[i].size);
ALANGO_TRACE(2,"I need %d bytes of memory in memory region %d to work.\n", reg[i].size, i + 1);
}
err = vcp_init_debug(curr_profile, reg);
if (err.err == ERR_NOT_ENOUGH_MEMORY) {
ALANGO_TRACE(2,"%d more bytes needed in region %d!\n", -reg[err.pid].size, err.pid);
} else if (err.err == ERR_UNKNOWN) {
ALANGO_TRACE(0,"vcp_init_debug() returns UNKNOWN error\n!");
} else if (err.err != ERR_NO_ERROR) {
ALANGO_TRACE(2,"vcp_init_debug() returns error %d, pid %d!\n", err.err, err.pid);
}
#if SPEECH_CODEC_CAPTURE_CHANNEL_NUM >= 2
deinterleaved_buf = speech_malloc(curr_profile->p_gen->frlen * SPEECH_CODEC_CAPTURE_CHANNEL_NUM * sizeof(int16_t));
#endif
audio_dump_init(frame_len, sizeof(int16_t), 3);
return 0;
}
int speech_deinit(void)
{
speech_free(aec_echo_buf_ptr);
speech_free(mem);
for (int i = 0; i < NUM_MEM_REGIONS; i++)
speech_free(reg[i].mem);
#if SPEECH_CODEC_CAPTURE_CHANNEL_NUM >= 2
speech_free(deinterleaved_buf);
#endif
size_t total = 0, used = 0, max_used = 0;
speech_memory_info(&total, &used, &max_used);
TRACE(3,"SPEECH MALLOC MEM: total - %d, used - %d, max_used - %d.", total, used, max_used);
ASSERT(used == 0, "[%s] used != 0", __func__);
return 0;
}
#if defined(BONE_SENSOR_TDM)
extern void bt_sco_get_tdm_buffer(uint8_t **buf, uint32_t *len);
#endif
int speech_tx_process(void *pcm_buf, void *ref_buf, int *pcm_len)
{
int16_t *pcm16_buf = (int16_t *)pcm_buf;
int16_t *ref16_buf = (int16_t *)ref_buf;
int pcm16_len = *pcm_len;
#if defined(BONE_SENSOR_TDM)
uint8_t *bone_buf = NULL;
uint32_t bone_len = 0;
bt_sco_get_tdm_buffer(&bone_buf, &bone_len);
#endif
audio_dump_clear_up();
audio_dump_add_channel_data(0, ref_buf, pcm16_len / SPEECH_CODEC_CAPTURE_CHANNEL_NUM);
audio_dump_add_channel_data_from_multi_channels(1, pcm16_buf, pcm16_len / SPEECH_CODEC_CAPTURE_CHANNEL_NUM, SPEECH_CODEC_CAPTURE_CHANNEL_NUM, 0);
audio_dump_add_channel_data_from_multi_channels(2, pcm16_buf, pcm16_len / SPEECH_CODEC_CAPTURE_CHANNEL_NUM, SPEECH_CODEC_CAPTURE_CHANNEL_NUM, 1);
#if defined(BONE_SENSOR_TDM)
audio_dump_add_channel_data(3, bone_buf, pcm16_len/SPEECH_CODEC_CAPTURE_CHANNEL_NUM);
#endif
audio_dump_run();
// Add your algrithm here and disable #if macro
#if 0
for (int i = 0, j = 0; i < pcm16_len; i += SPEECH_CODEC_CAPTURE_CHANNEL_NUM, j++) {
// choose main microphone data
pcm16_buf[j] = pcm16_buf[i];
// choose reference data, i.e. loopback
//pcm16_buf[j] = ref16_buf[j];
}
pcm16_len /= SPEECH_CODEC_CAPTURE_CHANNEL_NUM;
#else
for (int i = 0, j = 0; i < pcm16_len; i += curr_profile->p_gen->frlen * SPEECH_CODEC_CAPTURE_CHANNEL_NUM, j += curr_profile->p_gen->frlen) {
#if SPEECH_CODEC_CAPTURE_CHANNEL_NUM >= 2
deinterleave_audio(deinterleaved_buf, &pcm16_buf[i], curr_profile->p_gen->frlen * SPEECH_CODEC_CAPTURE_CHANNEL_NUM, SPEECH_CODEC_CAPTURE_CHANNEL_NUM);
err_t err = vcp_process_tx(reg, deinterleaved_buf, &ref16_buf[j], &pcm16_buf[j]);
//memcpy(&pcm16_buf[j], deinterleaved_buf, curr_profile->p_gen->frlen * sizeof(int16_t));
#else
err_t err = vcp_process_tx(reg, &pcm16_buf[i], &ref16_buf[j], &pcm16_buf[j]);
#endif
if (err.err != ERR_NO_ERROR) {
ALANGO_TRACE(1,"vcp_process_tx error: %d", err.err);
}
}
pcm16_len /= SPEECH_CODEC_CAPTURE_CHANNEL_NUM;
#endif
#if defined(BONE_SENSOR_TDM)
memcpy(pcm_buf, bone_buf, bone_len);
#endif
*pcm_len = pcm16_len;
return 0;
}
int speech_rx_process(void *pcm_buf, int *pcm_len)
{
int16_t *pcm16_buf = (int16_t *)pcm_buf;
int pcm16_len = *pcm_len;
for (int i = 0; i < pcm16_len; i += curr_profile->p_gen->frlen) {
err_t err = vcp_process_rx(reg, &pcm16_buf[i], &pcm16_buf[i]);
if (err.err != ERR_NO_ERROR) {
ALANGO_TRACE(1,"vcp_process_tx error: %d", err.err);
}
}
return 0;
}

View file

@ -0,0 +1,224 @@
/***************************************************************************
*
* 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 "bt_sco_chain_cfg.h"
#include "aud_section.h"
#include "hal_trace.h"
static bool speech_tuning_status = false;
extern int speech_store_config(const SpeechConfig *cfg);
#ifdef AUDIO_SECTION_ENABLE
typedef struct {
uint8_t reserved[AUDIO_SECTION_CFG_RESERVED_LEN];
SpeechConfig cfg;
} AUDIO_SECTION_SPEECH_CFG_T;
static AUDIO_SECTION_SPEECH_CFG_T audio_section_speech_cfg;
int store_speech_cfg_into_audio_section(SpeechConfig *cfg)
{
int res = 0;
memcpy(&audio_section_speech_cfg.cfg, cfg, sizeof(SpeechConfig));
res = audio_section_store_cfg(AUDIO_SECTION_DEVICE_SPEECH,
(uint8_t *)&audio_section_speech_cfg,
sizeof(AUDIO_SECTION_SPEECH_CFG_T));
if(res)
{
TRACE(2,"[%s] ERROR: res = %d", __func__, res);
}
else
{
TRACE(1,"[%s] Store speech cfg into audio section!!!", __func__);
}
return res;
}
void *load_speech_cfg_from_audio_section(void)
{
int res = 0;
res = audio_section_load_cfg(AUDIO_SECTION_DEVICE_SPEECH,
(uint8_t *)&audio_section_speech_cfg,
sizeof(AUDIO_SECTION_SPEECH_CFG_T));
void *res_ptr = NULL;
if (res)
{
TRACE(2,"[%s] ERROR: res = %d", __func__, res);
res_ptr = NULL;
}
else
{
TRACE(1,"[%s] Load speech cfg from audio section!!!", __func__);
res_ptr = (void *)&audio_section_speech_cfg.cfg;
}
return res_ptr;
}
#endif
int speech_tuning_set_status(bool en)
{
speech_tuning_status = en;
return 0;
}
bool speech_tuning_get_status(void)
{
return speech_tuning_status;
}
uint32_t speech_tuning_check(unsigned char *buf, uint32_t len)
{
uint32_t res = 0;
// Check valid
uint32_t config_size = sizeof(SpeechConfig);
if (config_size != len)
{
TRACE(2,"[speech tuning] len(%d) != config_size(%d)", len, config_size);
res = 1;
}
else
{
TRACE(1,"[speech tuning] len(%d) is OK", len);
//SpeechConfig POSSIBLY_UNUSED *cfg = (SpeechConfig *)buf;
// Test parameters
//#if defined(SPEECH_TX_2MIC_NS2)
// TRACE(1,"[speech tuning] TX: delay_taps(x100): %d", (int)(cfg->tx_2mic_ns2.delay_taps * 100));
//#endif
//#if defined(SPEECH_TX_NOISE_GATE)
// TRACE(1,"[speech tuning] TX: data_threshold: %d", cfg->tx_noise_gate.data_threshold);
//#endif
//#if defined(SPEECH_TX_EQ)
// TRACE(1,"[speech tuning] TX: eq num: %d", cfg->tx_eq.num);
//#endif
//#if defined(SPEECH_RX_EQ)
// TRACE(1,"[speech tuning] RX: eq num: %d", cfg->rx_eq.num);
//#endif
}
return res;
}
uint32_t speech_tuning_rx_callback(unsigned char *buf, uint32_t len)
{
uint32_t res = 0;
res = speech_tuning_check(buf, len);
if (res)
{
TRACE(1,"[speech tuning] ERROR: Send check res = %d", res);
TRACE(0,"[Speech Tuning] res : 1; info : Send len(%d) != config_size(%d);", len, sizeof(SpeechConfig));
}
else
{
// Save cfg
speech_store_config((SpeechConfig *)buf);
// Set status
speech_tuning_set_status(true);
TRACE(0,"[speech tuning] OK: Send cfg");
TRACE(0,"[Speech Tuning] res : 0;");
}
return res;
}
#ifdef AUDIO_SECTION_ENABLE
uint32_t speech_tuning_burn_rx_callback(unsigned char *buf, uint32_t len)
{
uint32_t res = 0;
res = speech_tuning_check(buf, len);
if (res)
{
TRACE(1,"[speech tuning] ERROR: Burn check res = %d", res);
TRACE(0,"[Speech Tuning] res : 1; info : Burn len(%d) != config_size(%d);", len, sizeof(SpeechConfig));
}
else
{
res = store_speech_cfg_into_audio_section((SpeechConfig *)buf);
if(res)
{
TRACE(1,"[speech tuning] ERROR: Store res = %d", res);
res += 100;
TRACE(0,"[Speech Tuning] res : 2; info : Do not enable AUDIO_SECTION_ENABLE;");
}
else
{
TRACE(0,"[speech tuning] OK: Store cfg");
TRACE(0,"[Speech Tuning] res : 0;");
}
}
return res;
}
#endif
int speech_tuning_init(void)
{
#if defined(HAL_TRACE_RX_ENABLE) && !defined(SPEECH_TX_THIRDPARTY)
hal_trace_rx_register("Speech Tuning", (HAL_TRACE_RX_CALLBACK_T)speech_tuning_rx_callback);
#ifdef AUDIO_SECTION_ENABLE
hal_trace_rx_register("Speech Tuning Burn", (HAL_TRACE_RX_CALLBACK_T)speech_tuning_burn_rx_callback);
#endif
#endif
speech_tuning_set_status(false);
return 0;
}
int speech_tuning_open(void)
{
#ifdef AUDIO_SECTION_ENABLE
SpeechConfig *speech_cfg_load = NULL;
speech_cfg_load = (SpeechConfig *)load_speech_cfg_from_audio_section();
if (speech_cfg_load)
{
speech_store_config(speech_cfg_load);
}
#endif
speech_tuning_set_status(false);
return 0;
}
int speech_tuning_close(void)
{
speech_tuning_set_status(false);
return 0;
}

View file

@ -0,0 +1,40 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __BT_SCO_CHAIN_TUNING_H__
#define __BT_SCO_CHAIN_TUNING_H__
#ifdef __cplusplus
extern "C" {
#endif
// Initialize this module when platform setup
int speech_tuning_init(void);
// Open this module when speech stream open
int speech_tuning_open(void);
// Close this module when speech stream close
int speech_tuning_close(void);
bool speech_tuning_get_status(void);
int speech_tuning_set_status(bool en);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,264 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifdef MBED
#include "mbed.h"
#endif
// Standard C Included Files
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef MBED
//#include "rtos.h"
#endif
#ifdef MBED
#include "SDFileSystem.h"
#endif
#include "cqueue.h"
#include "hal_uart.h"
#include "hal_timer.h"
#include "hal_trace.h"
#include "app_audio.h"
// BT
#if 0
/* mutex */
osMutexId g_voicecvsd_queue_mutex_id = NULL;
osMutexDef(g_voicecvsd_queue_mutex);
/* cvsd queue */
#define VOICECVSD_TEMP_BUFFER_SIZE 128
#define VOICECVSD_QUEUE_SIZE (VOICECVSD_TEMP_BUFFER_SIZE*20)
CQueue voicecvsd_queue;
static enum APP_AUDIO_CACHE_T voicecvsd_cache_status = APP_AUDIO_CACHE_QTY;
#define LOCK_VOICECVSD_QUEUE() \
osMutexWait(g_voicecvsd_queue_mutex_id, osWaitForever)
#define UNLOCK_VOICECVSD_QUEUE() \
osMutexRelease(g_voicecvsd_queue_mutex_id)
void xLOCK_VOICECVSD_QUEUE(void)
{
osMutexWait(g_voicecvsd_queue_mutex_id, osWaitForever);
}
void xUNLOCK_VOICECVSD_QUEUE(void)
{
osMutexRelease(g_voicecvsd_queue_mutex_id);
}
//static void dump_buffer_to_psram(char *buf, unsigned int len)
//{
// static unsigned int offset = 0;
// memcpy((void *)(0x1c000000 + offset), buf, len);
//}
static void copy_one_trace_to_two_track_16bits(uint16_t *src_buf, uint16_t *dst_buf, uint32_t src_len)
{
uint32_t i = 0;
for (i = 0; i < src_len; ++i) {
dst_buf[i*2 + 0] = dst_buf[i*2 + 1] = src_buf[i];
}
}
int store_voicecvsd_buffer(unsigned char *buf, unsigned int len)
{
LOCK_VOICECVSD_QUEUE();
EnCQueue(&voicecvsd_queue, buf, len);
#if 0
dump_buffer_to_psram((char *)buf, len);
TRACE(1,"%d\n", LengthOfCQueue(&voicecvsd_queue));
#endif
if (LengthOfCQueue(&voicecvsd_queue) > VOICECVSD_TEMP_BUFFER_SIZE*10) {
voicecvsd_cache_status = APP_AUDIO_CACHE_OK;
}
UNLOCK_VOICECVSD_QUEUE();
return 0;
}
int store_voice_pcm2cvsd(unsigned char *buf, unsigned int len)
{
uint8_t cvsdtmpbuffer[VOICECVSD_TEMP_BUFFER_SIZE];
short * pBuffProcessed = (short *)buf;
uint32_t processed_len = 0;
uint32_t remain_len = 0;
len >>= 1;
LOCK_VOICECVSD_QUEUE();
while(processed_len < len){
remain_len = len-processed_len;
if (remain_len>VOICECVSD_TEMP_BUFFER_SIZE){
Pcm8kToCvsd(pBuffProcessed + processed_len, cvsdtmpbuffer, VOICECVSD_TEMP_BUFFER_SIZE);
EnCQueue(&voicecvsd_queue, cvsdtmpbuffer, VOICECVSD_TEMP_BUFFER_SIZE);
processed_len += VOICECVSD_TEMP_BUFFER_SIZE;
}else{
Pcm8kToCvsd(pBuffProcessed + processed_len, cvsdtmpbuffer, remain_len);
EnCQueue(&voicecvsd_queue, cvsdtmpbuffer, remain_len);
processed_len += remain_len;
}
}
UNLOCK_VOICECVSD_QUEUE();
#if 0
dump_buffer_to_psram((char *)buf, len);
TRACE(1,"%d\n", LengthOfCQueue(&voicecvsd_queue));
#endif
if (LengthOfCQueue(&voicecvsd_queue) > VOICECVSD_TEMP_BUFFER_SIZE*10) {
voicecvsd_cache_status = APP_AUDIO_CACHE_OK;
}
return 0;
}
int get_voicecvsd_buffer_size(void)
{
int n;
LOCK_VOICECVSD_QUEUE();
n = LengthOfCQueue(&voicecvsd_queue);
UNLOCK_VOICECVSD_QUEUE();
return n;
}
static short tmp_decode_buf[VOICECVSD_TEMP_BUFFER_SIZE*2];
int decode_cvsd_frame(unsigned char *pcm_buffer, unsigned int pcm_len)
{
uint32_t r = 0, decode_len = 0;
unsigned char *e1 = NULL, *e2 = NULL;
unsigned int len1 = 0, len2 = 0;
while (decode_len < pcm_len) {
get_again:
LOCK_VOICECVSD_QUEUE();
len1 = len2 = 0;
r = PeekCQueue(&voicecvsd_queue, VOICECVSD_TEMP_BUFFER_SIZE, &e1, &len1, &e2, &len2);
UNLOCK_VOICECVSD_QUEUE();
if(r == CQ_ERR || len1 == 0) {
//return 0;
Thread::wait(4);
goto get_again;
}
if (len1 != 0) {
//CvsdToPcm8k(e1, (short *)(pcm_buffer + decode_len*4), len1, 0);
CvsdToPcm8k(e1, (short *)(tmp_decode_buf), len1, 0);
copy_one_trace_to_two_track_16bits((uint16_t *)tmp_decode_buf, (uint16_t *)(pcm_buffer + decode_len), len1);
LOCK_VOICECVSD_QUEUE();
DeCQueue(&voicecvsd_queue, 0, len1);
UNLOCK_VOICECVSD_QUEUE();
decode_len += len1*4;
}
if (len2 != 0) {
//CvsdToPcm8k(e2, (short *)(pcm_buffer + decode_len*4), len2, 0);
CvsdToPcm8k(e2, (short *)(tmp_decode_buf), len2, 0);
copy_one_trace_to_two_track_16bits((uint16_t *)tmp_decode_buf, (uint16_t *)(pcm_buffer + decode_len), len2);
LOCK_VOICECVSD_QUEUE();
DeCQueue(&voicecvsd_queue, 0, len2);
UNLOCK_VOICECVSD_QUEUE();
decode_len += len2*4;
}
}
return 0;
}
uint32_t decode_cvsd_frame_noblock(uint8_t *pcm_buffer, uint32_t pcm_len)
{
unsigned int len[2];
uint8_t *e[2];
uint32_t decode_len = 0;
LOCK_VOICECVSD_QUEUE();
while (decode_len < pcm_len)
{
len[0] = len[1] = 0;
e[0] = e[1] = NULL;
if(PeekCQueue(&voicecvsd_queue, VOICECVSD_TEMP_BUFFER_SIZE, &e[0], &len[0], &e[1], &len[1]) == CQ_OK)
{
for(uint8_t i=0; i<2; i++)
{
if (len[i] != 0)
{
CvsdToPcm8k(e[i], (short *)(tmp_decode_buf), len[i], 0);
copy_one_trace_to_two_track_16bits((uint16_t *)tmp_decode_buf, (uint16_t *)(pcm_buffer + decode_len), len[i]);
DeCQueue(&voicecvsd_queue, 0, len[i]);
decode_len += len[i]*4;
}
}
}
else
{
break;
}
}
UNLOCK_VOICECVSD_QUEUE();
return decode_len;
}
uint32_t voicecvsd_audio_more_data(uint8_t *buf, uint32_t len)
{
uint32_t l = 0;
uint32_t cur_ticks = 0, ticks = 0;
if (voicecvsd_cache_status == APP_AUDIO_CACHE_CACHEING)
return 0;
TRACE(2,"%s enter reamin:%d", __func__, LengthOfCQueue(&voicecvsd_queue));
ticks = hal_sys_timer_get();
l = decode_cvsd_frame_noblock(buf, len);
cur_ticks = hal_sys_timer_get();
TRACE(3,"%s exit reamin:%d spend:%d\n", __func__, LengthOfCQueue(&voicecvsd_queue) ,TICKS_TO_MS(cur_ticks-ticks));
return l;
}
int voicecvsd_audio_init(void)
{
uint8_t *buff = NULL;
app_audio_mempool_get_buff(&buff, VOICECVSD_QUEUE_SIZE);
memset(buff, 0, VOICECVSD_QUEUE_SIZE);
/* voicebtpcm_pcm queue*/
APP_AUDIO_InitCQueue(&voicecvsd_queue, VOICECVSD_QUEUE_SIZE, buff);
Pcm8k_CvsdInit();
if (g_voicecvsd_queue_mutex_id == NULL)
{
g_voicecvsd_queue_mutex_id = osMutexCreate((osMutex(g_voicecvsd_queue_mutex)));
}
voicecvsd_cache_status = APP_AUDIO_CACHE_CACHEING;
}
#endif

View file

@ -0,0 +1,47 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
// Standard C Included Files
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include "cqueue.h"
#include "hal_uart.h"
#include "hal_timer.h"
#include "hal_trace.h"
uint8_t digmic_buf[100*1024];
uint32_t digmic_buf_len = 0;
uint32_t dig_mic_audio_more_data(uint8_t *buf, uint32_t len)
{
TRACE(2,"%s:%d\n", __func__, __LINE__);
memcpy(buf, digmic_buf, len);
return len;
}
uint32_t dig_mic_audio_data_come(uint8_t *buf, uint32_t len)
{
TRACE(2,"%s:%d\n", __func__, __LINE__);
memcpy(digmic_buf + digmic_buf_len, buf, len);
#if 1
digmic_buf_len = (digmic_buf_len + len)%(100*1024);
#endif
return len;
}

View file

@ -0,0 +1,138 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
// Standard C Included Files
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include "cqueue.h"
#include "hal_uart.h"
#include "hal_timer.h"
#include "hal_trace.h"
#ifdef RTOS
#include "cmsis_os.h"
#endif
/* mutex */
osMutexId g_flac_queue_mutex_id;
osMutexDef(g_flac_queue_mutex);
/* flac queue */
#define FLAC_TEMP_BUFFER_SIZE 2048
#define FLAC_QUEUE_SIZE (FLAC_TEMP_BUFFER_SIZE*4)
unsigned char flac_queue_buf[FLAC_QUEUE_SIZE];
CQueue flac_queue;
static uint32_t ok_to_decode = 0;
#define LOCK_FLAC_QUEUE() \
osMutexWait(g_flac_queue_mutex_id, osWaitForever)
#define UNLOCK_FLAC_QUEUE() \
osMutexRelease(g_flac_queue_mutex_id)
static void copy_one_trace_to_two_track_16bits(uint16_t *src_buf, uint16_t *dst_buf, uint32_t src_len)
{
uint32_t i = 0;
for (i = 0; i < src_len; ++i) {
dst_buf[i*2 + 0] = dst_buf[i*2 + 1] = src_buf[i];
}
}
int store_flac_buffer(unsigned char *buf, unsigned int len)
{
LOCK_FLAC_QUEUE();
EnCQueue(&flac_queue, buf, len);
if (LengthOfCQueue(&flac_queue) > FLAC_TEMP_BUFFER_SIZE*2) {
ok_to_decode = 1;
}
UNLOCK_FLAC_QUEUE();
return 0;
}
int decode_flac_frame(unsigned char *pcm_buffer, unsigned int pcm_len)
{
uint32_t r = 0, got_len = 0;
unsigned char *e1 = NULL, *e2 = NULL;
unsigned int len1 = 0, len2 = 0;
get_again:
LOCK_FLAC_QUEUE();
r = PeekCQueue(&flac_queue, (pcm_len - got_len)/2, &e1, &len1, &e2, &len2);
UNLOCK_FLAC_QUEUE();
if(r == CQ_ERR || len1 == 0) {
osDelay(2);
goto get_again;
}
//memcpy(pcm_buffer + got_len, e1, len1);
copy_one_trace_to_two_track_16bits((uint16_t *)e1, (uint16_t *)(pcm_buffer + got_len), len1/2);
LOCK_FLAC_QUEUE();
DeCQueue(&flac_queue, 0, len1);
UNLOCK_FLAC_QUEUE();
got_len += len1*2;
if (len2 != 0) {
//memcpy(pcm_buffer + got_len, e2, len2);
copy_one_trace_to_two_track_16bits((uint16_t *)e2, (uint16_t *)(pcm_buffer + got_len), len2/2);
LOCK_FLAC_QUEUE();
DeCQueue(&flac_queue, 0, len2);
UNLOCK_FLAC_QUEUE();
}
got_len += len2*2;
if (got_len < pcm_len)
goto get_again;
return pcm_len;
}
uint32_t flac_audio_data_come(uint8_t *buf, uint32_t len)
{
TRACE(1,"data come %d\n", len);
return 0;
}
uint32_t flac_audio_more_data(uint8_t *buf, uint32_t len)
{
uint32_t l = 0;
//uint32_t cur_ticks = 0, ticks = 0;
if (ok_to_decode == 0)
return 0;
//ticks = hal_sys_timer_get();
l = decode_flac_frame(buf, len);
//cur_ticks = hal_sys_timer_get();
// TRACE(1,"flac %d t\n", (cur_ticks-ticks));
return l;
}
int flac_audio_init(void)
{
g_flac_queue_mutex_id = osMutexCreate((osMutex(g_flac_queue_mutex)));
/* flac queue*/
InitCQueue(&flac_queue, FLAC_QUEUE_SIZE, (unsigned char *)&flac_queue_buf);
return 0;
}

View file

@ -0,0 +1,529 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifdef CHIP_BEST1000
#include "cmsis.h"
#include "cmsis_os.h"
#include "hal_trace.h"
#include "fmdec.h"
#include "hal_dma.h"
#include "hal_timer.h"
#include "hal_cmu.h"
#include "hal_analogif.h"
#include "hal_chipid.h"
#include "audioflinger.h"
#include "audiobuffer.h"
#include "cqueue.h"
#include "app_audio.h"
#include "app_utils.h"
#include "app_overlay.h"
#include "string.h"
#include "pmu.h"
//#define FM_DEBUG 1
#define FM_DIGITAL_REG(a) *(volatile uint32_t *)(a)
#define fm_read_rf_reg(reg,val) hal_analogif_reg_read(reg,val)
#define fm_write_rf_reg(reg,val) hal_analogif_reg_write(reg,val)
#define FM_FRAME_NUM 4
#define FM_SAMPLE_NUM NUMOFSAMPLE
#ifdef ATAN2_HARDWARE
#ifdef FM_NEWMODE
#define FM_SAMPLE_BUFFER_SIZE (FM_FRAME_NUM*FM_SAMPLE_NUM*4)
#else
#define FM_SAMPLE_BUFFER_SIZE (FM_FRAME_NUM*FM_SAMPLE_NUM/2*4)
#endif
#else
#define FM_SAMPLE_BUFFER_SIZE (FM_FRAME_NUM*FM_SAMPLE_NUM*4)
#endif
#define FM_AUDIO_BUFFER_SIZE (4096)
extern int app_bt_stream_local_volume_get(void);
static int32_t *fm_sample_buffer_p;
static void fm_handler(uint8_t chan, uint32_t remains, uint32_t error, struct HAL_DMA_DESC_T *lli)
{
static int cnt = 0;
int16_t fm_decbuf[(FM_SAMPLE_NUM/9)];
FmDemodulate((int16_t *)(fm_sample_buffer_p +((cnt%FM_FRAME_NUM)*FM_SAMPLE_NUM)), fm_decbuf,FM_SAMPLE_NUM);
cnt++;
app_audio_pcmbuff_put((uint8_t *)fm_decbuf, (FM_SAMPLE_NUM/9)<<1);
FmDemodulate((int16_t *)(fm_sample_buffer_p +((cnt%FM_FRAME_NUM)*FM_SAMPLE_NUM)), fm_decbuf,FM_SAMPLE_NUM);
cnt++;
app_audio_pcmbuff_put((uint8_t *)fm_decbuf, (FM_SAMPLE_NUM/9)<<1);
#ifdef FM_DEBUG
{
static uint32_t preTicks;
uint32_t diff_ticks = 0;
uint32_t cur_ticks;
cur_ticks = hal_sys_timer_get();
if (!preTicks){
preTicks = cur_ticks;
}else{
diff_ticks = TICKS_TO_MS(cur_ticks - preTicks);
preTicks = cur_ticks;
}
TRACE(3,"[fm_handler] diff=%d add:%d remain:%d input", diff_ticks, (FM_SAMPLE_NUM/9)<<1, app_audio_pcmbuff_length());
}
#endif
}
uint32_t fm_pcm_more_data(uint8_t *buf, uint32_t len)
{
app_audio_pcmbuff_get(buf, len);
#ifdef FM_DEBUG
{
static uint32_t preTicks;
uint32_t diff_ticks = 0;
uint32_t cur_ticks= hal_sys_timer_get();
if (!preTicks){
preTicks = cur_ticks;
}else{
diff_ticks = TICKS_TO_MS(cur_ticks - preTicks);
preTicks = cur_ticks;
}
TRACE(5,"[fm_pcm_more_data] diff=%d get:%d remain:%d output isr:0x%08x cnt:%d", diff_ticks, len/2, app_audio_pcmbuff_length(), FM_DIGITAL_REG(0x40160020), FM_DIGITAL_REG(0x40160028));
}
#endif
return 0;
}
uint32_t fm_capture_more_data(uint8_t *buf, uint32_t len)
{
fm_handler(0,0,0,NULL);
return len;
}
void fm_radio_digit_init(void)
{
FM_DIGITAL_REG(0xd0350244) = (FM_DIGITAL_REG(0xd0350244) & ~0x01fff) | 0x20f; //-890k -> 0 if_shift, for 110.5292m adc
// FM_DIGITAL_REG(0x40180e0c) = 0x34;
//FM_DIGITAL_REG(0x4000a050) = (FM_DIGITAL_REG(0x4000a050) & ~0x18000) | 0x18000;
#ifdef ATAN2_HARDWARE
FM_DIGITAL_REG(0xd0330038) |= (1 << 11);
FM_DIGITAL_REG(0xd0330038) |= (1 << 17);
FM_DIGITAL_REG(0xd0350248) = 0x80c00000;
// FM_DIGITAL_REG(0x40160030) = 1;
// FM_DIGITAL_REG(0x40160000) = 0x21;
#else
FM_DIGITAL_REG(0xd0330038) |= (1 << 11);
FM_DIGITAL_REG(0xd0350248) = 0x80c00000;
// FM_DIGITAL_REG(0x40160030) = 1;
// FM_DIGITAL_REG(0x40160000) = 1;
#endif
#ifdef SINGLECHANLE
//0x4000a010 bit2 写0 单channel dac
FM_DIGITAL_REG(0x4000a010) = (1 << 5) |(1<<4);
#else
FM_DIGITAL_REG(0x4000a010) = (1 << 5) | (1 << 2)|(1<<4);
#endif
FM_DIGITAL_REG(0x4000a020) = ~0UL;
FM_DIGITAL_REG(0x4000a02c) = 4;
FM_DIGITAL_REG(0x4000a030) = 4;
FM_DIGITAL_REG(0x4000a034) = (1 << 2) | (1 << 1) | (1 << 0);
// Start DAC
// FM_DIGITAL_REG(0x4000a010) |= (1 << 1);
#if 0
//52M
FM_DIGITAL_REG(0x40000060) |= (1 << 21);
FM_DIGITAL_REG(0x40000060) |= (1 << 24);
FM_DIGITAL_REG(0x40000060) |= (1 << 27);
FM_DIGITAL_REG(0x40000060) =(FM_DIGITAL_REG(0x40000060) & ~ (1 << 20));
FM_DIGITAL_REG(0x40000060) |= (1 << 29);
// FM_DIGITAL_REG(0x40000060) |= (1 << 27);
FM_DIGITAL_REG(0x40000064) = (FM_DIGITAL_REG(0x40000064) & ~0xFF) | 0x7A | (1 << 10) | (1<<30);
#endif
FM_DIGITAL_REG(0x4000a040) = 0xc0810000;
FM_DIGITAL_REG(0x4000a044) = 0x08040c04;
FM_DIGITAL_REG(0x4000a048) = 0x0e01f268;
FM_DIGITAL_REG(0x4000a04c) = 0x00005100;
// FM_DIGITAL_REG(0x40010010) = 0;
// FM_DIGITAL_REG(0x40010014) = 0x03a80005;
//FM_DIGITAL_REG(0x40010018) = 0x00200019;
FM_DIGITAL_REG(0x4000a050) = 0x24200000; //for adc_div_3_6 bypass
FM_DIGITAL_REG(0x4000a050) = (FM_DIGITAL_REG(0x4000a050) & ~0x780) | 0x380; // for channel 1 adc volume, bit10~7
FM_DIGITAL_REG(0x4000a050) = (FM_DIGITAL_REG(0x4000a050) & ~0x18000) | 0x18000; // for dual channel adc/dac
#ifdef SINGLECHANLE
//0x4000a050 bit16 写0 单channel dac for codec
FM_DIGITAL_REG(0x4000a050) =(FM_DIGITAL_REG(0x4000a050) & ~ (1 << 16));
#endif
FM_DIGITAL_REG(0x4000a048) = (FM_DIGITAL_REG(0x4000a048) & ~0x00000f00) | 0x40000900; //set for sdm gain
FM_DIGITAL_REG(0x4000a044) = (FM_DIGITAL_REG(0x4000a044) & ~0x60000000) | 0x60000000; //for adc en, and dac en
// Start DAC
FM_DIGITAL_REG(0x4000a010) |= (1 << 1);
// Delay 2 ms
// for (volatile int kk = 0; kk < 1000/64; kk++);
osDelay(2);
//hal_sys_timer_delay(MS_TO_TICKS(2));
// Start ADC
// FM_DIGITAL_REG(0x4000a010) |= (1 << 0);
#ifdef ATAN2_HARDWARE
#ifdef FM_NEWMODE
FM_DIGITAL_REG(0x40160030) = 1;
FM_DIGITAL_REG(0x40160000) = 0x1;
#else
FM_DIGITAL_REG(0x40160030) = 1;
FM_DIGITAL_REG(0x40160000) = 0x21;
#endif
#else
//start FM
FM_DIGITAL_REG(0x40160030) = 1;
FM_DIGITAL_REG(0x40160000) =1;
#endif
}
int fm_radio_analog_init(void)
{
int ret;
/*
// fm initial
rfspi_wvalue( 8'h2c , 16'b0111_0000_0101_1100 ) ; // dig_vtoi_en
rfspi_wvalue( 8'h01 , 16'b1010_1101_1111_1111 ) ; // power on fm lna
rfspi_wvalue( 8'h02 , 16'b1000_0000_1001_0100 ) ; // reg_fm_lna_pu_mixersw
rfspi_wvalue( 8'h1a , 16'b0101_0000_1011_0000 ) ; // reg_bt_vco_fm_buff_vctrl_dr=1
rfspi_wvalue( 8'h18 , 16'b0000_0110_1000_0000 ) ; // power on vco
rfspi_wvalue( 8'h19 , 16'b0110_0100_0100_0000 ) ; // reg_bt_vco_fm_buff_vctrl
rfspi_wvalue( 8'h1d , 16'b0111_1000_1010_0100 ) ; // reg_bt_rfpll_pu_dr
rfspi_wvalue( 8'h1c , 16'b0000_0000_1100_1000 ) ; // reg_bt_vco_fm_lo_en reg_bt_vco_fm_div_ctrl=8
rfspi_wvalue( 8'h0a , 16'b0001_0010_0010_1111 ) ; // reg_btfm_flt_fm_en
rfspi_wvalue( 8'h2d , 16'b0000_0111_1000_0010 ) ; // bb ldo on reg_bb_ldo_pu_vddr15a_dr
rfspi_wvalue( 8'h07 , 16'b0000_0010_1011_1001 ) ; // reg_btfm_flt_pu_dr
rfspi_wvalue( 8'h2a , 16'b0001_0110_1100_0000 ) ; // reg_bt_rfpll_sdm_freq_dr
rfspi_wvalue( 8'h26 , 16'b0000_0000_0000_0000 ) ; // vco freq[31:16] ( 2400 + x )*2^25/26MHZ*N (2400+x= frf)
rfspi_wvalue( 8'h25 , 16'b0000_0000_0000_0000 ) ; // vco freq[15:00] fm_freq = frf/(4*reg_bt_vco_fm_div_ctrl)
rfspi_wvalue( 8'h17 , 16'b1000_0000_0000_0000 ) ; // reg_bt_vco_calen
*/
fm_write_rf_reg( 0x2c , 0b0111000001011100 ) ; // dig_vtoi_en
fm_write_rf_reg( 0x01 , 0b1010110111111111 ) ; // power on fm lna
fm_write_rf_reg( 0x02 , 0b1000000010010100 ) ; // reg_fm_lna_pu_mixersw
fm_write_rf_reg( 0x1a , 0b0101000010110000 ) ; // reg_bt_vco_fm_buff_vctrl_dr=1
fm_write_rf_reg( 0x18 , 0b0000011010000000 ) ; // power on vco
fm_write_rf_reg( 0x19 , 0b0110010001000000 ) ; // reg_bt_vco_fm_buff_vctrl
fm_write_rf_reg( 0x1d , 0b0111100010100100 ) ; // reg_bt_rfpll_pu_dr
fm_write_rf_reg( 0x1c , 0b0000000011001000 ) ; // reg_bt_vco_fm_lo_en reg_bt_vco_fm_div_ctrl=8
fm_write_rf_reg( 0x0a , 0b0001001000101111 ) ; // reg_btfm_flt_fm_en
fm_write_rf_reg( 0x2d , 0b0000011110000010 ) ; // bb ldo on reg_bb_ldo_pu_vddr15a_dr
fm_write_rf_reg( 0x07 , 0b0000001010111001 ) ; // reg_btfm_flt_pu_dr
fm_write_rf_reg( 0x2a , 0b0001011011000000 ) ; // reg_bt_rfpll_sdm_freq_dr
fm_write_rf_reg( 0x26 , 0b0000000000000000 ) ; // vco freq[31:16] ( 2400 + x )*2^25/26MHZ*N (2400+x= frf)
fm_write_rf_reg( 0x25 , 0b0000000000000000 ) ; // vco freq[15:00] fm_freq = frf/(4*reg_bt_vco_fm_div_ctrl)
fm_write_rf_reg( 0x17 , 0b1000000000000000 ) ; // reg_bt_vco_calen
//adc也要开的话需要配 cmu
//0x40000060[29] = 1 最好先读再写否则把别的bit冲掉了。
//需要配置的spi寄存器ana interface:
//0x05 = 0xFCB1 // Audio Pll
//0x06 = 0x881C
//0x31 = 0x0100 // audio_freq_en
//0x37 = 0x1000 // codec_bbpll1_fm_adc_clk_en
//0x31 = 0x0130 // codec_tx_en_ldac codec_tx_en_rdac
ret = fm_write_rf_reg(0x05 , 0xfcb1);
if (ret) {
return ret;
}
ret = fm_write_rf_reg(0x06 , 0x881c);
if (ret) {
return ret;
}
ret = fm_write_rf_reg(0x3a , 0xe644);
if (ret) {
return ret;
}
ret = fm_write_rf_reg(0x31 , 0x0100);
if (ret) {
return ret;
}
ret = fm_write_rf_reg(0x37 , 0x1000);
if (ret) {
return ret;
}
ret = fm_write_rf_reg(0x31 , 0x01f0);
if (ret) {
return ret;
}
//delay 32ms
osDelay(32);
ret = fm_write_rf_reg(0x31 , 0x0130);
if (ret) {
return ret;
}
//[FM_RX]
fm_write_rf_reg(0x01,0x91ff); //pu fm
fm_write_rf_reg(0x2d,0x07fa); //ldo on
fm_write_rf_reg(0x2e,0x6aaa); //tune fm filter IF
fm_write_rf_reg(0x02,0xe694);
fm_write_rf_reg(0x03,0xfe3a);
fm_write_rf_reg(0x04,0x52a8);
fm_write_rf_reg(0x07,0x02b9);
fm_write_rf_reg(0x0a,0x1a2c);
fm_write_rf_reg(0x0b,0x402b);
fm_write_rf_reg(0x0c,0x7584);
fm_write_rf_reg(0x0e,0x0000);
fm_write_rf_reg(0x0f,0x2e18);
fm_write_rf_reg(0x10,0x02b4);
fm_write_rf_reg(0x13,0x0a48);
//[vco init]
fm_write_rf_reg(0x18,0x077f);
fm_write_rf_reg(0x19,0x3ff8);
fm_write_rf_reg(0x1a,0xc090);
fm_write_rf_reg(0x1b,0x0f88);
fm_write_rf_reg(0x1c,0x04c6); //[3:0] 5,6,7,8 --> vco/2
return 0;
}
void fm_radio_poweron(void)
{
hal_cmu_reset_clear(HAL_CMU_MOD_BTCPU);
osDelay(2000);
{
//wakp interface
unsigned short read_val;
fm_read_rf_reg(0x50, &read_val);
}
pmu_fm_config(1);
fm_write_rf_reg(0x0c, 0x3584);
if(hal_get_chip_metal_id() == HAL_CHIP_METAL_ID_2 || hal_get_chip_metal_id() == HAL_CHIP_METAL_ID_3) ////
{
FM_DIGITAL_REG(0xc00003b4)=0x00060020;//turn off bt sleep
}
else if(hal_get_chip_metal_id() == HAL_CHIP_METAL_ID_4)
{
FM_DIGITAL_REG(0xc00003b0)=0x00060020;//turn off bt sleep
}
else
{
FM_DIGITAL_REG(0xc00003ac)=0x00060020;//turn off bt sleep
}
FM_DIGITAL_REG(0xd0330038) = 0x00008D0D;
FM_DIGITAL_REG(0xd0340020)=0x010E01C0;// open ana rxon for open adc clk
//fm_write_rf_reg(0x02, 0xe694);
}
void* fm_radio_get_ext_buff(int size)
{
uint8_t *pBuff = NULL;
size = size+size%4;
app_audio_mempool_get_buff(&pBuff, size);
return (void*)pBuff;
}
int fm_radio_player(bool on)
{
static struct AF_STREAM_CONFIG_T stream_cfg;
static bool isRun = false;
uint8_t *buff = NULL;
TRACE(2,"fm_radio_player work:%d op:%d", isRun, on);
if (isRun==on)
return 0;
if (on){
app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_52M);
app_audio_mempool_init();
fm_radio_poweron();
fm_radio_analog_init();
fm_radio_digit_init();
osDelay(200);
buff = (uint8_t *)fm_radio_get_ext_buff(FM_AUDIO_BUFFER_SIZE*2);
app_audio_pcmbuff_init(buff, FM_AUDIO_BUFFER_SIZE*2);
fm_sample_buffer_p = (int32_t *)fm_radio_get_ext_buff(FM_SAMPLE_BUFFER_SIZE);
#if FPGA==0
app_overlay_select(APP_OVERLAY_FM);
#endif
memset(&stream_cfg, 0, sizeof(stream_cfg));
stream_cfg.vol = app_bt_stream_local_volume_get();
stream_cfg.handler = fm_capture_more_data;
stream_cfg.data_ptr = (uint8_t *)fm_sample_buffer_p;
stream_cfg.data_size = FM_SAMPLE_BUFFER_SIZE;
stream_cfg.device = AUD_STREAM_USE_DPD_RX;
af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE, &stream_cfg);
af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
memset(&stream_cfg, 0, sizeof(stream_cfg));
buff = (uint8_t *)fm_radio_get_ext_buff(FM_AUDIO_BUFFER_SIZE);
stream_cfg.bits = AUD_BITS_16;
stream_cfg.channel_num = AUD_CHANNEL_NUM_1;
stream_cfg.sample_rate = AUD_SAMPRATE_48000;
#if FPGA==0
stream_cfg.device = AUD_STREAM_USE_INT_CODEC;
#else
stream_cfg.device = AUD_STREAM_USE_EXT_CODEC;
#endif
stream_cfg.io_path = AUD_OUTPUT_PATH_SPEAKER;
stream_cfg.vol = app_bt_stream_local_volume_get();
stream_cfg.handler = fm_pcm_more_data;
stream_cfg.data_ptr = buff;
stream_cfg.data_size = FM_AUDIO_BUFFER_SIZE;
af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg);
af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
}else{
af_stream_stop(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
af_stream_close(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
af_stream_stop(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
af_stream_close(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_32K);
}
isRun=on;
return 0;
}
int fm_tune(uint32_t freqkhz)
{
uint32_t reg;
unsigned long long tmp = 0;
//[rfpll_cal]
fm_write_rf_reg(0x21,0x3979); // ref sel 52MHz
fm_write_rf_reg(0x22,0x7A22); // doubler setting
fm_write_rf_reg(0x23,0x0380);
fm_write_rf_reg(0x2b,0x32a0); // sdm
fm_write_rf_reg(0x2a,0x12d1); // cal ini
//(freq(Mhz)-0.89(Mhz))*(2^28)*3/26
tmp = freqkhz;
reg =(((tmp-890))<<27)*3/13/1000;
fm_write_rf_reg(0x25, (reg&0xffff0000)>>16);
fm_write_rf_reg(0x26, reg&0x0000ffff);
fm_write_rf_reg(0x1d,0x58e4); // pll_cal_en
fm_write_rf_reg(0xf7,0x5597); // rst and enable pll_cal clk
fm_write_rf_reg(0xf7,0x55d7); // rst and enable pll_cal clk
fm_write_rf_reg(0x1d,0x7ae4); // pll cal start
fm_write_rf_reg(0xff,0x0000); // wait 100us
osDelay(20);
fm_write_rf_reg(0x1d,0x7ac4); // close pll loop
return 0;
}
void fm_test_main(void)
{
fm_radio_player(true);
osDelay(20);
fm_tune(90500);
}
#endif

View file

@ -0,0 +1,32 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __APP_AUDIO_H__
#define __FMRADIO_H__
#ifdef __cplusplus
extern "C" {
#endif
int fm_radio_player(bool on);
void fm_tune(uint32_t freqkhz);
#ifdef __cplusplus
}
#endif
#endif//__FMRADIO_H__

View file

@ -0,0 +1,152 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
// Standard C Included Files
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include "cmsis_os.h"
#include "cqueue.h"
#include "hal_uart.h"
#include "hal_timer.h"
#include "hal_trace.h"
// BT
#if 0
/* mutex */
osMutexId g_voicemsbc_queue_mutex_id;
osMutexDef(g_voicemsbc_queue_mutex);
/* msbc queue */
#define VOICEMSBC_TEMP_BUFFER_SIZE 128
#define VOICEMSBC_QUEUE_SIZE (VOICEMSBC_TEMP_BUFFER_SIZE*100)
unsigned char voicemsbc_queue_buf[VOICEMSBC_QUEUE_SIZE];
CQueue voicemsbc_queue;
static uint32_t ok_to_decode = 0;
#define LOCK_VOICEMSBC_QUEUE() \
osMutexWait(g_voicemsbc_queue_mutex_id, osWaitForever)
#define UNLOCK_VOICEMSBC_QUEUE() \
osMutexRelease(g_voicemsbc_queue_mutex_id)
static void dump_buffer_to_psram(char *buf, unsigned int len)
{
static unsigned int offset = 0;
memcpy((void *)(0x1c000000 + offset), buf, len);
}
static void copy_one_trace_to_two_track_16bits(uint16_t *src_buf, uint16_t *dst_buf, uint32_t src_len)
{
uint32_t i = 0;
for (i = 0; i < src_len; ++i) {
dst_buf[i*2 + 0] = dst_buf[i*2 + 1] = src_buf[i];
}
}
int store_voicemsbc_buffer(unsigned char *buf, unsigned int len)
{
LOCK_VOICEMSBC_QUEUE();
EnCQueue(&voicemsbc_queue, buf, len);
dump_buffer_to_psram((char *)buf, len);
TRACE(1,"%d\n", LengthOfCQueue(&voicemsbc_queue));
if (LengthOfCQueue(&voicemsbc_queue) > VOICEMSBC_TEMP_BUFFER_SIZE*20) {
ok_to_decode = 1;
}
UNLOCK_VOICEMSBC_QUEUE();
return 0;
}
static short tmp_decode_buf[VOICEMSBC_TEMP_BUFFER_SIZE*2];
int decode_msbc_frame(unsigned char *pcm_buffer, unsigned int pcm_len)
{
int r = 0;
uint32_t decode_len = 0;
unsigned char *e1 = NULL, *e2 = NULL;
unsigned int len1 = 0, len2 = 0;
while (decode_len < pcm_len) {
get_again:
LOCK_VOICEMSBC_QUEUE();
len1 = len2 = 0;
r = PeekCQueue(&voicemsbc_queue, VOICEMSBC_TEMP_BUFFER_SIZE, &e1, &len1, &e2, &len2);
UNLOCK_VOICEMSBC_QUEUE();
if(r == CQ_ERR || len1 == 0) {
//return 0;
Thread::wait(4);
goto get_again;
}
if (len1 != 0) {
//msbcToPcm8k(e1, (short *)(pcm_buffer + decode_len*4), len1, 0);
CvsdToPcm8k(e1, (short *)(tmp_decode_buf), len1, 0);
copy_one_trace_to_two_track_16bits((uint16_t *)tmp_decode_buf, (uint16_t *)(pcm_buffer + decode_len), len1);
LOCK_VOICEMSBC_QUEUE();
DeCQueue(&voicemsbc_queue, 0, len1);
UNLOCK_VOICEMSBC_QUEUE();
decode_len += len1*4;
}
if (len2 != 0) {
//msbcToPcm8k(e2, (short *)(pcm_buffer + decode_len*4), len2, 0);
CvsdToPcm8k(e2, (short *)(tmp_decode_buf), len2, 0);
copy_one_trace_to_two_track_16bits((uint16_t *)tmp_decode_buf, (uint16_t *)(pcm_buffer + decode_len), len2);
LOCK_VOICEMSBC_QUEUE();
DeCQueue(&voicemsbc_queue, 0, len2);
UNLOCK_VOICEMSBC_QUEUE();
decode_len += len2*4;
}
}
return 0;
}
uint32_t voicemsbc_audio_more_data(uint8_t *buf, uint32_t len)
{
uint32_t l = 0;
uint32_t cur_ticks = 0, ticks = 0;
if (ok_to_decode == 0)
return 0;
ticks = hal_sys_timer_get();
l = decode_msbc_frame(buf, len);
cur_ticks = hal_sys_timer_get();
TRACE(1,"msbc %d t\n", (cur_ticks-ticks));
return l;
}
int voicemsbc_audio_init(void)
{
Pcm8k_CvsdInit();
g_voicemsbc_queue_mutex_id = osMutexCreate((osMutex(g_voicemsbc_queue_mutex)));
/* msbc queue*/
InitCQueue(&voicemsbc_queue, VOICEMSBC_QUEUE_SIZE, (unsigned char *)&voicemsbc_queue_buf);
return 0;
}
#endif

View file

@ -0,0 +1,328 @@
#include <stdbool.h>
#include <string.h>
#include "plc_utils.h"
#include "hal_trace.h"
#if defined(CHIP_BEST1400) || defined(CHIP_BEST1402) || defined(CHIP_BEST2300P) || defined(CHIP_BEST2300A)
#define MSBC_MUTE_PATTERN (0x55)
#else
#define MSBC_MUTE_PATTERN (0x00)
#endif
#define MSBC_PKTSIZE (60)
/*
* msbc frame's last byte is a padding byte, we assume it is zero,
* but it is not always true.
* Do not check this by default
*/
//#define ENABLE_PAD_CHECK
/*
* if msbc frame is filled by 10+ samples in the trail, crc maybe not detect this
* satuation.
* Do not check this by default
*/
//#define ENABLE_TRAILING_ZERO_CHECK
/*
*
*/
#define ENABLE_BLE_CONFLICT_CHECK
#define ENABLE_CRC_CHECK
/* check msbc sequence number */
#define ENABLE_SEQ_CHECK
#ifdef ENABLE_CRC_CHECK
static const uint8_t sbc_crc_tbl[256] = {
0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53, 0xE8, 0xF5, 0xD2, 0xCF,
0x9C, 0x81, 0xA6, 0xBB, 0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E,
0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76, 0x87, 0x9A, 0xBD, 0xA0,
0xF3, 0xEE, 0xC9, 0xD4, 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C,
0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19, 0xA2, 0xBF, 0x98, 0x85,
0xD6, 0xCB, 0xEC, 0xF1, 0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40,
0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8, 0xDE, 0xC3, 0xE4, 0xF9,
0xAA, 0xB7, 0x90, 0x8D, 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65,
0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7, 0x7C, 0x61, 0x46, 0x5B,
0x08, 0x15, 0x32, 0x2F, 0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A,
0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2, 0x26, 0x3B, 0x1C, 0x01,
0x52, 0x4F, 0x68, 0x75, 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D,
0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8, 0x03, 0x1E, 0x39, 0x24,
0x77, 0x6A, 0x4D, 0x50, 0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2,
0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A, 0x6C, 0x71, 0x56, 0x4B,
0x18, 0x05, 0x22, 0x3F, 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7,
0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66, 0xDD, 0xC0, 0xE7, 0xFA,
0xA9, 0xB4, 0x93, 0x8E, 0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB,
0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43, 0xB2, 0xAF, 0x88, 0x95,
0xC6, 0xDB, 0xFC, 0xE1, 0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09,
0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C, 0x97, 0x8A, 0xAD, 0xB0,
0xE3, 0xFE, 0xD9, 0xC4
};
#endif
static int sco_parse_synchronization_header(uint8_t *buf, uint8_t *sn)
{
uint8_t sn1, sn2;
#ifdef ENABLE_CRC_CHECK
uint8_t fcs = 0x0F;
uint8_t crc = 0;
uint8_t i, sb, bit, shift;
uint8_t ind = 6, bitOffset = 24;
#endif
*sn = 0xff;
#if defined(MSBC_SYNC_HACKER)
if (((buf[0] != 0x01) && (buf[0] != 0x00)) ||
((buf[1] & 0x0f) != 0x08) ||
(buf[2] != 0xad)) {
return -1;
}
#else
if ((buf[0] != 0x01) ||
((buf[1] & 0x0f) != 0x08) ||
(buf[2] != 0xad)) {
return -1;
}
#endif
sn1 = (buf[1] & 0x30) >> 4;
sn2 = (buf[1] & 0xc0) >> 6;
if ((sn1 != 0) && (sn1 != 0x3)) {
return -2;
}
if ((sn2 != 0) && (sn2 != 0x3)) {
return -3;
}
#ifdef ENABLE_CRC_CHECK
fcs = sbc_crc_tbl[fcs ^ buf[3]];
if (buf[3] != 0x00)
return -4;
fcs = sbc_crc_tbl[fcs ^ buf[4]];
if (buf[4] != 0x00)
return -4;
crc = buf[5];
for (sb = 0; sb < 8; sb++) {
if (bitOffset % 8) {
/* Sum the whole byte */
fcs = sbc_crc_tbl[fcs ^ buf[ind]];
ind = ind + 1;
}
else {
if (sb == 7) {
/* Sum the next 4 bits */
/* Just sum the most significant 4 bits */
shift = 7;
for (i = 0; i < 4; i++) {
bit = (uint8_t)((0x01 & (buf[ind] >> shift--)) ^ (fcs >> 7));
if (bit) {
fcs = (uint8_t)(((fcs << 1) | bit) ^ 0x1C);
}
else {
fcs = (uint8_t)((fcs << 1));
}
}
}
}
bitOffset += 4;
}
//TRACE(2,"msbc crc:%d fcs:%d", crc,fcs);
if (crc != fcs)
return -4;
#endif
*sn = (sn1 & 0x01) | (sn2 & 0x02);
#ifdef ENABLE_PAD_CHECK
// when pad error detected, we should return sn
if (buf[MSBC_PKTSIZE - 1] != 0x0) {
return -5;
}
#endif
return 0;
}
#ifdef ENABLE_BLE_CONFLICT_CHECK
static bool memcmp_U8(uint8_t *x, uint8_t *y, uint16_t size)
{
for (int i = 0; i < size; i++) {
if (x[i] != y[i])
return true;
}
return false;
}
// when signal is mute, msbc data remains the same except seq num. We should check history flag,
// otherwise a single conflict may be detected twice
static bool update_ble_sco_conflict(PacketLossState* st, uint8_t *last_pkt, uint8_t *pkt)
{
// do not check padding byte as it maybe useless when msbc_offset is 1
bool ret = (st->prev_ble_sco_conflict_flag[1] == false && memcmp_U8(last_pkt, pkt, MSBC_PKTSIZE - 1) == false);
memcpy(&last_pkt[0], &last_pkt[MSBC_PKTSIZE], MSBC_PKTSIZE);
memcpy(&last_pkt[MSBC_PKTSIZE], pkt, MSBC_PKTSIZE);
return ret;
}
static bool check_ble_sco_conflict(PacketLossState* st, bool ret)
{
st->prev_ble_sco_conflict_flag[1] = st->prev_ble_sco_conflict_flag[0];
st->prev_ble_sco_conflict_flag[0] = ret;
return ret;
}
#endif
static bool msbc_check_controller_mute_pattern(uint8_t *pkt, uint8_t pattern)
{
// do not check padding byte as it maybe useless when msbc_offset is 1
for (int i = 0; i < MSBC_PKTSIZE - 1; i++)
if (pkt[i] != pattern)
return false;
return true;
}
#ifdef ENABLE_TRAILING_ZERO_CHECK
static int msbc_check_pkt_trailing_zeros(uint8_t *pkt)
{
int idx = MSBC_PKTSIZE;
for (int i = MSBC_PKTSIZE - 1; i >= 0; i--) {
if (pkt[i] != 0) {
idx = i;
break;
}
}
return (MSBC_PKTSIZE - 1 - idx);
}
#endif
static uint8_t get_next_sequence_num(uint8_t seq_num)
{
return (seq_num + 1 == 4) ? 0 : (seq_num + 1);
}
void packet_loss_detection_init(PacketLossState *st)
{
st->last_seq_num = 0xff;
memset(st->last_pkt, 0, sizeof(st->last_pkt));
memset(st->prev_ble_sco_conflict_flag, 0, sizeof(st->prev_ble_sco_conflict_flag));
memset(st->hist, 0, sizeof(st->hist));
}
plc_type_t packet_loss_detection_process(PacketLossState *st, uint8_t *sbc_buf)
{
plc_type_t plc_type = PLC_TYPE_PASS;
#ifdef ENABLE_BLE_CONFLICT_CHECK
bool ble_sco_conflict = update_ble_sco_conflict(st, st->last_pkt, sbc_buf);
#endif
uint8_t seq_num;
if (msbc_check_controller_mute_pattern(sbc_buf, MSBC_MUTE_PATTERN) == true) {
plc_type = PLC_TYPE_CONTROLLER_MUTE;
st->last_seq_num = 0xff;
}
#ifdef ENABLE_BLE_CONFLICT_CHECK
else if (check_ble_sco_conflict(st, ble_sco_conflict) == true) {
plc_type = PLC_TYPE_BLE_CONFLICT;
st->last_seq_num = 0xff;
}
#endif
else {
int err = sco_parse_synchronization_header(sbc_buf, &seq_num);
if (err < 0 && err >= -3) {
plc_type = PLC_TYPE_HEADER_ERROR;
st->last_seq_num = 0xff;
}
#ifdef ENABLE_CRC_CHECK
else if (err == -4) {
plc_type = PLC_TYPE_CRC_ERROR;
st->last_seq_num = 0xff;
}
#endif
#ifdef ENABLE_PAD_CHECK
else if (err == -5) {
plc_type = PLC_TYPE_PAD_ERROR;
st->last_seq_num = seq_num;
}
#endif
#ifdef ENABLE_TRAILING_ZERO_CHECK
else if (msbc_check_pkt_trailing_zeros(sbc_buf) > 10) {
plc_type = PLC_TYPE_DATA_MISSING;
st->last_seq_num = 0xff;
}
#endif
else {
#ifdef ENABLE_SEQ_CHECK
if (st->last_seq_num == 0xff) {
if (seq_num == 0xff) {
plc_type = PLC_TYPE_SEQUENCE_DISCONTINUE;
}
else {
plc_type = PLC_TYPE_PASS;
}
st->last_seq_num = seq_num;
}
else {
if (seq_num == 0xff) {
st->last_seq_num = 0xff;
plc_type = PLC_TYPE_SEQUENCE_DISCONTINUE;
}
else if (seq_num == get_next_sequence_num(st->last_seq_num)) {
st->last_seq_num = seq_num;
plc_type = PLC_TYPE_PASS;
}
else {
st->last_seq_num = 0xff;
plc_type = PLC_TYPE_SEQUENCE_DISCONTINUE;
}
}
#else
plc_type = PLC_TYPE_PASS;
#endif
}
}
packet_loss_detection_update_histogram(st, plc_type);
return plc_type;
}
void packet_loss_detection_update_histogram(PacketLossState *st, plc_type_t plc_type)
{
if (plc_type < 0 || plc_type >= PLC_TYPE_NUM) {
TRACE(2,"[%s] plc type %d is invalid", __FUNCTION__, plc_type);
return;
}
// The packet is detected as PLC_TYPE_PASS, but causes a decoder error.
if (plc_type == PLC_TYPE_DECODER_ERROR) {
st->hist[0] -= 1;
}
st->hist[plc_type] += 1;
}
void packet_loss_detection_report(PacketLossState *st)
{
uint32_t packet_loss_num = 0;
for (uint8_t i = 1; i < PLC_TYPE_NUM; i++) {
TRACE(3,"[%s] plc type %d occurs %d times", __FUNCTION__, i, st->hist[i]);
packet_loss_num += st->hist[i];
}
uint32_t packet_total_num = st->hist[0] + packet_loss_num;
TRACE(4,"[%s] packet loss percent %d/10000(%d/%d)", __FUNCTION__,
(int32_t)(10000.f * packet_loss_num/ packet_total_num), packet_loss_num, packet_total_num);
}

View file

@ -0,0 +1,54 @@
#ifndef PLC_UTILS_H
#define PLC_UTILS_H
#include <stdint.h>
#include <stdbool.h>
typedef enum plc_type
{
PLC_TYPE_PASS = 0,
PLC_TYPE_CONTROLLER_MUTE,
PLC_TYPE_HEADER_ERROR,
PLC_TYPE_CRC_ERROR,
PLC_TYPE_PAD_ERROR,
PLC_TYPE_DATA_MISSING,
PLC_TYPE_SEQUENCE_DISCONTINUE,
PLC_TYPE_BLE_CONFLICT,
PLC_TYPE_DECODER_ERROR,
PLC_TYPE_NUM,
} plc_type_t;
typedef struct
{
uint8_t last_seq_num;
uint8_t last_pkt[60 * 2];
// for ble sco conflict
bool prev_ble_sco_conflict_flag[2];
// histogram
uint32_t hist[PLC_TYPE_NUM];
} PacketLossState;
#ifdef __cplusplus
extern "C" {
#endif
void packet_loss_detection_init(PacketLossState *st);
plc_type_t packet_loss_detection_process(PacketLossState *st, uint8_t *sbc_buf);
/*
* Update plc type histogram
* Normally this function is called at the end of packet_loss_detection_process,
* but if a decoder error occurs outside, it should be updated maually.
*/
void packet_loss_detection_update_histogram(PacketLossState *st, plc_type_t plc_type);
void packet_loss_detection_report(PacketLossState *st);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,887 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
/* rbplay source */
/* playback control & rockbox codec porting & codec thread */
#ifdef MBED
#include "mbed.h"
#include "rtos.h"
#endif
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <unistd.h>
#include "SDFileSystem.h"
#include "hal_uart.h"
#include "hal_timer.h"
#include "hal_trace.h"
#include "audioflinger.h"
#include "cqueue.h"
#include "app_audio.h"
#include "eq.h"
#include "pga.h"
#include "metadata.h"
#include "dsp_core.h"
#include "codecs.h"
#include "codeclib.h"
#include "compressor.h"
#include "channel_mode.h"
#include "audiohw.h"
#include "codec_platform.h"
#include "metadata_parsers.h"
#include "hal_overlay.h"
#include "app_overlay.h"
#include "rbpcmbuf.h"
#include "rbplay.h"
#include "app_thread.h"
#include "app_utils.h"
#include "app_key.h"
#include "rbplaysd.h"
#include "rb_ctl.h"
/* Internals */
void rb_ctl_wait_lock_thread(bool lock);
void app_rbcodec_ctl_set_play_status(bool st);
extern bool app_rbcodec_check_hfp_active(void );
#include "SDFileSystem.h"
extern "C" void hal_sysfreq_print(void);
#define _LOG_TAG "[rb_ctl] "
#undef __attribute__(a)
#define RBPLAY_DEBUG 1
#if RBPLAY_DEBUG
#define _LOG_DBG(str,...) TRACE(0,_LOG_TAG""str, ##__VA_ARGS__)
#define _LOG_ERR(str,...) TRACE(0,_LOG_TAG"err:"""str, ##__VA_ARGS__)
#else
#define _LOG_DBG(str,...)
#define _LOG_ERR(str,...) TRACE(0,_LOG_TAG"err:"""str, ##__VA_ARGS__)
#endif
#include "rb_ctl.h"
void rb_thread_send_resume(void);
typedef struct {
uint32_t evt;
uint32_t arg;
} RBCTL_MSG_BLOCK;
static osThreadId rb_ctl_tid;
static void rb_ctl_thread(void const *argument);
static int rb_ctl_default_priority;
osThreadDef(rb_ctl_thread, osPriorityHigh, 1, 1024 * 4, "rb_ctl");
#define RBCTL_MAILBOX_MAX (20)
osMailQDef (rb_ctl_mailbox, RBCTL_MAILBOX_MAX, RBCTL_MSG_BLOCK);
static osMailQId rb_ctl_mailbox = NULL;
int rb_ctl_mailbox_put(RBCTL_MSG_BLOCK* msg_src);
//playlist
extern playlist_struct sd_playlist;
rb_ctl_struct rb_ctl_context;
extern void rb_thread_set_decode_vars(int fd, int type ,void* id3);
extern void rb_play_codec_run(void);
extern void rb_codec_set_halt(int halt);
extern void rb_player_sync_set_wait_thread(osThreadId tid);
extern void rb_player_sync_wait_close(void );
extern bool rb_pcmbuf_suspend_play_loop(void);
void app_rbplay_load_playlist(playlist_struct *list );
int rb_thread_post_msg(RB_MODULE_EVT evt,uint32_t arg );
static rb_ctl_status rb_ctl_get_status(void)
{
return rb_ctl_context.status;
}
bool rb_ctl_parse_file(const char* file_path)
{
/* open file */
_LOG_DBG(1,"open file %s\n", file_path);
rb_ctl_context.file_handle = open((const char *)file_path, O_RDWR);
if (rb_ctl_context.file_handle <= 0) {
_LOG_DBG(1,"open file %s failed\n", file_path);
return false;
}
if (!get_metadata(&rb_ctl_context.song_id3, rb_ctl_context.file_handle, rb_ctl_context.rb_fname)) {
_LOG_DBG(0,"get_metadata failed\n");
close(rb_ctl_context.file_handle);
return false;
}
_LOG_DBG(4,"%s bitr:%d,saps %d, freq:%d\n",__func__,rb_ctl_context.song_id3.bitrate,rb_ctl_context.song_id3.samples,rb_ctl_context.song_id3.frequency);
rb_thread_set_decode_vars(rb_ctl_context.file_handle, rb_ctl_context.song_id3.codectype,&rb_ctl_context.song_id3);
return true;
}
void rb_ctl_vol_operation(bool inc )
{
uint32_t ret;
struct AF_STREAM_CONFIG_T *stream_cfg = NULL;
_LOG_DBG(2,"%s inc:%d , ",__func__,inc);
if(inc ) {
if(rb_ctl_context.rb_player_vol < 16 ) {
rb_ctl_context.rb_player_vol++;
}
} else {
if(rb_ctl_context.rb_player_vol > 1 ) {
rb_ctl_context.rb_player_vol--;
}
}
if(rb_ctl_context.status != RB_CTL_PLAYING)
return ;
ret = af_stream_get_cfg(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg, true);
if (ret == 0) {
stream_cfg->vol = rb_ctl_context.rb_player_vol;
af_stream_setup(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, stream_cfg);
}
}
bool rb_ctl_is_playing(void)
{
return (rb_ctl_context.status == RB_CTL_PLAYING);
}
void rb_ctl_set_vol(uint32_t vol)
{
uint32_t ret;
struct AF_STREAM_CONFIG_T *stream_cfg = NULL;
_LOG_DBG(2,"%s set vol as :%d , ",__func__,vol);
if(rb_ctl_context.status != RB_CTL_PLAYING)
return ;
vol = (vol > 16)?16:vol;
rb_ctl_context.rb_player_vol = vol;
ret = af_stream_get_cfg(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg, true);
if (ret == 0) {
stream_cfg->vol = rb_ctl_context.rb_player_vol;
af_stream_setup(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, stream_cfg);
}
}
void rb_ctl_stop_play(void )
{
_LOG_DBG(1,"%s \n",__func__);
rb_codec_set_halt(1);
//close file
_LOG_DBG(0," af stream stop \n");
af_stream_stop(AUD_STREAM_ID_0,AUD_STREAM_PLAYBACK);
_LOG_DBG(0," af stream close \n");
af_stream_close(AUD_STREAM_ID_0,AUD_STREAM_PLAYBACK);
_LOG_DBG(0," close file \n");
if(rb_ctl_context.file_handle != -1)
close(rb_ctl_context.file_handle );
rb_ctl_context.file_handle = -1;
//release frequency
_LOG_DBG(0," release freq \n");
return ;
}
void rb_ctl_sync_stop_play(void )
{
rb_player_sync_set_wait_thread(osThreadGetId());
rb_ctl_stop_play();
rb_player_sync_wait_close();
//close file
_LOG_DBG(0," close file \n");
if(rb_ctl_context.file_handle != -1)
close(rb_ctl_context.file_handle );
rb_ctl_context.file_handle = -1;
}
void rb_ctl_pause_playing(void )
{
af_stream_stop(AUD_STREAM_ID_0,AUD_STREAM_PLAYBACK);
_LOG_DBG(0," af stream close \n");
af_stream_close(AUD_STREAM_ID_0,AUD_STREAM_PLAYBACK);
//wait decoder suspend
//osDelay(200);
// while(!rb_pcmbuf_suspend_play_loop()) {
//osThreadYield();
// osDelay(1);
// }
_LOG_DBG(1,"%s sucessed ",__func__);
}
void rb_ctl_resume_playing(void )
{
#ifndef __TWS__
rb_pcmbuf_init();
#endif
}
void rb_ctl_set_priority(int priority)
{
osThreadSetPriority(rb_ctl_tid, (osPriority)priority);
}
int rb_ctl_get_priority(void)
{
return (int)osThreadGetPriority(rb_ctl_tid);
}
int rb_ctl_get_default_priority(void)
{
return rb_ctl_default_priority;
}
void rb_ctl_reset_priority(void)
{
osThreadSetPriority(rb_ctl_tid, (osPriority)rb_ctl_default_priority);
}
#ifdef __IAG_BLE_INCLUDE__
extern "C" void app_ble_inform_music_switch(uint16_t index);
#endif
static int rb_ctl_handle_event(RBCTL_MSG_BLOCK *msg_body)
{
RB_MODULE_EVT evt =(RB_MODULE_EVT) msg_body->evt;
uint32_t arg = msg_body->arg;
// hal_sysfreq_print();
switch(evt) {
case RB_MODULE_EVT_PLAY:
if(rb_ctl_context.status != RB_CTL_IDLE) {
if(rb_ctl_context.status == RB_CTL_SUSPEND)
rb_thread_send_resume();
else
_LOG_DBG(2,"%s st %d not in idle \n",__func__,rb_ctl_context.status);
break;
}
_LOG_DBG(3," %s start %d/%d ",__func__, rb_ctl_context.curr_song_idx ,sd_playlist.total_songs);
if(sd_playlist.total_songs > 0 ) {
playlist_item *it;
it = app_rbplay_get_playitem(rb_ctl_context.curr_song_idx) ;
if(it == NULL) {
_LOG_DBG(2," %s get item fail idx %d",__func__,rb_ctl_context.curr_song_idx);
}
_LOG_DBG(2,"%s start songidx %d \n",__func__,rb_ctl_context.curr_song_idx);
memcpy(rb_ctl_context.rb_audio_file,it->file_path,sizeof(uint16_t)*FILE_PATH_LEN - 4);
memcpy(rb_ctl_context.rb_fname,it->file_name,sizeof(rb_ctl_context.rb_fname));
if(rb_ctl_parse_file((const char*)rb_ctl_context.rb_audio_file)) {
_LOG_DBG(2,"%s start init, the tid 0x%x\n",__func__,osThreadGetId());
rb_play_codec_init();
_LOG_DBG(1,"%s start run\n",__func__);
rb_play_codec_run();
rb_ctl_context.status = RB_CTL_PLAYING;
app_rbcodec_ctl_set_play_status(true);
break;
} else {
_LOG_DBG(2,"%s evt %d parse fail,find next\n",__func__,msg_body->evt);
rb_thread_post_msg(RB_MODULE_EVT_PLAY_NEXT,true);
}
} else {
_LOG_DBG(2,"%s evt %d no songs\n",__func__,msg_body->evt);
}
break;
case RB_MODULE_EVT_STOP:
if(rb_ctl_context.status == RB_CTL_IDLE) {
_LOG_DBG(2,"%s st %d in idle \n",__func__,rb_ctl_context.status);
break;
}
if(rb_ctl_context.status == RB_CTL_SUSPEND) {
//osDelay(100);
rb_ctl_resume_playing();
rb_ctl_context.status = RB_CTL_PLAYING;
}
rb_ctl_sync_stop_play();
rb_ctl_context.status = RB_CTL_IDLE;
app_rbcodec_ctl_set_play_status(false);
break;
case RB_MODULE_EVT_SUSPEND:
if (rb_ctl_context.status != RB_CTL_PLAYING) {
_LOG_DBG(2,"%s st %d not running \n",__func__,rb_ctl_context.status);
break;
}
rb_ctl_pause_playing();
rb_ctl_context.status = RB_CTL_SUSPEND;
break;
case RB_MODULE_EVT_RESUME:
if (rb_ctl_context.status != RB_CTL_SUSPEND) {
_LOG_DBG(2,"%s st %d not suspend \n",__func__,rb_ctl_context.status);
break;
}
rb_ctl_resume_playing();
rb_ctl_context.status = RB_CTL_PLAYING;
break;
case RB_MODULE_EVT_PLAY_NEXT:
if( rb_ctl_context.status == RB_CTL_PLAYING) {
rb_thread_post_msg(RB_MODULE_EVT_STOP,0 );
} else if( rb_ctl_context.status == RB_CTL_SUSPEND) {
rb_thread_post_msg(RB_MODULE_EVT_STOP,0 );
} else {
}
if(arg == 0) {
rb_ctl_context.curr_song_idx--;
if(rb_ctl_context.curr_song_idx == 0xffff)
rb_ctl_context.curr_song_idx = sd_playlist.total_songs -1;
} else {
rb_ctl_context.curr_song_idx++;
if(rb_ctl_context.curr_song_idx >= sd_playlist.total_songs)
rb_ctl_context.curr_song_idx = 0;
}
#ifdef __IAG_BLE_INCLUDE__
app_ble_inform_music_switch(rb_ctl_context.curr_song_idx);
#endif
rb_thread_post_msg(RB_MODULE_EVT_PLAY,0 );
break;
case RB_MODULE_EVT_CHANGE_VOL:
rb_ctl_vol_operation(arg);
break;
case RB_MODULE_EVT_SET_VOL:
rb_ctl_set_vol(arg);
break;
case RB_MODULE_EVT_CHANGE_IDLE:
rb_ctl_stop_play();
rb_ctl_context.status = RB_CTL_IDLE;
break;
case RB_MODULE_EVT_PLAY_IDX:
if(arg > sd_playlist.total_songs -1 ) {
break;
}
if( rb_ctl_context.status == RB_CTL_PLAYING) {
rb_thread_post_msg(RB_MODULE_EVT_STOP,0 );
} else if( rb_ctl_context.status == RB_CTL_SUSPEND) {
rb_thread_post_msg(RB_MODULE_EVT_STOP,0 );
} else {
}
rb_ctl_context.curr_song_idx = (uint16_t)arg;
rb_thread_post_msg(RB_MODULE_EVT_PLAY,0 );
break;
//for voice cocah
#if 0
case SBCREADER_ACTION_INIT:
//prepare fs
voiceCocah_prepare_fs();
//init the data buff
voiceCocah_read_sbc_data();
break;
case SBCREADER_ACTION_RUN:
//fill sbc queue
voiceCocah_read_sbc_data();
break;
case SBCREADER_ACTION_STOP:
//release the res
voiceCocah_stop_clean();
rb_ctl_reset_priority();
break;
#endif
#ifdef __TWS__
case RB_MODULE_EVT_RESTORE_DUAL_PLAY:
extern void rb_restore_dual_play(uint8_t stream_type);
rb_restore_dual_play(arg);
break;
#endif
case RB_MODULE_EVT_DEL_FILE:
static rb_ctl_status prev_status = rb_ctl_context.status;
if( rb_ctl_context.status == RB_CTL_PLAYING) {
rb_thread_post_msg(RB_MODULE_EVT_STOP,0 );
rb_thread_post_msg(RB_MODULE_EVT_DEL_FILE,arg);
} else if( rb_ctl_context.status == RB_CTL_SUSPEND) {
rb_thread_post_msg(RB_MODULE_EVT_STOP,0 );
rb_thread_post_msg(RB_MODULE_EVT_DEL_FILE,arg);
} else {
app_ctl_remove_file(arg);
if(prev_status == RB_CTL_PLAYING) {
rb_thread_post_msg(RB_MODULE_EVT_PLAY,0 );
}
}
break;
#if defined(TWS_LINEIN_PLAYER)
case RB_MODULE_EVT_LINEIN_START:
extern int app_linein_codec_start(void);
app_linein_codec_start();
break;
case RB_MODULE_EVT_RECONFIG_STREAM:
extern void rb_tws_reconfig_stream(uint32_t arg);
rb_tws_reconfig_stream(arg);
break;
case RB_MODULE_EVT_SET_TWS_MODE:
break;
#endif
#ifdef SBC_RECORD_TEST
case SBC_RECORD_ACTION_START:
{
rb_ctl_context.sbc_record_on = true;
app_rbplay_set_store_flag(true);
app_rbplay_open_sbc_file();
}
break;
case SBC_RECORD_ACTION_DATA_IND:
{
if(rb_ctl_context.sbc_record_on) {
app_rbplay_process_sbc_data();
}
}
break;
case SBC_RECORD_ACTION_STOP:
{
rb_ctl_context.sbc_record_on = false;
app_rbplay_set_store_flag(false);
app_rbplay_close_sbc_file();
}
break;
#endif
default:
break;
}
if(SBC_RECORD_ACTION_DATA_IND !=msg_body->evt)
_LOG_DBG(3,"%s rbcodec evt %d ,st %d ended\n",__func__,msg_body->evt,rb_ctl_context.status);
return 0;
}
int rb_thread_post_msg(RB_MODULE_EVT evt,uint32_t arg )
{
int ret;
RBCTL_MSG_BLOCK msg;
if(!rb_ctl_tid)
return 0;
/* APIs */
msg.evt = (uint32_t)evt;
msg.arg = (uint32_t)arg;
ret = rb_ctl_mailbox_put(&msg);
_LOG_DBG(3,"%s ret %d evt:%d\n",__func__,ret ,evt);
return 0;
}
void app_wait_player_stoped(void )
{
while(rb_ctl_context.status != RB_CTL_IDLE)
osThreadYield();
}
void app_wait_player_suspend(void )
{
if(rb_ctl_context.status == RB_CTL_IDLE)
return;
while(rb_ctl_context.status != RB_CTL_SUSPEND)
osThreadYield();
}
void app_wait_player_resumed(void )
{
if(rb_ctl_context.status == RB_CTL_IDLE)
return;
while(rb_ctl_context.status != RB_CTL_PLAYING)
osThreadYield();
}
void rb_thread_send_play(void )
{
_LOG_DBG(1," %s ",__FUNCTION__);
rb_thread_post_msg(RB_MODULE_EVT_PLAY, (uint32_t)osThreadGetId());
}
void rb_thread_send_stop(void )
{
_LOG_DBG(1," %s ",__FUNCTION__);
rb_thread_post_msg(RB_MODULE_EVT_STOP, (uint32_t)osThreadGetId());
osDelay(200);
app_wait_player_stoped();
}
void rb_thread_send_pause(void)
{
_LOG_DBG(1," %s ",__FUNCTION__);
rb_thread_post_msg(RB_MODULE_EVT_SUSPEND,(uint32_t)osThreadGetId());
app_wait_player_suspend();
_LOG_DBG(1," %s end",__FUNCTION__);
}
void rb_thread_send_resume(void)
{
_LOG_DBG(1," %s ",__FUNCTION__);
rb_thread_post_msg(RB_MODULE_EVT_RESUME,(uint32_t)osThreadGetId());
_LOG_DBG(1," %s end",__FUNCTION__);
}
void rb_play_dual_play_restore(uint8_t stream_type )
{
_LOG_DBG(2,"%s %d \n", __func__, __LINE__);
rb_thread_post_msg(RB_MODULE_EVT_RESTORE_DUAL_PLAY, stream_type);
_LOG_DBG(2,"%s %d \n", __func__, __LINE__);
}
void rb_thread_send_switch(bool next)
{
_LOG_DBG(2,"%s %d \n", __func__, __LINE__);
rb_thread_post_msg(RB_MODULE_EVT_PLAY_NEXT,next);
_LOG_DBG(2,"%s %d \n", __func__, __LINE__);
}
void rb_play_linein_start(void )
{
_LOG_DBG(2,"%s %d \n", __func__, __LINE__);
rb_thread_post_msg(RB_MODULE_EVT_LINEIN_START, 0);
_LOG_DBG(2,"%s %d \n", __func__, __LINE__);
}
void rb_play_reconfig_stream(uint32_t arg )
{
_LOG_DBG(3,"%s %d arg:0x%x\n", __func__, __LINE__, arg);
rb_thread_post_msg(RB_MODULE_EVT_RECONFIG_STREAM, arg);
_LOG_DBG(2,"%s %d \n", __func__, __LINE__);
}
void rb_play_set_tws_mode(uint32_t arg )
{
_LOG_DBG(3,"%s %d arg:0x%x\n", __func__, __LINE__, arg);
rb_thread_post_msg(RB_MODULE_EVT_SET_TWS_MODE, arg);
_LOG_DBG(2,"%s %d \n", __func__, __LINE__);
}
void rb_thread_send_play_idx(uint32_t array_subidx)
{
_LOG_DBG(2," %s array_subidx %d, ",__FUNCTION__,array_subidx);
rb_thread_post_msg(RB_MODULE_EVT_PLAY_IDX,array_subidx);
}
void rb_thread_send_vol(bool inc)
{
_LOG_DBG(2," %s inc %d, ",__FUNCTION__,inc);
rb_thread_post_msg(RB_MODULE_EVT_CHANGE_VOL,inc);
}
void rb_thread_send_status_change(void )
{
_LOG_DBG(1," %s , ",__FUNCTION__);
rb_thread_post_msg(RB_MODULE_EVT_CHANGE_IDLE,0);
}
void rb_thread_set_vol(uint32_t vol)
{
_LOG_DBG(1," %s , ",__FUNCTION__);
rb_thread_post_msg(RB_MODULE_EVT_SET_VOL, vol);
}
void rb_thread_send_del_file(uint16_t idx )
{
_LOG_DBG(1," %s , ",__FUNCTION__);
rb_thread_post_msg(RB_MODULE_EVT_DEL_FILE,idx);
}
void rb_thread_send_sbc_record_start(void )
{
_LOG_DBG(1," %s , ",__FUNCTION__);
rb_thread_post_msg(SBC_RECORD_ACTION_START,(uint32_t)osThreadGetId());
}
void rb_thread_send_sbc_record_data_ind(void )
{
if(!rb_ctl_context.sbc_record_on)
return ;
// _LOG_DBG(1," %s , ",__FUNCTION__);
rb_thread_post_msg(SBC_RECORD_ACTION_DATA_IND,(uint32_t)osThreadGetId());
}
void rb_thread_send_sbc_record_stop(void )
{
_LOG_DBG(1," %s , ",__FUNCTION__);
rb_thread_post_msg(SBC_RECORD_ACTION_STOP,(uint32_t)osThreadGetId());
}
//interface for audio module
static bool user_key_pause_stream = false;
void app_rbplay_audio_reset_pause_status(void)
{
user_key_pause_stream = false;
}
int app_rbplay_audio_onoff(bool onoff, uint16_t aud_id)
{
_LOG_DBG(3," %s onoff %d, get status:%d",__FUNCTION__,onoff, rb_ctl_get_status());
if(app_rbcodec_check_hfp_active()&& !onoff) {
if( RB_CTL_PLAYING == rb_ctl_get_status()) {
rb_thread_send_pause();
}
} else if ( !onoff) {
//rb_thread_send_stop();
rb_thread_send_pause();
} else {
if(!user_key_pause_stream) {
if( RB_CTL_SUSPEND == rb_ctl_get_status()) {
rb_thread_send_resume();
app_wait_player_resumed();
} else {
rb_thread_send_play();
}
}
}
return 0;
}
void app_rbplay_pause_resume(void)
{
_LOG_DBG(2," %s get status:%d",__func__, rb_ctl_get_status());
user_key_pause_stream = true;
if( RB_CTL_SUSPEND == rb_ctl_get_status()) {
user_key_pause_stream = false;
rb_thread_send_resume();
}
if( RB_CTL_PLAYING == rb_ctl_get_status()) {
user_key_pause_stream = true;
rb_thread_send_pause();
}
}
//sbc reader run within thread
static int rb_ctl_mailbox_init(void)
{
rb_ctl_mailbox = osMailCreate(osMailQ(rb_ctl_mailbox), NULL);
if (rb_ctl_mailbox == NULL) {
TRACE(0,"Failed to Create rb_ctl_mailbox\n");
return -1;
}
return 0;
}
int rb_ctl_mailbox_put(RBCTL_MSG_BLOCK* msg_src)
{
osStatus status;
RBCTL_MSG_BLOCK *msg_p = NULL;
msg_p = (RBCTL_MSG_BLOCK*)osMailAlloc(rb_ctl_mailbox, 0);
if(!msg_p) {
TRACE(3,"%s fail, evt:%d,arg=%d \n",__func__,msg_src->evt,msg_src->arg);
return -1;
}
ASSERT(msg_p, "osMailAlloc error");
msg_p->evt = msg_src->evt;
msg_p->arg = msg_src->arg;
status = osMailPut(rb_ctl_mailbox, msg_p);
return (int)status;
}
int rb_ctl_mailbox_free(RBCTL_MSG_BLOCK* msg_p)
{
osStatus status;
status = osMailFree(rb_ctl_mailbox, msg_p);
return (int)status;
}
int rb_ctl_mailbox_get(RBCTL_MSG_BLOCK** msg_p)
{
osEvent evt;
evt = osMailGet(rb_ctl_mailbox, osWaitForever);
if (evt.status == osEventMail) {
*msg_p = (RBCTL_MSG_BLOCK *)evt.value.p;
return 0;
}
return -1;
}
#if 0
void rb_ctl_action_init(void)
{
bool ind = voiceCocah_get_indication();
TRACE(2," %s Cocah %d",__func__,ind);
if( !ind) return ;
// rb_ctl_set_priority(osPriorityHigh);
rb_thread_post_msg(SBCREADER_ACTION_INIT,(uint32_t)osThreadGetId());
}
void rb_ctl_action_run(void)
{
bool ind = voiceCocah_get_indication();
TRACE(2," %s Cocah %d",__func__,ind);
if( !ind) return ;
rb_thread_post_msg(SBCREADER_ACTION_RUN,(uint32_t)osThreadGetId());
}
void rb_ctl_action_stop(void)
{
bool ind = voiceCocah_get_indication();
TRACE(2," %s Cocah %d",__func__,ind);
if( !ind) return ;
rb_thread_post_msg(SBCREADER_ACTION_STOP,(uint32_t)osThreadGetId());
}
#endif
static void rb_ctl_thread(void const *argument)
{
osEvent evt;
#if 1
app_sysfreq_req(APP_SYSFREQ_USER_APP_PLAYER, APP_SYSFREQ_208M);
app_rbplay_load_playlist(&sd_playlist);
#endif
memset(&rb_ctl_context,0x0,sizeof(rb_ctl_struct));
rb_ctl_context.rb_player_vol = 6;
rb_ctl_context.status = RB_CTL_IDLE;
rb_ctl_context.curr_song_idx = 0;
//load playlist here
//voiceCocah_init();
rb_ctl_context.init_done = true;
while(1) {
RBCTL_MSG_BLOCK *msg_p = NULL;
app_sysfreq_req(APP_SYSFREQ_USER_APP_PLAYER, APP_SYSFREQ_32K);
if (!rb_ctl_mailbox_get(&msg_p)) {
app_sysfreq_req(APP_SYSFREQ_USER_APP_PLAYER, APP_SYSFREQ_104M);
rb_ctl_handle_event(msg_p);
rb_ctl_mailbox_free(msg_p);
}
}
}
int rb_ctl_init(void)
{
_LOG_DBG(1,"%s \n",__func__);
rb_ctl_context.init_done = false;
rb_ctl_context.sbc_record_on = false;
app_rbplay_open();
rb_ctl_mailbox_init();
rb_ctl_tid = osThreadCreate(osThread(rb_ctl_thread), NULL);
rb_ctl_default_priority = osPriorityAboveNormal;
if (rb_ctl_tid == NULL) {
TRACE(0,"Failed to Create rb_ctl_thread\n");
return 0;
}
_LOG_DBG(1,"Leave %s \n",__func__);
return 0;
}
uint8_t rb_ctl_get_vol(void)
{
return rb_ctl_context.rb_player_vol;
}
bool rb_ctl_is_init_done(void)
{
return rb_ctl_context.init_done;
}
bool rb_ctl_is_paused(void)
{
return ( RB_CTL_SUSPEND == rb_ctl_get_status());
}
uint16_t rb_ctl_songs_count(void)
{
return sd_playlist.total_songs;
}

View file

@ -0,0 +1,75 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
/* rbplay source */
/* playback control & rockbox codec porting & codec thread */
#ifndef __RB_CTL_H__
#define __RB_CTL_H__
typedef enum {
RB_MODULE_EVT_NONE,
RB_MODULE_EVT_PLAY,
RB_MODULE_EVT_PLAY_IDX,
RB_MODULE_EVT_STOP,
RB_MODULE_EVT_SUSPEND,
RB_MODULE_EVT_RESUME,
RB_MODULE_EVT_PLAY_NEXT,
RB_MODULE_EVT_CHANGE_VOL,
RB_MODULE_EVT_SET_VOL,
RB_MODULE_EVT_CHANGE_IDLE,
RB_MODULE_EVT_DEL_FILE,
RB_MODULE_EVT_RESTORE_DUAL_PLAY,
RB_MODULE_EVT_LINEIN_START,
RB_MODULE_EVT_RECONFIG_STREAM,
RB_MODULE_EVT_SET_TWS_MODE,
SBCREADER_ACTION_NONE,
SBCREADER_ACTION_INIT,
SBCREADER_ACTION_RUN,
SBCREADER_ACTION_STOP,
SBC_RECORD_ACTION_START,
SBC_RECORD_ACTION_DATA_IND,
SBC_RECORD_ACTION_STOP,
RB_MODULE_EVT_MAX
} RB_MODULE_EVT;
typedef enum {
RB_CTL_IDLE,
RB_CTL_PLAYING,
RB_CTL_SUSPEND,
} rb_ctl_status;
typedef struct {
struct mp3entry song_id3;
char rb_fname[FILE_SHORT_NAME_LEN];
rb_ctl_status status ; //playing,idle,pause,
uint16_t rb_audio_file[FILE_PATH_LEN];
uint16_t curr_song_idx ;
uint8_t rb_player_vol ;
int file_handle;
int init_done;
BOOL sbc_record_on;
} rb_ctl_struct;
extern int app_rbmodule_post_msg(RB_MODULE_EVT evt,uint32_t arg);
extern int rb_ctl_is_audio_file(const char* file_path);
uint8_t rb_ctl_get_vol(void);
#endif

View file

@ -0,0 +1,140 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
/* rbpcmbuf source */
/* pcmbuf management & af control & mixer */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#ifdef MBED
#include "mbed.h"
#include "rtos.h"
#endif
#include "audioflinger.h"
#include "cqueue.h"
#include "app_audio.h"
#include "app_utils.h"
#include "hal_trace.h"
#include "rbplay.h"
#include "rbpcmbuf.h"
#include "utils.h"
#define RB_PCMBUF_DMA_BUFFER_SIZE (1024*12)
#define RB_PCMBUF_MEDIA_BUFFER_SIZE (1024*12)
#define RB_DECODE_OUT_BUFFER_SIZE 1024
static uint8_t *rb_decode_out_buff;
static uint8_t *rbplay_dma_buffer;
static uint8_t *rb_pcmbuf_media_buf;
static CQueue rb_pcmbuf_media_buf_queue;
static osMutexId _rb_media_buf_queue_mutex_id = NULL;
static osMutexDef(_rb_media_buf_queue_mutex);
#define LOCK_MEDIA_BUF_QUEUE() \
if(osErrorISR == osMutexWait(_rb_media_buf_queue_mutex_id, osWaitForever)) {\
error("%s LOCK_MEDIA_BUF_QUEUE from IRQ!!!!!!!\n",__func__);\
}\
#define UNLOCK_MEDIA_BUF_QUEUE() \
if(osErrorISR == osMutexRelease(_rb_media_buf_queue_mutex_id)){ \
error("%s UNLOCK_MEDIA_BUF_QUEUE from IRQ!!!!!!\n"); \
} \
static uint32_t rbplay_more_data(uint8_t *buf, uint32_t len)
{
CQItemType *e1 = NULL;
CQItemType *e2 = NULL;
unsigned int len1 = 0;
unsigned int len2 = 0;
LOCK_MEDIA_BUF_QUEUE();
int ret = PeekCQueue(&rb_pcmbuf_media_buf_queue, len, &e1, &len1, &e2, &len2);
UNLOCK_MEDIA_BUF_QUEUE();
if (ret == CQ_OK) {
if (len1 > 0)
memcpy(buf, e1, len1);
if (len2 > 0)
memcpy(buf + len1, e2, len - len1);
LOCK_MEDIA_BUF_QUEUE();
DeCQueue(&rb_pcmbuf_media_buf_queue, 0, len);
UNLOCK_MEDIA_BUF_QUEUE();
} else {
warn("RBplay cache underflow");
}
return len;
}
extern uint8_t rb_ctl_get_vol(void);
void rb_pcmbuf_init(void)
{
info("pcmbuff init");
if(!_rb_media_buf_queue_mutex_id)
_rb_media_buf_queue_mutex_id = osMutexCreate((osMutex(_rb_media_buf_queue_mutex)));
app_audio_mempool_init();
app_audio_mempool_get_buff(&rb_pcmbuf_media_buf, RB_PCMBUF_MEDIA_BUFFER_SIZE);
InitCQueue(&rb_pcmbuf_media_buf_queue, RB_PCMBUF_MEDIA_BUFFER_SIZE, (unsigned char *)rb_pcmbuf_media_buf);
app_audio_mempool_get_buff(&rbplay_dma_buffer, RB_PCMBUF_DMA_BUFFER_SIZE);
app_audio_mempool_get_buff(&rb_decode_out_buff, RB_DECODE_OUT_BUFFER_SIZE);
struct AF_STREAM_CONFIG_T stream_cfg;
memset(&stream_cfg, 0, sizeof(stream_cfg));
stream_cfg.bits = AUD_BITS_16;
stream_cfg.channel_num = AUD_CHANNEL_NUM_2;
stream_cfg.sample_rate = AUD_SAMPRATE_44100;
stream_cfg.device = AUD_STREAM_USE_INT_CODEC;
stream_cfg.io_path = AUD_OUTPUT_PATH_SPEAKER;
stream_cfg.vol = rb_ctl_get_vol();
stream_cfg.handler = rbplay_more_data;
stream_cfg.data_ptr = BT_AUDIO_CACHE_2_UNCACHE(rbplay_dma_buffer);
stream_cfg.data_size = RB_PCMBUF_DMA_BUFFER_SIZE;
af_stream_open(AUD_STREAM_ID_0,AUD_STREAM_PLAYBACK, &stream_cfg);
af_stream_start(AUD_STREAM_ID_0,AUD_STREAM_PLAYBACK);
}
void *rb_pcmbuf_request_buffer(int *size)
{
*size = RB_DECODE_OUT_BUFFER_SIZE / 4;
return rb_decode_out_buff;
}
void rb_pcmbuf_write(unsigned int size)
{
int ret ;
do {
LOCK_MEDIA_BUF_QUEUE();
ret = EnCQueue(&rb_pcmbuf_media_buf_queue, (CQItemType *)rb_decode_out_buff, size*(2*2));
UNLOCK_MEDIA_BUF_QUEUE();
osThreadYield();
} while (ret == CQ_ERR);
}
void rb_pcmbuf_stop(void)
{
af_stream_stop(AUD_STREAM_ID_0,AUD_STREAM_PLAYBACK);
af_stream_close(AUD_STREAM_ID_0,AUD_STREAM_PLAYBACK);
}

View file

@ -0,0 +1,39 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef RBPCMBUF_HEADER
#define RBPCMBUF_HEADER
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum _RB_PCMBUF_AUD_STATE_T {
RB_PCMBUF_AUD_STATE_STOP = 0,
RB_PCMBUF_AUD_STATE_START,
} RB_PCMBUF_AUD_STATE_T;
void rb_pcmbuf_init(void);
void rb_pcmbuf_stop(void);
void *rb_pcmbuf_request_buffer(int *size);
void rb_pcmbuf_write(unsigned int size);
#ifdef __cplusplus
}
#endif
#endif /* RBPCMBUF_HEADER */

View file

@ -0,0 +1,615 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
/* rbplay source */
/* playback control & rockbox codec porting & codec thread */
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <unistd.h>
#ifdef MBED
#include "mbed.h"
#include "rtos.h"
#endif
#include "metadata.h"
#include "codecs.h"
#include "eq_export.h"
#include "hal_overlay.h"
#include "app_overlay.h"
#include "audioflinger.h"
#include "hal_trace.h"
#include "apps.h"
#include "rbpcmbuf.h"
#include "rbplaysd.h"
#include "app_thread.h"
#include "app_utils.h"
#include "app_key.h"
#include "rbplay.h"
#include "utils.h"
#ifdef __TWS__
#include "app_tws.h"
#endif
// TODO: remove
#define BT_STREAM_RBCODEC 0x10 //from rockbox decoder
extern "C" {
void flac_codec_main(int r);
void flac_codec_run(void);
void wav_codec_main(int r);
void wav_codec_run(void);
void mpa_codec_main(int r);
void mpa_codec_run(void);
void ape_codec_main(int r);
void ape_codec_run(void);
void sbc_codec_main(int r);
void sbc_codec_run(void);
}
extern void rb_pcm_player_open(enum AUD_BITS_T bits,enum AUD_SAMPRATE_T sample_rate,enum AUD_CHANNEL_NUM_T channel_num,uint8_t vol) ;
#if defined(__TWS__)
typedef struct _rb_tws_codec_info{
uint8_t update_codec_info;
int32_t sample_freq;
uint8_t channel_num;
} rb_tws_codec_info;
rb_tws_codec_info codec_info = {1, 44100, 2};
#endif
static osThreadId rb_decode_tid = NULL;
static osThreadId rb_caller_tid = NULL;
typedef struct {
uint32_t evt;
uint32_t arg;
} RBTHREAD_MSG_BLOCK;
#define RBTHREAD_MAILBOX_MAX (10)
osMailQDef (rb_decode_mailbox, RBTHREAD_MAILBOX_MAX, RBTHREAD_MSG_BLOCK);
int rb_decode_mailbox_put(RBTHREAD_MSG_BLOCK* msg_src);
static osMailQId rb_decode_mailbox = NULL;
static void rb_decode_thread(void const *argument);
osThreadDef(rb_decode_thread, osPriorityAboveNormal, 1, 1024 * 2, "rb_decorder");
// rbcodec info
static int song_fd;
static int song_format;
static struct mp3entry *current_id3;
static uint8_t rbplay_loop_on;
static volatile int rb_decode_halt_flag = 1;
struct codec_api ci_api;
struct codec_api *ci = &ci_api;
// TODO
volatile osThreadId thread_tid_waiter = NULL;
void init_dsp(void);
void codec_configure(int setting, intptr_t value);
uint16_t g_rbplayer_curr_song_idx = 0;
extern void app_rbplay_exit(void);
extern void bt_change_to_iic(APP_KEY_STATUS *status, void *param);
extern void rb_thread_send_switch(bool next);
extern void rb_thread_send_status_change(void );
enum APP_SYSFREQ_FREQ_T rb_player_get_work_freq(void);
static void rb_player_sync_close_done(void)
{
thread_tid_waiter = NULL;
}
extern void rb_check_stream_reconfig(int32_t freq, uint8_t ch);
static void f_codec_pcmbuf_insert_callback(
const void *ch1, const void *ch2, int count)
{
struct dsp_buffer src;
struct dsp_buffer dst;
src.remcount = count;
src.pin[0] = (const unsigned char *)ch1;
src.pin[1] = (const unsigned char *)ch2;
src.proc_mask = 0;
if (rb_codec_running() == 0)
return ;
#ifndef __TWS__
while (src.remcount > 0) {
dst.remcount = 0;
dst.p16out = (short *)rb_pcmbuf_request_buffer(&dst.bufcount);
if (dst.p16out == NULL) {
warn("No pcm buffer");
osThreadYield();
} else {
dsp_process(ci->dsp, &src, &dst);
if (dst.remcount > 0) {
rb_pcmbuf_write(dst.remcount);
}
}
}
#else
if(codec_info.update_codec_info){
rb_set_sbc_encoder_freq_ch(codec_info.sample_freq, codec_info.channel_num); //should call this to set trigger timer
rb_check_stream_reconfig(codec_info.sample_freq, codec_info.channel_num);
codec_info.update_codec_info = 0;
}
if(tws_local_player_need_tran_2_slave()){
rb_tws_start_master_player(BT_STREAM_RBCODEC);
}
while(1){
uint8_t * pcm_buff = NULL;
dst.remcount = 0;
dst.bufcount = MIN(src.remcount, 128); /* Arbitrary min request */
dst.p16out = (short *)rb_pcmbuf_request_buffer(&dst.bufcount);
pcm_buff = (uint8_t *)dst.p16out;
ASSERT(pcm_buff, "Should request buffer");
dsp_process(ci->dsp, &src, &dst);
if (dst.remcount > 0) {
while(rb_push_pcm_in_tws_buffer(pcm_buff, dst.remcount*2*2) == 0){
osDelay(2);
}
}
if (src.remcount <= 0) {
return; /* No input remains and DSP purged */
}
}
#endif
}
static void f_audio_codec_update_elapsed(unsigned long elapsed)
{
//info("Update elapsed: %d", elapsed);
return;
}
static size_t f_codec_filebuf_callback(void *ptr, size_t size)
{
ssize_t ret;
ret = read(song_fd, ptr, size);
if(ret < 0) {
error("File read error: %d",ret);
}
return ret;
}
static void * f_codec_request_buffer_callback(size_t *realsize, size_t reqsize)
{
return NULL;
}
static void * f_codec_advance_buffer_callback(size_t amount)
{
off_t ret = lseek(song_fd, (off_t)(ci->curpos + amount), SEEK_SET);
if(ret < 0) {
error("File seek fail");
return NULL;
}
ci->curpos += amount;
return (void *)ci;
}
static bool f_codec_seek_buffer_callback(size_t newpos)
{
off_t ret = lseek(song_fd, (off_t)newpos, SEEK_SET);
if(ret < 0) {
error("File seek fail");
return false;
}
ci->curpos = newpos;
return true;
}
static void f_codec_seek_complete_callback(void)
{
info("Seek complete");
dsp_configure(ci->dsp, DSP_FLUSH, 0);
}
static void f_audio_codec_update_offset(size_t offset)
{
}
static void f_codec_configure_callback(int setting, intptr_t value)
{
dsp_configure(ci->dsp, setting, value);
#ifdef __TWS__
if(setting == DSP_SET_FREQUENCY){
if(codec_info.sample_freq != value)
codec_info.update_codec_info = 1;
codec_info.sample_freq = value;
}
else if(setting == DSP_SET_STEREO_MODE){
if(codec_info.channel_num != (value == STEREO_MONO ? 1 : 2))
codec_info.update_codec_info = 1;
codec_info.channel_num = value == STEREO_MONO ? 1 : 2;
}
#endif
}
static enum codec_command_action f_codec_get_command_callback(intptr_t *param)
{
if (rb_decode_halt_flag == 1)
return CODEC_ACTION_HALT ;
return CODEC_ACTION_NULL;
}
static bool f_codec_loop_track_callback(void)
{
return false;
}
static void init_ci_file(void)
{
ci->codec_get_buffer = 0;
ci->pcmbuf_insert = f_codec_pcmbuf_insert_callback;
ci->set_elapsed = f_audio_codec_update_elapsed;
ci->read_filebuf = f_codec_filebuf_callback;
ci->request_buffer = f_codec_request_buffer_callback;
ci->advance_buffer = f_codec_advance_buffer_callback;
ci->seek_buffer = f_codec_seek_buffer_callback;
ci->seek_complete = f_codec_seek_complete_callback;
ci->set_offset = f_audio_codec_update_offset;
ci->configure = f_codec_configure_callback;
ci->get_command = f_codec_get_command_callback;
ci->loop_track = f_codec_loop_track_callback;
}
static void rb_play_init(void)
{
init_dsp();
init_ci_file();
#ifndef __TWS__
rb_pcmbuf_init();
#endif
}
void rb_play_codec_init(void)
{
RBTHREAD_MSG_BLOCK msg;
msg.evt = (uint32_t)RB_CTRL_CMD_CODEC_INIT;
msg.arg = (uint32_t)0;
rb_decode_mailbox_put(&msg);
}
void rb_play_codec_run(void)
{
RBTHREAD_MSG_BLOCK msg;
msg.evt = (uint32_t)RB_CTRL_CMD_CODEC_RUN;
msg.arg = (uint32_t)0;
rb_decode_mailbox_put(&msg);
}
static int rb_codec_init_desc(void )
{
info("Init decode format: %d", song_format);
switch (song_format) {
case AFMT_MPA_L1:
case AFMT_MPA_L2:
case AFMT_MPA_L3:
app_overlay_select(APP_OVERLAY_MPA);
mpa_codec_main(CODEC_LOAD);
break;
// TODO: add APP_OVERLAY_APE
#if 0
case AFMT_APE:
app_overlay_select(APP_OVERLAY_APE);
ape_codec_main(CODEC_LOAD);
break;
case AFMT_SBC:
app_overlay_select(APP_OVERLAY_A2DP);
sbc_codec_main(CODEC_LOAD);
break;
case AFMT_FLAC:
app_overlay_select(APP_OVERLAY_FLAC);
flac_codec_main(CODEC_LOAD);
break;
case AFMT_PCM_WAV:
app_overlay_select(APP_OVERLAY_WAV);
wav_codec_main(CODEC_LOAD);
break;
#endif
default:
error("unkown codec type init\n");
break;
}
return 0;
}
static int rb_codec_loop_on(void)
{
#ifdef __TWS__
//set start transfer to slave
tws_local_player_set_tran_2_slave_flag(1);
#endif
switch (song_format) {
case AFMT_MPA_L1:
case AFMT_MPA_L2:
case AFMT_MPA_L3:
mpa_codec_run();
break;
#if 0
case AFMT_SBC:
sbc_codec_run();
break;
case AFMT_FLAC:
flac_codec_run();
break;
case AFMT_PCM_WAV:
wav_codec_run();
break;
case AFMT_APE:
ape_codec_run();
break;
#endif
default:
error("unkown codec type run\n");
break;
}
return 0;
}
static int rb_thread_process_evt(RB_CTRL_CMD_T evt)
{
info("Decode event:%d", evt);
switch(evt) {
case RB_CTRL_CMD_CODEC_INIT:
rb_decode_halt_flag = 0;
rb_play_init();
/* get id3 */
/* init ci info */
ci->filesize = filesize(song_fd);
ci->id3 = current_id3;
ci->curpos = 0;
dsp_configure(ci->dsp, DSP_RESET, 0);
dsp_configure(ci->dsp, DSP_FLUSH, 0);
rb_codec_init_desc();
break;
case RB_CTRL_CMD_CODEC_RUN:
rbplay_loop_on = 1;
info("Play start");
app_sysfreq_req(APP_SYSFREQ_USER_APP_PLAYER, rb_player_get_work_freq());
app_stop_10_second_timer(APP_POWEROFF_TIMER_ID);
rb_codec_loop_on();
#if defined(__BTIF_AUTOPOWEROFF__)
app_start_10_second_timer(APP_POWEROFF_TIMER_ID);
#endif
song_fd = 0;
rb_decode_halt_flag = 1;
if(thread_tid_waiter) {
rb_player_sync_close_done();
} else {
rb_thread_send_status_change();
rb_thread_send_switch(true);
}
#ifdef __TWS__
//should update codec info after play one music
codec_info.update_codec_info = 1;
#endif
rbplay_loop_on = 0;
info("Play end");
break;
default:
error("Unkown rb cmd %d\n",evt);
break;
}
return 0;
}
int rb_decode_mailbox_put(RBTHREAD_MSG_BLOCK* msg_src)
{
osStatus status;
RBTHREAD_MSG_BLOCK *msg_p = NULL;
msg_p = (RBTHREAD_MSG_BLOCK*)osMailAlloc(rb_decode_mailbox, 0);
if(!msg_p) {
TRACE(3,"%s fail, evt:%d,arg=%d \n",__func__,msg_src->evt,msg_src->arg);
return -1;
}
msg_p->evt = msg_src->evt;
msg_p->arg = msg_src->arg;
status = osMailPut(rb_decode_mailbox, msg_p);
return (int)status;
}
int rb_decode_mailbox_free(RBTHREAD_MSG_BLOCK* msg_p)
{
osStatus status;
status = osMailFree(rb_decode_mailbox, msg_p);
return (int)status;
}
int rb_decode_mailbox_get(RBTHREAD_MSG_BLOCK** msg_p)
{
osEvent evt;
evt = osMailGet(rb_decode_mailbox, osWaitForever);
if (evt.status == osEventMail) {
*msg_p = (RBTHREAD_MSG_BLOCK *)evt.value.p;
return 0;
}
return -1;
}
static void rb_decode_thread(void const *argument)
{
RB_CTRL_CMD_T action;
RBTHREAD_MSG_BLOCK* msg_p;
while(1) {
app_sysfreq_req(APP_SYSFREQ_USER_APP_PLAYER, APP_SYSFREQ_32K);
// evt = osSignalWait(0, osWaitForever);
if(0 == rb_decode_mailbox_get(&msg_p)) {
app_sysfreq_req(APP_SYSFREQ_USER_APP_PLAYER, APP_SYSFREQ_104M);
action = (RB_CTRL_CMD_T) msg_p->evt;
rb_caller_tid = (osThreadId) msg_p->arg ;
TRACE(3,"[%s] action:%d ,tid,0x%x", __func__, action,rb_caller_tid);
rb_thread_process_evt(action);
rb_decode_mailbox_free(msg_p);
if( rb_caller_tid)
osSignalSet(rb_decode_tid, 0x1203);
rb_caller_tid = NULL;
}
}
}
int app_rbplay_open(void)
{
if (rb_decode_tid != NULL) {
warn("Decode thread reopen");
return -1;
}
rb_decode_mailbox = osMailCreate(osMailQ(rb_decode_mailbox), NULL);
if (rb_decode_mailbox == NULL) {
error("Failed to Create rb_decode_mailbox");
return -1;
}
rb_decode_tid = osThreadCreate(osThread(rb_decode_thread), NULL);
if (rb_decode_tid == NULL) {
error("Failed to Create rb_thread \n");
return -1;
}
return 0;
}
int rb_codec_running(void)
{
return ((rb_decode_halt_flag == 0)?1:0);
}
void rb_codec_set_halt(int halt)
{
rb_decode_halt_flag = halt;
}
void rb_thread_set_decode_vars(int fd, int type ,void* id3)
{
song_fd =fd;
song_format = type;
current_id3 = (struct mp3entry *)id3;
}
void rb_player_sync_set_wait_thread(osThreadId tid)
{
if(rbplay_loop_on)
thread_tid_waiter = tid;
else
thread_tid_waiter = NULL;
}
void rb_player_sync_wait_close(void )
{
while(NULL != thread_tid_waiter) {
osThreadYield();
}
}
enum APP_SYSFREQ_FREQ_T rb_player_get_work_freq(void)
{
enum APP_SYSFREQ_FREQ_T freq;
hal_sysfreq_print();
info("bitrate:%d freq:%d\n", ci->id3->bitrate, ci->id3->frequency);
#ifndef __TWS__
enum AUD_SAMPRATE_T sample_rate = AUD_SAMPRATE_44100;
sample_rate =(enum AUD_SAMPRATE_T ) ci->id3->frequency;
if(sample_rate > AUD_SAMPRATE_48000)
freq = APP_SYSFREQ_208M;
else if (sample_rate > AUD_SAMPRATE_44100)
freq = APP_SYSFREQ_104M;
else
freq = APP_SYSFREQ_52M;
if(ci->id3->bitrate > 192)
freq = APP_SYSFREQ_208M;
else if (ci->id3->bitrate > 128)
freq = APP_SYSFREQ_104M;
else
freq = APP_SYSFREQ_52M;
switch( song_format ) {
case AFMT_APE:
freq = APP_SYSFREQ_208M;
break;
case AFMT_FLAC:
freq = APP_SYSFREQ_208M;
break;
case AFMT_PCM_WAV:
freq = APP_SYSFREQ_208M;
break;
default:
break;
}
#else
freq = APP_SYSFREQ_208M;
#endif
info("Decode thread run at: %d", freq);
return freq;
}

View file

@ -0,0 +1,41 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
/* rbplay header */
/* playback control & rockbox codec porting & codec thread */
#ifndef RBPLAY_HEADER
#define RBPLAY_HEADER
/* ---- APIs ---- */
typedef enum _RB_CTRL_CMD_T {
RB_CTRL_CMD_NONE = 0,
RB_CTRL_CMD_SCAN_SONGS,
RB_CTRL_CMD_CODEC_PARSE_FILE,
RB_CTRL_CMD_CODEC_INIT,
RB_CTRL_CMD_CODEC_RUN,
RB_CTRL_CMD_CODEC_PAUSE,
RB_CTRL_CMD_CODEC_STOP,
RB_CTRL_CMD_CODEC_DEINIT,
RB_CTRL_CMD_CODEC_SEEK,
RB_CTRL_CMD_CODEC_MAX,
} RB_CTRL_CMD_T;
int app_rbplay_open(void);
void rb_play_codec_init(void);
int rb_codec_running(void);
#endif /* RBPLAY_HEADER */

View file

@ -0,0 +1,225 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
/* rbplay source */
/* playback control & rockbox codec porting & codec thread */
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <unistd.h>
#include "hal_trace.h"
#include "metadata.h"
#include "SDFileSystem.h"
#include "rbplaysd.h"
#include "utils.h"
#define SD_LABEL "sd"
#define PLAYLIST_PATH "/sd/Playlist"
static SDFileSystem *sdfs = NULL;
// TODO: remove ?
static playlist_item sd_curritem;
playlist_struct sd_playlist;
static void playlist_insert(playlist_item* item)
{
int fd;
fd = open(PLAYLIST_PATH, O_RDWR | O_CREAT);
if (fd <= 0) {
error("Playlist open fail");
return;
}
lseek(fd, item->song_idx * sizeof(playlist_item), SEEK_SET);
write(fd, item, sizeof(playlist_item));
close(fd);
}
static bool sdcard_mount(void)
{
if (sdfs) {
info("SD card already mount");
return true;
}
sdfs = new SDFileSystem(SD_LABEL);
if (sdfs == NULL) {
error("No memory for sd file system");
return false;
}
DIR *d;
d = opendir("/" SD_LABEL);
if (!d) {
warn("SD card mount error");
return false;
}
closedir(d);
return true;
}
static void app_rbplay_gen_playlist(playlist_struct *list)
{
struct dirent *p;
DIR *d;
uint32_t total;
int fd = 0;
struct mp3entry current_id3;
playlist_item* sd_curritem_p = &sd_curritem;
memset(list,0x0,sizeof(playlist_struct));
d = opendir("/" SD_LABEL);
if (!d) {
error("SD card open fail");
return;
}
info("---------gen audio list---------");
total = 0;
while (p = readdir(d)) {
if (probe_file_format(p->d_name) == AFMT_UNKNOWN)
continue;
memset(&sd_curritem,0x0,sizeof(playlist_item));
sd_curritem.song_idx = total;
sprintf(sd_curritem.file_path, "/" SD_LABEL "/%s", p->d_name);
sprintf(sd_curritem.file_name, "%s", p->d_name);
info("Adding music: %s", sd_curritem.file_path);
fd = open(sd_curritem.file_path, O_RDONLY);
if (fd <= 0) {
error("File %s open error", p->d_name);
break;
}
get_metadata(&current_id3, fd, sd_curritem.file_path);
close(fd);
if(current_id3.bitrate == 0 || current_id3.filesize == 0 || current_id3.length == 0)
break;
info("bits:%d, type:%d, freq:%d", current_id3.bitrate,
current_id3.codectype, current_id3.frequency);
sd_curritem_p->bitrate = current_id3.bitrate;
sd_curritem_p->codectype = current_id3.codectype;
sd_curritem_p->filesize = current_id3.filesize;
sd_curritem_p->length = current_id3.length;
sd_curritem_p->frequency = current_id3.frequency;
#ifdef PARSER_DETAIL
char *str;
str = current_id3.title;
if(str != NULL) {
memset(sd_curritem_p->title,0x0,MP3_TITLE_LEN);
memcpy(sd_curritem_p->title ,str,strlen(str)>MP3_TITLE_LEN?MP3_TITLE_LEN:strlen(str));
}
str = current_id3.artist;
if(str != NULL) {
memset(sd_curritem_p->artist,0x0,MP3_ARTIST_LEN);
memcpy(sd_curritem_p->artist ,str,strlen(str)>MP3_ARTIST_LEN?MP3_ARTIST_LEN:strlen(str));
}
str = current_id3.album;
if(str != NULL) {
memset(sd_curritem_p->album,0x0,MP3_ALBUM_LEN);
memcpy(sd_curritem_p->album ,str,strlen(str)>MP3_ALBUM_LEN?MP3_ALBUM_LEN:strlen(str));
}
str = current_id3.genre_string;
if(str != NULL) {
memset(sd_curritem_p->genre,0x0,MP3_GENRE_LEN);
memcpy(sd_curritem_p->genre ,str,strlen(str)>MP3_GENRE_LEN?MP3_GENRE_LEN:strlen(str));
}
str = current_id3.composer;
if(str != NULL) {
memset(sd_curritem_p->composer,0x0,MP3_COMPOSER_LEN);
memcpy(sd_curritem_p->composer ,str,strlen(str)>MP3_COMPOSER_LEN?MP3_COMPOSER_LEN:strlen(str));
}
#endif
playlist_insert(sd_curritem_p);
total++;
}
list->total_songs = total ;
list->current_item = sd_curritem_p;
closedir(d);
info("---------%d audio file searched---------" , total);
}
void app_rbplay_load_playlist(playlist_struct *list)
{
if(sdcard_mount() == false)
return;
remove(PLAYLIST_PATH);
app_rbplay_gen_playlist(list);
}
playlist_item *app_rbplay_get_playitem(const int idx)
{
int fd;
if(idx >= sd_playlist.total_songs) {
warn("Index exceed: %d / %d", idx, sd_playlist.total_songs);
return NULL;
}
fd = open(PLAYLIST_PATH, O_RDONLY);
if (fd <= 0) {
warn("SD card playlist can not open");
return NULL;
}
lseek(fd, sizeof(playlist_item) * idx, SEEK_SET);
read(fd, sd_playlist.current_item, sizeof(playlist_item));
info("Get playitem: %d: %s", idx, sd_playlist.current_item->file_path);
close(fd);
return sd_playlist.current_item;
}
int app_ctl_remove_file(const int idx)
{
playlist_item *item = app_rbplay_get_playitem(idx);
if (!item)
return -1;
remove(item->file_path);
return 0;
}

View file

@ -0,0 +1,63 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __RBPLAYSD_H_
#define __RBPLAYSD_H_
#include <stdint.h>
//playlist
#define FILE_PATH_LEN (128+4)
#define FILE_SHORT_NAME_LEN (128)
#define MP3_TITLE_LEN (128)
#define MP3_ARTIST_LEN (128)
#define MP3_ALBUM_LEN (128)
#define MP3_GENRE_LEN (128)
#define MP3_COMPOSER_LEN (128)
#define MP3_YEAR_STRING_LEN (8)
#define MP3_TRACK_LEN (128)
typedef struct {
char file_path[FILE_PATH_LEN];
char file_name[FILE_SHORT_NAME_LEN];
#ifdef PARSER_DETAIL
uint16_t title[MP3_TITLE_LEN];
uint16_t artist[MP3_ARTIST_LEN];
uint16_t album[MP3_ALBUM_LEN];
uint16_t genre[MP3_GENRE_LEN];
uint16_t composer[MP3_COMPOSER_LEN];
uint16_t year[MP3_YEAR_STRING_LEN];
uint16_t track[MP3_TRACK_LEN];
#endif
uint16_t song_idx;
unsigned int codectype;
unsigned int bitrate;
unsigned long frequency;
unsigned long filesize; /* without headers; in bytes */
unsigned long length; /* song length in ms */
} playlist_item;
typedef struct {
playlist_item *current_item;
uint16_t total_songs;
} playlist_struct;
void app_rbplay_load_playlist(playlist_struct *list);
playlist_item *app_rbplay_get_playitem(const int idx);
int app_ctl_remove_file(const int idx);
#endif

View file

@ -0,0 +1,26 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef RBPLAY_UTILS_H
#define RBPLAY_UTILS_H
#undef warn
#undef error
#define info(str, ...) TRACE(str, ##__VA_ARGS__)
#define warn(str, ...) TRACE("\033[31mwarn: \033[0m" str, ##__VA_ARGS__)
#define error(str, ...) TRACE("\033[31merr: \033[0m" str, ##__VA_ARGS__)
#endif

View file

@ -0,0 +1,185 @@
/***************************************************************************
*
* 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 "cmsis_os.h"
#include "app_utils.h"
#include "audioflinger.h"
#include "hal_timer.h"
#include "hal_trace.h"
#include "string.h"
#include "audio_dump.h"
// #include "local_wav.h"
#define CHANNEL_NUM (2)
#define CHAR_BYTES (1)
#define SHORT_BYTES (2)
#define INT_BYTES (4)
#define SAMPLE_BITS (16)
#define SAMPLE_BYTES (SAMPLE_BITS / 8)
#define TX_SAMPLE_RATE (16000)
#define RX_SAMPLE_RATE (16000)
#define TX_FRAME_LEN (256)
#define RX_FRAME_LEN (256)
#define TX_BUF_SIZE (TX_FRAME_LEN * CHANNEL_NUM * SAMPLE_BYTES * 2)
#define RX_BUF_SIZE (RX_FRAME_LEN * CHANNEL_NUM * SAMPLE_BYTES * 2)
#if SAMPLE_BYTES == SHORT_BYTES
typedef short VOICE_PCM_T;
#elif SAMPLE_BYTES == INT_BYTES
typedef int VOICE_PCM_T;
#else
#error "Invalid SAMPLE_BYTES!!!"
#endif
static uint8_t POSSIBLY_UNUSED codec_capture_buf[TX_BUF_SIZE];
static uint8_t POSSIBLY_UNUSED codec_playback_buf[RX_BUF_SIZE];
static uint32_t POSSIBLY_UNUSED codec_capture_cnt = 0;
static uint32_t POSSIBLY_UNUSED codec_playback_cnt = 0;
#define CODEC_STREAM_ID AUD_STREAM_ID_0
static uint32_t codec_capture_callback(uint8_t *buf, uint32_t len)
{
int POSSIBLY_UNUSED pcm_len = len / sizeof(VOICE_PCM_T) / CHANNEL_NUM;
VOICE_PCM_T POSSIBLY_UNUSED *pcm_buf[CHANNEL_NUM];
int interval_len = len * 2 / CHANNEL_NUM;
for (int i=0; i<CHANNEL_NUM; i++) {
pcm_buf[i] = (VOICE_PCM_T *)(buf + i * interval_len);
}
// TRACE(2,"[%s] cnt = %d", __func__, codec_capture_cnt++);
audio_dump_add_channel_data(0, pcm_buf[0], pcm_len);
audio_dump_add_channel_data(1, pcm_buf[0], pcm_len);
audio_dump_run();
return len;
}
static uint32_t codec_playback_callback(uint8_t *buf, uint32_t len)
{
int POSSIBLY_UNUSED pcm_len = len / sizeof(VOICE_PCM_T) / CHANNEL_NUM;
VOICE_PCM_T POSSIBLY_UNUSED *pcm_buf[CHANNEL_NUM];
int interval_len = len * 2 / CHANNEL_NUM;
for (int i=0; i<CHANNEL_NUM; i++) {
pcm_buf[i] = (VOICE_PCM_T *)(buf + i * interval_len);
}
// TRACE(2,"[%s] cnt = %d", __func__, codec_playback_cnt++);
return len;
}
static int voice_start(bool on)
{
int ret = 0;
static bool isRun = false;
enum APP_SYSFREQ_FREQ_T freq = APP_SYSFREQ_208M;
struct AF_STREAM_CONFIG_T stream_cfg;
if (isRun == on) {
return 0;
}
if (on) {
TRACE(1, "[%s]] ON", __func__);
af_set_priority(AF_USER_TEST, osPriorityHigh);
app_sysfreq_req(APP_SYSFREQ_USER_APP_0, freq);
TRACE(2, "[%s] sys freq calc : %d\n", __func__, hal_sys_timer_calc_cpu_freq(5, 0));
// Initialize Cqueue
codec_capture_cnt = 0;
codec_playback_cnt = 0;
memset(&stream_cfg, 0, sizeof(stream_cfg));
stream_cfg.channel_num = (enum AUD_CHANNEL_NUM_T)CHANNEL_NUM;
stream_cfg.data_size = TX_BUF_SIZE;
stream_cfg.sample_rate = (enum AUD_SAMPRATE_T)TX_SAMPLE_RATE;
stream_cfg.bits = (enum AUD_BITS_T)SAMPLE_BITS;
stream_cfg.vol = 12;
stream_cfg.chan_sep_buf = true;
stream_cfg.device = AUD_STREAM_USE_INT_CODEC;
stream_cfg.io_path = AUD_INPUT_PATH_MAINMIC;
stream_cfg.handler = codec_capture_callback;
stream_cfg.data_ptr = codec_capture_buf;
TRACE(3, "[%s] codec capture sample_rate: %d, data_size: %d", __func__, stream_cfg.sample_rate, stream_cfg.data_size);
af_stream_open(CODEC_STREAM_ID, AUD_STREAM_CAPTURE, &stream_cfg);
ASSERT(ret == 0, "codec capture failed: %d", ret);
memset(&stream_cfg, 0, sizeof(stream_cfg));
stream_cfg.channel_num = (enum AUD_CHANNEL_NUM_T)CHANNEL_NUM;
stream_cfg.data_size = RX_BUF_SIZE;
stream_cfg.sample_rate = (enum AUD_SAMPRATE_T)RX_SAMPLE_RATE;
stream_cfg.bits = (enum AUD_BITS_T)SAMPLE_BITS;
stream_cfg.vol = 12;
stream_cfg.chan_sep_buf = true;
stream_cfg.device = AUD_STREAM_USE_INT_CODEC;
stream_cfg.io_path = AUD_OUTPUT_PATH_SPEAKER;
stream_cfg.handler = codec_playback_callback;
stream_cfg.data_ptr = codec_playback_buf;
TRACE(3, "[%s] codec playback sample_rate: %d, data_size: %d", __func__, stream_cfg.sample_rate, stream_cfg.data_size);
af_stream_open(CODEC_STREAM_ID, AUD_STREAM_PLAYBACK, &stream_cfg);
ASSERT(ret == 0, "codec playback failed: %d", ret);
audio_dump_init(TX_FRAME_LEN, sizeof(VOICE_PCM_T), 1);
// Start
af_stream_start(CODEC_STREAM_ID, AUD_STREAM_CAPTURE);
af_stream_start(CODEC_STREAM_ID, AUD_STREAM_PLAYBACK);
}
else
{
// Close stream
af_stream_stop(CODEC_STREAM_ID, AUD_STREAM_PLAYBACK);
af_stream_stop(CODEC_STREAM_ID, AUD_STREAM_CAPTURE);
audio_dump_deinit();
af_stream_close(CODEC_STREAM_ID, AUD_STREAM_PLAYBACK);
af_stream_close(CODEC_STREAM_ID, AUD_STREAM_CAPTURE);
app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_32K);
af_set_priority(AF_USER_TEST, osPriorityAboveNormal);
TRACE(1, "[%s] OFF", __func__);
}
isRun=on;
return 0;
}
static bool voice_test_status = true;
void voice_test(void)
{
TRACE(2, "[%s] status = %d", __func__, voice_test_status);
voice_start(voice_test_status);
voice_test_status = !voice_test_status;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,948 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
// Standard C Included Files
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include "cmsis_os.h"
#include "plat_types.h"
#include "hal_uart.h"
#include "hal_timer.h"
#include "hal_trace.h"
#include "cqueue.h"
#include "app_audio.h"
#include "app_overlay.h"
#include "app_ring_merge.h"
#include "tgt_hardware.h"
#include "bt_sco_chain.h"
#include "iir_resample.h"
#include "hfp_api.h"
#include "audio_prompt_sbc.h"
#ifdef TX_RX_PCM_MASK
#include "bt_drv_interface.h"
#endif
#define ENABLE_LPC_PLC
#define ENABLE_PLC_ENCODER
// BT
#include "a2dp_api.h"
#include "plc_utils.h"
extern "C" {
#include "plc_8000.h"
#include "speech_utils.h"
#if defined(HFP_1_6_ENABLE)
#include "codec_sbc.h"
#ifndef ENABLE_LPC_PLC
#include "plc_16000.h"
#endif
#endif
#if defined(CVSD_BYPASS)
#include "Pcm8k_Cvsd.h"
#endif
#ifndef ENABLE_LPC_PLC
static void *speech_plc;
#endif
}
#if defined(ENABLE_LPC_PLC)
#include "lpc_plc_api.h"
#endif
#if defined(SPEECH_TX_24BIT)
extern int32_t *aec_echo_buf;
#else
extern short *aec_echo_buf;
#endif
// #define SPEECH_RX_PLC_DUMP_DATA
// #define PLC_DEBUG_PRINT_DATA
//#define DEBUG_SCO_DUMP
#ifdef SPEECH_RX_PLC_DUMP_DATA
#include "audio_dump.h"
int16_t *audio_dump_temp_buf = NULL;
#endif
// app_bt_stream.cpp::bt_sco_player(), used buffer size
#define APP_BT_STREAM_USE_BUF_SIZE (1024*2)
#if defined(SCO_OPTIMIZE_FOR_RAM)
uint8_t *sco_overlay_ram_buf = NULL;
int sco_overlay_ram_buf_len = 0;
#endif
static bool resample_needed_flag = false;
static int sco_frame_length;
static int codec_frame_length;
static int16_t *resample_buf = NULL;
static IirResampleState *uplink_resample_st = NULL;
static IirResampleState *downlink_resample_st = NULL;
#define MSBC_FRAME_SIZE (60)
#if defined(HFP_1_6_ENABLE)
static btif_sbc_decoder_t *msbc_decoder;
static float msbc_eq_band_gain[CFG_HW_AUD_EQ_NUM_BANDS]= {0,0,0,0,0,0,0,0};
#define MSBC_ENCODE_PCM_LEN (240)
#ifndef ENABLE_LPC_PLC
struct PLC_State msbc_plc_state;
#endif
#ifdef ENABLE_PLC_ENCODER
static btif_sbc_encoder_t *msbc_plc_encoder;
static int16_t *msbc_plc_encoder_buffer = NULL;
#define MSBC_CODEC_DELAY (73)
#endif
static btif_sbc_encoder_t *msbc_encoder;
#endif
#if defined(ENABLE_LPC_PLC)
LpcPlcState *msbc_plc_state = NULL;
#endif
#define VOICEBTPCM_TRACE(s,...)
//TRACE(s, ##__VA_ARGS__)
#if defined(CHIP_BEST1400) || defined(CHIP_BEST1402) || defined(CHIP_BEST2300P) || defined(CHIP_BEST2300A) || defined(CHIP_BEST2001)
#define MSBC_MUTE_PATTERN (0x55)
#else
#define MSBC_MUTE_PATTERN (0x00)
#endif
#define MSBC_LEN_FORMBT_PER_FRAME (60) //Bytes; only for BES platform.
#define SAMPLES_LEN_PER_FRAME (120)
#define MSBC_LEN_PER_FRAME (57+3)
#define BYTES_PER_PCM_FRAME (SAMPLES_LEN_PER_FRAME*2)
// Add 1 to ensure it never be out of bounds when msbc_offset is 1
unsigned char msbc_buf_all[MSBC_LEN_FORMBT_PER_FRAME*3+1];
#if defined(HFP_1_6_ENABLE)
static int msbc_find_first_sync = 0;
static unsigned int msbc_offset = 0;
static unsigned int next_frame_flag = 0;
#endif
static PacketLossState pld;
extern bool bt_sco_codec_is_msbc(void);
int process_downlink_msbc_frames(unsigned char *msbc_buf, unsigned int msbc_len, unsigned char *pcm_buf,unsigned int pcm_len);
int process_downlink_cvsd_frames(unsigned char *cvsd_buf, unsigned int cvsd_len, unsigned char *pcm_buf,unsigned int pcm_len);
int process_uplink_msbc_frames(unsigned char *pcm_buf, unsigned int pcm_len, unsigned char *msbc_buf,unsigned int msbc_len);
int process_uplink_cvsd_frames(unsigned char *pcm_buf, unsigned int pcm_len, unsigned char *cvsd_buf,unsigned int cvsd_len);
int process_downlink_bt_voice_frames(uint8_t *in_buf, uint32_t in_len, uint8_t *out_buf,uint32_t out_len,int32_t codec_type)
{
//TRACE(3,"[%s] in_len = %d, out_len = %d", __FUNCTION__, in_len, out_len);
#if defined(SPEECH_RX_24BIT)
out_len /= 2;
#endif
int16_t *pcm_buf = (int16_t *)out_buf;
int pcm_len = out_len / sizeof(int16_t);
if (resample_needed_flag == true) {
pcm_buf = resample_buf;
pcm_len = sco_frame_length;
}
if (bt_sco_codec_is_msbc()) {
process_downlink_msbc_frames(in_buf, in_len, (uint8_t *)pcm_buf, pcm_len * sizeof(int16_t));
// Down sampling
if (resample_needed_flag) {
iir_resample_process(downlink_resample_st, pcm_buf, (int16_t *)out_buf, pcm_len);
pcm_buf = (int16_t *)out_buf;
pcm_len >>= 1;
}
} else {
process_downlink_cvsd_frames(in_buf, in_len, (uint8_t *)pcm_buf, pcm_len * sizeof(int16_t));
// Up sampling
if (resample_needed_flag) {
iir_resample_process(downlink_resample_st, pcm_buf, (int16_t *)out_buf, pcm_len);
pcm_buf = (int16_t *)out_buf;
pcm_len <<= 1;
}
}
#if defined(SPEECH_RX_24BIT)
int32_t *buf32 = (int32_t *)out_buf;
for (int i = pcm_len - 1; i >= 0; i--) {
buf32[i] = ((int32_t)pcm_buf[i] << 8);
}
#endif
speech_rx_process(pcm_buf, &pcm_len);
#if defined(SPEECH_RX_24BIT)
out_len *= 2;
#endif
return 0;
}
int process_uplink_bt_voice_frames(uint8_t *in_buf, uint32_t in_len, uint8_t *ref_buf, uint32_t ref_len, uint8_t *out_buf,uint32_t out_len,int32_t codec_type)
{
//TRACE(3,"[%s] in_len = %d, out_len = %d", __FUNCTION__, in_len, out_len);
#if defined(SPEECH_TX_24BIT)
int32_t *pcm_buf = (int32_t *)in_buf;
int pcm_len = in_len / sizeof(int32_t);
#else
int16_t *pcm_buf = (int16_t *)in_buf;
int pcm_len = in_len / sizeof(int16_t);
#endif
#if defined(SPEECH_TX_AEC_CODEC_REF)
ASSERT(pcm_len % (SPEECH_CODEC_CAPTURE_CHANNEL_NUM + 1) == 0, "[%s] pcm_len(%d) should be divided by %d", __FUNCTION__, pcm_len, SPEECH_CODEC_CAPTURE_CHANNEL_NUM + 1);
// copy reference buffer
#if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT) || defined(SPEECH_TX_THIRDPARTY)
for (int i = SPEECH_CODEC_CAPTURE_CHANNEL_NUM, j = 0; i < pcm_len; i += SPEECH_CODEC_CAPTURE_CHANNEL_NUM + 1, j++) {
aec_echo_buf[j] = pcm_buf[i];
}
#endif
for (int i = 0, j = 0; i < pcm_len; i += SPEECH_CODEC_CAPTURE_CHANNEL_NUM + 1, j += SPEECH_CODEC_CAPTURE_CHANNEL_NUM) {
for (int k = 0; k < SPEECH_CODEC_CAPTURE_CHANNEL_NUM; k++)
pcm_buf[j + k] = pcm_buf[i + k];
}
pcm_len = pcm_len / (SPEECH_CODEC_CAPTURE_CHANNEL_NUM + 1) * SPEECH_CODEC_CAPTURE_CHANNEL_NUM;
#elif (defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT) || defined(SPEECH_TX_THIRDPARTY))
int ref_pcm_len = ref_len / sizeof(int16_t);
ASSERT(pcm_len / SPEECH_CODEC_CAPTURE_CHANNEL_NUM == ref_pcm_len, "[%s] Length error: %d / %d != %d", __func__, pcm_len, SPEECH_CODEC_CAPTURE_CHANNEL_NUM, ref_pcm_len);
for (int i = 0; i < ref_pcm_len; i++) {
aec_echo_buf[i] = ref_buf[i];
}
#endif
speech_tx_process(pcm_buf, aec_echo_buf, &pcm_len);
#if defined(SPEECH_TX_24BIT)
int32_t *buf24 = (int32_t *)pcm_buf;
int16_t *buf16 = (int16_t *)pcm_buf;
for (int i = 0; i < pcm_len; i++)
buf16[i] = (buf24[i] >> 8);
#endif
int16_t *pcm_buf_16bits = (int16_t *)pcm_buf;
if (bt_sco_codec_is_msbc()) {
// Up sampling
if (resample_needed_flag) {
iir_resample_process(uplink_resample_st, (int16_t *)pcm_buf_16bits, resample_buf, pcm_len);
pcm_buf_16bits = resample_buf;
pcm_len = sco_frame_length;
}
process_uplink_msbc_frames((uint8_t *)pcm_buf_16bits, pcm_len * sizeof(int16_t), out_buf, out_len);
} else {
// Down sampling
if (resample_needed_flag) {
iir_resample_process(uplink_resample_st, (int16_t *)pcm_buf_16bits, resample_buf, pcm_len);
pcm_buf_16bits = resample_buf;
pcm_len = sco_frame_length;
}
process_uplink_cvsd_frames((uint8_t *)pcm_buf_16bits, pcm_len * sizeof(int16_t), out_buf, out_len);
}
return 0;
}
int process_downlink_msbc_frames(unsigned char *msbc_buf, unsigned int msbc_len, unsigned char *pcm_buf,unsigned int pcm_len)
{
#if defined(HFP_1_6_ENABLE)
btif_sbc_pcm_data_t pcm_data;
unsigned int msbc_offset_lowdelay = 0;
unsigned int i,j;
unsigned char *msbc_buffer=(unsigned char *)msbc_buf;
int frame_flag[6]; // 1: good frame; 0:bad frame;
bt_status_t ret;
unsigned int frame_counter=0;
unsigned short byte_decode = 0;
unsigned int msbc_offset_total = 0;
int msbc_offset_drift[6] = {0, };
short *dec_pcm_buf=( short *)pcm_buf;
unsigned char dec_msbc_buf[MSBC_LEN_PER_FRAME] = {0, };
//unsigned int timer_begin=hal_sys_timer_get();
//TRACE(2,"process_downlink_msbc_frames:pcm_len:%d,msbc_len:%d",pcm_len,msbc_len);
//TRACE(1,"decode_msbc_frame,msbc_len:%d",msbc_len);
for(i =0; i<msbc_len; i++)
{
msbc_buf_all[i+MSBC_LEN_FORMBT_PER_FRAME]=msbc_buffer[i];
}
/*
for(i =0; i<msbc_len/2; i=i+10)
{
TRACE(10,"0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,",
DecMsbcBufAll[i],DecMsbcBufAll[i+1],DecMsbcBufAll[i+2],DecMsbcBufAll[i+3],DecMsbcBufAll[i+4],
DecMsbcBufAll[i+5],DecMsbcBufAll[i+6],DecMsbcBufAll[i+7],DecMsbcBufAll[i+8],DecMsbcBufAll[i+9]);
}
*/
for(j =0; j<msbc_len/MSBC_LEN_FORMBT_PER_FRAME; j++)
{
frame_flag[j]=0;
}
if(msbc_find_first_sync==0)
{
for(i =0; i<msbc_len; i++)
{
if((msbc_buf_all[i]==0x01)&&((msbc_buf_all[i+1]&0x0f)==0x08)&&(msbc_buf_all[i+2]==0xad))break;
}
TRACE(1,"sync......:%d",i);
if(i<msbc_len)
{
msbc_find_first_sync=1;
msbc_offset=i%MSBC_LEN_FORMBT_PER_FRAME;
msbc_offset_total=i;
}
else
{
for (j = 0; j < msbc_len / MSBC_LEN_FORMBT_PER_FRAME; j++)
{
frame_flag[j] = 1;
}
}
}
if(msbc_find_first_sync==1)
{
int value=0;
unsigned char headerm1 = 0;
unsigned char header0 = 0;
unsigned char header1 = 0;
unsigned char header2 = 0;
unsigned char header3 = 0;
// unsigned char tail0 = 0;
if(msbc_offset==0||msbc_offset==1)
{
msbc_offset_lowdelay=msbc_offset+60;
//msbc_offset_lowdelay=msbc_offset;
}
else
{
msbc_offset_lowdelay=msbc_offset;
}
//check again
for(j =0; j<(msbc_len/MSBC_LEN_FORMBT_PER_FRAME); j++)
{
if (next_frame_flag == 1)
{
next_frame_flag = 0;
frame_flag[j] = 1;
continue;
}
if(msbc_offset_lowdelay==0&&j==0)
{
headerm1=0x01;
}
else
{
headerm1 = msbc_buf_all[msbc_offset_lowdelay + j*MSBC_LEN_FORMBT_PER_FRAME-1];
}
header0 = msbc_buf_all[msbc_offset_lowdelay + j*MSBC_LEN_FORMBT_PER_FRAME];
header1 = msbc_buf_all[msbc_offset_lowdelay + j*MSBC_LEN_FORMBT_PER_FRAME + 1];
header2 = msbc_buf_all[msbc_offset_lowdelay + j*MSBC_LEN_FORMBT_PER_FRAME + 2];
header3 = msbc_buf_all[msbc_offset_lowdelay + j*MSBC_LEN_FORMBT_PER_FRAME + 3];
/*if ((headerm1 == 0x01) && ((header0 & 0x0f) == 0x08) && (header1 == 0xad) ||
(header0 == 0x01) && ((header1 & 0x0f) == 0x08) && (header2 == 0xad) ||
(header1 == 0x01) && ((header2 & 0x0f) == 0x08) && (header3 == 0xad))
{
frame_flag[j] = 0;
}*/
if ((headerm1 == 0x01) && ((header0 & 0x0f) == 0x08) && (header1 == 0xad))
{
frame_flag[j] = 0;
// It seems that offset is reduced by 1
msbc_offset_drift[j] = -1;
TRACE(1,"[%s] msbc_offset is reduced by 1", __FUNCTION__);
/*
tail0 = msbc_buf_all[msbc_offset_lowdelay + j*MSBC_LEN_FORMBT_PER_FRAME + 59 - 1];
if (tail0 == 0x00 || tail0 == 0x01|| tail0==0xff)
{
frame_flag[j] = 0;
}
else
{
frame_flag[j] = 1;
next_frame_flag = 1;
}
*/
}
else if ((header0 == 0x01) && ((header1 & 0x0f) == 0x08) && (header2 == 0xad))
{
frame_flag[j] = 0;
/*
tail0 = msbc_buf_all[msbc_offset_lowdelay + j*MSBC_LEN_FORMBT_PER_FRAME + 59];
if (tail0 == 0x00 || tail0 == 0x01|| tail0==0xff)
{
frame_flag[j] = 0;
}
else
{
frame_flag[j] = 1;
next_frame_flag = 1;
}
*/
}
else if ((header1 == 0x01) && ((header2 & 0x0f) == 0x08) && (header3 == 0xad))
{
frame_flag[j] = 0;
msbc_offset_drift[j] = 1;
TRACE(1,"[%s] msbc_offset is increased by 1", __FUNCTION__);
/*
tail0 = msbc_buf_all[msbc_offset_lowdelay + j*MSBC_LEN_FORMBT_PER_FRAME + 59 + 1];
if (tail0 == 0x00 || tail0==0x01|| tail0==0xff)
{
frame_flag[j] = 0;
}
else
{
frame_flag[j] = 1;
next_frame_flag = 1;
}
*/
}
else
{
if ((header0 == MSBC_MUTE_PATTERN)&& ((header1 & 0x0f) == (MSBC_MUTE_PATTERN & 0x0f)) && (header2 == MSBC_MUTE_PATTERN))
{
frame_flag[j]=1;
}
else
{
if((msbc_offset_lowdelay+j*MSBC_LEN_FORMBT_PER_FRAME)>=msbc_offset_total)
{
frame_flag[j]=3;
}
else
{
frame_flag[j]=1;
}
}
}
}
for(j =0; j<msbc_len/MSBC_LEN_FORMBT_PER_FRAME; j++)
{
value=value|frame_flag[j];
}
//abnormal msbc packet.
if(value>1)msbc_find_first_sync=0;
}
while((frame_counter<msbc_len/MSBC_LEN_FORMBT_PER_FRAME)&&(frame_counter<pcm_len/BYTES_PER_PCM_FRAME))
{
//TRACE(3,"[%s] decoding, offset %d, offset drift %d", __FUNCTION__, msbc_offset, msbc_offset_drift[frame_counter]);
// skip first byte when msbc_offset == 0 and msbc_offset_drift == -1
unsigned int start_idx = 0;
if (msbc_offset_lowdelay == 0 && msbc_offset_drift[frame_counter] == -1) {
start_idx = 1;
dec_msbc_buf[0] = 0x01;
}
for(i = start_idx; i<MSBC_LEN_PER_FRAME; i++)
{
//DecMsbcBuf[i]=DecMsbcBufAll[i+msbc_offset_lowdelay+frame_counter*MSBC_LEN_FORMBT_PER_FRAME+2];
dec_msbc_buf[i]=msbc_buf_all[i+msbc_offset_lowdelay+msbc_offset_drift[frame_counter]+frame_counter*MSBC_LEN_FORMBT_PER_FRAME];
}
//TRACE(1,"msbc header:0x%x",DecMsbcBuf[0]);
#ifdef SPEECH_RX_PLC_DUMP_DATA
audio_dump_add_channel_data(2, (short *)dec_msbc_buf, MSBC_LEN_PER_FRAME/2);
#endif
plc_type_t plc_type = packet_loss_detection_process(&pld, dec_msbc_buf);
if(plc_type != PLC_TYPE_PASS) {
memset(dec_pcm_buf, 0, SAMPLES_LEN_PER_FRAME * sizeof(int16_t));
goto do_plc;
}
pcm_data.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
pcm_data.numChannels = 1;
pcm_data.dataLen = 0;
pcm_data.data = (uint8_t *)dec_pcm_buf;
ret = btif_sbc_decode_frames(msbc_decoder,
(unsigned char *)dec_msbc_buf,
MSBC_LEN_PER_FRAME, &byte_decode,
&pcm_data, SAMPLES_LEN_PER_FRAME*2,
msbc_eq_band_gain);
//ASSERT(ret == BT_STS_SUCCESS, "[%s] msbc decoder should never fail", __FUNCTION__);
if (ret != BT_STS_SUCCESS) {
plc_type = PLC_TYPE_DECODER_ERROR;
packet_loss_detection_update_histogram(&pld, plc_type);
}
do_plc:
if (plc_type == PLC_TYPE_PASS) {
#if defined(ENABLE_LPC_PLC)
lpc_plc_save(msbc_plc_state, dec_pcm_buf);
#else
PLC_good_frame(&msbc_plc_state, dec_pcm_buf, dec_pcm_buf);
#endif
#ifdef SPEECH_RX_PLC_DUMP_DATA
audio_dump_add_channel_data(0, (short *)dec_pcm_buf, MSBC_ENCODE_PCM_LEN/2);
#endif
}
else
{
TRACE(1,"PLC bad frame, plc type: %d", plc_type);
#if defined(PLC_DEBUG_PRINT_DATA)
DUMP8("0x%02x, ", dec_msbc_buf, 60);
#endif
#ifdef SPEECH_RX_PLC_DUMP_DATA
for(uint32_t i=0; i< MSBC_ENCODE_PCM_LEN/2; i++)
{
audio_dump_temp_buf[i] = (plc_type - 1) * 5000;
}
audio_dump_add_channel_data(0, audio_dump_temp_buf, MSBC_ENCODE_PCM_LEN/2);
#endif
#if defined(ENABLE_LPC_PLC)
lpc_plc_generate(msbc_plc_state, dec_pcm_buf,
#if defined(ENABLE_PLC_ENCODER)
msbc_plc_encoder_buffer
#else
NULL
#endif
);
#if defined(ENABLE_PLC_ENCODER)
pcm_data.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
pcm_data.numChannels = 1;
pcm_data.dataLen = MSBC_ENCODE_PCM_LEN;
pcm_data.data = (uint8_t *)(msbc_plc_encoder_buffer + MSBC_CODEC_DELAY);
btif_plc_update_sbc_decoder_state(msbc_plc_encoder, &pcm_data, msbc_decoder, msbc_eq_band_gain);
#endif
#else
pcm_data.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
pcm_data.numChannels = 1;
pcm_data.dataLen = 0;
pcm_data.data = (uint8_t *)dec_pcm_buf;
ret = btif_sbc_decode_frames(msbc_decoder,
(unsigned char *)indices0,
MSBC_LEN_PER_FRAME, &byte_decode,
&pcm_data, SAMPLES_LEN_PER_FRAME*2,
msbc_eq_band_gain);
PLC_bad_frame(&msbc_plc_state, dec_pcm_buf, dec_pcm_buf);
ASSERT(ret == BT_STS_SUCCESS, "[%s] msbc decoder should never fail", __FUNCTION__);
#endif
}
#ifdef SPEECH_RX_PLC_DUMP_DATA
audio_dump_add_channel_data(1, (short *)dec_pcm_buf, MSBC_ENCODE_PCM_LEN/2);
audio_dump_run();
#endif
dec_pcm_buf=dec_pcm_buf+SAMPLES_LEN_PER_FRAME;
frame_counter++;
}
for(i =0; i<MSBC_LEN_FORMBT_PER_FRAME; i++)
{
msbc_buf_all[i]=msbc_buf_all[i+msbc_len];
}
#endif
//TRACE(1,"msbc + plc:%d", (hal_sys_timer_get()-timer_begin));
return 0;
}
#ifdef TX_RX_PCM_MASK
#define MSBC_OFFSET_BYTES (0)
#else
#if defined (PCM_FAST_MODE)
#define MSBC_OFFSET_BYTES (1) //This is reletive with chip.
#else
#define MSBC_OFFSET_BYTES (2) //This is reletive with chip.
#endif
#endif
#define MSBC_OFFSET_HEADER0_BYTES ((MSBC_LEN_PER_FRAME-MSBC_OFFSET_BYTES)%MSBC_LEN_PER_FRAME)
#define MSBC_OFFSET_HEADER1_BYTES ((MSBC_LEN_PER_FRAME-MSBC_OFFSET_BYTES+1)%MSBC_LEN_PER_FRAME)
int process_uplink_msbc_frames(unsigned char *pcm_buf, unsigned int pcm_len, unsigned char *msbc_buf,unsigned int msbc_len)
{
#if defined(HFP_1_6_ENABLE)
uint32_t frame_counter=0;
static uint32_t frame_counter_total=0;
static btif_sbc_pcm_data_t pcm_data_enc;
uint16_t bytes_encoded = 0;
static uint8_t msbc_buf_frame[MSBC_LEN_PER_FRAME*2];
uint16_t msbc_len_frame=MSBC_LEN_PER_FRAME-3;
//TRACE(2,"process_uplink_msbc_frames:pcm_len:%d,msbc_len:%d",pcm_len,msbc_len);
while((frame_counter<msbc_len/MSBC_LEN_FORMBT_PER_FRAME)&&(frame_counter<pcm_len/BYTES_PER_PCM_FRAME))
{
unsigned short *msbc_buf_dst_p;
pcm_data_enc.data = pcm_buf+frame_counter*BYTES_PER_PCM_FRAME;
pcm_data_enc.dataLen = BYTES_PER_PCM_FRAME;
#if (MSBC_OFFSET_BYTES==0)||(MSBC_OFFSET_BYTES==1)||(MSBC_OFFSET_BYTES==2)
//body
btif_sbc_encode_frames(msbc_encoder, &pcm_data_enc, &bytes_encoded, &(msbc_buf_frame[2-MSBC_OFFSET_BYTES]), (uint16_t *)&msbc_len_frame, 0xFFFF);
//tail
msbc_buf_frame[59-MSBC_OFFSET_BYTES]=0x00;
//header
msbc_buf_frame[MSBC_OFFSET_HEADER0_BYTES]=0x01;
switch((frame_counter_total%4))
{
case 0:
msbc_buf_frame[MSBC_OFFSET_HEADER1_BYTES]=0x08;
break;
case 1:
msbc_buf_frame[MSBC_OFFSET_HEADER1_BYTES]=0x38;
break;
case 2:
msbc_buf_frame[MSBC_OFFSET_HEADER1_BYTES]=0xc8;
break;
default:
msbc_buf_frame[MSBC_OFFSET_HEADER1_BYTES]=0xf8;
break;
}
msbc_buf_dst_p=(uint16_t *)(msbc_buf+frame_counter*MSBC_LEN_PER_FRAME*2);
for (int i = 0; i < MSBC_LEN_PER_FRAME; i++)
{
msbc_buf_dst_p[i] = msbc_buf_frame[i]<<8;
}
#else
btif_sbc_encode_frames(msbc_encoder, &pcm_data_enc, &bytes_encoded, &(msbc_buf_frame[MSBC_LEN_PER_FRAME+2]), (uint16_t *)&msbc_len_frame, 0xFFFF);
msbc_buf_frame[MSBC_LEN_PER_FRAME+0]=0x01;
switch((frame_counter_total%4))
{
case 0:
msbc_buf_frame[MSBC_LEN_PER_FRAME+1]=0x08;
break;
case 1:
msbc_buf_frame[MSBC_LEN_PER_FRAME+1]=0x38;
break;
case 2:
msbc_buf_frame[MSBC_LEN_PER_FRAME+1]=0xc8;
break;
default:
msbc_buf_frame[MSBC_LEN_PER_FRAME+1]=0xf8;
break;
}
msbc_buf_frame[MSBC_LEN_PER_FRAME+59]=0x00;
msbc_buf_dst_p=(uint16_t *)(msbc_buf+frame_counter*MSBC_LEN_PER_FRAME*2);
for (int i = 0; i < MSBC_LEN_PER_FRAME; i++)
{
msbc_buf_dst_p[i] = msbc_buf_frame[MSBC_OFFSET_BYTES+i]<<8;
}
for (int i = 0; i < MSBC_LEN_PER_FRAME; i++)
{
msbc_buf_frame[i] = msbc_buf_frame[MSBC_LEN_PER_FRAME+i];
}
#endif
frame_counter_total++;
frame_counter++;
}
#endif
return 0;
}
#if defined(CHIP_BEST2300A)
#define CVSD_OFFSET_BYTES (120)
#else
#define CVSD_OFFSET_BYTES (120 - 2)
#endif
#define CVSD_PACKET_SIZE (120)
#define CVSD_PACKET_NUM (2)
#define CVSD_MUTE_PATTERN (0x55)
#define CVSD_PCM_SIZE (120)
static POSSIBLY_UNUSED uint8_t cvsd_buf_all[CVSD_PACKET_SIZE + CVSD_OFFSET_BYTES];
POSSIBLY_UNUSED plc_type_t check_cvsd_mute_pattern(uint8_t *buf, uint32_t len)
{
for (uint32_t i = 0; i < len; i++)
if (buf[i] != CVSD_MUTE_PATTERN)
return PLC_TYPE_PASS;
return PLC_TYPE_CONTROLLER_MUTE;
}
int process_downlink_cvsd_frames(unsigned char *cvsd_buf, unsigned int cvsd_len, unsigned char *pcm_buf,unsigned int pcm_len)
{
//TRACE(2,"process_downlink_cvsd_frames pcm_len:%d,cvsd_len:%d",pcm_len,cvsd_len);
#if defined(CVSD_BYPASS) && defined(ENABLE_LPC_PLC)
ASSERT(cvsd_len % CVSD_PACKET_SIZE == 0, "[%s] cvsd input length(%d) error", __FUNCTION__, cvsd_len);
for (uint32_t i = 0; i < cvsd_len; i += CVSD_PACKET_SIZE) {
memcpy(&cvsd_buf_all[CVSD_OFFSET_BYTES], cvsd_buf, CVSD_PACKET_SIZE);
memcpy(cvsd_buf, cvsd_buf_all, CVSD_PACKET_SIZE);
memcpy(cvsd_buf_all, &cvsd_buf_all[CVSD_PACKET_SIZE], CVSD_OFFSET_BYTES);
//DUMP16("0x%x, ", cvsd_buf, CVSD_PACKET_SIZE / 2);
plc_type_t plc_type = check_cvsd_mute_pattern(cvsd_buf, CVSD_PACKET_SIZE);
if (plc_type != PLC_TYPE_PASS) {
memset(pcm_buf, 0, CVSD_PCM_SIZE);
goto do_plc;
}
CvsdToPcm8k(cvsd_buf, (short *)(pcm_buf), CVSD_PACKET_SIZE/2, 0);
do_plc:
if (plc_type == PLC_TYPE_PASS) {
lpc_plc_save(msbc_plc_state, (int16_t *)pcm_buf);
} else {
TRACE(1,"PLC bad frame, plc type: %d", plc_type);
#if defined(PLC_DEBUG_PRINT_DATA)
DUMP16("0x%x, ", cvsd_buf, CVSD_PACKET_SIZE / 2);
#endif
lpc_plc_generate(msbc_plc_state, (int16_t *)pcm_buf, NULL);
}
cvsd_buf += CVSD_PACKET_SIZE;
pcm_buf += CVSD_PCM_SIZE;
}
#else
#if defined(CVSD_BYPASS)
CvsdToPcm8k(cvsd_buf, (short *)(pcm_buf), cvsd_len/2, 0);
#else
memcpy(pcm_buf,cvsd_buf,cvsd_len);
#endif
#ifndef ENABLE_LPC_PLC
speech_plc_8000((PlcSt_8000 *)speech_plc, (short *)pcm_buf, pcm_len);
#endif
#endif
return 0;
}
int process_uplink_cvsd_frames(unsigned char *pcm_buf, unsigned int pcm_len, unsigned char *cvsd_buf,unsigned int cvsd_len)
{
//TRACE(2,"process_uplink_cvsd_frames pcm_len:%d,cvsd_len:%d",pcm_len,cvsd_len);
#if defined(CVSD_BYPASS)
Pcm8kToCvsd((short *)pcm_buf, cvsd_buf, pcm_len/2);
#endif
return 0;
}
void *voicebtpcm_get_ext_buff(int size)
{
uint8_t *pBuff = NULL;
if (size % 4)
{
size = size + (4 - size % 4);
}
app_audio_mempool_get_buff(&pBuff, size);
VOICEBTPCM_TRACE(2,"[%s] len:%d", __func__, size);
return (void*)pBuff;
}
// sco sample rate: encoder/decoder sample rate
// codec sample rate: hardware sample rate
int voicebtpcm_pcm_audio_init(int sco_sample_rate, int codec_sample_rate)
{
uint8_t POSSIBLY_UNUSED *speech_buf = NULL;
int POSSIBLY_UNUSED speech_len = 0;
sco_frame_length = SPEECH_FRAME_MS_TO_LEN(sco_sample_rate, SPEECH_SCO_FRAME_MS);
codec_frame_length = SPEECH_FRAME_MS_TO_LEN(codec_sample_rate, SPEECH_SCO_FRAME_MS);
TRACE(3, "[%s] TX: sample rate = %d, frame len = %d", __func__, codec_sample_rate, codec_frame_length);
TRACE(3, "[%s] RX: sample rate = %d, frame len = %d", __func__, codec_sample_rate, codec_frame_length);
memset(cvsd_buf_all, CVSD_MUTE_PATTERN, sizeof(cvsd_buf_all));
#if defined(HFP_1_6_ENABLE)
memset(msbc_buf_all,MSBC_MUTE_PATTERN&0xFF, sizeof(msbc_buf_all));
if (bt_sco_codec_is_msbc())
{
app_audio_mempool_get_buff((uint8_t **)&msbc_encoder, sizeof(btif_sbc_encoder_t));
app_audio_mempool_get_buff((uint8_t **)&msbc_decoder, sizeof(btif_sbc_decoder_t));
//init msbc encoder
btif_sbc_init_encoder(msbc_encoder);
msbc_encoder->streamInfo.mSbcFlag = 1;
msbc_encoder->streamInfo.numChannels = 1;
msbc_encoder->streamInfo.channelMode = BTIF_SBC_CHNL_MODE_MONO;
msbc_encoder->streamInfo.bitPool = 26;
msbc_encoder->streamInfo.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
msbc_encoder->streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_LOUDNESS;
msbc_encoder->streamInfo.numBlocks = BTIF_MSBC_BLOCKS;
msbc_encoder->streamInfo.numSubBands = 8;
//init msbc decoder
const float EQLevel[25] =
{
0.0630957, 0.0794328, 0.1, 0.1258925, 0.1584893,
0.1995262, 0.2511886, 0.3162278, 0.398107, 0.5011872,
0.6309573, 0.794328, 1, 1.258925, 1.584893,
1.995262, 2.5118864, 3.1622776, 3.9810717, 5.011872,
6.309573, 7.943282, 10, 12.589254, 15.848932
};//-12~12
uint8_t i;
for (i=0; i<sizeof(msbc_eq_band_gain)/sizeof(float); i++)
{
msbc_eq_band_gain[i] = EQLevel[cfg_aud_eq_sbc_band_settings[i]+12];
}
btif_sbc_init_decoder(msbc_decoder);
msbc_decoder->streamInfo.mSbcFlag = 1;
msbc_decoder->streamInfo.bitPool = 26;
msbc_decoder->streamInfo.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
msbc_decoder->streamInfo.channelMode = BTIF_SBC_CHNL_MODE_MONO;
msbc_decoder->streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_LOUDNESS;
/* Number of blocks used to encode the stream (4, 8, 12, or 16) */
msbc_decoder->streamInfo.numBlocks = BTIF_MSBC_BLOCKS;
/* The number of subbands in the stream (4 or 8) */
msbc_decoder->streamInfo.numSubBands = 8;
msbc_decoder->streamInfo.numChannels = 1;
//init msbc plc
#ifndef ENABLE_LPC_PLC
InitPLC(&msbc_plc_state);
#endif
next_frame_flag = 0;
msbc_find_first_sync = 0;
packet_loss_detection_init(&pld);
#if defined(ENABLE_PLC_ENCODER)
app_audio_mempool_get_buff((uint8_t **)&msbc_plc_encoder, sizeof(btif_sbc_encoder_t));
btif_sbc_init_encoder(msbc_plc_encoder);
msbc_plc_encoder->streamInfo.mSbcFlag = 1;
msbc_plc_encoder->streamInfo.bitPool = 26;
msbc_plc_encoder->streamInfo.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
msbc_plc_encoder->streamInfo.channelMode = BTIF_SBC_CHNL_MODE_MONO;
msbc_plc_encoder->streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_LOUDNESS;
/* Number of blocks used to encode the stream (4, 8, 12, or 16) */
msbc_plc_encoder->streamInfo.numBlocks = BTIF_MSBC_BLOCKS;
/* The number of subbands in the stream (4 or 8) */
msbc_plc_encoder->streamInfo.numSubBands = 8;
msbc_plc_encoder->streamInfo.numChannels = 1;
app_audio_mempool_get_buff((uint8_t **)&msbc_plc_encoder_buffer, sizeof(int16_t) * (SAMPLES_LEN_PER_FRAME + MSBC_CODEC_DELAY));
#endif
}
else
#endif
{
#ifndef ENABLE_LPC_PLC
speech_plc = (PlcSt_8000 *)speech_plc_8000_init(voicebtpcm_get_ext_buff);
#endif
}
#if defined(CVSD_BYPASS)
Pcm8k_CvsdInit();
#endif
#ifdef SPEECH_RX_PLC_DUMP_DATA
audio_dump_temp_buf = (int16_t *)voicebtpcm_get_ext_buff(sizeof(int16_t) * 120);
audio_dump_init(120, sizeof(short), 3);
#endif
resample_needed_flag = (sco_sample_rate == codec_sample_rate) ? 0 : 1;
if (resample_needed_flag) {
TRACE(1, "[%s] SCO <-- Resample --> CODEC", __func__);
resample_buf = (int16_t *)voicebtpcm_get_ext_buff(sizeof(int16_t) * sco_frame_length);
}
#if defined(SCO_OPTIMIZE_FOR_RAM)
sco_overlay_ram_buf_len = hal_overlay_get_text_free_size((enum HAL_OVERLAY_ID_T)APP_OVERLAY_HFP);
sco_overlay_ram_buf = (uint8_t *)hal_overlay_get_text_free_addr((enum HAL_OVERLAY_ID_T)APP_OVERLAY_HFP);
#endif
speech_len = app_audio_mempool_free_buff_size() - APP_BT_STREAM_USE_BUF_SIZE;
speech_buf = (uint8_t *)voicebtpcm_get_ext_buff(speech_len);
int tx_frame_ms = SPEECH_PROCESS_FRAME_MS;
int rx_frame_ms = SPEECH_SCO_FRAME_MS;
speech_init(codec_sample_rate, codec_sample_rate, tx_frame_ms, rx_frame_ms, SPEECH_SCO_FRAME_MS, speech_buf, speech_len);
if (resample_needed_flag) {
uplink_resample_st = iir_resample_init(codec_frame_length, iir_resample_choose_mode(codec_sample_rate, sco_sample_rate));
downlink_resample_st = iir_resample_init(sco_frame_length, iir_resample_choose_mode(sco_sample_rate, codec_sample_rate));
}
#if defined(ENABLE_LPC_PLC)
msbc_plc_state = lpc_plc_create(sco_sample_rate);
#endif
return 0;
}
int voicebtpcm_pcm_audio_deinit(void)
{
TRACE(1,"[%s] Close...", __func__);
// TRACE(2,"[%s] app audio buffer free = %d", __func__, app_audio_mempool_free_buff_size());
#if defined(ENABLE_LPC_PLC)
lpc_plc_destroy(msbc_plc_state);
#endif
if (resample_needed_flag) {
iir_resample_destroy(uplink_resample_st);
iir_resample_destroy(downlink_resample_st);
}
speech_deinit();
packet_loss_detection_report(&pld);
#if defined(SCO_OPTIMIZE_FOR_RAM)
sco_overlay_ram_buf = NULL;
sco_overlay_ram_buf_len = 0;
#endif
// TRACE(1,"Free buf = %d", app_audio_mempool_free_buff_size());
return 0;
}

View file

@ -0,0 +1,253 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifdef MBED
#include "mbed.h"
#endif
// Standard C Included Files
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include "hal_uart.h"
#include "hal_trace.h"
#include "hal_timer.h"
/*!
* * @brief Standard Winodws PCM wave file header length
* */
#define WAVE_FILE_HEADER_SIZE 0x2CU
typedef struct wave_header
{
uint8_t riff[4];
uint32_t size;
uint8_t waveFlag[4];
uint8_t fmt[4];
uint32_t fmtLen;
uint16_t tag;
uint16_t channels;
uint32_t sampFreq;
uint32_t byteRate;
uint16_t blockAlign;
uint16_t bitSamp;
uint8_t dataFlag[4];
uint32_t length;
} wave_header_t;
/*!
* * @brief Wave file structure
* */
typedef struct wave_file
{
wave_header_t header;
uint32_t *data;
}wave_file_t;
/* player */
static unsigned int g_total_play_count = 0;
static unsigned int g_curr_play_index = 0;
/* wave */
wave_file_t g_wave_file_info;
static char g_wav_header[WAVE_FILE_HEADER_SIZE];
FILE *g_wave_file_handle = NULL;
static int32_t (*wav_file_palyback_callback)(int32_t ) = NULL;
////////////////////////////////////////////////////////////////////////////////
// Code
////////////////////////////////////////////////////////////////////////////////
void wav_file_set_playeback_cb(int32_t (* cb)(int32_t))
{
wav_file_palyback_callback = cb;
}
bool wav_file_isplaydone(void)
{
return (g_curr_play_index >= g_total_play_count)? true : false;
}
uint32_t wav_file_audio_more_data(uint8_t *buf, uint32_t len)
{
// static uint32_t g_preIrqTime = 0;
uint32_t reallen = 0;
// int32_t stime,etime;
int32_t status;
/* play done ? */
if(wav_file_isplaydone()) {
memset(buf, 0, len);
status = 0;
if (wav_file_palyback_callback)
wav_file_palyback_callback(status);
return (len);
}
// stime = hal_sys_timer_get();
/* read file */
if (g_wave_file_handle)
reallen = fread(buf, 1, len, g_wave_file_handle);
// etime = hal_sys_timer_get();
if (reallen != len){
memset(buf, 0, len);
status = -1;
if (wav_file_palyback_callback)
wav_file_palyback_callback(status);
return (len);
}
// TRACE(5,"wav_file_audio_more_data irqDur:%d fsSpend:%d, readbuff:0x%08x %d/%d\n ", TICKS_TO_MS(stime - g_preIrqTime),TICKS_TO_MS(etime - stime),buf,reallen,len);
// g_preIrqTime = stime;
/* walk index */
g_curr_play_index += reallen;
return reallen;
}
uint32_t get_wav_data(wave_file_t *waveFile)
{
uint8_t *dataTemp = (uint8_t *)waveFile->data;
// check for RIFF
memcpy(waveFile->header.riff, dataTemp, 4);
dataTemp += 4;
if( memcmp( (uint8_t*)waveFile->header.riff, "RIFF", 4) )
{
return 0;
}
// Get size
memcpy(&waveFile->header.size, dataTemp, 4);
dataTemp += 4;
TRACE(1,"WAV header size [%d]\n", waveFile->header.size);
// .wav file flag
memcpy(waveFile->header.waveFlag, dataTemp, 4);
dataTemp += 4;
if( memcmp( (uint8_t*)waveFile->header.waveFlag, "WAVE", 4) )
{
return 0;
}
// fmt
memcpy(waveFile->header.fmt, dataTemp, 4);
dataTemp += 4;
if( memcmp( (uint8_t*)waveFile->header.fmt, "fmt ", 4) )
{
return 0;
}
// fmt length
memcpy(&waveFile->header.fmtLen, dataTemp, 4);
dataTemp += 4;
// Tag: PCM or not
memcpy(&waveFile->header.tag, dataTemp, 4);
dataTemp += 2;
// Channels
memcpy(&waveFile->header.channels, dataTemp, 4);
dataTemp += 2;
TRACE(1,"WAV channels [%d]\n", waveFile->header.channels);
// Sample Rate in Hz
memcpy(&waveFile->header.sampFreq, dataTemp, 4);
dataTemp += 4;
memcpy(&waveFile->header.byteRate, dataTemp, 4);
dataTemp += 4;
TRACE(1,"WAV sample_rate [%d]\n", waveFile->header.sampFreq);
TRACE(1,"WAV byteRate [%d]\n", waveFile->header.byteRate);
// quantize bytes for per samp point
memcpy(&waveFile->header.blockAlign, dataTemp, 4);
dataTemp += 2;
memcpy(&waveFile->header.bitSamp, dataTemp, 4);
dataTemp += 2;
TRACE(1,"WAV bitSamp [%d]\n", waveFile->header.bitSamp);
// Data
memcpy(waveFile->header.dataFlag, dataTemp, 4);
dataTemp += 4;
if( memcmp( (uint8_t*)waveFile->header.dataFlag, "data ", 4) )
{
return 0;
}
memcpy(&waveFile->header.length, dataTemp, 4);
dataTemp += 4;
return 0;
}
void audio_wav_init(wave_file_t *newWav)
{
get_wav_data(newWav);
// Configure the play audio g_format
//g_format.bits = newWav->header.bitSamp;
//g_format.sample_rate = newWav->header.sampFreq;
//g_format.mclk = 256 * g_format.sample_rate ;
//g_format.mono_streo = (sai_mono_streo_t)((newWav->header.channels) - 1);
}
uint32_t play_wav_file(char *file_path)
{
uint32_t bytesToRead = 0;
wave_file_t *newWav = &g_wave_file_info;
memset(&g_wave_file_info, 0, sizeof(g_wave_file_info));
g_wave_file_handle = fopen(file_path, "rb");
if(g_wave_file_handle == NULL) {
TRACE(1,"WAV file %s open fail\n", file_path);
return 1;
}
fread(&g_wav_header, WAVE_FILE_HEADER_SIZE, 1, g_wave_file_handle);
newWav->data = (uint32_t *)&g_wav_header;
audio_wav_init(newWav);
// Remove header size from byte count
// Adjust note duration by divider value, wav tables in pcm_data.h are 200ms by default
bytesToRead = (newWav->header.length - WAVE_FILE_HEADER_SIZE);
g_curr_play_index = 0;
g_total_play_count = bytesToRead;
return newWav->header.sampFreq;
}
uint32_t stop_wav_file(void)
{
memset(&g_wave_file_info, 0, sizeof(g_wave_file_info));
g_curr_play_index = 0;
g_total_play_count = 0;
if (g_wave_file_handle){
fclose(g_wave_file_handle);
g_wave_file_handle = NULL;
}
if (wav_file_palyback_callback)
wav_file_palyback_callback = NULL;
return 0;
}

18
apps/battery/Makefile Normal file
View file

@ -0,0 +1,18 @@
cur_dir := $(dir $(lastword $(MAKEFILE_LIST)))
obj-y := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)*.c $(cur_dir)*.cpp $(cur_dir)*.S))
obj-y := $(obj-y:.c=.o)
obj-y := $(obj-y:.cpp=.o)
obj-y := $(obj-y:.S=.o)
subdir-ccflags-y += -Iplatform/drivers/ana \
$(BT_IF_INCLUDES) \
-Iservices/ble_app/app_main \
-Iservices/app_ibrt/inc \
-Iservices/ibrt_ui/inc \
-Iservices/ibrt_core/inc
ifeq ($(VOICE_PROMPT),1)
CFLAGS_app_battery.o += -DMEDIA_PLAYER_SUPPORT
endif

View file

@ -0,0 +1,903 @@
/***************************************************************************
*
* 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 "cmsis_os.h"
#include "tgt_hardware.h"
#include "pmu.h"
#include "hal_timer.h"
#include "hal_gpadc.h"
#include "hal_trace.h"
#include "hal_gpio.h"
#include "hal_iomux.h"
#include "hal_chipid.h"
#include "app_thread.h"
#include "app_battery.h"
#include "apps.h"
#include "app_status_ind.h"
#ifdef BT_USB_AUDIO_DUAL_MODE
#include "btusb_audio.h"
#endif
#include <stdlib.h>
#ifdef __INTERCONNECTION__
#include "app_ble_mode_switch.h"
#endif
#if (defined(BTUSB_AUDIO_MODE) || defined(BTUSB_AUDIO_MODE))
extern "C" bool app_usbaudio_mode_on(void);
#endif
#define APP_BATTERY_TRACE(s,...)
// TRACE(s, ##__VA_ARGS__)
#ifndef APP_BATTERY_MIN_MV
#define APP_BATTERY_MIN_MV (3200)
#endif
#ifndef APP_BATTERY_MAX_MV
#define APP_BATTERY_MAX_MV (4200)
#endif
#ifndef APP_BATTERY_PD_MV
#define APP_BATTERY_PD_MV (3100)
#endif
#ifndef APP_BATTERY_CHARGE_TIMEOUT_MIN
#define APP_BATTERY_CHARGE_TIMEOUT_MIN (90)
#endif
#ifndef APP_BATTERY_CHARGE_OFFSET_MV
#define APP_BATTERY_CHARGE_OFFSET_MV (20)
#endif
#ifndef CHARGER_PLUGINOUT_RESET
#define CHARGER_PLUGINOUT_RESET (0)
#endif
#ifndef CHARGER_PLUGINOUT_DEBOUNCE_MS
#define CHARGER_PLUGINOUT_DEBOUNCE_MS (50)
#endif
#ifndef CHARGER_PLUGINOUT_DEBOUNCE_CNT
#define CHARGER_PLUGINOUT_DEBOUNCE_CNT (3)
#endif
#define APP_BATTERY_CHARGING_PLUGOUT_DEDOUNCE_CNT (APP_BATTERY_CHARGING_PERIODIC_MS<500?3:1)
#define APP_BATTERY_CHARGING_EXTPIN_MEASURE_CNT (APP_BATTERY_CHARGING_PERIODIC_MS<2*1000?2*1000/APP_BATTERY_CHARGING_PERIODIC_MS:1)
#define APP_BATTERY_CHARGING_EXTPIN_DEDOUNCE_CNT (6)
#define APP_BATTERY_CHARGING_OVERVOLT_MEASURE_CNT (APP_BATTERY_CHARGING_PERIODIC_MS<2*1000?2*1000/APP_BATTERY_CHARGING_PERIODIC_MS:1)
#define APP_BATTERY_CHARGING_OVERVOLT_DEDOUNCE_CNT (3)
#define APP_BATTERY_CHARGING_SLOPE_MEASURE_CNT (APP_BATTERY_CHARGING_PERIODIC_MS<20*1000?20*1000/APP_BATTERY_CHARGING_PERIODIC_MS:1)
#define APP_BATTERY_CHARGING_SLOPE_TABLE_COUNT (6)
#define APP_BATTERY_REPORT_INTERVAL (5)
#define APP_BATTERY_MV_BASE ((APP_BATTERY_MAX_MV-APP_BATTERY_PD_MV)/(APP_BATTERY_LEVEL_NUM))
#define APP_BATTERY_STABLE_COUNT (5)
#define APP_BATTERY_MEASURE_PERIODIC_FAST_MS (200)
#ifdef BLE_ONLY_ENABLED
#define APP_BATTERY_MEASURE_PERIODIC_NORMAL_MS (25000)
#else
#define APP_BATTERY_MEASURE_PERIODIC_NORMAL_MS (10000)
#endif
#define APP_BATTERY_CHARGING_PERIODIC_MS (APP_BATTERY_MEASURE_PERIODIC_NORMAL_MS)
#define APP_BATTERY_SET_MESSAGE(appevt, status, volt) (appevt = (((uint32_t)status&0xffff)<<16)|(volt&0xffff))
#define APP_BATTERY_GET_STATUS(appevt, status) (status = (appevt>>16)&0xffff)
#define APP_BATTERY_GET_VOLT(appevt, volt) (volt = appevt&0xffff)
#define APP_BATTERY_GET_PRAMS(appevt, prams) ((prams) = appevt&0xffff)
enum APP_BATTERY_MEASURE_PERIODIC_T
{
APP_BATTERY_MEASURE_PERIODIC_FAST = 0,
APP_BATTERY_MEASURE_PERIODIC_NORMAL,
APP_BATTERY_MEASURE_PERIODIC_CHARGING,
APP_BATTERY_MEASURE_PERIODIC_QTY,
};
struct APP_BATTERY_MEASURE_CHARGER_STATUS_T
{
HAL_GPADC_MV_T prevolt;
int32_t slope_1000[APP_BATTERY_CHARGING_SLOPE_TABLE_COUNT];
int slope_1000_index;
int cnt;
};
typedef void (*APP_BATTERY_EVENT_CB_T)(enum APP_BATTERY_STATUS_T, APP_BATTERY_MV_T volt);
struct APP_BATTERY_MEASURE_T
{
uint32_t start_time;
enum APP_BATTERY_STATUS_T status;
#ifdef __INTERCONNECTION__
uint8_t currentBatteryInfo;
uint8_t lastBatteryInfo;
uint8_t isMobileSupportSelfDefinedCommand;
#else
uint8_t currlevel;
#endif
APP_BATTERY_MV_T currvolt;
APP_BATTERY_MV_T lowvolt;
APP_BATTERY_MV_T highvolt;
APP_BATTERY_MV_T pdvolt;
uint32_t chargetimeout;
enum APP_BATTERY_MEASURE_PERIODIC_T periodic;
HAL_GPADC_MV_T voltage[APP_BATTERY_STABLE_COUNT];
uint16_t index;
struct APP_BATTERY_MEASURE_CHARGER_STATUS_T charger_status;
APP_BATTERY_EVENT_CB_T cb;
APP_BATTERY_CB_T user_cb;
};
static enum APP_BATTERY_CHARGER_T app_battery_charger_forcegetstatus(void);
static void app_battery_pluginout_debounce_start(void);
static void app_battery_pluginout_debounce_handler(void const *param);
osTimerDef (APP_BATTERY_PLUGINOUT_DEBOUNCE, app_battery_pluginout_debounce_handler);
static osTimerId app_battery_pluginout_debounce_timer = NULL;
static uint32_t app_battery_pluginout_debounce_ctx = 0;
static uint32_t app_battery_pluginout_debounce_cnt = 0;
static void app_battery_timer_handler(void const *param);
osTimerDef (APP_BATTERY, app_battery_timer_handler);
static osTimerId app_battery_timer = NULL;
static struct APP_BATTERY_MEASURE_T app_battery_measure;
static int app_battery_charger_handle_process(void);
#ifdef __INTERCONNECTION__
uint8_t* app_battery_get_mobile_support_self_defined_command_p(void)
{
return &app_battery_measure.isMobileSupportSelfDefinedCommand;
}
#endif
void app_battery_irqhandler(uint16_t irq_val, HAL_GPADC_MV_T volt)
{
uint8_t i;
uint32_t meanBattVolt = 0;
HAL_GPADC_MV_T vbat = volt;
APP_BATTERY_TRACE(2,"%s %d",__func__, vbat);
if (vbat == HAL_GPADC_BAD_VALUE)
{
app_battery_measure.cb(APP_BATTERY_STATUS_INVALID, vbat);
return;
}
#if (defined(BTUSB_AUDIO_MODE) || defined(BTUSB_AUDIO_MODE))
if(app_usbaudio_mode_on()) return ;
#endif
app_battery_measure.voltage[app_battery_measure.index++%APP_BATTERY_STABLE_COUNT] = vbat<<2;
if (app_battery_measure.index > APP_BATTERY_STABLE_COUNT)
{
for (i=0; i<APP_BATTERY_STABLE_COUNT; i++)
{
meanBattVolt += app_battery_measure.voltage[i];
}
meanBattVolt /= APP_BATTERY_STABLE_COUNT;
if (app_battery_measure.cb)
{
if (meanBattVolt>app_battery_measure.highvolt)
{
app_battery_measure.cb(APP_BATTERY_STATUS_OVERVOLT, meanBattVolt);
}
else if((meanBattVolt>app_battery_measure.pdvolt) && (meanBattVolt<app_battery_measure.lowvolt))
{
app_battery_measure.cb(APP_BATTERY_STATUS_UNDERVOLT, meanBattVolt);
}
else if(meanBattVolt<app_battery_measure.pdvolt)
{
app_battery_measure.cb(APP_BATTERY_STATUS_PDVOLT, meanBattVolt);
}
else
{
app_battery_measure.cb(APP_BATTERY_STATUS_NORMAL, meanBattVolt);
}
}
}
else
{
int8_t level = 0;
meanBattVolt = vbat<<2;
level = (meanBattVolt-APP_BATTERY_PD_MV)/APP_BATTERY_MV_BASE;
if (level<APP_BATTERY_LEVEL_MIN)
level = APP_BATTERY_LEVEL_MIN;
if (level>APP_BATTERY_LEVEL_MAX)
level = APP_BATTERY_LEVEL_MAX;
app_battery_measure.currvolt = meanBattVolt;
#ifdef __INTERCONNECTION__
APP_BATTERY_INFO_T* pBatteryInfo = (APP_BATTERY_INFO_T*)&app_battery_measure.currentBatteryInfo;
pBatteryInfo->batteryLevel = level;
#else
app_battery_measure.currlevel = level;
#endif
}
}
static void app_battery_timer_start(enum APP_BATTERY_MEASURE_PERIODIC_T periodic)
{
uint32_t periodic_millisec = 0;
if (app_battery_measure.periodic != periodic){
app_battery_measure.periodic = periodic;
switch (periodic)
{
case APP_BATTERY_MEASURE_PERIODIC_FAST:
periodic_millisec = APP_BATTERY_MEASURE_PERIODIC_FAST_MS;
break;
case APP_BATTERY_MEASURE_PERIODIC_CHARGING:
periodic_millisec = APP_BATTERY_CHARGING_PERIODIC_MS;
break;
case APP_BATTERY_MEASURE_PERIODIC_NORMAL:
periodic_millisec = APP_BATTERY_MEASURE_PERIODIC_NORMAL_MS;
default:
break;
}
osTimerStop(app_battery_timer);
osTimerStart(app_battery_timer, periodic_millisec);
}
}
static void app_battery_timer_handler(void const *param)
{
hal_gpadc_open(HAL_GPADC_CHAN_BATTERY, HAL_GPADC_ATP_ONESHOT, app_battery_irqhandler);
}
static void app_battery_event_process(enum APP_BATTERY_STATUS_T status, APP_BATTERY_MV_T volt)
{
uint32_t app_battevt;
APP_MESSAGE_BLOCK msg;
APP_BATTERY_TRACE(3,"%s %d,%d",__func__, status, volt);
msg.mod_id = APP_MODUAL_BATTERY;
APP_BATTERY_SET_MESSAGE(app_battevt, status, volt);
msg.msg_body.message_id = app_battevt;
msg.msg_body.message_ptr = (uint32_t)NULL;
app_mailbox_put(&msg);
}
int app_battery_handle_process_normal(uint32_t status, union APP_BATTERY_MSG_PRAMS prams)
{
int8_t level = 0;
switch (status)
{
case APP_BATTERY_STATUS_UNDERVOLT:
TRACE(1,"UNDERVOLT:%d", prams.volt);
app_status_indication_set(APP_STATUS_INDICATION_CHARGENEED);
#ifdef MEDIA_PLAYER_SUPPORT
#if defined(IBRT)
#else
app_voice_report(APP_STATUS_INDICATION_CHARGENEED, 0);
#endif
#endif
case APP_BATTERY_STATUS_NORMAL:
case APP_BATTERY_STATUS_OVERVOLT:
app_battery_measure.currvolt = prams.volt;
level = (prams.volt-APP_BATTERY_PD_MV)/APP_BATTERY_MV_BASE;
if (level<APP_BATTERY_LEVEL_MIN)
level = APP_BATTERY_LEVEL_MIN;
if (level>APP_BATTERY_LEVEL_MAX)
level = APP_BATTERY_LEVEL_MAX;
#ifdef __INTERCONNECTION__
APP_BATTERY_INFO_T* pBatteryInfo;
pBatteryInfo = (APP_BATTERY_INFO_T*)&app_battery_measure.currentBatteryInfo;
pBatteryInfo->batteryLevel = level;
if(level == APP_BATTERY_LEVEL_MAX)
{
level = 9;
}
else
{
level /= 10;
}
#else
app_battery_measure.currlevel = level;
#endif
app_status_battery_report(level);
break;
case APP_BATTERY_STATUS_PDVOLT:
#ifndef BT_USB_AUDIO_DUAL_MODE
TRACE(1,"PDVOLT-->POWEROFF:%d", prams.volt);
osTimerStop(app_battery_timer);
app_shutdown();
#endif
break;
case APP_BATTERY_STATUS_CHARGING:
TRACE(1,"CHARGING-->APP_BATTERY_CHARGER :%d", prams.charger);
if (prams.charger == APP_BATTERY_CHARGER_PLUGIN)
{
#ifdef BT_USB_AUDIO_DUAL_MODE
TRACE(1,"%s:PLUGIN.", __func__);
btusb_switch(BTUSB_MODE_USB);
#else
#if CHARGER_PLUGINOUT_RESET
app_reset();
#else
app_battery_measure.status = APP_BATTERY_STATUS_CHARGING;
#endif
#endif
}else{
app_reset();
}
break;
case APP_BATTERY_STATUS_INVALID:
default:
break;
}
app_battery_timer_start(APP_BATTERY_MEASURE_PERIODIC_NORMAL);
return 0;
}
int app_battery_handle_process_charging(uint32_t status, union APP_BATTERY_MSG_PRAMS prams)
{
switch (status)
{
case APP_BATTERY_STATUS_OVERVOLT:
case APP_BATTERY_STATUS_NORMAL:
case APP_BATTERY_STATUS_UNDERVOLT:
app_battery_measure.currvolt = prams.volt;
app_status_battery_report(prams.volt);
break;
case APP_BATTERY_STATUS_CHARGING:
TRACE(1,"CHARGING:%d", prams.charger);
if (prams.charger == APP_BATTERY_CHARGER_PLUGOUT)
{
#ifdef BT_USB_AUDIO_DUAL_MODE
TRACE(1,"%s:PlUGOUT.", __func__);
btusb_switch(BTUSB_MODE_BT);
#else
#if CHARGER_PLUGINOUT_RESET
TRACE(0,"CHARGING-->RESET");
osTimerStop(app_battery_timer);
app_shutdown();
#else
app_battery_measure.status = APP_BATTERY_STATUS_NORMAL;
#endif
#endif
}
else if (prams.charger == APP_BATTERY_CHARGER_PLUGIN)
{
#ifdef BT_USB_AUDIO_DUAL_MODE
TRACE(1,"%s:PLUGIN.", __func__);
btusb_switch(BTUSB_MODE_USB);
#endif
}
break;
case APP_BATTERY_STATUS_INVALID:
default:
break;
}
if (app_battery_charger_handle_process()<=0)
{
if (app_status_indication_get() != APP_STATUS_INDICATION_FULLCHARGE)
{
TRACE(1,"FULL_CHARGING:%d", app_battery_measure.currvolt);
app_status_indication_set(APP_STATUS_INDICATION_FULLCHARGE);
#ifdef MEDIA_PLAYER_SUPPORT
#if defined(BT_USB_AUDIO_DUAL_MODE) || defined(IBRT)
#else
app_voice_report(APP_STATUS_INDICATION_FULLCHARGE, 0);
#endif
#endif
}
}
app_battery_timer_start(APP_BATTERY_MEASURE_PERIODIC_CHARGING);
return 0;
}
static int app_battery_handle_process(APP_MESSAGE_BODY *msg_body)
{
uint8_t status;
union APP_BATTERY_MSG_PRAMS msg_prams;
APP_BATTERY_GET_STATUS(msg_body->message_id, status);
APP_BATTERY_GET_PRAMS(msg_body->message_id, msg_prams.prams);
uint32_t generatedSeed = hal_sys_timer_get();
for (uint8_t index = 0; index < sizeof(bt_addr); index++)
{
generatedSeed ^= (((uint32_t)(bt_addr[index])) << (hal_sys_timer_get()&0xF));
}
srand(generatedSeed);
if (status == APP_BATTERY_STATUS_PLUGINOUT){
app_battery_pluginout_debounce_start();
}
else
{
switch (app_battery_measure.status)
{
case APP_BATTERY_STATUS_NORMAL:
app_battery_handle_process_normal((uint32_t)status, msg_prams);
break;
case APP_BATTERY_STATUS_CHARGING:
app_battery_handle_process_charging((uint32_t)status, msg_prams);
break;
default:
break;
}
}
if (NULL != app_battery_measure.user_cb)
{
uint8_t batteryLevel;
#ifdef __INTERCONNECTION__
APP_BATTERY_INFO_T* pBatteryInfo;
pBatteryInfo = (APP_BATTERY_INFO_T*)&app_battery_measure.currentBatteryInfo;
pBatteryInfo->chargingStatus = ((app_battery_measure.status == APP_BATTERY_STATUS_CHARGING)? 1:0);
batteryLevel = pBatteryInfo->batteryLevel;
#else
batteryLevel = app_battery_measure.currlevel;
#endif
app_battery_measure.user_cb(app_battery_measure.currvolt,
batteryLevel, app_battery_measure.status,status,msg_prams);
}
return 0;
}
int app_battery_register(APP_BATTERY_CB_T user_cb)
{
if(NULL == app_battery_measure.user_cb)
{
app_battery_measure.user_cb = user_cb;
return 0;
}
return 1;
}
int app_battery_get_info(APP_BATTERY_MV_T *currvolt, uint8_t *currlevel, enum APP_BATTERY_STATUS_T *status)
{
if (currvolt)
{
*currvolt = app_battery_measure.currvolt;
}
if (currlevel)
{
#ifdef __INTERCONNECTION__
*currlevel = app_battery_measure.currentBatteryInfo;
#else
*currlevel = app_battery_measure.currlevel;
#endif
}
if (status)
{
*status = app_battery_measure.status;
}
return 0;
}
int app_battery_open(void)
{
APP_BATTERY_TRACE(3,"%s batt range:%d~%d",__func__, APP_BATTERY_MIN_MV, APP_BATTERY_MAX_MV);
int nRet = APP_BATTERY_OPEN_MODE_INVALID;
if (app_battery_timer == NULL)
app_battery_timer = osTimerCreate (osTimer(APP_BATTERY), osTimerPeriodic, NULL);
if (app_battery_pluginout_debounce_timer == NULL)
app_battery_pluginout_debounce_timer = osTimerCreate (osTimer(APP_BATTERY_PLUGINOUT_DEBOUNCE), osTimerOnce, &app_battery_pluginout_debounce_ctx);
app_battery_measure.status = APP_BATTERY_STATUS_NORMAL;
#ifdef __INTERCONNECTION__
app_battery_measure.currentBatteryInfo = APP_BATTERY_DEFAULT_INFO;
app_battery_measure.lastBatteryInfo = APP_BATTERY_DEFAULT_INFO;
app_battery_measure.isMobileSupportSelfDefinedCommand = 0;
#else
app_battery_measure.currlevel = APP_BATTERY_LEVEL_MAX;
#endif
app_battery_measure.currvolt = APP_BATTERY_MAX_MV;
app_battery_measure.lowvolt = APP_BATTERY_MIN_MV;
app_battery_measure.highvolt = APP_BATTERY_MAX_MV;
app_battery_measure.pdvolt = APP_BATTERY_PD_MV;
app_battery_measure.chargetimeout = APP_BATTERY_CHARGE_TIMEOUT_MIN;
app_battery_measure.periodic = APP_BATTERY_MEASURE_PERIODIC_QTY;
app_battery_measure.cb = app_battery_event_process;
app_battery_measure.user_cb = NULL;
app_battery_measure.charger_status.prevolt = 0;
app_battery_measure.charger_status.slope_1000_index = 0;
app_battery_measure.charger_status.cnt = 0;
app_set_threadhandle(APP_MODUAL_BATTERY, app_battery_handle_process);
if (app_battery_ext_charger_detecter_cfg.pin != HAL_IOMUX_PIN_NUM)
{
hal_iomux_init((struct HAL_IOMUX_PIN_FUNCTION_MAP *)&app_battery_ext_charger_detecter_cfg, 1);
hal_gpio_pin_set_dir((enum HAL_GPIO_PIN_T)app_battery_ext_charger_detecter_cfg.pin, HAL_GPIO_DIR_IN, 1);
}
if (app_battery_ext_charger_enable_cfg.pin != HAL_IOMUX_PIN_NUM)
{
hal_iomux_init((struct HAL_IOMUX_PIN_FUNCTION_MAP *)&app_battery_ext_charger_detecter_cfg, 1);
hal_gpio_pin_set_dir((enum HAL_GPIO_PIN_T)app_battery_ext_charger_detecter_cfg.pin, HAL_GPIO_DIR_OUT, 1);
}
if (app_battery_charger_indication_open() == APP_BATTERY_CHARGER_PLUGIN)
{
app_battery_measure.status = APP_BATTERY_STATUS_CHARGING;
app_battery_measure.start_time = hal_sys_timer_get();
//pmu_charger_plugin_config();
if (app_battery_ext_charger_enable_cfg.pin != HAL_IOMUX_PIN_NUM)
{
hal_gpio_pin_set_dir((enum HAL_GPIO_PIN_T)app_battery_ext_charger_detecter_cfg.pin, HAL_GPIO_DIR_OUT, 0);
}
#if (CHARGER_PLUGINOUT_RESET == 0)
nRet = APP_BATTERY_OPEN_MODE_CHARGING_PWRON;
#else
nRet = APP_BATTERY_OPEN_MODE_CHARGING;
#endif
}
else
{
app_battery_measure.status = APP_BATTERY_STATUS_NORMAL;
//pmu_charger_plugout_config();
nRet = APP_BATTERY_OPEN_MODE_NORMAL;
}
return nRet;
}
int app_battery_start(void)
{
APP_BATTERY_TRACE(2,"%s %d",__func__, APP_BATTERY_MEASURE_PERIODIC_FAST_MS);
app_battery_timer_start(APP_BATTERY_MEASURE_PERIODIC_FAST);
return 0;
}
int app_battery_stop(void)
{
osTimerStop(app_battery_timer);
return 0;
}
int app_battery_close(void)
{
hal_gpadc_close(HAL_GPADC_CHAN_BATTERY);
return 0;
}
static int32_t app_battery_charger_slope_calc(int32_t t1, int32_t v1, int32_t t2, int32_t v2)
{
int32_t slope_1000;
slope_1000 = (v2-v1)*1000/(t2-t1);
return slope_1000;
}
static int app_battery_charger_handle_process(void)
{
int nRet = 1;
int8_t i=0,cnt=0;
uint32_t slope_1000 = 0;
uint32_t charging_min;
static uint8_t overvolt_full_charge_cnt = 0;
static uint8_t ext_pin_full_charge_cnt = 0;
charging_min = hal_sys_timer_get() - app_battery_measure.start_time;
charging_min = TICKS_TO_MS(charging_min)/1000/60;
if (charging_min >= app_battery_measure.chargetimeout)
{
// TRACE(0,"TIMEROUT-->FULL_CHARGING");
nRet = -1;
goto exit;
}
if ((app_battery_measure.charger_status.cnt++%APP_BATTERY_CHARGING_OVERVOLT_MEASURE_CNT) == 0)
{
if (app_battery_measure.currvolt>=(app_battery_measure.highvolt+APP_BATTERY_CHARGE_OFFSET_MV))
{
overvolt_full_charge_cnt++;
}
else
{
overvolt_full_charge_cnt = 0;
}
if (overvolt_full_charge_cnt>=APP_BATTERY_CHARGING_OVERVOLT_DEDOUNCE_CNT)
{
//TRACE(0,"OVERVOLT-->FULL_CHARGING");
nRet = -1;
goto exit;
}
}
if ((app_battery_measure.charger_status.cnt++%APP_BATTERY_CHARGING_EXTPIN_MEASURE_CNT) == 0)
{
if (app_battery_ext_charger_detecter_cfg.pin != HAL_IOMUX_PIN_NUM)
{
if (hal_gpio_pin_get_val((enum HAL_GPIO_PIN_T)app_battery_ext_charger_detecter_cfg.pin))
{
ext_pin_full_charge_cnt++;
}
else
{
ext_pin_full_charge_cnt = 0;
}
if (ext_pin_full_charge_cnt>=APP_BATTERY_CHARGING_EXTPIN_DEDOUNCE_CNT)
{
TRACE(0,"EXT PIN-->FULL_CHARGING");
nRet = -1;
goto exit;
}
}
}
if ((app_battery_measure.charger_status.cnt++%APP_BATTERY_CHARGING_SLOPE_MEASURE_CNT) == 0)
{
if (!app_battery_measure.charger_status.prevolt)
{
app_battery_measure.charger_status.slope_1000[app_battery_measure.charger_status.slope_1000_index%APP_BATTERY_CHARGING_SLOPE_TABLE_COUNT] = slope_1000;
app_battery_measure.charger_status.prevolt = app_battery_measure.currvolt;
for (i=0; i<APP_BATTERY_CHARGING_SLOPE_TABLE_COUNT; i++)
{
app_battery_measure.charger_status.slope_1000[i]=100;
}
}
else
{
slope_1000 = app_battery_charger_slope_calc(0, app_battery_measure.charger_status.prevolt,
APP_BATTERY_CHARGING_PERIODIC_MS*APP_BATTERY_CHARGING_SLOPE_MEASURE_CNT/1000, app_battery_measure.currvolt);
app_battery_measure.charger_status.slope_1000[app_battery_measure.charger_status.slope_1000_index%APP_BATTERY_CHARGING_SLOPE_TABLE_COUNT] = slope_1000;
app_battery_measure.charger_status.prevolt = app_battery_measure.currvolt;
for (i=0; i<APP_BATTERY_CHARGING_SLOPE_TABLE_COUNT; i++)
{
if (app_battery_measure.charger_status.slope_1000[i]>0)
cnt++;
else
cnt--;
TRACE(3,"slope_1000[%d]=%d cnt:%d", i,app_battery_measure.charger_status.slope_1000[i], cnt);
}
TRACE(3,"app_battery_charger_slope_proc slope*1000=%d cnt:%d nRet:%d", slope_1000, cnt, nRet);
if (cnt>1)
{
nRet = 1;
}/*else (3>=cnt && cnt>=-3){
nRet = 0;
}*/else
{
if (app_battery_measure.currvolt>=(app_battery_measure.highvolt-APP_BATTERY_CHARGE_OFFSET_MV))
{
TRACE(0,"SLOPE-->FULL_CHARGING");
nRet = -1;
}
}
}
app_battery_measure.charger_status.slope_1000_index++;
}
exit:
return nRet;
}
static enum APP_BATTERY_CHARGER_T app_battery_charger_forcegetstatus(void)
{
enum APP_BATTERY_CHARGER_T status = APP_BATTERY_CHARGER_QTY;
enum PMU_CHARGER_STATUS_T charger;
charger = pmu_charger_get_status();
if (charger == PMU_CHARGER_PLUGIN)
{
status = APP_BATTERY_CHARGER_PLUGIN;
// TRACE(0,"force APP_BATTERY_CHARGER_PLUGIN");
}
else
{
status = APP_BATTERY_CHARGER_PLUGOUT;
// TRACE(0,"force APP_BATTERY_CHARGER_PLUGOUT");
}
return status;
}
static void app_battery_charger_handler(enum PMU_CHARGER_STATUS_T status)
{
TRACE(2,"%s: status=%d", __func__, status);
pmu_charger_set_irq_handler(NULL);
app_battery_event_process(APP_BATTERY_STATUS_PLUGINOUT,
(status == PMU_CHARGER_PLUGIN) ? APP_BATTERY_CHARGER_PLUGIN : APP_BATTERY_CHARGER_PLUGOUT);
}
static void app_battery_pluginout_debounce_start(void)
{
TRACE(1,"%s", __func__);
app_battery_pluginout_debounce_ctx = (uint32_t)app_battery_charger_forcegetstatus();
app_battery_pluginout_debounce_cnt = 1;
osTimerStart(app_battery_pluginout_debounce_timer, CHARGER_PLUGINOUT_DEBOUNCE_MS);
}
static void app_battery_pluginout_debounce_handler(void const *param)
{
enum APP_BATTERY_CHARGER_T status_charger = app_battery_charger_forcegetstatus();
if(app_battery_pluginout_debounce_ctx == (uint32_t) status_charger){
app_battery_pluginout_debounce_cnt++;
}
else
{
TRACE(2,"%s dithering cnt %u", __func__, app_battery_pluginout_debounce_cnt);
app_battery_pluginout_debounce_cnt = 0;
app_battery_pluginout_debounce_ctx = (uint32_t)status_charger;
}
if (app_battery_pluginout_debounce_cnt >= CHARGER_PLUGINOUT_DEBOUNCE_CNT){
TRACE(2,"%s %s", __func__, status_charger == APP_BATTERY_CHARGER_PLUGOUT ? "PLUGOUT" : "PLUGIN");
if (status_charger == APP_BATTERY_CHARGER_PLUGIN)
{
if (app_battery_ext_charger_enable_cfg.pin != HAL_IOMUX_PIN_NUM)
{
hal_gpio_pin_set_dir((enum HAL_GPIO_PIN_T)app_battery_ext_charger_detecter_cfg.pin, HAL_GPIO_DIR_OUT, 0);
}
app_battery_measure.start_time = hal_sys_timer_get();
}
else
{
if (app_battery_ext_charger_enable_cfg.pin != HAL_IOMUX_PIN_NUM)
{
hal_gpio_pin_set_dir((enum HAL_GPIO_PIN_T)app_battery_ext_charger_detecter_cfg.pin, HAL_GPIO_DIR_OUT, 1);
}
}
app_battery_event_process(APP_BATTERY_STATUS_CHARGING, status_charger);
pmu_charger_set_irq_handler(app_battery_charger_handler);
osTimerStop(app_battery_pluginout_debounce_timer);
}else{
osTimerStart(app_battery_pluginout_debounce_timer, CHARGER_PLUGINOUT_DEBOUNCE_MS);
}
}
int app_battery_charger_indication_open(void)
{
enum APP_BATTERY_CHARGER_T status = APP_BATTERY_CHARGER_QTY;
uint8_t cnt = 0;
APP_BATTERY_TRACE(1,"%s",__func__);
pmu_charger_init();
do
{
status = app_battery_charger_forcegetstatus();
if (status == APP_BATTERY_CHARGER_PLUGIN)
break;
osDelay(20);
}
while(cnt++<5);
if (app_battery_ext_charger_detecter_cfg.pin != HAL_IOMUX_PIN_NUM)
{
if (!hal_gpio_pin_get_val((enum HAL_GPIO_PIN_T)app_battery_ext_charger_detecter_cfg.pin))
{
status = APP_BATTERY_CHARGER_PLUGIN;
}
}
pmu_charger_set_irq_handler(app_battery_charger_handler);
return status;
}
int8_t app_battery_current_level(void)
{
#ifdef __INTERCONNECTION__
return app_battery_measure.currentBatteryInfo & 0x7f;
#else
return app_battery_measure.currlevel;
#endif
}
int8_t app_battery_is_charging(void)
{
return (APP_BATTERY_STATUS_CHARGING == app_battery_measure.status);
}
typedef uint16_t NTP_VOLTAGE_MV_T;
typedef uint16_t NTP_TEMPERATURE_C_T;
#define NTC_CAPTURE_STABLE_COUNT (5)
#define NTC_CAPTURE_TEMPERATURE_STEP (4)
#define NTC_CAPTURE_TEMPERATURE_REF (15)
#define NTC_CAPTURE_VOLTAGE_REF (1100)
typedef void (*NTC_CAPTURE_MEASURE_CB_T)(NTP_TEMPERATURE_C_T);
struct NTC_CAPTURE_MEASURE_T
{
NTP_TEMPERATURE_C_T temperature;
NTP_VOLTAGE_MV_T currvolt;
NTP_VOLTAGE_MV_T voltage[NTC_CAPTURE_STABLE_COUNT];
uint16_t index;
NTC_CAPTURE_MEASURE_CB_T cb;
};
static struct NTC_CAPTURE_MEASURE_T ntc_capture_measure;
void ntc_capture_irqhandler(uint16_t irq_val, HAL_GPADC_MV_T volt)
{
uint32_t meanVolt = 0;
TRACE(3,"%s %d irq:0x%04x",__func__, volt, irq_val);
if (volt == HAL_GPADC_BAD_VALUE)
{
return;
}
ntc_capture_measure.voltage[ntc_capture_measure.index++%NTC_CAPTURE_STABLE_COUNT] = volt;
if (ntc_capture_measure.index > NTC_CAPTURE_STABLE_COUNT)
{
for (uint8_t i=0; i<NTC_CAPTURE_STABLE_COUNT; i++)
{
meanVolt += ntc_capture_measure.voltage[i];
}
meanVolt /= NTC_CAPTURE_STABLE_COUNT;
ntc_capture_measure.currvolt = meanVolt;
}
else if (!ntc_capture_measure.currvolt)
{
ntc_capture_measure.currvolt = volt;
}
ntc_capture_measure.temperature = ((int32_t)ntc_capture_measure.currvolt - NTC_CAPTURE_VOLTAGE_REF)/NTC_CAPTURE_TEMPERATURE_STEP + NTC_CAPTURE_TEMPERATURE_REF;
pmu_ntc_capture_disable();
TRACE(3,"%s ad:%d temperature:%d",__func__, ntc_capture_measure.currvolt, ntc_capture_measure.temperature);
}
int ntc_capture_open(void)
{
ntc_capture_measure.currvolt = 0;
ntc_capture_measure.index = 0;
ntc_capture_measure.temperature = 0;
ntc_capture_measure.cb = NULL;
pmu_ntc_capture_enable();
hal_gpadc_open(HAL_GPADC_CHAN_0, HAL_GPADC_ATP_ONESHOT, ntc_capture_irqhandler);
return 0;
}
int ntc_capture_start(void)
{
pmu_ntc_capture_enable();
hal_gpadc_open(HAL_GPADC_CHAN_0, HAL_GPADC_ATP_ONESHOT, ntc_capture_irqhandler);
return 0;
}

121
apps/battery/app_battery.h Normal file
View file

@ -0,0 +1,121 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __APP_BATTERY_H__
#define __APP_BATTERY_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#define APP_BATTERY_LEVEL_MIN (0)
#ifdef __INTERCONNECTION__
#define APP_BATTERY_LEVEL_MAX (100)
#define APP_BATTERY_DEFAULT_INFO 0xE4
typedef struct
{
uint8_t chargingStatus : 1;
uint8_t batteryLevel : 7;
}APP_BATTERY_INFO_T;
uint8_t* app_battery_get_mobile_support_self_defined_command_p(void);
#else // #ifdef __INTERCONNECTION__
#define APP_BATTERY_LEVEL_MAX (9)
#endif // #ifdef __INTERCONNECTION__
#define APP_BATTERY_LEVEL_NUM (APP_BATTERY_LEVEL_MAX-APP_BATTERY_LEVEL_MIN+1)
enum APP_BATTERY_STATUS_T {
APP_BATTERY_STATUS_NORMAL,
APP_BATTERY_STATUS_CHARGING,
APP_BATTERY_STATUS_OVERVOLT,
APP_BATTERY_STATUS_UNDERVOLT,
APP_BATTERY_STATUS_PDVOLT,
APP_BATTERY_STATUS_PLUGINOUT,
APP_BATTERY_STATUS_INVALID,
APP_BATTERY_STATUS_QTY
};
#define APP_BATTERY_OPEN_MODE_INVALID (-1)
#define APP_BATTERY_OPEN_MODE_NORMAL (0)
#define APP_BATTERY_OPEN_MODE_CHARGING (1)
#define APP_BATTERY_OPEN_MODE_CHARGING_PWRON (2)
typedef uint16_t APP_BATTERY_MV_T;
enum APP_BATTERY_CHARGER_T
{
APP_BATTERY_CHARGER_PLUGOUT = 0,
APP_BATTERY_CHARGER_PLUGIN,
APP_BATTERY_CHARGER_QTY,
};
union APP_BATTERY_MSG_PRAMS{
APP_BATTERY_MV_T volt;
enum APP_BATTERY_CHARGER_T charger;
uint32_t prams;
};
typedef void (*APP_BATTERY_CB_T)(APP_BATTERY_MV_T currvolt, uint8_t currlevel,enum APP_BATTERY_STATUS_T curstatus,uint32_t status, union APP_BATTERY_MSG_PRAMS prams);
int app_battery_get_info(APP_BATTERY_MV_T *currvolt, uint8_t *currlevel, enum APP_BATTERY_STATUS_T *status);
/**
* Battery App owns its own context where it will periodically update the
* battery level and state. Makes sense for it to act as a Model and publish
* battery change events to any interested users.
*
* Note: Callback will execute out of BES "App Thread" context.
*
* TODO: ideally implemented as proper observer pattern with support for multiple
* listeners
*
* Returns
* - 0: On success
* - 1: If registration failed
*/
int app_battery_register(APP_BATTERY_CB_T user_cb);
int app_battery_open(void);
int app_battery_start(void);
int app_battery_stop(void);
int app_battery_close(void);
int app_battery_charger_indication_open(void);
int8_t app_battery_current_level(void);
int8_t app_battery_is_charging(void);
int ntc_capture_open(void);
int ntc_capture_start(void);
#ifdef __cplusplus
}
#endif
#endif

41
apps/btusbaudio/Makefile Normal file
View file

@ -0,0 +1,41 @@
cur_dir := $(dir $(lastword $(MAKEFILE_LIST)))
obj-y := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)*.c $(cur_dir)*.cpp $(cur_dir)*.S))
obj-y := $(obj-y:.c=.o)
obj-y := $(obj-y:.cpp=.o)
obj-y := $(obj-y:.S=.o)
ccflags-y += \
$(BT_IF_INCLUDES) \
$(BT_PROFILES_INCLUDES) \
-Iservices/bt_app \
-Iservices/bt_app/a2dp_codecs/include \
-Iservices/audioflinger \
-Iservices/nvrecord \
-Iservices/overlay \
-Iservices/resources \
-Iservices/audio_process \
-Iapps/apptester \
-Iapps/factory \
-Iutils/crc32 \
-Iplatform/drivers/bt \
-Iplatform/drivers/ana \
-Iapps/audioplayers/rbplay \
-Itests/anc_usb \
-Iapps/anc/inc \
-Iapps/ota \
-Ithirdparty/userapi \
-Iservices/voicepath \
-Iservices/voicepath/gsound/gsound_service \
-Iservices/voicepath/gsound/gsound_target \
-Iservices/communication \
-Iutils/cqueue \
-Iservices/ai_voice/ama/ama_manager \
-Iservices/ai_voice/manager \
-Iservices/multimedia/audio/codec/sbc/inc \
-Iservices/multimedia/audio/codec/sbc/src/inc \
-Iservices/interconnection

View file

@ -0,0 +1,307 @@
/***************************************************************************
*
* 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 "stdio.h"
#include "cmsis_os.h"
#include "hal_timer.h"
#include "hal_trace.h"
#include "app_audio.h"
#include "a2dp_api.h"
#include "app_bt.h"
#include "btapp.h"
#include "usb_audio_app.h"
#include "btusb_audio.h"
extern void btusbaudio_entry(void);
extern void btusbaudio_exit(void);
extern a2dp_stream_t* app_bt_get_steam(enum BT_DEVICE_ID_T id);
extern int app_bt_get_bt_addr(enum BT_DEVICE_ID_T id,bt_bdaddr_t *bdaddr);
extern bool app_bt_a2dp_service_is_connected(void);
int app_bt_A2DP_OpenStream(a2dp_stream_t *Stream, bt_bdaddr_t *Addr);
int app_bt_A2DP_CloseStream(a2dp_stream_t *Stream);
extern bool btapp_hfp_is_call_active(void);
static bool btusb_usb_is_on = false;
static enum BTUSB_MODE btusb_mode = BTUSB_MODE_INVALID;
static bool btusb_bt_audio_is_suspend = false;
#define BT_USB_DEBUG() //TRACE(2,"_debug: %s,%d",__func__,__LINE__)
extern struct BT_DEVICE_T app_bt_device;
static void _btusb_stream_open(unsigned int timeout_ms)
{
a2dp_stream_t *stream = NULL;
bt_bdaddr_t bdaddr;
uint32_t stime = 0;
uint32_t etime = 0;
stime = hal_sys_timer_get();
//BT_USB_DEBUG();
stream = (a2dp_stream_t*)app_bt_get_steam(BT_DEVICE_ID_1);
app_bt_get_bt_addr(BT_DEVICE_ID_1,&bdaddr);
if(stream)
{
//struct BT_DEVICE_T *bt_dev = &app_bt_device;
//A2DP_Register((a2dp_stream_t *)bt_dev->a2dp_stream[BT_DEVICE_ID_1]->a2dp_stream, &a2dp_avdtpcodec, NULL, (A2dpCallback) a2dp_callback);
//AVRCP_Register((AvrcpChannel *)bt_dev->avrcp_channel[BT_DEVICE_ID_1]->avrcp_channel_handle, (AvrcpCallback)avrcp_callback_CT, BTIF_AVRCP_CT_CATEGORY_1 | BTIF_AVRCP_CT_CATEGORY_2 | BTIF_AVRCP_TG_CATEGORY_2);
BT_USB_DEBUG();
osDelay(10);
app_bt_A2DP_OpenStream(stream,&bdaddr);
}
else
{
BT_USB_DEBUG();
return;
}
while(1)
{
if(app_bt_a2dp_service_is_connected()){
etime = hal_sys_timer_get();
TRACE(1,"_debug: a2dp service connected, wait time = 0x%x.",TICKS_TO_MS(etime - stime));
break;
}
else
{
etime = hal_sys_timer_get();
if(TICKS_TO_MS(etime - stime) >= timeout_ms)
{
TRACE(1,"_debug: a2dp service connect timeout = 0x%x.",
TICKS_TO_MS(etime - stime));
break;
}
osDelay(10);
}
}
//BT_USB_DEBUG();
}
static void _btusb_stream_close(unsigned int timeout_ms)
{
a2dp_stream_t *stream = NULL;
uint32_t stime = 0;
uint32_t etime = 0;
stime = hal_sys_timer_get();
BT_USB_DEBUG();
stream = (a2dp_stream_t*)app_bt_get_steam(BT_DEVICE_ID_1);
if(stream)
{
BT_USB_DEBUG();
app_bt_A2DP_CloseStream(stream);
}
else
{
BT_USB_DEBUG();
return;
}
stime = hal_sys_timer_get();
while(1)
{
if(!app_bt_a2dp_service_is_connected()){
//struct BT_DEVICE_T *bt_dev = &app_bt_device;
//AVRCP_Deregister(bt_dev->avrcp_channel[BT_DEVICE_ID_1]->avrcp_channel_handle);
//A2DP_Deregister(stream);
etime = hal_sys_timer_get();
TRACE(1,"a2dp service diconnected, wait time = 0x%x.",
TICKS_TO_MS(etime - stime));
break;
}
else
{
etime = hal_sys_timer_get();
if(TICKS_TO_MS(etime - stime) >= timeout_ms)
{
TRACE(1,"a2dp service diconnect timeout = 0x%x.",
TICKS_TO_MS(etime - stime));
break;
}
osDelay(10);
}
}
BT_USB_DEBUG();
}
static void btusb_usbaudio_entry(void)
{
BT_USB_DEBUG();
btusbaudio_entry();
btusb_usb_is_on = true ;
}
void btusb_usbaudio_open(void)
{
BT_USB_DEBUG();
if(!btusb_usb_is_on)
{
btusb_usbaudio_entry();
BT_USB_DEBUG();
}
else
{
usb_audio_app(1);
}
BT_USB_DEBUG();
}
void btusb_usbaudio_close(void)
{
BT_USB_DEBUG();
if(btusb_usb_is_on)
{
usb_audio_app(0);
BT_USB_DEBUG();
}
else
{
BT_USB_DEBUG();
}
}
void btusb_btaudio_close(bool is_wait)
{
BT_USB_DEBUG();
//if(!btusb_bt_audio_is_suspend)
{
BT_USB_DEBUG();
if(is_wait)
{
app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_CLOSEALL, 0);
_btusb_stream_close(BTUSB_OUTTIME_MS);
}
else
{
_btusb_stream_close(0);
}
btusb_bt_audio_is_suspend = true;
}
}
void btusb_btaudio_open(bool is_wait)
{
BT_USB_DEBUG();
//if(btusb_bt_audio_is_suspend)
{
TRACE(2,"%s: %d.",__func__,__LINE__);
if(is_wait)
{
_btusb_stream_open(BTUSB_OUTTIME_MS);
app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_CLOSE, 0);
app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_SETUP, 0);
}
else
{
_btusb_stream_open(0);
}
TRACE(2,"%s: %d.",__func__,__LINE__);
btusb_bt_audio_is_suspend = false;
}
}
void btusb_switch(enum BTUSB_MODE mode)
{
//BT_USB_DEBUG();
if(mode != BTUSB_MODE_BT && mode != BTUSB_MODE_USB)
{
ASSERT(0, "%s:%d, mode = %d.",__func__,__LINE__,mode);
}
if(btusb_mode == mode) {
BT_USB_DEBUG();
return;
}
if(btusb_mode == BTUSB_MODE_INVALID)
{
if(mode == BTUSB_MODE_BT) {
TRACE(1,"%s: switch to BT mode.",__func__);
btusb_mode = BTUSB_MODE_BT;
}
else {
TRACE(1,"%s: switch to USB mode.",__func__);
//btusb_btaudio_close(true);
osDelay(500);
btusb_usbaudio_open();
btusb_mode = BTUSB_MODE_USB;
}
}
else
{
if(mode == BTUSB_MODE_BT) {
TRACE(1,"%s: switch to BT mode.",__func__);
if(btusb_usb_is_on)
{
TRACE(1,"%s: btusb_usbaudio_close.",__func__);
btusb_usbaudio_close();
TRACE(1,"%s: btusb_usbaudio_close done.",__func__);
osDelay(500);
}
btusb_mode = BTUSB_MODE_BT;
btusb_btaudio_open(true);
TRACE(1,"%s: switch to BT mode done.",__func__);
}
else {
if(btapp_hfp_is_call_active() == 1)
{
TRACE(1,"%s: hfp is call active.",__func__);
return;
}
TRACE(1,"%s: switch to USB mode.",__func__);
btusb_btaudio_close(true);
TRACE(1,"%s: btusb_btaudio_close done.",__func__);
osDelay(500);
btusb_usbaudio_open();
btusb_mode = BTUSB_MODE_USB;
TRACE(1,"%s: switch to USB mode done.",__func__);
}
}
}
bool btusb_is_bt_mode(void)
{
BT_USB_DEBUG();
return btusb_mode == BTUSB_MODE_BT ? true : false;
}
bool btusb_is_usb_mode(void)
{
return btusb_mode == BTUSB_MODE_USB ? true : false;
}
#if defined(BT_USB_AUDIO_DUAL_MODE_TEST)
void test_btusb_switch(void)
{
if(btusb_mode == BTUSB_MODE_BT)
{
btusb_switch(BTUSB_MODE_USB);
}
else
{
btusb_switch(BTUSB_MODE_BT);
}
}
void test_btusb_switch_to_bt(void)
{
btusb_switch(BTUSB_MODE_BT);
}
void test_btusb_switch_to_usb(void)
{
btusb_switch(BTUSB_MODE_USB);
}
#endif

View file

@ -0,0 +1,40 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef _BTUSB_AUDIO_H_
#define _BTUSB_AUDIO_H_
#ifdef __cplusplus
extern "C" {
#endif
#define BTUSB_OUTTIME_MS 1000
enum BTUSB_MODE{
BTUSB_MODE_BT,
BTUSB_MODE_USB,
BTUSB_MODE_INVALID
};
void btusb_usbaudio_open(void);
void btusb_usbaudio_close(void);
void btusb_btaudio_open(bool is_wait);
void btusb_btaudio_close(bool is_wait);
void btusb_switch(enum BTUSB_MODE mode);
bool btusb_is_bt_mode(void);
bool btusb_is_usb_mode(void);
#ifdef __cplusplus
}
#endif
#endif // _BTUSB_AUDIO_H_

View file

@ -0,0 +1,139 @@
/***************************************************************************
*
* 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 "cmsis_os.h"
#include "hal_trace.h"
#include "app_utils.h"
#include "usb_audio_app.h"
#include "usbaudio_thread.h"
static void usb_thread(void const *argument);
osThreadDef(usb_thread, osPriorityHigh, 1, 2048, "usb");
osMailQDef (usb_mailbox, USB_MAILBOX_MAX, USB_MESSAGE);
static osMailQId usb_mailbox = NULL;
static uint8_t usb_mailbox_cnt = 0;
#define USBAUDIO_DEBUG TRACE
static int usb_mailbox_init(void)
{
USBAUDIO_DEBUG("%s,%d",__func__,__LINE__);
usb_mailbox = osMailCreate(osMailQ(usb_mailbox), NULL);
if (usb_mailbox == NULL) {
USBAUDIO_DEBUG("Failed to Create usb_mailbox\n");
return -1;
}
usb_mailbox_cnt = 0;
return 0;
}
int usb_mailbox_put(USB_MESSAGE* msg_src)
{
osStatus status;
USB_MESSAGE *msg_p = NULL;
USBAUDIO_DEBUG("%s,%d",__func__,__LINE__);
if(usb_mailbox_cnt >= 1)
{
USBAUDIO_DEBUG("%s,%d usb_mailbox_cnt = %d.",
__func__,__LINE__,usb_mailbox_cnt);
return 0;
}
msg_p = (USB_MESSAGE*)osMailAlloc(usb_mailbox, 0);
ASSERT(msg_p, "osMailAlloc error");
msg_p->id = msg_src->id;
msg_p->ptr = msg_src->ptr;
msg_p->param0 = msg_src->param0;
msg_p->param1 = msg_src->param1;
status = osMailPut(usb_mailbox, msg_p);
if (osOK == status)
usb_mailbox_cnt++;
USBAUDIO_DEBUG("%s,%d,usb_mailbox_cnt = %d.",__func__,__LINE__,usb_mailbox_cnt);
return (int)status;
}
int usb_mailbox_free(USB_MESSAGE* msg_p)
{
osStatus status;
USBAUDIO_DEBUG("%s,%d",__func__,__LINE__);
status = osMailFree(usb_mailbox, msg_p);
if (osOK == status)
usb_mailbox_cnt--;
USBAUDIO_DEBUG("%s,%d,usb_mailbox_cnt = %d.",__func__,__LINE__,usb_mailbox_cnt);
return (int)status;
}
int usb_mailbox_get(USB_MESSAGE **msg_p)
{
osEvent evt;
evt = osMailGet(usb_mailbox, osWaitForever);
if (evt.status == osEventMail) {
*msg_p = (USB_MESSAGE*)evt.value.p;
return 0;
}
return -1;
}
static void usb_thread(void const *argument)
{
// USB_FUNC_T usb_funcp;
USBAUDIO_DEBUG("%s,%d",__func__,__LINE__);
while(1){
USB_MESSAGE *msg_p = NULL;
if (!usb_mailbox_get(&msg_p)) {
//TRACE(2,"_debug: %s,%d",__func__,__LINE__);
USBAUDIO_DEBUG("usb_thread: id = 0x%x, ptr = 0x%x,param0 = 0x%x,param1 = 0x%x.",
msg_p->id,msg_p->ptr,msg_p->param0,msg_p->param1);
usb_mailbox_free(msg_p);
usb_audio_app_loop();
}
}
}
static void usb_enqueue_cmd(uint32_t data)
{
USB_MESSAGE usb_msg;
usb_msg.id = 0;
usb_msg.param0 = 0;
usb_msg.param1 = 0;
usb_msg.ptr = 0;
usb_mailbox_put(&usb_msg);
}
int usb_os_init(void)
{
osThreadId usb_tid;
USBAUDIO_DEBUG("%s,%d",__func__,__LINE__);
if (usb_mailbox_init()) {
USBAUDIO_DEBUG("_debug: %s,%d",__func__,__LINE__);
return -1;
}
usb_tid = osThreadCreate(osThread(usb_thread), NULL);
if (usb_tid == NULL) {
USBAUDIO_DEBUG("Failed to Create usb_thread\n");
return 0;
}
usb_audio_set_enqueue_cmd_callback(usb_enqueue_cmd);
return 0;
}

View file

@ -0,0 +1,49 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __USB_THREAD_H__
#define __USB_THREAD_H__
#ifdef __cplusplus
extern "C" {
#endif
#define USB_MAILBOX_MAX (20)
typedef struct {
uint32_t id;
uint32_t ptr;
uint32_t param0;
uint32_t param1;
} USB_MESSAGE;
//typedef int (*USB_MOD_HANDLER_T)(USB_MESSAGE_BODY *);
typedef void (*USB_FUNC_T)(uint32_t, uint32_t);
int usb_mailbox_put(USB_MESSAGE* msg_src);
int usb_mailbox_free(USB_MESSAGE* msg_p);
int usb_mailbox_get(USB_MESSAGE** msg_p);
int usb_os_init(void);
#ifdef __cplusplus
}
#endif
#endif // __USB_THREAD_H__

10
apps/cmd/Makefile Normal file
View file

@ -0,0 +1,10 @@
cur_dir := $(dir $(lastword $(MAKEFILE_LIST)))
obj-y := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)*.c $(cur_dir)*.cpp $(cur_dir)*.S))
obj-y := $(obj-y:.c=.o)
obj-y := $(obj-y:.cpp=.o)
obj-y := $(obj-y:.S=.o)
subdir-ccflags-y += \
-Iservices/audio_process \
-Iservices/multimedia/audio/process/filters/include

71
apps/cmd/app_cmd.cpp Normal file
View file

@ -0,0 +1,71 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifdef __PC_CMD_UART__
#include "cmsis_os.h"
#include "list.h"
#include "string.h"
#include "app_thread.h"
#include "app_cmd.h"
#include "hal_cmd.h"
#include "hal_trace.h"
#include "audio_process.h"
#define APP_CMD_TRACE(s,...) TRACE(s, ##__VA_ARGS__)
void cmd_event_process(hal_cmd_rx_status_t status)
{
APP_CMD_TRACE(1,"%s",__func__);
APP_MESSAGE_BLOCK msg;
msg.mod_id = APP_MODUAL_CMD;
msg.msg_body.message_id = status;
msg.msg_body.message_ptr = (uint32_t)NULL;
app_mailbox_put(&msg);
return;
}
static int app_cmd_handle_process(APP_MESSAGE_BODY *msg_body)
{
hal_cmd_run((hal_cmd_rx_status_t)msg_body->message_id);
return 0;
}
uint8_t app_cmd_flag = 0;
void app_cmd_open(void)
{
APP_CMD_TRACE(1,"%s",__func__);
app_cmd_flag = 1;
app_set_threadhandle(APP_MODUAL_CMD, app_cmd_handle_process);
hal_cmd_set_callback(cmd_event_process);
hal_cmd_open();
return;
}
void app_cmd_close(void)
{
APP_CMD_TRACE(1,"%s",__func__);
if(app_cmd_flag)
{
app_cmd_flag = 0;
hal_cmd_close();
app_set_threadhandle(APP_MODUAL_CMD, NULL);
}
return;
}
#endif

29
apps/cmd/app_cmd.h Normal file
View file

@ -0,0 +1,29 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __APP_CMD_H__
#define __APP_CMD_H__
#ifdef __PC_CMD_UART__
#include "hal_cmd.h"
typedef struct {
void *param;
} APP_CMD_HANDLE;
void app_cmd_open(void);
void app_cmd_close(void);
#endif
#endif//__FMDEC_H__

17
apps/common/Makefile Normal file
View file

@ -0,0 +1,17 @@
cur_dir := $(dir $(lastword $(MAKEFILE_LIST)))
obj-y := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)*.c $(cur_dir)*.cpp $(cur_dir)*.S))
obj-y := $(obj-y:.c=.o)
obj-y := $(obj-y:.cpp=.o)
obj-y := $(obj-y:.S=.o)
subdir-ccflags-y += \
-Iplatform/drivers/ana \
-Iservices/ibrt_ui/inc \
-Iservices/ibrt_core/inc
ifeq ($(RAND_FROM_MIC),1)
subdir-ccflags-y += \
-Iservices/bt_app \
-Iservices/app_ai/inc
endif

View file

@ -0,0 +1,97 @@
/***************************************************************************
*
* 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 "cmsis_os.h"
#include "stdint.h"
#include "app_spec_ostimer.h"
#include "hal_trace.h"
/// Create timer
osStatus app_spec_timer_create (SPEC_TIMER_CTX_T *spec_timer_ctx, const osTimerDef_t *timer_def, os_timer_type type, void *argument)
{
spec_timer_ctx->type = type;
spec_timer_ctx->argument = argument;
spec_timer_ctx->timerid = osTimerCreate(timer_def, type, spec_timer_ctx);
return spec_timer_ctx->timerid ? osOK: osErrorOS;
}
/// Start or restart timer
osStatus app_spec_timer_start (SPEC_TIMER_CTX_T *spec_timer_ctx, uint32_t millisec)
{
osStatus status;
//TRACE(1,"%s", __func__);
if (millisec > UINT16_MAX){
spec_timer_ctx->interval = millisec;
spec_timer_ctx->ctx = millisec;
status = osTimerStart(spec_timer_ctx->timerid, UINT16_MAX);
}else{
spec_timer_ctx->interval = millisec;
spec_timer_ctx->ctx = millisec;
status = osTimerStart(spec_timer_ctx->timerid, (uint32_t)millisec);
}
return status;
}
/// Stop timer
osStatus app_spec_timer_stop (SPEC_TIMER_CTX_T *spec_timer_ctx)
{
return osTimerStop(spec_timer_ctx->timerid);
}
/// Delete timer
osStatus app_spec_timer_delete (SPEC_TIMER_CTX_T *spec_timer_ctx)
{
return osTimerDelete(spec_timer_ctx->timerid);
}
void app_spec_timer_handler(void const *para)
{
SPEC_TIMER_CTX_T *spec_timer_ctx = (SPEC_TIMER_CTX_T *)para;
if (spec_timer_ctx->ctx > UINT16_MAX){
spec_timer_ctx->ctx -= UINT16_MAX;
if (spec_timer_ctx->ctx > UINT16_MAX){
osTimerStart(spec_timer_ctx->timerid, UINT16_MAX);
}else{
osTimerStart(spec_timer_ctx->timerid, spec_timer_ctx->ctx);
}
}else{
(*spec_timer_ctx->ptimer)(spec_timer_ctx->argument);
if (spec_timer_ctx->type == osTimerPeriodic){
app_spec_timer_start(spec_timer_ctx, spec_timer_ctx->interval);
}
}
}
#if 0
//tester
uint32_t ibrt_test_arg;
void app_tws_ibrt_test_timer_cb(void const *para);
specTimerDef (IBRT_TEST_TIMER, app_tws_ibrt_test_timer_cb);
void app_tws_ibrt_test_timer_cb(void const *para)
{
TRACE(2,"%s %08x", __func__, para);
}
void app_tws_ibrt_test_timer(void)
{
app_spec_timer_create(specTimerCtx(IBRT_TEST_TIMER), specTimer(IBRT_TEST_TIMER), osTimerOnce, &ibrt_test_arg);
app_spec_timer_start(specTimerCtx(IBRT_TEST_TIMER), 0x10100);
}
#endif

View file

@ -0,0 +1,45 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __APP_SPEC_OSTIMER__
#define __APP_SPEC_OSTIMER__
#include "cmsis_os.h"
typedef struct{
osTimerId timerid;
os_timer_type type;
os_ptimer ptimer;
uint32_t interval;
uint32_t ctx;
void *argument;
}SPEC_TIMER_CTX_T;
#define specTimerDef(name, function) \
SPEC_TIMER_CTX_T spec_timer_ctx_##name = \
{NULL, osTimerOnce, function, 0, 0, NULL}; \
osTimerDef(name, app_spec_timer_handler)
#define specTimer osTimer
#define specTimerCtx(name) \
&spec_timer_ctx_##name
void app_spec_timer_handler(void const *para);
osStatus app_spec_timer_create (SPEC_TIMER_CTX_T *spec_timer_ctx, const osTimerDef_t *timer_def, os_timer_type type, void *argument);
osStatus app_spec_timer_start (SPEC_TIMER_CTX_T *spec_timer_ctx, uint32_t millisec);
osStatus app_spec_timer_stop (SPEC_TIMER_CTX_T *spec_timer_ctx);
osStatus app_spec_timer_delete (SPEC_TIMER_CTX_T *spec_timer_ctx);
#endif

164
apps/common/app_thread.c Normal file
View file

@ -0,0 +1,164 @@
/***************************************************************************
*
* 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 "cmsis_os.h"
#include "hal_trace.h"
#include "hal_timer.h"
#include "app_utils.h"
#include "app_thread.h"
static APP_MOD_HANDLER_T mod_handler[APP_MODUAL_NUM];
static void app_thread(void const *argument);
osThreadDef(app_thread, osPriorityHigh, 1, 1024*3, "app_thread");
osMailQDef (app_mailbox, APP_MAILBOX_MAX, APP_MESSAGE_BLOCK);
static osMailQId app_mailbox = NULL;
static uint8_t app_mailbox_cnt = 0;
osThreadId app_thread_tid;
static int app_mailbox_init(void)
{
app_mailbox = osMailCreate(osMailQ(app_mailbox), NULL);
if (app_mailbox == NULL) {
TRACE(0,"Failed to Create app_mailbox\n");
return -1;
}
app_mailbox_cnt = 0;
return 0;
}
int app_mailbox_put(APP_MESSAGE_BLOCK* msg_src)
{
osStatus status;
APP_MESSAGE_BLOCK *msg_p = NULL;
msg_p = (APP_MESSAGE_BLOCK*)osMailAlloc(app_mailbox, 0);
if (!msg_p){
osEvent evt;
TRACE_IMM(0,"osMailAlloc error dump");
for (uint8_t i=0; i<APP_MAILBOX_MAX; i++){
evt = osMailGet(app_mailbox, 0);
if (evt.status == osEventMail) {
TRACE_IMM(9,"cnt:%d mod:%d src:%08x tim:%d id:%x ptr:%08x para:%08x/%08x/%08x",
i,
((APP_MESSAGE_BLOCK *)(evt.value.p))->mod_id,
((APP_MESSAGE_BLOCK *)(evt.value.p))->src_thread,
((APP_MESSAGE_BLOCK *)(evt.value.p))->system_time,
((APP_MESSAGE_BLOCK *)(evt.value.p))->msg_body.message_id,
((APP_MESSAGE_BLOCK *)(evt.value.p))->msg_body.message_ptr,
((APP_MESSAGE_BLOCK *)(evt.value.p))->msg_body.message_Param0,
((APP_MESSAGE_BLOCK *)(evt.value.p))->msg_body.message_Param1,
((APP_MESSAGE_BLOCK *)(evt.value.p))->msg_body.message_Param2);
}else{
TRACE_IMM(2,"cnt:%d %d", i, evt.status);
break;
}
}
TRACE_IMM(0,"osMailAlloc error dump end");
}
ASSERT(msg_p, "osMailAlloc error");
msg_p->src_thread = (uint32_t)osThreadGetId();
msg_p->dest_thread = (uint32_t)NULL;
msg_p->system_time = hal_sys_timer_get();
msg_p->mod_id = msg_src->mod_id;
msg_p->msg_body.message_id = msg_src->msg_body.message_id;
msg_p->msg_body.message_ptr = msg_src->msg_body.message_ptr;
msg_p->msg_body.message_Param0 = msg_src->msg_body.message_Param0;
msg_p->msg_body.message_Param1 = msg_src->msg_body.message_Param1;
msg_p->msg_body.message_Param2 = msg_src->msg_body.message_Param2;
status = osMailPut(app_mailbox, msg_p);
if (osOK == status)
app_mailbox_cnt++;
return (int)status;
}
int app_mailbox_free(APP_MESSAGE_BLOCK* msg_p)
{
osStatus status;
status = osMailFree(app_mailbox, msg_p);
if (osOK == status)
app_mailbox_cnt--;
return (int)status;
}
int app_mailbox_get(APP_MESSAGE_BLOCK** msg_p)
{
osEvent evt;
evt = osMailGet(app_mailbox, osWaitForever);
if (evt.status == osEventMail) {
*msg_p = (APP_MESSAGE_BLOCK *)evt.value.p;
return 0;
}
return -1;
}
static void app_thread(void const *argument)
{
while(1){
APP_MESSAGE_BLOCK *msg_p = NULL;
if (!app_mailbox_get(&msg_p)) {
if (msg_p->mod_id < APP_MODUAL_NUM) {
if (mod_handler[msg_p->mod_id]) {
int ret = mod_handler[msg_p->mod_id](&(msg_p->msg_body));
if (ret)
TRACE(2,"mod_handler[%d] ret=%d", msg_p->mod_id, ret);
}
}
app_mailbox_free(msg_p);
}
}
}
int app_os_init(void)
{
if (app_mailbox_init())
return -1;
app_thread_tid = osThreadCreate(osThread(app_thread), NULL);
if (app_thread_tid == NULL) {
TRACE(0,"Failed to Create app_thread\n");
return 0;
}
return 0;
}
int app_set_threadhandle(enum APP_MODUAL_ID_T mod_id, APP_MOD_HANDLER_T handler)
{
if (mod_id>=APP_MODUAL_NUM)
return -1;
mod_handler[mod_id] = handler;
return 0;
}
void * app_os_tid_get(void)
{
return (void *)app_thread_tid;
}
bool app_is_module_registered(enum APP_MODUAL_ID_T mod_id)
{
return mod_handler[mod_id];
}

92
apps/common/app_thread.h Normal file
View file

@ -0,0 +1,92 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __APP_THREAD_H__
#define __APP_THREAD_H__
#ifdef __cplusplus
extern "C" {
#endif
#define APP_MAILBOX_MAX (20)
enum APP_MODUAL_ID_T {
APP_MODUAL_KEY = 0,
APP_MODUAL_AUDIO,
APP_MODUAL_BATTERY,
APP_MODUAL_BT,
APP_MODUAL_FM,
APP_MODUAL_SD,
APP_MODUAL_LINEIN,
APP_MODUAL_USBHOST,
APP_MODUAL_USBDEVICE,
APP_MODUAL_WATCHDOG,
APP_MODUAL_AUDIO_MANAGE,
APP_MODUAL_ANC,
APP_MODUAL_SMART_MIC,
#ifdef __PC_CMD_UART__
APP_MODUAL_CMD,
#endif
#ifdef TILE_DATAPATH
APP_MODUAL_TILE,
#endif
APP_MODUAL_MIC,
#ifdef VOICE_DETECTOR_EN
APP_MODUAL_VOICE_DETECTOR,
#endif
APP_MODUAL_CUSTOM_FUNCTION,
APP_MODUAL_OHTER,
APP_MODUAL_WNR,
APP_MODUAL_NUM
};
typedef struct {
uint32_t message_id;
uint32_t message_ptr;
uint32_t message_Param0;
uint32_t message_Param1;
uint32_t message_Param2;
} APP_MESSAGE_BODY;
typedef struct {
uint32_t src_thread;
uint32_t dest_thread;
uint32_t system_time;
uint32_t mod_id;
APP_MESSAGE_BODY msg_body;
} APP_MESSAGE_BLOCK;
typedef int (*APP_MOD_HANDLER_T)(APP_MESSAGE_BODY *);
int app_mailbox_put(APP_MESSAGE_BLOCK* msg_src);
int app_mailbox_free(APP_MESSAGE_BLOCK* msg_p);
int app_mailbox_get(APP_MESSAGE_BLOCK** msg_p);
int app_os_init(void);
int app_set_threadhandle(enum APP_MODUAL_ID_T mod_id, APP_MOD_HANDLER_T handler);
void * app_os_tid_get(void);
bool app_is_module_registered(enum APP_MODUAL_ID_T mod_id);
#ifdef __cplusplus
}
#endif
#endif//__FMDEC_H__

281
apps/common/app_utils.c Normal file
View file

@ -0,0 +1,281 @@
/***************************************************************************
*
* 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 "cmsis.h"
#include "hal_trace.h"
#include "hal_timer.h"
#include "hal_wdt.h"
#include "pmu.h"
#include "analog.h"
#include "app_utils.h"
#ifdef RTOS
#include "cmsis_os.h"
#endif
#define FREQ_FREE 0UL
#define FREQ_26M 26UL
#define FREQ_52M 52UL
#define FREQ_78M 78UL
#define FREQ_104M 104UL
#define FREQ_208M 208UL
/*
* qos_users, quality of services users, this kind of user must run with the
* minist frequency they requiested, if there are more users, the frequency
* should be boost for these users
* e.g. the key word recorgnithion function request 26M Hz, and the music
* also need 26M, if both of them are running, the cpu freq should boost to
* 26M + 26M = 52M Hz
*/
/*
* NOTE:
* The macro QOS_USERS works only when the APP_SYSFREQ_USER_APP_XXX is not large than
* 32, currently this works, but if the are more user, another way needed
*/
#define QOS_USERS ((1 << (APP_SYSFREQ_USER_AI_VOICE)) | \
(1 << (APP_SYSFREQ_USER_BT_A2DP)))
static const uint32_t freq_map[] = {
[HAL_CMU_FREQ_32K] = FREQ_FREE,
[HAL_CMU_FREQ_26M] = FREQ_26M,
[HAL_CMU_FREQ_52M] = FREQ_52M,
[HAL_CMU_FREQ_78M] = FREQ_78M,
[HAL_CMU_FREQ_104M] = FREQ_104M,
[HAL_CMU_FREQ_208M] = FREQ_208M,
};
static const uint32_t user_map[] = {
[0] = APP_SYSFREQ_USER_AI_VOICE,
[1] = APP_SYSFREQ_USER_BT_A2DP,
};
/*
* qos_freqs_map
* filled with user's freq, one user's freq occupy 4bits,
* that limit the frequecy number is not large than 16
*
* bit field structure:
-----------------------------------------------------
|user7 | user6 |..................|user1 | user 0|
-----------------------------------------------------
|31~28 | 27~24 |..................|7~4 | 3~0 |
-----------------------------------------------------
*
* Ok, this is ugly, but there is not so much frequecy level,
* and maybe work for a long time
*/
static uint32_t qos_freqs_map;
/*
* qos_users_map
* filled with user's number, one user's occupy 1 bit,
*
bit field structure:
-----------------------------------------------------
|user31~7(reseverd)| user7 |........| user 1| user 0|
-----------------------------------------------------
*
*/
static uint32_t qos_users_map;
static int app_qosfreq_req(enum APP_SYSFREQ_USER_T user, enum APP_SYSFREQ_FREQ_T freq)
{
int ret;
int qos_freq_num = 0;
uint32_t max_qos_freq = 0;
int user_idx;
int i;
uint32_t lock;
if (freq >= APP_SYSFREQ_FREQ_QTY)
return -1;
lock = int_lock();
for (i = 0; i < ARRAY_SIZE(user_map); i++) {
if (user == user_map[i]) {
break;
}
}
if (i >= ARRAY_SIZE(user_map)) {
int_unlock(lock);
ASSERT(0, "can not find qos user");
return 0;
}
user_idx = i;
if ((int)freq != (int)HAL_CMU_FREQ_32K) { // require freq
qos_freqs_map &= ~(0xf << (4 * i));
qos_freqs_map |= freq << (4 * i);
qos_users_map |= 1 << user_idx;
} else { //release freq
qos_freqs_map &= ~(0xf << (4 * i));
qos_users_map &= ~ (1 << user_idx);
}
//scan the qos_user_map and sum every user's request freq
for(i = 0; i < ARRAY_SIZE(user_map); i++) {
if ((qos_users_map >> i) & 0x1) {
uint32_t real_freq;
int freq_num;
freq_num = (qos_freqs_map >> (4 * i )) & 0xf;
real_freq = freq_map[freq_num];
max_qos_freq += real_freq;
}
}
for (i = 0; i < ARRAY_SIZE(freq_map); i++) {
if (i) {
if ((max_qos_freq > freq_map[i-1]) && (max_qos_freq <= freq_map[i])) {
qos_freq_num = i;
break;
}
} else {
if (max_qos_freq == freq_map[i]) {
qos_freq_num = i;
break;
}
}
}
if (i >= ARRAY_SIZE(freq_map)) {
qos_freq_num = (HAL_CMU_FREQ_QTY - 1);
int_unlock(lock);
TRACE(0, "WARNING: required sysfreq exceed");
// ASSERT(0, "can not find actual freq");
return 0;
}
user = APP_SYSFREQ_USER_QOS;
TRACE(2, "User %d require sysfreq %d", user, qos_freq_num);
ret = hal_sysfreq_req((enum HAL_SYSFREQ_USER_T)user, (enum HAL_CMU_FREQ_T)qos_freq_num);
int_unlock(lock);
return ret;
}
int app_sysfreq_req(enum APP_SYSFREQ_USER_T user, enum APP_SYSFREQ_FREQ_T freq)
{
int ret;
// if user is qos user
if ((1 << user) & QOS_USERS) {
ret = app_qosfreq_req(user, freq);
} else { // if user is NOT qos user
ret = hal_sysfreq_req((enum HAL_SYSFREQ_USER_T)user, (enum HAL_CMU_FREQ_T)freq);
}
return ret;
}
#ifdef RTOS
extern int rtx_task_idle_health_check(void);
static void watchdog_ping_handler(void const *n);
static osTimerId wdt_ping_timer_id;
osTimerDef(wdt_ping_timer, watchdog_ping_handler);
static uint32_t wdt_ping_period;
static void watchdog_ping(void)
{
hal_wdt_ping(HAL_WDT_ID_0);
#ifndef CHIP_BEST2000
pmu_wdt_feed();
#endif
}
static void app_wdt_irq_handle(enum HAL_WDT_ID_T id, uint32_t status)
{
analog_aud_codec_mute();
ASSERT(0, "%s id:%d status:%d",__func__, id, status);
}
static void pmu_wdt_irq_handle(void)
{
analog_aud_codec_mute();
ASSERT(1, "%s", __func__);
}
static void watchdog_ping_handler(void const *unused)
{
int ret;
watchdog_ping();
ret = rtx_task_idle_health_check();
if (ret < 0) {
ASSERT(0, "System soft lockup");
}
osTimerStart(wdt_ping_timer_id, wdt_ping_period);
}
int app_wdt_open(int seconds)
{
uint32_t lock = int_lock();
hal_wdt_set_irq_callback(HAL_WDT_ID_0, app_wdt_irq_handle);
hal_wdt_set_timeout(HAL_WDT_ID_0, seconds);
hal_wdt_start(HAL_WDT_ID_0);
pmu_wdt_set_irq_handler(pmu_wdt_irq_handle);
#ifndef CHIP_BEST2000
pmu_wdt_config(seconds * 1100, seconds * 1100);
pmu_wdt_start();
#endif
int_unlock(lock);
wdt_ping_timer_id = osTimerCreate(osTimer(wdt_ping_timer), osTimerOnce, NULL);
if (!wdt_ping_timer_id) {
TRACE(0,"Warning: can not create watchdog ping timer");
return -1;
}
wdt_ping_period = seconds * 1000 / 4;
osTimerStart(wdt_ping_timer_id, wdt_ping_period);
return 0;
}
int app_wdt_reopen(int seconds)
{
uint32_t lock = int_lock();
hal_wdt_stop(HAL_WDT_ID_0);
hal_wdt_set_timeout(HAL_WDT_ID_0, seconds);
hal_wdt_start(HAL_WDT_ID_0);
#ifndef CHIP_BEST2000
pmu_wdt_config(seconds * 1000, seconds * 1000);
pmu_wdt_start();
#endif
int_unlock(lock);
osTimerStart(wdt_ping_timer_id, wdt_ping_period);
return 0;
}
int app_wdt_close(void)
{
uint32_t lock;
osTimerStop(wdt_ping_timer_id);
lock = int_lock();
hal_wdt_stop(HAL_WDT_ID_0);
#ifndef CHIP_BEST2000
pmu_wdt_stop();
#endif
int_unlock(lock);
return 0;
}
#endif

108
apps/common/app_utils.h Normal file
View file

@ -0,0 +1,108 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __APP_UTILS_H__
#define __APP_UTILS_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "hal_sysfreq.h"
// APP_SYSFREQ_USER_APP_0 is APP_MAIN
#define APP_SYSFREQ_USER_BT_MAIN APP_SYSFREQ_USER_APP_1
#define APP_SYSFREQ_USER_HCI APP_SYSFREQ_USER_APP_2
#define APP_SYSFREQ_USER_BT_A2DP APP_SYSFREQ_USER_APP_3
#define APP_SYSFREQ_USER_UNUSED APP_SYSFREQ_USER_APP_4
#define APP_SYSFREQ_USER_AI_VOICE APP_SYSFREQ_USER_APP_5
#define APP_SYSFREQ_USER_BT_SCO APP_SYSFREQ_USER_APP_6
#define APP_SYSFREQ_USER_OTA APP_SYSFREQ_USER_APP_7
#define APP_SYSFREQ_USER_PROMPT_MIXER APP_SYSFREQ_USER_APP_8
#define APP_SYSFREQ_USER_APP_NT APP_SYSFREQ_USER_APP_9
#define APP_SYSFREQ_USER_ANC_WNR APP_SYSFREQ_USER_APP_10
#ifdef __RAND_FROM_MIC__
#define APP_SYSFREQ_USER_RANDOM APP_SYSFREQ_USER_APP_11
#endif
#ifdef __DUAL_MIC_RECORDING__
#define APP_SYSFREQ_USER_RECORDING APP_SYSFREQ_USER_APP_12
#endif
/*
* Pseudo user, if one of user is belong to qos(quality of service) user,
* when request cpu freq, it will changed to this user
*/
#define APP_SYSFREQ_USER_QOS APP_SYSFREQ_USER_APP_12
enum APP_SYSFREQ_USER_T {
APP_SYSFREQ_USER_APP_INIT = HAL_SYSFREQ_USER_INIT,
APP_SYSFREQ_USER_APP_0 = HAL_SYSFREQ_USER_APP_0,
APP_SYSFREQ_USER_APP_1 = HAL_SYSFREQ_USER_APP_1,
APP_SYSFREQ_USER_APP_2 = HAL_SYSFREQ_USER_APP_2,
APP_SYSFREQ_USER_APP_3 = HAL_SYSFREQ_USER_APP_3,
APP_SYSFREQ_USER_APP_4 = HAL_SYSFREQ_USER_APP_4,
APP_SYSFREQ_USER_APP_5 = HAL_SYSFREQ_USER_APP_5,
APP_SYSFREQ_USER_APP_6 = HAL_SYSFREQ_USER_APP_6,
APP_SYSFREQ_USER_APP_7 = HAL_SYSFREQ_USER_APP_7,
APP_SYSFREQ_USER_APP_8 = HAL_SYSFREQ_USER_APP_8,
APP_SYSFREQ_USER_APP_9 = HAL_SYSFREQ_USER_APP_9,
APP_SYSFREQ_USER_APP_10 = HAL_SYSFREQ_USER_APP_10,
APP_SYSFREQ_USER_APP_11 = HAL_SYSFREQ_USER_APP_11,
APP_SYSFREQ_USER_APP_12 = HAL_SYSFREQ_USER_APP_12,
APP_SYSFREQ_USER_APP_13 = HAL_SYSFREQ_USER_APP_13,
APP_SYSFREQ_USER_APP_14 = HAL_SYSFREQ_USER_APP_14,
APP_SYSFREQ_USER_APP_15 = HAL_SYSFREQ_USER_APP_15,
APP_SYSFREQ_USER_QTY
};
enum APP_SYSFREQ_FREQ_T {
APP_SYSFREQ_32K = HAL_CMU_FREQ_32K,
APP_SYSFREQ_26M = HAL_CMU_FREQ_26M,
APP_SYSFREQ_52M = HAL_CMU_FREQ_52M,
APP_SYSFREQ_78M = HAL_CMU_FREQ_78M,
APP_SYSFREQ_104M = HAL_CMU_FREQ_104M,
APP_SYSFREQ_208M = HAL_CMU_FREQ_208M,
APP_SYSFREQ_FREQ_QTY = HAL_CMU_FREQ_QTY
};
enum APP_WDT_THREAD_CHECK_USER_T {
APP_WDT_THREAD_CHECK_USER_APP,
APP_WDT_THREAD_CHECK_USER_AF,
APP_WDT_THREAD_CHECK_USER_BT,
APP_WDT_THREAD_CHECK_USER_3,
APP_WDT_THREAD_CHECK_USER_4,
APP_WDT_THREAD_CHECK_USER_5,
APP_WDT_THREAD_CHECK_USER_6,
APP_WDT_THREAD_CHECK_USER_7,
APP_WDT_THREAD_CHECK_USER_8,
APP_WDT_THREAD_CHECK_USER_9,
APP_WDT_THREAD_CHECK_USER_10,
APP_WDT_THREAD_CHECK_USER_QTY
};
int app_sysfreq_req(enum APP_SYSFREQ_USER_T user, enum APP_SYSFREQ_FREQ_T freq);
int app_wdt_open(int seconds);
int app_wdt_reopen(int seconds);
int app_wdt_close(void);
#ifdef __cplusplus
}
#endif
#endif//__FMDEC_H__

267
apps/common/randfrommic.c Normal file
View file

@ -0,0 +1,267 @@
#ifdef __RAND_FROM_MIC__
#include "audioflinger.h"
#include "hal_trace.h"
#include "app_utils.h"
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#include "app_bt_stream.h"
#include "randfrommic.h"
#include "hal_timer.h"
#include "cmsis_os.h"
#include "cmsis_gcc.h"
#include "app_audio.h"
#if BT_DRV_DEBUG
#define RAND_TRACE(n, fmt, ...) TRACE(n, fmt, ##__VA_ARGS__)
#define RAND_DUMP(s,buff,len) DUMP8(s,buff,len)
#else
#define RAND_TRACE(n, fmt, ...)
#define RAND_DUMP(s,buff,len)
#endif
static void generateRand(bool on);
static uint32_t rand_data_handle(uint8_t *buf, uint32_t len);
static uint8_t deviceId = 0;
static uint8_t *captureBuffer = NULL;
static uint32_t randSeed = 1;
static bool randInitialised = false;
// 4 bytes aligned
#define RAND_GRAB_BITS_PER_SAMPLE 4
#define RAND_GRAB_BITS_MASK_PER_SAMPLE ((1 << RAND_GRAB_BITS_PER_SAMPLE)-1)
RAND_NUMBER_T randomBuffer =
{
25,
RAND_STATUS_CLOSE,
};
/**
* Description: parse mic data according to the stream cfg(bit mode and channel number)
* only the lowest byte of each frame is taken
* ADC format:
* 16bit mode -> [15:0] is valid
* 24bit mode -> [23:4] is valid
* 32bit mode -> [31:12] is valid
*
*/
static int randDataParse(uint8_t *buf, uint32_t len, enum AUD_BITS_T bits,
enum AUD_CHANNEL_NUM_T ch_num)
{
uint8_t index = 0;
union {
uint32_t seedValue;
uint8_t value[4];
}seedData;
if ((NULL == buf) ||
((RANDOM_CAPTURE_BUFFER_SIZE/2) > len)) // ping-pong buffer
{
return -1;
}
RAND_TRACE(1, "%s", __func__);
RAND_DUMP("%x ",buf, 16);
switch (bits)
{
case AUD_BITS_16:
{
uint16_t* content = (uint16_t *)buf;
for (index = 0;index < 4; index++)
{
seedData.value[index] = ((*content) & RAND_GRAB_BITS_MASK_PER_SAMPLE) |
(((*(content+ch_num)) & RAND_GRAB_BITS_MASK_PER_SAMPLE) << RAND_GRAB_BITS_PER_SAMPLE);
content += ((8/RAND_GRAB_BITS_PER_SAMPLE)*ch_num);
}
break;
}
case AUD_BITS_24:
{
uint32_t* content = (uint32_t *)buf;
for (index = 0;index < 4; index++)
{
// bit 23:4 are valid
seedData.value[index] = (((*content) >> 4) & RAND_GRAB_BITS_MASK_PER_SAMPLE) |
((((*(content+ch_num)) >> 4)&RAND_GRAB_BITS_MASK_PER_SAMPLE) << RAND_GRAB_BITS_PER_SAMPLE);
content += ((8/RAND_GRAB_BITS_PER_SAMPLE)*ch_num);
}
break;
}
case AUD_BITS_32:
{
uint32_t* content = (uint32_t *)buf;
for (index = 0;index < 4; index++)
{
// bit 31:12 are valid
seedData.value[index] = (((*content) >> 12) & RAND_GRAB_BITS_MASK_PER_SAMPLE) |
((((*(content+ch_num)) >> 12) & RAND_GRAB_BITS_MASK_PER_SAMPLE) << RAND_GRAB_BITS_PER_SAMPLE);
content += ((8/RAND_GRAB_BITS_PER_SAMPLE)*ch_num);
}
break;
}
default:
{
return -1;
}
break;
}
randSeed = seedData.seedValue;
return 0;
}
static void generateRand(bool on)
{
struct AF_STREAM_CONFIG_T stream_cfg;
RAND_TRACE(2, "%s op:%d", __func__, on);
if (on)
{
randomBuffer.skipRound = 10;
randomBuffer.status = random_mic_is_on(&deviceId);
RAND_TRACE(2, "%s random status = %d", __func__, randomBuffer.status);
if (RAND_STATUS_CLOSE == randomBuffer.status)
{
app_sysfreq_req(APP_SYSFREQ_USER_RANDOM, APP_SYSFREQ_208M);
app_capture_audio_mempool_init();
app_capture_audio_mempool_get_buff(&captureBuffer,
RANDOM_CAPTURE_BUFFER_SIZE);
memset(&stream_cfg, 0, sizeof(stream_cfg));
stream_cfg.bits = AUD_BITS_16;
stream_cfg.channel_num = AUD_CHANNEL_NUM_1;
stream_cfg.device = AUD_STREAM_USE_INT_CODEC;
stream_cfg.sample_rate = AUD_SAMPRATE_8000;
stream_cfg.vol = TGT_VOLUME_LEVEL_15;
stream_cfg.io_path = AUD_INPUT_PATH_MAINMIC;
stream_cfg.handler = rand_data_handle;
stream_cfg.data_ptr = BT_AUDIO_CACHE_2_UNCACHE(captureBuffer);
stream_cfg.data_size = RANDOM_CAPTURE_BUFFER_SIZE;
af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE, &stream_cfg);
af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
randomBuffer.status = RAND_STATUS_OPEN;
}
else if(RAND_STATUS_MIC_OPENED == randomBuffer.status)
{
af_stream_start(deviceId, AUD_STREAM_CAPTURE);
}
}
else
{
// release the acquired system clock
app_sysfreq_req(APP_SYSFREQ_USER_RANDOM, APP_SYSFREQ_32K);
if (RAND_STATUS_MIC_OPENED == randomBuffer.status)
{
af_stream_stop(deviceId, AUD_STREAM_CAPTURE);
}
else if (RAND_STATUS_OPEN == randomBuffer.status)
{
af_stream_stop(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
af_stream_close(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
}
randomBuffer.status = RAND_STATUS_CLOSE;
}
}
static uint32_t rand_data_handle(uint8_t *buf, uint32_t len)
{
if (buf == NULL)
{
return len;
}
if ((1 == randomBuffer.skipRound) &&
(!randDataParse(buf, len, AUD_BITS_16, AUD_CHANNEL_NUM_1)))
{
generateRand(false);
randomBuffer.skipRound = 0;
}
else if (1 != randomBuffer.skipRound)
{
randomBuffer.skipRound--;
}
return len;
}
void initSeed(void)
{
uint8_t count = 100; // avoid deed loop
RAND_TRACE(2, "%s:+++ initialised = %d", __func__, randInitialised);
if (randInitialised)
{
generateRand(true);
while ((0 != randomBuffer.skipRound) && (0 != count))
{
osDelay(10);
count --;
}
}
if ((0 == count) || (false == randInitialised))
{
RAND_TRACE(1, "%s not ready", __func__);
randSeed = (uint32_t)hal_sys_timer_get();
generateRand(false);
}
srand(randSeed);
RAND_TRACE(2, "%s:--- count = %d", __func__, count);
}
void random_status_sync(void)
{
if (RAND_STATUS_OPEN == randomBuffer.status)
{
RAND_TRACE(1, "%s random mic has already on,should be closed", __func__);
generateRand(false);
}
}
void random_data_process(uint8_t *buf, uint32_t len,enum AUD_BITS_T bits,
enum AUD_CHANNEL_NUM_T ch_num)
{
if (buf == NULL)
{
return;
}
if ((RAND_STATUS_MIC_STARTED == randomBuffer.status) ||
(RAND_STATUS_MIC_OPENED == randomBuffer.status))
{
if (len >= RANDOM_CAPTURE_BUFFER_SIZE/2)
{
RAND_TRACE(4, "%s buf address = 0x%p, bits = %d, channel num = %d", __func__, buf, bits, ch_num);
RAND_DUMP("%02x ", buf, 32);
if ((1 == randomBuffer.skipRound) &&
(!randDataParse(buf, len, bits, ch_num)))
{
generateRand(false);
randomBuffer.skipRound = 0;
}
else if (1 != randomBuffer.skipRound)
{
randomBuffer.skipRound--;
}
}
}
}
void randInit(void)
{
randInitialised = true;
}
#endif

33
apps/common/randfrommic.h Normal file
View file

@ -0,0 +1,33 @@
#ifdef __RAND_FROM_MIC__
#ifndef __RANDFROMMIC_H__
#define __RANDFROMMIC_H__
#ifdef __cplusplus
extern "C" {
#endif
#define RANDOM_CAPTURE_BUFFER_SIZE 512
// random module state machine
typedef enum {
RAND_STATUS_CLOSE = 0x00, // initial state
RAND_STATUS_OPEN = 0x01, // indicate MIC has been started by random module
RAND_STATUS_MIC_STARTED = 0x02, // indicate MIC has been started
RAND_STATUS_MIC_OPENED = 0x03, // indicate MIC has been opened but not start
RAND_STATUS_NUM = 0x0F
}RAND_STATUS_E;
typedef struct{
uint8_t skipRound; // used to indicate the number of rounds should be skipped to avoid all zero value
RAND_STATUS_E status;
}__attribute__ ((__packed__))RAND_NUMBER_T;
void initSeed(void);
void random_status_sync(void);
void random_data_process(uint8_t *buf, uint32_t len,enum AUD_BITS_T bits, enum AUD_CHANNEL_NUM_T ch_num);
void randInit(void);
#ifdef __cplusplus
}
#endif
#endif
#endif

View file

@ -0,0 +1,882 @@
0, 0,
4652, 4653,
9211, 9210,
13583, 13583,
17679, 17680,
21418, 21417,
24722, 24722,
27525, 27524,
29770, 29770,
31413, 31413,
32418, 32418,
32767, 32767,
32452, 32452,
31478, 31479,
29867, 29867,
27651, 27651,
24875, 24874,
21594, 21594,
17876, 17876,
13795, 13795,
9435, 9434,
4884, 4884,
234, 234,
-4421, -4422,
-8986, -8987,
-13370, -13371,
-17483, -17482,
-21240, -21241,
-24568, -24568,
-27398, -27398,
-29672, -29673,
-31345, -31346,
-32384, -32383,
-32766, -32765,
-32483, -32483,
-31542, -31542,
-29963, -29963,
-27776, -27775,
-25026, -25026,
-21769, -21769,
-18071, -18071,
-14007, -14006,
-9659, -9658,
-5114, -5114,
-466, -467,
4190, 4190,
8763, 8763,
13157, 13157,
17284, 17284,
21062, 21063,
24413, 24413,
27269, 27268,
29572, 29573,
31277, 31277,
32347, 32347,
32762, 32762,
32512, 32513,
31605, 31605,
30057, 30057,
27898, 27899,
25175, 25176,
21943, 21943,
18265, 18265,
14217, 14217,
9881, 9881,
5345, 5345,
700, 700,
-3959, -3958,
-8537, -8536,
-12943, -12943,
-17086, -17086,
-20883, -20883,
-24257, -24256,
-27139, -27139,
-29470, -29471,
-31207, -31207,
-32309, -32308,
-32757, -32756,
-32540, -32541,
-31665, -31666,
-30149, -30148,
-28020, -28020,
-25324, -25325,
-22115, -22116,
-18458, -18458,
-14427, -14428,
-10104, -10102,
-5575, -5575,
-934, -934,
3727, 3727,
8312, 8311,
12728, 12728,
16886, 16886,
20702, 20702,
24100, 24099,
27008, 27008,
29369, 29368,
31135, 31135,
32270, 32269,
32750, 32750,
32567, 32567,
31725, 31725,
30239, 30239,
28141, 28140,
25472, 25471,
22287, 22288,
18650, 18651,
14636, 14637,
10326, 10325,
5805, 5805,
1166, 1166,
-3495, -3495,
-8086, -8086,
-12513, -12513,
-16686, -16685,
-20521, -20521,
-23940, -23940,
-26875, -26875,
-29265, -29263,
-31062, -31060,
-32228, -32228,
-32741, -32742,
-32592, -32592,
-31783, -31781,
-30328, -30329,
-28260, -28259,
-25618, -25617,
-22458, -22457,
-18842, -18843,
-14844, -14845,
-10547, -10547,
-6034, -6034,
-1400, -1400,
3263, 3263,
7859, 7859,
12297, 12296,
16484, 16485,
20338, 20338,
23781, 23780,
26741, 26740,
29158, 29159,
30986, 30986,
32184, 32185,
32731, 32733,
32615, 32616,
31839, 31838,
30417, 30416,
28377, 28377,
25763, 25763,
22627, 22628,
19032, 19033,
15052, 15052,
10767, 10767,
6263, 6264,
1633, 1634,
-3030, -3030,
-7632, -7633,
-12079, -12080,
-16283, -16283,
-20155, -20154,
-23620, -23619,
-26604, -26605,
-29051, -29051,
-30908, -30909,
-32140, -32141,
-32720, -32721,
-32638, -32638,
-31893, -31892,
-30502, -30502,
-28494, -28493,
-25907, -25906,
-22796, -22795,
-19222, -19222,
-15259, -15259,
-10987, -10987,
-6493, -6492,
-1866, -1866,
2797, 2797,
7404, 7405,
11862, 11862,
16079, 16079,
19971, 19971,
23457, 23457,
26468, 26468,
28943, 28942,
30830, 30831,
32094, 32093,
32707, 32707,
32657, 32656,
31946, 31946,
30586, 30586,
28608, 28608,
26049, 26050,
22962, 22963,
19411, 19411,
15466, 15465,
11207, 11206,
6722, 6722,
2099, 2099,
-2565, -2565,
-7177, -7178,
-11644, -11645,
-15875, -15875,
-19785, -19784,
-23294, -23294,
-26330, -26330,
-28833, -28832,
-30751, -30751,
-32046, -32046,
-32692, -32692,
-32676, -32675,
-31997, -31997,
-30670, -30670,
-28721, -28721,
-26190, -26190,
-23128, -23129,
-19598, -19599,
-15671, -15672,
-11425, -11426,
-6950, -6950,
-2331, -2332,
2332, 2333,
6949, 6949,
11426, 11426,
15671, 15671,
19598, 19598,
23128, 23128,
26190, 26190,
28722, 28720,
30669, 30669,
31997, 31996,
32676, 32675,
32692, 32692,
32046, 32046,
30751, 30751,
28832, 28833,
26330, 26330,
23293, 23294,
19785, 19785,
15876, 15875,
11645, 11645,
7177, 7177,
2566, 2565,
-2100, -2100,
-6722, -6721,
-11207, -11208,
-15465, -15465,
-19412, -19412,
-22963, -22962,
-26049, -26049,
-28608, -28608,
-30586, -30586,
-31946, -31946,
-32657, -32657,
-32707, -32707,
-32095, -32093,
-30830, -30830,
-28943, -28943,
-26467, -26468,
-23457, -23457,
-19970, -19971,
-16079, -16079,
-11862, -11863,
-7406, -7404,
-2798, -2798,
1866, 1866,
6492, 6493,
10987, 10987,
15260, 15259,
19222, 19222,
22795, 22795,
25906, 25907,
28493, 28493,
30502, 30502,
31893, 31893,
32638, 32637,
32721, 32721,
32141, 32140,
30909, 30909,
29051, 29052,
26605, 26605,
23619, 23619,
20155, 20155,
16282, 16282,
12080, 12080,
7631, 7632,
3031, 3031,
-1633, -1633,
-6263, -6264,
-10767, -10767,
-15053, -15052,
-19033, -19033,
-22627, -22627,
-25763, -25763,
-28377, -28377,
-30416, -30416,
-31839, -31838,
-32616, -32616,
-32732, -32731,
-32184, -32185,
-30986, -30985,
-29159, -29159,
-26740, -26740,
-23780, -23780,
-20339, -20339,
-16485, -16484,
-12297, -12296,
-7859, -7859,
-3263, -3262,
1399, 1401,
6034, 6034,
10547, 10546,
14845, 14844,
18842, 18842,
22457, 22458,
25619, 25619,
28260, 28259,
30329, 30328,
31783, 31783,
32593, 32593,
32742, 32742,
32228, 32228,
31061, 31060,
29264, 29264,
26875, 26875,
23940, 23940,
20521, 20521,
16686, 16686,
12512, 12513,
8085, 8085,
3495, 3494,
-1167, -1167,
-5804, -5805,
-10325, -10326,
-14636, -14636,
-18651, -18651,
-22287, -22288,
-25472, -25472,
-28141, -28141,
-30239, -30239,
-31725, -31725,
-32568, -32567,
-32750, -32751,
-32270, -32269,
-31134, -31135,
-29368, -29369,
-27007, -27008,
-24099, -24099,
-20703, -20703,
-16886, -16886,
-12728, -12728,
-8311, -8311,
-3726, -3728,
934, 933,
5575, 5575,
10104, 10104,
14426, 14427,
18458, 18458,
22115, 22115,
25324, 25324,
28021, 28021,
30149, 30148,
31666, 31665,
32541, 32541,
32757, 32757,
32310, 32309,
31206, 31206,
29471, 29472,
27139, 27139,
24257, 24257,
20883, 20883,
17085, 17086,
12943, 12944,
8537, 8537,
3958, 3959,
-700, -700,
-5345, -5345,
-9882, -9881,
-14217, -14217,
-18265, -18265,
-21942, -21943,
-25176, -25175,
-27899, -27899,
-30056, -30056,
-31605, -31605,
-32513, -32513,
-32762, -32761,
-32347, -32347,
-31277, -31277,
-29573, -29573,
-27269, -27269,
-24413, -24414,
-21062, -21062,
-17284, -17284,
-13156, -13157,
-8762, -8762,
-4190, -4190,
467, 466,
5115, 5115,
9659, 9658,
14006, 14007,
18070, 18070,
21769, 21769,
25026, 25025,
27776, 27776,
29962, 29963,
31541, 31542,
32482, 32483,
32765, 32765,
32383, 32383,
31346, 31346,
29672, 29672,
27397, 27398,
24568, 24568,
21240, 21241,
17482, 17482,
13371, 13370,
8987, 8987,
4421, 4422,
-233, -234,
-4883, -4883,
-9435, -9435,
-13795, -13795,
-17876, -17875,
-21594, -21594,
-24874, -24875,
-27651, -27651,
-29868, -29867,
-31478, -31478,
-32451, -32451,
-32767, -32767,
-32419, -32418,
-31413, -31413,
-29770, -29770,
-27525, -27525,
-24722, -24722,
-21418, -21417,
-17680, -17680,
-13583, -13582,
-9211, -9212,
-4653, -4653,
-1, 1,
4652, 4652,
9211, 9211,
13584, 13582,
17679, 17679,
21418, 21418,
24722, 24722,
27525, 27525,
29771, 29771,
31412, 31413,
32418, 32419,
32767, 32767,
32452, 32451,
31478, 31478,
29868, 29867,
27650, 27651,
24874, 24874,
21593, 21593,
17876, 17875,
13795, 13795,
9435, 9436,
4883, 4884,
234, 233,
-4421, -4422,
-8987, -8987,
-13370, -13370,
-17483, -17483,
-21240, -21240,
-24568, -24569,
-27398, -27398,
-29672, -29672,
-31346, -31346,
-32383, -32384,
-32765, -32765,
-32483, -32484,
-31542, -31542,
-29963, -29963,
-27775, -27775,
-25026, -25026,
-21769, -21769,
-18070, -18071,
-14006, -14007,
-9658, -9658,
-5115, -5115,
-467, -467,
4190, 4190,
8762, 8763,
13157, 13157,
17285, 17284,
21062, 21062,
24413, 24413,
27269, 27269,
29573, 29572,
31276, 31277,
32347, 32346,
32762, 32762,
32513, 32512,
31605, 31604,
30056, 30057,
27899, 27899,
25176, 25176,
21943, 21943,
18265, 18265,
14217, 14217,
9881, 9881,
5344, 5345,
700, 700,
-3958, -3958,
-8537, -8537,
-12942, -12943,
-17085, -17086,
-20883, -20883,
-24257, -24257,
-27138, -27138,
-29471, -29471,
-31206, -31207,
-32309, -32308,
-32757, -32757,
-32541, -32540,
-31666, -31666,
-30148, -30148,
-28021, -28020,
-25325, -25325,
-22115, -22116,
-18458, -18458,
-14427, -14427,
-10103, -10103,
-5575, -5575,
-934, -933,
3727, 3726,
8312, 8311,
12729, 12728,
16886, 16886,
20703, 20702,
24099, 24100,
27007, 27008,
29369, 29369,
31135, 31134,
32270, 32270,
32750, 32750,
32568, 32567,
31724, 31724,
30239, 30240,
28140, 28142,
25472, 25473,
22287, 22288,
18651, 18651,
14636, 14635,
10325, 10325,
5805, 5805,
1167, 1167,
-3495, -3495,
-8085, -8085,
-12512, -12513,
-16685, -16685,
-20521, -20521,
-23941, -23940,
-26875, -26875,
-29264, -29265,
-31060, -31061,
-32228, -32228,
-32742, -32742,
-32593, -32593,
-31782, -31782,
-30328, -30328,
-28260, -28260,
-25618, -25619,
-22458, -22458,
-18842, -18842,
-14845, -14844,
-10546, -10546,
-6035, -6035,
-1400, -1400,
3262, 3263,
7859, 7859,
12296, 12297,
16485, 16485,
20339, 20339,
23780, 23780,
26741, 26741,
29159, 29158,
30985, 30985,
32185, 32185,
32732, 32733,
32615, 32616,
31839, 31839,
30416, 30416,
28377, 28377,
25763, 25762,
22627, 22628,
19032, 19032,
15053, 15052,
10767, 10767,
6264, 6263,
1633, 1634,
-3030, -3030,
-7632, -7632,
-12081, -12079,
-16282, -16283,
-20154, -20155,
-23618, -23619,
-26604, -26605,
-29051, -29051,
-30910, -30909,
-32140, -32141,
-32721, -32720,
-32637, -32637,
-31892, -31893,
-30502, -30502,
-28493, -28493,
-25907, -25907,
-22795, -22796,
-19222, -19222,
-15260, -15259,
-10987, -10987,
-6493, -6492,
-1867, -1867,
2798, 2798,
7405, 7405,
11862, 11862,
16079, 16079,
19971, 19970,
23457, 23456,
26468, 26468,
28942, 28942,
30831, 30830,
32095, 32095,
32707, 32706,
32657, 32657,
31946, 31945,
30587, 30586,
28607, 28607,
26049, 26049,
22963, 22963,
19411, 19411,
15466, 15465,
11206, 11208,
6721, 6721,
2100, 2099,
-2565, -2565,
-7177, -7177,
-11644, -11644,
-15875, -15876,
-19785, -19785,
-23293, -23294,
-26330, -26330,
-28833, -28832,
-30751, -30751,
-32046, -32047,
-32692, -32692,
-32675, -32675,
-31997, -31997,
-30669, -30669,
-28720, -28720,
-26190, -26190,
-23129, -23128,
-19598, -19598,
-15671, -15671,
-11425, -11426,
-6949, -6949,
-2332, -2332,
2333, 2333,
6950, 6950,
11426, 11427,
15670, 15671,
19599, 19598,
23128, 23128,
26190, 26189,
28720, 28720,
30670, 30669,
31996, 31996,
32675, 32676,
32692, 32692,
32046, 32046,
30751, 30751,
28832, 28831,
26330, 26329,
23293, 23293,
19784, 19785,
15875, 15875,
11645, 11645,
7177, 7178,
2564, 2565,
-2100, -2099,
-6722, -6722,
-11207, -11206,
-15466, -15466,
-19410, -19411,
-22962, -22962,
-26049, -26049,
-28608, -28607,
-30586, -30586,
-31945, -31946,
-32658, -32657,
-32707, -32707,
-32095, -32094,
-30832, -30830,
-28943, -28943,
-26468, -26467,
-23457, -23456,
-19971, -19970,
-16080, -16080,
-11862, -11863,
-7406, -7405,
-2797, -2797,
1867, 1866,
6492, 6492,
10987, 10987,
15260, 15259,
19222, 19222,
22796, 22796,
25907, 25906,
28494, 28493,
30502, 30502,
31893, 31893,
32637, 32637,
32720, 32721,
32140, 32140,
30909, 30909,
29052, 29052,
26605, 26605,
23619, 23619,
20155, 20155,
16281, 16282,
12080, 12079,
7632, 7632,
3031, 3030,
-1634, -1633,
-6263, -6264,
-10767, -10767,
-15052, -15053,
-19033, -19032,
-22627, -22628,
-25763, -25763,
-28377, -28377,
-30416, -30416,
-31838, -31838,
-32616, -32616,
-32732, -32732,
-32185, -32185,
-30986, -30986,
-29158, -29158,
-26741, -26741,
-23780, -23780,
-20339, -20338,
-16485, -16484,
-12296, -12296,
-7859, -7859,
-3262, -3263,
1400, 1400,
6035, 6034,
10546, 10546,
14845, 14845,
18842, 18842,
22457, 22458,
25619, 25619,
28260, 28260,
30327, 30328,
31782, 31782,
32592, 32592,
32742, 32742,
32229, 32227,
31061, 31061,
29264, 29264,
26875, 26874,
23940, 23941,
20521, 20521,
16685, 16686,
12513, 12513,
8086, 8085,
3495, 3495,
-1167, -1167,
-5804, -5805,
-10325, -10324,
-14636, -14636,
-18651, -18651,
-22287, -22287,
-25471, -25473,
-28141, -28140,
-30239, -30240,
-31724, -31725,
-32567, -32567,
-32750, -32751,
-32270, -32269,
-31135, -31135,
-29369, -29369,
-27007, -27007,
-24099, -24099,
-20703, -20703,
-16886, -16886,
-12728, -12728,
-8311, -8312,
-3727, -3727,
934, 934,
5576, 5575,
10104, 10104,
14427, 14427,
18459, 18458,
22115, 22115,
25325, 25324,
28020, 28020,
30148, 30148,
31665, 31666,
32541, 32541,
32757, 32757,
32309, 32310,
31206, 31206,
29472, 29472,
27139, 27138,
24257, 24257,
20883, 20883,
17086, 17086,
12942, 12942,
8537, 8537,
3958, 3958,
-700, -701,
-5344, -5345,
-9881, -9881,
-14218, -14217,
-18264, -18265,
-21942, -21943,
-25175, -25176,
-27899, -27898,
-30057, -30057,
-31605, -31605,
-32512, -32513,
-32761, -32761,
-32347, -32347,
-31277, -31277,
-29573, -29572,
-27269, -27269,
-24414, -24414,
-21062, -21062,
-17284, -17285,
-13156, -13157,
-8763, -8762,
-4190, -4190,
467, 467,
5114, 5114,
9658, 9659,
14006, 14006,
18071, 18071,
21769, 21769,
25026, 25026,
27775, 27776,
29963, 29962,
31543, 31542,
32483, 32483,
32765, 32765,
32384, 32384,
31345, 31345,
29671, 29672,
27398, 27398,
24568, 24568,
21241, 21241,
17483, 17483,
13369, 13370,
8986, 8987,
4422, 4421,
-233, -234,
-4885, -4884,
-9435, -9435,
-13795, -13794,
-17876, -17875,
-21594, -21594,
-24875, -24874,
-27651, -27651,
-29867, -29868,
-31478, -31478,
-32452, -32451,
-32768, -32767,
-32419, -32418,
-31412, -31413,
-29771, -29771,
-27525, -27526,
-24722, -24721,
-21417, -21418,
-17680, -17679,
-13583, -13583,
-9211, -9210,
-4653, -4653

View file

@ -0,0 +1,96 @@
0,
0,
4234,
4234,
8396,
8396,
12414,
12414,
16220,
16220,
19748,
19748,
22938,
22938,
25736,
25736,
28094,
28094,
29970,
29970,
31334,
31334,
32162,
32162,
32440,
32440,
32162,
32162,
31334,
31334,
29970,
29970,
28094,
28094,
25736,
25736,
22938,
22938,
19748,
19748,
16220,
16220,
12414,
12414,
8396,
8396,
4234,
4234,
0,
0,
-4234,
-4234,
-8396,
-8396,
-12414,
-12414,
-16220,
-16220,
-19748,
-19748,
-22938,
-22938,
-25736,
-25736,
-28094,
-28094,
-29970,
-29970,
-31334,
-31334,
-32162,
-32162,
-32440,
-32440,
-32162,
-32162,
-31334,
-31334,
-29970,
-29970,
-28094,
-28094,
-25736,
-25736,
-22938,
-22938,
-19748,
-19748,
-16220,
-16220,
-12414,
-12414,
-8396,
-8396,
-4234,
-4234

43
apps/factory/Makefile Normal file
View file

@ -0,0 +1,43 @@
cur_dir := $(dir $(lastword $(MAKEFILE_LIST)))
obj-y := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)*.c $(cur_dir)*.cpp $(cur_dir)*.S))
obj-y := $(obj-y:.c=.o)
obj-y := $(obj-y:.cpp=.o)
obj-y := $(obj-y:.S=.o)
ccflags-y += \
-Iutils/boot_struct \
-Iutils/intersyshci \
-Iutils/hwtimer_list \
-Iservices/bt_app \
-Iservices/nvrecord \
$(BT_IF_INCLUDES) \
-Iservices/resources \
-Iservices/overlay \
-Iservices/multimedia/algorithm/fft/include \
-Iapps/key \
-Iplatform/drivers/bt \
-Iplatform/drivers/ana \
-Iplatform/drivers/usb/usb_dev/inc \
-Iapps/battery \
-Iservices/multimedia/audio/codec/sbc/inc \
-Iservices/multimedia/audio/codec/sbc/src/inc \
-Iutils/cqueue \
-Iservices/nv_section/factory_section \
-Iservices/app_ai/inc \
ifeq ($(AUDIO_RESAMPLE),1)
CFLAGS_app_factory_audio.o += -D__AUDIO_RESAMPLE__
endif
ifeq ($(SW_CAPTURE_RESAMPLE),1)
CFLAGS_app_factory_audio.o += -DSW_CAPTURE_RESAMPLE
endif
ifeq ($(POWERKEY_I2C_SWITCH),1)
CFLAGS_app_factory.o += -DPOWERKEY_I2C_SWITCH
endif
ifeq ($(SPEECH_TX_AEC_CODEC_REF),1)
CFLAGS_app_factory_audio.o += -DSPEECH_TX_AEC_CODEC_REF
endif

View file

@ -0,0 +1,689 @@
/***************************************************************************
*
* 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 "cmsis_os.h"
#include "list.h"
#include "hal_trace.h"
#include "hal_bootmode.h"
#include "hal_cmu.h"
#include "hal_sleep.h"
#include "app_key.h"
#include "app_factory.h"
#include "bt_drv_interface.h"
#include "bt_drv_reg_op.h"
#include "bluetooth.h"
#include "nvrecord.h"
#include "nvrecord_dev.h"
#include "nvrecord_env.h"
#include "resources.h"
#include "app_bt_stream.h"
#include "app_media_player.h"
#include "pmu.h"
// for init
#include "apps.h"
#include "app_status_ind.h"
#include "app_thread.h"
#include "app_key.h"
#include "app_pwl.h"
#include "app_overlay.h"
#include "app_battery.h"
#include "app_utils.h"
// for bt
#include "besbt.h"
#include "app_bt.h"
#include "app_factory_bt.h"
// for audio
#include "audioflinger.h"
#include "app_audio.h"
#include "app_utils.h"
// for progress
#include "hal_uart.h"
#include "tool_msg.h"
#include "factory_section.h"
#ifdef __FACTORY_MODE_SUPPORT__
#define APP_FACTORYMODE_RETRY_LIMITED (2)
typedef enum APP_FACTORYMODE_STATUS_INDICATION_T {
APP_FACTORYMODE_STATUS_INDICATION_RUNNING = 0,
APP_FACTORYMODE_STATUS_INDICATION_PASS,
APP_FACTORYMODE_STATUS_INDICATION_FAILED,
APP_FACTORYMODE_STATUS_INDICATION_INVALID,
APP_FACTORYMODE_STATUS_INDICATION_NUM
}APP_FACTORYMODE_STATUS_INDICATION_T;
static void app_factorymode_timehandler(void const *param);
void app_bt_key_shutdown(APP_KEY_STATUS *status, void *param);
void app_factorymode_result_set(bool result);
static osThreadId app_factorymode_tid= NULL;
static struct message_t send_msg = { { PREFIX_CHAR, }, };
static unsigned char send_seq = 0;
osTimerId app_factory_timer = NULL;
osTimerDef (APP_FACTORY_TIMER, app_factorymode_timehandler);
int app_factorymode_languageswitch_proc(void)
{
#ifdef MEDIA_PLAYER_SUPPORT
int lan;
int new_lan;
struct nvrecord_env_t *nvrecord_env;
APP_FACTORY_TRACE(1,"%s",__func__);
lan = app_play_audio_get_lang();
new_lan = lan;
app_play_audio_set_lang(new_lan);
nv_record_env_get(&nvrecord_env);
nvrecord_env->media_language.language = new_lan;
nv_record_env_set(nvrecord_env);
APP_FACTORY_TRACE(2,"languages old:%d new:%d",lan ,new_lan);
media_PlayAudio(AUD_ID_LANGUAGE_SWITCH, 0);
#endif
return 0;
}
void app_factorymode_languageswitch(APP_KEY_STATUS *status, void *param)
{
app_factorymode_languageswitch_proc();
}
void app_factorymode_enter(void)
{
APP_FACTORY_TRACE(1,"%s",__func__);
hal_sw_bootmode_set(HAL_SW_BOOTMODE_TEST_MODE|HAL_SW_BOOTMODE_TEST_SIGNALINGMODE);
hal_cmu_sys_reboot();
}
extern "C" {
static bool isInFactoryMode = false;
bool app_factorymode_get(void)
{
return isInFactoryMode;
}
void app_factorymode_set(bool set)
{
isInFactoryMode = set;
}
}
#ifdef POWERKEY_I2C_SWITCH
void app_factorymode_i2c_switch(APP_KEY_STATUS *status, void *param)
{
static int i = 0;
i++;
if (i & 1) {
TRACE(0,"set analog i2c mode !!!");
osDelay(100);
hal_iomux_set_analog_i2c();
} else {
hal_iomux_set_uart0();
osDelay(100);
TRACE(0,"hal_iomux_set_uart0 !!!");
}
}
#endif
#ifdef __IBRT_IBRT_TESTMODE__
void bt_drv_ibrt_test_key_click(APP_KEY_STATUS *status, void *param);
void bt_drv_ibrt_test_key_click(APP_KEY_STATUS *status, void *param)
{
btdrv_connect_ibrt_device(bt_addr);
}
#endif
void app_factorymode_key_init(void)
{
const APP_KEY_HANDLE app_factorymode_handle_cfg[] = {
#ifdef POWERKEY_I2C_SWITCH
{{APP_KEY_CODE_PWR,APP_KEY_EVENT_RAMPAGECLICK},"bt i2c key",app_factorymode_i2c_switch, NULL},
#endif
#ifdef __POWERKEY_CTRL_ONOFF_ONLY__
{{APP_KEY_CODE_PWR,APP_KEY_EVENT_UP},"bt function key",app_bt_key_shutdown, NULL},
#else
{{APP_KEY_CODE_PWR,APP_KEY_EVENT_LONGLONGPRESS},"bt function key",app_bt_key_shutdown, NULL},
#endif
#ifdef __IBRT_IBRT_TESTMODE__
{{APP_KEY_CODE_PWR,APP_KEY_EVENT_CLICK},"bt function key",bt_drv_ibrt_test_key_click, NULL},
#else
{{APP_KEY_CODE_PWR,APP_KEY_EVENT_CLICK},"bt function key",app_factorymode_languageswitch, NULL},
#endif
{{APP_KEY_CODE_PWR,APP_KEY_EVENT_DOUBLECLICK},"bt function key",app_factorymode_bt_xtalcalib, NULL},
{{APP_KEY_CODE_PWR,APP_KEY_EVENT_LONGPRESS},"bt function key",app_factorymode_bt_signalingtest, NULL},
};
uint8_t i = 0;
APP_FACTORY_TRACE(1,"%s",__func__);
app_key_handle_clear();
for (i=0; i<(sizeof(app_factorymode_handle_cfg)/sizeof(APP_KEY_HANDLE)); i++){
app_key_handle_registration(&app_factorymode_handle_cfg[i]);
}
}
static void app_factorymode_audioloopswitch(APP_KEY_STATUS *status, void *param)
{
static bool onaudioloop = false;
onaudioloop = onaudioloop?false:true;
if (onaudioloop)
app_audio_sendrequest(APP_FACTORYMODE_AUDIO_LOOP, (uint8_t)APP_BT_SETTING_OPEN, 0);
else
app_audio_sendrequest(APP_FACTORYMODE_AUDIO_LOOP, (uint8_t)APP_BT_SETTING_CLOSE, 0);
}
void app_factorymode_test_key_init(void)
{
const APP_KEY_HANDLE app_factorymode_handle_cfg[] = {
{{APP_KEY_CODE_PWR,APP_KEY_EVENT_CLICK},"bt function key",app_factorymode_audioloopswitch, NULL},
};
uint8_t i = 0;
APP_FACTORY_TRACE(1,"%s",__func__);
for (i=0; i<(sizeof(app_factorymode_handle_cfg)/sizeof(APP_KEY_HANDLE)); i++){
app_key_handle_registration(&app_factorymode_handle_cfg[i]);
}
}
void app_factorymode_result_clean(void)
{
osSignalClear(app_factorymode_tid, 0x01);
osSignalClear(app_factorymode_tid, 0x02);
}
void app_factorymode_result_set(bool result)
{
if (result)
osSignalSet(app_factorymode_tid ,0x01);
else
osSignalSet(app_factorymode_tid ,0x02);
}
bool app_factorymode_result_wait(void)
{
bool nRet;
osEvent evt;
while(1)
{
//wait any signal
evt = osSignalWait(0x0, osWaitForever);
//get role from signal value
if(evt.status == osEventSignal)
{
if(evt.value.signals & 0x01)
{
nRet = true;
break;
}
else if(evt.value.signals & 0x02)
{
nRet = false;
break;
}
}
}
return nRet;
}
static int app_factorymode_send_progress (uint8_t progress)
{
APP_MESSAGE_BLOCK msg;
msg.mod_id = APP_MODUAL_OHTER;
msg.msg_body.message_id = 2;
msg.msg_body.message_Param0 = progress;
app_mailbox_put(&msg);
return 0;
}
static int app_factorymode_send_code (uint32_t progress)
{
APP_MESSAGE_BLOCK msg;
msg.mod_id = APP_MODUAL_OHTER;
msg.msg_body.message_id = 3;
msg.msg_body.message_Param0 = progress;
app_mailbox_put(&msg);
return 0;
}
int app_factorymode_proc(void)
{
uint8_t cnt = 0;
bool nRet;
app_factorymode_tid = osThreadGetId();
app_factorymode_send_progress(60);
app_factorymode_bt_init_connect();
do{
app_factorymode_result_clean();
app_factorymode_bt_create_connect();
nRet = app_factorymode_result_wait();
}while(!nRet && ++cnt < APP_FACTORYMODE_RETRY_LIMITED);
if (!nRet)
goto exit;
app_factorymode_send_progress(90);
app_factorymode_result_clean();
if (!nRet)
goto exit;
app_factorymode_send_progress(100);
osDelay(100);
exit:
app_factorymode_result_clean();
if (nRet){
return 0;
}else{
return -1;
}
}
static unsigned char app_factorymode_msg_check_sum(unsigned char *buf, unsigned char len)
{
int i;
unsigned char sum = 0;
for (i = 0; i < len; i++) {
sum += buf[i];
}
return sum;
}
static int app_factorymode_msg_uart_send(const unsigned char *buf, size_t len)
{
uint32_t sent = 0;
while (sent < len) {
hal_uart_blocked_putc(HAL_UART_ID_0, buf[sent++]);
}
if (sent != len) {
return 1;
}
return 0;
}
static int app_factorymode_msg_send_ping(void)
{
int ret;
send_msg.hdr.type = 0x88;
send_msg.hdr.seq = send_seq++;
send_msg.hdr.len = 2;
send_msg.data[0] = 0xaa;
send_msg.data[1] = 0x55;
send_msg.data[2] = ~app_factorymode_msg_check_sum((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg) - 1);
ret = app_factorymode_msg_uart_send((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg));
return ret;
}
static int app_factorymode_msg_send_progress (uint8_t progress)
{
int ret;
send_msg.hdr.type = 0x88;
send_msg.hdr.seq = send_seq++;
send_msg.hdr.len = 2;
send_msg.data[0] = progress;
send_msg.data[1] = 100;
send_msg.data[2] = ~app_factorymode_msg_check_sum((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg) - 1);
ret = app_factorymode_msg_uart_send((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg));
return ret;
}
static int app_factorymode_msg_send_32bitcode(uint32_t code)
{
int ret;
send_msg.hdr.type = 0x88;
send_msg.hdr.seq = send_seq++;
send_msg.hdr.len = 4;
send_msg.data[0] = 0xf2;
*(uint32_t *)&(send_msg.data[1]) = code;
send_msg.data[4] = ~app_factorymode_msg_check_sum((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg) - 1);
ret = app_factorymode_msg_uart_send((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg));
return ret;
}
static int app_factorymode_process(APP_MESSAGE_BODY *msg_body)
{
if (msg_body->message_id == 1){
app_factorymode_msg_send_ping();
}
if (msg_body->message_id == 2){
app_factorymode_msg_send_progress(msg_body->message_Param0);
}
if (msg_body->message_id == 3){
app_factorymode_msg_send_32bitcode(msg_body->message_Param0);
}
return 0;
}
static int app_factorymode_uart_init(void)
{
struct HAL_UART_CFG_T uart_cfg;
memset(&uart_cfg, 0, sizeof(struct HAL_UART_CFG_T));
uart_cfg.parity = HAL_UART_PARITY_NONE,
uart_cfg.stop = HAL_UART_STOP_BITS_1,
uart_cfg.data = HAL_UART_DATA_BITS_8,
uart_cfg.flow = HAL_UART_FLOW_CONTROL_NONE,//HAL_UART_FLOW_CONTROL_RTSCTS,
uart_cfg.tx_level = HAL_UART_FIFO_LEVEL_1_2,
uart_cfg.rx_level = HAL_UART_FIFO_LEVEL_1_4,
uart_cfg.baud = 921600,
uart_cfg.dma_rx = false,
uart_cfg.dma_tx = false,
uart_cfg.dma_rx_stop_on_err = false;
hal_uart_close(HAL_UART_ID_0);
hal_uart_open(HAL_UART_ID_0, &uart_cfg);
return 0;
}
static void app_factorymode_timehandler(void const *param)
{
APP_MESSAGE_BLOCK msg;
msg.mod_id = APP_MODUAL_OHTER;
msg.msg_body.message_id = 1;
app_mailbox_put(&msg);
}
static uint8_t app_factorymode_indication_init(void)
{
struct APP_PWL_CFG_T cfg;
memset(&cfg, 0, sizeof(struct APP_PWL_CFG_T));
app_pwl_open();
app_pwl_setup(APP_PWL_ID_0, &cfg);
app_pwl_setup(APP_PWL_ID_1, &cfg);
return 0;
}
static uint8_t app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_T status)
{
struct APP_PWL_CFG_T cfg0;
struct APP_PWL_CFG_T cfg1;
APP_FACTORY_TRACE(2,"%s %d",__func__, status);
memset(&cfg0, 0, sizeof(struct APP_PWL_CFG_T));
memset(&cfg1, 0, sizeof(struct APP_PWL_CFG_T));
app_pwl_stop(APP_PWL_ID_0);
app_pwl_stop(APP_PWL_ID_1);
switch (status) {
case APP_FACTORYMODE_STATUS_INDICATION_RUNNING:
cfg0.part[0].level = 0;
cfg0.part[0].time = (300);
cfg0.part[1].level = 1;
cfg0.part[1].time = (300);
cfg0.parttotal = 2;
cfg0.startlevel = 0;
cfg0.periodic = true;
cfg1.part[0].level = 1;
cfg1.part[0].time = (300);
cfg1.part[1].level = 0;
cfg1.part[1].time = (300);
cfg1.parttotal = 2;
cfg1.startlevel = 1;
cfg1.periodic = true;
app_pwl_setup(APP_PWL_ID_0, &cfg0);
app_pwl_start(APP_PWL_ID_0);
app_pwl_setup(APP_PWL_ID_1, &cfg1);
app_pwl_start(APP_PWL_ID_1);
break;
case APP_FACTORYMODE_STATUS_INDICATION_PASS:
cfg0.part[0].level = 1;
cfg0.part[0].time = (5000);
cfg0.parttotal = 1;
cfg0.startlevel = 1;
cfg0.periodic = false;
app_pwl_setup(APP_PWL_ID_0, &cfg0);
app_pwl_start(APP_PWL_ID_0);
break;
case APP_FACTORYMODE_STATUS_INDICATION_FAILED:
cfg1.part[0].level = 1;
cfg1.part[0].time = (5000);
cfg1.parttotal = 1;
cfg1.startlevel = 1;
cfg1.periodic = false;
app_pwl_setup(APP_PWL_ID_1, &cfg1);
app_pwl_start(APP_PWL_ID_1);
break;
default:
break;
}
return 0;
}
int app_factorymode_init(uint32_t factorymode)
{
uint8_t cnt = 0;
int nRet = 0;
uint32_t capval = 0x00;
struct nvrecord_env_t *nvrecord_env;
APP_FACTORY_TRACE(1,"app_factorymode_init mode:%x\n", factorymode);
osThreadSetPriority(osThreadGetId(), osPriorityRealtime);
app_factorymode_uart_init();
#ifdef __WATCHER_DOG_RESET__
app_wdt_open(60);
#endif
app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_52M);
list_init();
app_os_init();
app_factorymode_indication_init();
app_battery_open();
if (app_key_open(false)){
nRet = -1;
goto exit;
}
app_set_threadhandle(APP_MODUAL_OHTER, app_factorymode_process);
app_factory_timer = osTimerCreate (osTimer(APP_FACTORY_TIMER), osTimerPeriodic, NULL);
osTimerStart(app_factory_timer, 300);
app_factorymode_send_progress(10);
app_bt_init();
af_open();
app_audio_open();
app_overlay_open();
nv_record_env_init();
nvrec_dev_data_open();
nv_record_env_get(&nvrecord_env);
#ifdef MEDIA_PLAYER_SUPPORT
app_play_audio_set_lang(nvrecord_env->media_language.language);
app_voice_report(APP_STATUS_INDICATION_POWERON, 0);
#endif
app_status_indication_set(APP_STATUS_INDICATION_POWERON);
app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_RUNNING);
if (factorymode&HAL_SW_BOOTMODE_CALIB){
btdrv_start_bt();
app_factorymode_send_progress(20);
do {
nRet = app_factorymode_bt_xtalcalib_proc();
}while(nRet && cnt++<APP_FACTORYMODE_RETRY_LIMITED);
if (nRet)
goto err;
osDelay(200);
app_factorymode_send_progress(30);
}
nvrec_dev_get_xtal_fcap((unsigned int*)&capval);
app_factorymode_send_code(capval);
btdrv_start_bt();
bt_drv_reg_op_key_gen_after_reset(false);
app_factorymode_send_progress(40);
BesbtInit();
osDelay(600);
nRet = app_factorymode_proc();
if (nRet)
goto err;
app_factorymode_test_key_init();
//osTimerStop(app_factory_timer);
app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_PASS);
//wait forever
osSignalWait(0x01, osWaitForever);
goto exit;
err:
osTimerStop(app_factory_timer);
app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_FAILED);
app_factorymode_send_code(0xff);
osSignalWait(0x01, osWaitForever);
exit:
app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_32K);
pmu_shutdown();
return nRet;
}
int app_factorymode_calib_only(void)
{
uint8_t cnt = 0;
int nRet = 0;
uint32_t capval = 0x00;
app_factorymode_uart_init();
#ifdef __WATCHER_DOG_RESET__
app_wdt_reopen(60);
#endif
app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_52M);
list_init();
app_os_init();
nv_record_env_init();
nvrec_dev_data_open();
factory_section_open();
app_factorymode_indication_init();
app_set_threadhandle(APP_MODUAL_OHTER, app_factorymode_process);
app_factory_timer = osTimerCreate(osTimer(APP_FACTORY_TIMER),osTimerPeriodic,NULL);
osTimerStart(app_factory_timer,300);
app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_RUNNING);
app_factorymode_send_progress(10);
btdrv_start_bt();
osDelay(20);
app_factorymode_send_progress(20);
do {
nRet = app_factorymode_bt_xtalcalib_proc();
}while(nRet && ++cnt < APP_FACTORYMODE_RETRY_LIMITED);
if(nRet)
goto err;
nvrec_dev_get_xtal_fcap((unsigned int*)&capval);
app_factorymode_send_code(capval);
app_factorymode_send_progress(50);
osDelay(200);
app_factorymode_send_progress(80);
osDelay(100);
app_factorymode_send_progress(100);
app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_PASS);
osSignalWait(0x01, osWaitForever);
goto exit;
err:
osTimerStop(app_factory_timer);
app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_FAILED);
app_factorymode_send_code(0xff);
osSignalWait(0x01, osWaitForever);
exit:
app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_32K);
pmu_shutdown();
return nRet;
}
#ifdef __USB_COMM__
// for usb
#include "usb_cdc.h"
#include "hal_timer.h"
#include "hwtimer_list.h"
#include "hal_usb.h"
#include "app_factory_cdc_comm.h"
#include "sys_api_cdc_comm.h"
static const struct USB_SERIAL_CFG_T cdc_cfg = {
.mode = USB_SERIAL_API_NONBLOCKING,
};
static void usb_serial_recv_timeout(void *param)
{
usb_serial_cancel_recv();
}
int app_factorymode_cdc_comm(void)
{
HWTIMER_ID timer;
pmu_usb_config(PMU_USB_CONFIG_TYPE_DEVICE);
usb_serial_open(&cdc_cfg);
osDelay(500);
hwtimer_init();
timer = hwtimer_alloc(usb_serial_recv_timeout, NULL);
ASSERT(timer, "Failed to alloc usb serial recv timer");
usb_serial_flush_recv_buffer();
usb_serial_init_xfer();
af_open();
comm_loop();
return 1;
}
#endif
#endif

View file

@ -0,0 +1,53 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __APP_FACTORY_H__
#define __APP_FACTORY_H__
#define APP_FACTORY_TRACE(s,...) TRACE(s, ##__VA_ARGS__)
void app_factorymode_result_set(bool result);
void app_factorymode_result_clean(void);
bool app_factorymode_result_wait(void);
void app_factorymode_enter(void);
void app_factorymode_key_init(void);
int app_factorymode_init(uint32_t factorymode);
int app_factorymode_calib_only(void);
int app_factorymode_languageswitch_proc(void);
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __USB_COMM__
int app_factorymode_cdc_comm(void);
#endif
bool app_factorymode_get(void);
void app_factorymode_set(bool set);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,293 @@
/***************************************************************************
*
* 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 "cmsis_os.h"
#include "hal_trace.h"
#include "resources.h"
#include "app_bt_stream.h"
#include "app_media_player.h"
#include "app_factory.h"
#include "string.h"
// for audio
#include "audioflinger.h"
#include "app_audio.h"
#include "app_utils.h"
#include "app_factory_audio.h"
#ifdef __FACTORY_MODE_SUPPORT__
#define BT_AUDIO_FACTORMODE_BUFF_SIZE (1024*2)
static enum APP_AUDIO_CACHE_T a2dp_cache_status = APP_AUDIO_CACHE_QTY;
static int16_t *app_audioloop_play_cache = NULL;
static uint32_t app_factorymode_data_come(uint8_t *buf, uint32_t len)
{
app_audio_pcmbuff_put(buf, len);
if (a2dp_cache_status == APP_AUDIO_CACHE_QTY){
a2dp_cache_status = APP_AUDIO_CACHE_OK;
}
return len;
}
static uint32_t app_factorymode_more_data(uint8_t *buf, uint32_t len)
{
if (a2dp_cache_status != APP_AUDIO_CACHE_QTY){
app_audio_pcmbuff_get((uint8_t *)app_audioloop_play_cache, len/2);
app_bt_stream_copy_track_one_to_two_16bits((int16_t *)buf, app_audioloop_play_cache, len/2/2);
}
return len;
}
int app_factorymode_audioloop(bool on, enum APP_SYSFREQ_FREQ_T freq)
{
uint8_t *buff_play = NULL;
uint8_t *buff_capture = NULL;
uint8_t *buff_loop = NULL;
struct AF_STREAM_CONFIG_T stream_cfg;
static bool isRun = false;
APP_FACTORY_TRACE(3,"app_factorymode_audioloop work:%d op:%d freq:%d", isRun, on, freq);
if (isRun==on)
return 0;
if (on){
if (freq < APP_SYSFREQ_52M) {
freq = APP_SYSFREQ_52M;
}
app_sysfreq_req(APP_SYSFREQ_USER_APP_0, freq);
a2dp_cache_status = APP_AUDIO_CACHE_QTY;
app_audio_mempool_init();
app_audio_mempool_get_buff(&buff_capture, BT_AUDIO_FACTORMODE_BUFF_SIZE);
app_audio_mempool_get_buff(&buff_play, BT_AUDIO_FACTORMODE_BUFF_SIZE*2);
app_audio_mempool_get_buff((uint8_t **)&app_audioloop_play_cache, BT_AUDIO_FACTORMODE_BUFF_SIZE*2/2/2);
app_audio_mempool_get_buff(&buff_loop, BT_AUDIO_FACTORMODE_BUFF_SIZE<<2);
app_audio_pcmbuff_init(buff_loop, BT_AUDIO_FACTORMODE_BUFF_SIZE<<2);
memset(&stream_cfg, 0, sizeof(stream_cfg));
stream_cfg.bits = AUD_BITS_16;
//stream_cfg.channel_num = AUD_CHANNEL_NUM_1;
#ifdef SPEECH_TX_AEC_CODEC_REF
stream_cfg.channel_num = AUD_CHANNEL_NUM_2;
#else
stream_cfg.channel_num = AUD_CHANNEL_NUM_1;
#endif
#if defined(__AUDIO_RESAMPLE__) && defined(SW_CAPTURE_RESAMPLE)
stream_cfg.sample_rate = AUD_SAMPRATE_8463;
#else
stream_cfg.sample_rate = AUD_SAMPRATE_8000;
#endif
#if FPGA==0
stream_cfg.device = AUD_STREAM_USE_INT_CODEC;
#else
stream_cfg.device = AUD_STREAM_USE_EXT_CODEC;
#endif
stream_cfg.vol = TGT_VOLUME_LEVEL_15;
stream_cfg.io_path = AUD_INPUT_PATH_MAINMIC;
stream_cfg.handler = app_factorymode_data_come;
stream_cfg.data_ptr = BT_AUDIO_CACHE_2_UNCACHE(buff_capture);
stream_cfg.data_size = BT_AUDIO_FACTORMODE_BUFF_SIZE;
af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE, &stream_cfg);
stream_cfg.channel_num = AUD_CHANNEL_NUM_2;
stream_cfg.io_path = AUD_OUTPUT_PATH_SPEAKER;
stream_cfg.handler = app_factorymode_more_data;
stream_cfg.data_ptr = BT_AUDIO_CACHE_2_UNCACHE(buff_play);
stream_cfg.data_size = BT_AUDIO_FACTORMODE_BUFF_SIZE*2;
af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg);
af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
APP_FACTORY_TRACE(0,"app_factorymode_audioloop on");
} else {
af_stream_stop(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
af_stream_stop(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
af_stream_close(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
af_stream_close(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
APP_FACTORY_TRACE(0,"app_factorymode_audioloop off");
app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_32K);
}
isRun=on;
return 0;
}
int app_factorymode_output_pcmpatten(audio_test_pcmpatten_t *pcmpatten, uint8_t *buf, uint32_t len)
{
uint32_t remain_size = len;
uint32_t curr_size = 0;
if (remain_size > pcmpatten->len)
{
do{
if (pcmpatten->cuur_buf_pos)
{
curr_size = pcmpatten->len-pcmpatten->cuur_buf_pos;
memcpy(buf,&(pcmpatten->buf[pcmpatten->cuur_buf_pos/2]), curr_size);
remain_size -= curr_size;
pcmpatten->cuur_buf_pos = 0;
}
else if (remain_size>pcmpatten->len)
{
memcpy(buf+curr_size, pcmpatten->buf, pcmpatten->len);
curr_size += pcmpatten->len;
remain_size -= pcmpatten->len;
}
else
{
memcpy(buf+curr_size,pcmpatten->buf, remain_size);
pcmpatten->cuur_buf_pos = remain_size;
remain_size = 0;
}
}while(remain_size);
}
else
{
if ((pcmpatten->len - pcmpatten->cuur_buf_pos) >= len)
{
memcpy(buf, &(pcmpatten->buf[pcmpatten->cuur_buf_pos/2]),len);
pcmpatten->cuur_buf_pos += len;
}
else
{
curr_size = pcmpatten->len-pcmpatten->cuur_buf_pos;
memcpy(buf, &(pcmpatten->buf[pcmpatten->cuur_buf_pos/2]),curr_size);
pcmpatten->cuur_buf_pos = len - curr_size;
memcpy(buf+curr_size, pcmpatten->buf, pcmpatten->cuur_buf_pos);
}
}
return 0;
}
#include "fft128dot.h"
#define N 64
#define NFFT 128
struct mic_st_t{
FftTwiddle_t w[N];
FftTwiddle_t w128[N*2];
FftData_t x[N*2];
FftData_t data_odd[N];
FftData_t data_even[N];
FftData_t data_odd_d[N];
FftData_t data_even_d[N];
FftData_t data[N*2];
signed long out[N];
};
int app_factorymode_mic_cancellation_run(void * mic_st, signed short *inbuf, int sample)
{
struct mic_st_t *st = (struct mic_st_t *)mic_st;
int i,k,jj,ii;
//int dataWidth = 16; // input word format is 16 bit twos complement fractional format 1.15
int twiddleWidth = 16; // input word format is 16 bit twos complement fractional format 2.14
FftMode_t ifft = FFT_MODE;
make_symmetric_twiddles(st->w,N,twiddleWidth);
make_symmetric_twiddles(st->w128,N*2,twiddleWidth);
// input data
for (i=0; i<sample; i++){
st->x[i].re = inbuf[i];
st->x[i].im = 0;
}
for(ii = 0; ii < 1; ii++)
{
k = 0;
for (jj = 0; jj < N*2; jj+=2)
{
FftData_t tmp;
tmp.re = st->x[jj].re;
tmp.im = st->x[jj].im;
st->data_even[k].re = tmp.re;//(int) (double(tmp.re)*double(1 << FFTR4_INPUT_FORMAT_Y)) ;
st->data_even[k].im = tmp.im;//(int) (double(tmp.im)*double(1 << FFTR4_INPUT_FORMAT_Y)) ;
tmp.re = st->x[jj+1].re;
tmp.im = st->x[jj+1].im;
st->data_odd[k].re = tmp.re;//(int) (double(tmp.re)*double(1 << FFTR4_INPUT_FORMAT_Y)) ;
st->data_odd[k].im = tmp.im;//(int) (double(tmp.im)*double(1 << FFTR4_INPUT_FORMAT_Y)) ;
k++;
}
fftr4(NFFT/2, st->data_even, st->w, FFTR4_TWIDDLE_WIDTH, FFTR4_DATA_WIDTH, ifft);
fftr4(NFFT/2, st->data_odd, st->w, FFTR4_TWIDDLE_WIDTH, FFTR4_DATA_WIDTH, ifft);
for (jj = 0; jj < NFFT/2; jj++)
{
int idx = dibit_reverse_int(jj, NFFT/2);
st->data_even_d[jj].re = st->data_even[idx].re;
st->data_even_d[jj].im = st->data_even[idx].im;
st->data_odd_d[jj].re = st->data_odd[idx].re;
st->data_odd_d[jj].im = st->data_odd[idx].im;
}
for (jj=0;jj<NFFT/2;jj++)
{
long long mbr,mbi;
FftData_t ta;
FftData_t tmp;
double a;
mbr = (long long)(st->data_odd_d[jj].re) * st->w128[jj].re - (long long)(st->data_odd_d[jj].im) * st->w128[jj].im;
mbi = (long long)(st->data_odd_d[jj].im) * st->w128[jj].re + (long long)(st->data_odd_d[jj].re) * st->w128[jj].im;
ta.re = int(mbr>>(FFTR4_TWIDDLE_WIDTH-2));
ta.im = int(mbi>>(FFTR4_TWIDDLE_WIDTH-2));
st->data[jj].re = (st->data_even_d[jj].re + ta.re)/2;
st->data[jj].im = (st->data_even_d[jj].im + ta.im)/2;
//data[jj] = sat(data[jj],FFTR4_DATA_WIDTH);
st->data[jj+NFFT/2].re = (st->data_even_d[jj].re - ta.re)/2;
st->data[jj+NFFT/2].im = (st->data_even_d[jj].im - ta.im)/2;
//data[jj+NFFT/2] = sat(data[jj+NFFT/2],FFTR4_DATA_WIDTH);
a = st->data[jj].re;///double(1 << FFTR4_OUTPUT_FORMAT_Y);// * double(1 << FFTR4_SCALE);
tmp.re = (int)a;
a = st->data[jj].im;///double(1 << FFTR4_OUTPUT_FORMAT_Y);// * double(1 << FFTR4_SCALE);
tmp.im = (int)a;
st->x[ii*NFFT+jj].re = (int) tmp.re;
st->x[ii*NFFT+jj].im = (int) tmp.im;
a = st->data[jj+NFFT/2].re;///double(1 << FFTR4_OUTPUT_FORMAT_Y);// * double(1 << FFTR4_SCALE);
tmp.re = (int)a;
a = st->data[jj+NFFT/2].im;///double(1 << FFTR4_OUTPUT_FORMAT_Y);// * double(1 << FFTR4_SCALE);
tmp.im = (int)a;
st->x[ii*NFFT+jj+NFFT/2].re = (int) tmp.re;
st->x[ii*NFFT+jj+NFFT/2].im = (int) tmp.im;
}
}
for (i=0; i<N; i++){
st->out[i] = st->x[i].re * st->x[i].re + st->x[i].im * st->x[i].im;
}
return 0;
}
void *app_factorymode_mic_cancellation_init(void* (* alloc_ext)(int))
{
struct mic_st_t *mic_st;
mic_st = (struct mic_st_t *)alloc_ext(sizeof(struct mic_st_t));
return (void *)mic_st;
}
#endif

View file

@ -0,0 +1,35 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __APP_FACTORY_BT_H__
#define __APP_FACTORY__BTH__
#include "app_utils.h"
typedef struct {
uint16_t *buf;
uint32_t len;
uint32_t cuur_buf_pos;
}audio_test_pcmpatten_t;
int app_factorymode_audioloop(bool on, enum APP_SYSFREQ_FREQ_T freq);
int app_factorymode_output_pcmpatten(audio_test_pcmpatten_t *pcmpatten, uint8_t *buf, uint32_t len);
int app_factorymode_mic_cancellation_run(void * mic_st, signed short *inbuf, int sample);
void *app_factorymode_mic_cancellation_init(void* (* alloc_ext)(int));
#endif

View file

@ -0,0 +1,331 @@
/***************************************************************************
*
* 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 "cmsis_os.h"
#include "hal_trace.h"
#include "hal_sleep.h"
#include "bt_drv_interface.h"
#include "intersyshci.h"
#include "apps.h"
#include "app_factory.h"
#include "app_factory_bt.h"
#include "app_utils.h"
#include "bluetooth.h"
#include "nvrecord.h"
#include "nvrecord_dev.h"
#include "pmu.h"
#include "tgt_hardware.h"
#include "app_battery.h"
#include "bt_drv_reg_op.h"
#include "conmgr_api.h"
#include "me_api.h"
#include "hal_bootmode.h"
#include "hal_chipid.h"
#define APP_FACT_CPU_WAKE_LOCK HAL_CPU_WAKE_LOCK_USER_3
#ifdef __FACTORY_MODE_SUPPORT__
static uint8_t inquiry_buff[] = {0x01, 0x72, 0x77, 0xb0, 0x18, 0x57, 0x60,\
0x01, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00};
static btif_cmgr_handler_t *app_factorymode_cmgrHandler;
static void bt_error_check_timer_handler(void const *param);
osTimerDef(bt_error_check_timer, bt_error_check_timer_handler);
static osTimerId bt_error_check_timer_id = NULL;
uint8_t test_mode_type=0;
static void bt_error_check_timer_handler(void const *param)
{
//dump rssi
bt_drv_rssi_dump_handler();
//check BT core status
if(bt_drv_error_check_handler())
{
if(test_mode_type==1)
{
hal_sw_bootmode_set(HAL_SW_BOOTMODE_TEST_MODE|HAL_SW_BOOTMODE_TEST_SIGNALINGMODE);
}
else if(test_mode_type==2)
{
hal_sw_bootmode_set(HAL_SW_BOOTMODE_TEST_MODE|HAL_SW_BOOTMODE_TEST_NOSIGNALINGMODE);
}
hal_cmu_sys_reboot();
}
}
static void app_factorymode_bt_inquiry_buff_update(void)
{
bt_bdaddr_t flsh_dongle_addr;
int ret = -1;
ret = nvrec_dev_get_dongleaddr(&flsh_dongle_addr);
if(0 == ret) {
memcpy((void *)&inquiry_buff[1],(void *)flsh_dongle_addr.address,BTIF_BD_ADDR_SIZE);
DUMP8("0x%02x ", &inquiry_buff[2], BTIF_BD_ADDR_SIZE);
}
}
static void app_factorymode_CmgrCallback(btif_cmgr_handler_t *cHandler,
cmgr_event_t Event,
bt_status_t Status)
{
APP_FACTORY_TRACE(4,"%s cHandler:%p Event:%d status:%d", __func__, cHandler, Event, Status);
if (Event == BTIF_CMEVENT_DATA_LINK_CON_CNF){
if (Status == BT_STS_SUCCESS){
APP_FACTORY_TRACE(0,"connect ok");
app_factorymode_result_set(true);
btif_cmgr_remove_data_link(cHandler);
}else{
APP_FACTORY_TRACE(0,"connect failed");
app_factorymode_result_set(false);
}
}
if (Event == BTIF_CMEVENT_DATA_LINK_DIS){
if (Status == BT_STS_SUCCESS){
APP_FACTORY_TRACE(0,"disconnect ok");
}else{
APP_FACTORY_TRACE(0,"disconnect failed");
}
}
}
static void app_factorymode_bt_InquiryResult_add(void)
{
U8 len = 15;
bool rssi = false, extended = false;
U8* parm = (U8*)inquiry_buff;
/* Found one or more devices. Report to clients */
APP_FACTORY_TRACE(4,"%s len:%d rssi:%d extended:%d", __func__, len, rssi, extended);
DUMP8("0x%02x ", parm, len);
btif_me_inquiry_result_setup(parm, rssi, extended);
}
void app_factorymode_bt_create_connect(void)
{
bt_status_t status;
bt_bdaddr_t *bdAddr = (bt_bdaddr_t *)(inquiry_buff+1);
status = btif_cmgr_create_data_link(app_factorymode_cmgrHandler, bdAddr);
APP_FACTORY_TRACE(2,"%s:%d", __func__, status);
}
void app_factorymode_bt_init_connect(void)
{
app_factorymode_cmgrHandler = btif_cmgr_handler_create();
btif_cmgr_register_handler(app_factorymode_cmgrHandler,
app_factorymode_CmgrCallback);
app_factorymode_bt_inquiry_buff_update();
app_factorymode_bt_InquiryResult_add();
}
extern osTimerId app_bt_accessmode_timer;
#if defined(CHIP_BEST1400) || defined(CHIP_BEST1402)
#define XTAL_FCAP_RANGE (0x1FF)
#else
#define XTAL_FCAP_RANGE (0xFF)
#endif
void app_factorymode_bt_xtalrangetest(APP_KEY_STATUS *status, void *param)
{
dev_addr_name devinfo;
uint32_t fcap = 0;
APP_FACTORY_TRACE(1,"%s",__func__);
#ifdef __WATCHER_DOG_RESET__
app_wdt_close();
#endif
hal_cpu_wake_lock(APP_FACT_CPU_WAKE_LOCK);
app_stop_10_second_timer(APP_PAIR_TIMER_ID);
app_stop_10_second_timer(APP_POWEROFF_TIMER_ID);
if (app_bt_accessmode_timer){
osTimerStop(app_bt_accessmode_timer);
}
if (!bt_error_check_timer_id){
bt_error_check_timer_id = osTimerCreate(osTimer(bt_error_check_timer), osTimerPeriodic, NULL);
}
if (bt_error_check_timer_id != NULL) {
osTimerStart(bt_error_check_timer_id, 1000);
}
test_mode_type = 1;
app_status_indication_set(APP_STATUS_INDICATION_TESTMODE);
pmu_sleep_en(0);
BESHCI_Close();
btdrv_hciopen();
btdrv_hci_reset();
#ifndef BT_50_FUNCTION
btdrv_sleep_config(0);
osDelay(2000);
btdrv_ins_patch_test_init();
btdrv_feature_default();
#endif
devinfo.btd_addr = bt_addr;
devinfo.ble_addr = ble_addr;
devinfo.localname = BT_LOCAL_NAME;
nvrec_dev_localname_addr_init(&devinfo);
btdrv_write_localinfo((char *)devinfo.localname, strlen(devinfo.localname) + 1, devinfo.btd_addr);
btdrv_vco_test_start(78);
while(1){
btdrv_rf_set_xtal_fcap(fcap%XTAL_FCAP_RANGE, 1);
osDelay(300);
TRACE(2,"xtal tune:%d", fcap%XTAL_FCAP_RANGE);
fcap++;
}
}
void app_factorymode_bt_signalingtest(APP_KEY_STATUS *status, void *param)
{
dev_addr_name devinfo;
APP_FACTORY_TRACE(1,"%s",__func__);
#ifdef __WATCHER_DOG_RESET__
app_wdt_close();
#endif
hal_cpu_wake_lock(APP_FACT_CPU_WAKE_LOCK);
app_stop_10_second_timer(APP_PAIR_TIMER_ID);
app_stop_10_second_timer(APP_POWEROFF_TIMER_ID);
if (app_bt_accessmode_timer){
osTimerStop(app_bt_accessmode_timer);
}
if (!bt_error_check_timer_id){
bt_error_check_timer_id = osTimerCreate(osTimer(bt_error_check_timer), osTimerPeriodic, NULL);
}
if (bt_error_check_timer_id != NULL) {
osTimerStart(bt_error_check_timer_id, 1000);
}
test_mode_type = 1;
app_status_indication_set(APP_STATUS_INDICATION_TESTMODE);
pmu_sleep_en(0);
BESHCI_Close();
btdrv_hciopen();
btdrv_ins_patch_test_init();
btdrv_hci_reset();
#ifndef BT_50_FUNCTION
btdrv_sleep_config(0);
osDelay(2000);
btdrv_testmode_start();
btdrv_feature_default();
#endif
devinfo.btd_addr = bt_addr;
devinfo.ble_addr = ble_addr;
devinfo.localname = BT_LOCAL_NAME;
devinfo.ble_name= BT_LOCAL_NAME;
nvrec_dev_localname_addr_init(&devinfo);
#ifdef __IBRT_IBRT_TESTMODE__
uint8_t ibrt_address[6] = {0x11,0x22,0x33,0x44,0x55,0x66};
memcpy(bt_addr,ibrt_address,6);
memcpy(devinfo.btd_addr,ibrt_address,6);
#endif
btdrv_write_localinfo((char *)devinfo.localname, strlen(devinfo.localname) + 1, devinfo.btd_addr);
bt_drv_extra_config_after_init();
btdrv_enable_dut();
#ifdef __IBRT_IBRT_TESTMODE__
btdrv_enable_ibrt_test();
#endif
}
int app_battery_stop(void);
void app_factorymode_bt_nosignalingtest(APP_KEY_STATUS *status, void *param)
{
dev_addr_name devinfo;
APP_FACTORY_TRACE(1,"%s",__func__);
#ifdef __WATCHER_DOG_RESET__
app_wdt_close();
#endif
hal_cpu_wake_lock(APP_FACT_CPU_WAKE_LOCK);
app_stop_10_second_timer(APP_PAIR_TIMER_ID);
app_stop_10_second_timer(APP_POWEROFF_TIMER_ID);
app_status_indication_set(APP_STATUS_INDICATION_TESTMODE1);
osTimerStop(app_bt_accessmode_timer);
if (!bt_error_check_timer_id){
bt_error_check_timer_id = osTimerCreate(osTimer(bt_error_check_timer), osTimerPeriodic, NULL);
}
if (bt_error_check_timer_id != NULL) {
osTimerStart(bt_error_check_timer_id, 1000);
}
test_mode_type = 2;
app_battery_stop();
pmu_sleep_en(0);
BESHCI_Close();
btdrv_hciopen();
btdrv_ins_patch_test_init();
bt_drv_reg_op_key_gen_after_reset(false);
btdrv_hci_reset();
#ifndef BT_50_FUNCTION
btdrv_sleep_config(0);
#endif
osDelay(2000);
btdrv_testmode_start();
#ifndef BT_50_FUNCTION
btdrv_feature_default();
devinfo.btd_addr = bt_addr;
devinfo.ble_addr = ble_addr;
devinfo.localname = BT_LOCAL_NAME;
devinfo.ble_name= BT_LOCAL_NAME;
nvrec_dev_localname_addr_init(&devinfo);
btdrv_write_localinfo((char *)devinfo.localname, strlen(devinfo.localname) + 1, devinfo.btd_addr);
#endif
bt_drv_extra_config_after_init();
btdrv_hcioff();
#ifdef __BT_DEBUG_TPORTS__
{
extern void bt_enable_tports(void);
bt_enable_tports();
//hal_iomux_tportopen();
}
#endif
btdrv_uart_bridge_loop();
}
int app_factorymode_bt_xtalcalib_proc(void)
{
uint32_t capval = 0x80;
int nRet;
APP_FACTORY_TRACE(1,"%s",__func__);
hal_cpu_wake_lock(APP_FACT_CPU_WAKE_LOCK);
APP_FACTORY_TRACE(1,"calib default, capval:%d", capval);
btdrv_hciopen();
btdrv_hci_reset();
#ifndef BT_50_FUNCTION
btdrv_ins_patch_test_init();
#endif
btdrv_hcioff();
capval = 0x80;
bt_drv_calib_open();
nRet = bt_drv_calib_result_porc(&capval);
bt_drv_calib_close();
TRACE(2,"!!!!!!!!!!!!!!!!!!!!!!!!!!!calib ret:%d, capval:%d", nRet, capval);
if (!nRet)
nvrec_dev_set_xtal_fcap((unsigned int)capval);
return nRet;
}
void app_factorymode_bt_xtalcalib(APP_KEY_STATUS *status, void *param)
{
APP_FACTORY_TRACE(1,"%s",__func__);
app_factorymode_bt_xtalcalib_proc();
}
#endif

View file

@ -0,0 +1,36 @@
/***************************************************************************
*
* 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.
*
****************************************************************************/
#ifndef __APP_FACTORY_BT_H__
#define __APP_FACTORY__BTH__
#include "app_key.h"
void app_factorymode_bt_create_connect(void);
void app_factorymode_bt_init_connect(void);
int app_factorymode_bt_xtalcalib_proc(void);
void app_factorymode_bt_xtalrangetest(APP_KEY_STATUS *status, void *param);
void app_factorymode_bt_signalingtest(APP_KEY_STATUS *status, void *param);
void app_factorymode_bt_nosignalingtest(APP_KEY_STATUS *status, void *param);
void app_factorymode_bt_xtalcalib(APP_KEY_STATUS *status, void *param);
#endif

View file

@ -0,0 +1,314 @@
#ifdef __USB_COMM__
#include "stdint.h"
#include "stdbool.h"
#include "plat_types.h"
#include "string.h"
#include "stdio.h"
#include "tool_msg.h"
#include "sys_api_cdc_comm.h"
#include "app_factory_cdc_comm.h"
static enum PARSE_STATE parse_state;
static struct message_t recv_msg;
static struct message_t send_msg = { { PREFIX_CHAR, }, };
static unsigned char check_sum(unsigned char *buf, unsigned char len)
{
int i;
unsigned char sum = 0;
for (i = 0; i < len; i++) {
sum += buf[i];
}
return sum;
}
int send_reply(const unsigned char *payload, unsigned int len)
{
int ret = 0;
if (len + 1 > sizeof(send_msg.data)) {
TRACE(1,"Packet length too long: %u", len);
return -1;
}
send_msg.hdr.type = recv_msg.hdr.type;
send_msg.hdr.seq = recv_msg.hdr.seq;
send_msg.hdr.len = len;
memcpy(&send_msg.data[0], payload, len);
send_msg.data[len] = ~check_sum((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg) - 1);
ret = send_data((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg));
return ret;
}
static void reset_parse_state(unsigned char **buf, size_t *len)
{
parse_state = PARSE_HEADER;
memset(&recv_msg.hdr, 0, sizeof(recv_msg.hdr));
*buf = (unsigned char *)&recv_msg.hdr;
*len = sizeof(recv_msg.hdr);
}
static enum ERR_CODE check_msg_hdr(void)
{
enum ERR_CODE errcode = ERR_NONE;
switch (recv_msg.hdr.type) {
case TYPE_SYS:
if (recv_msg.hdr.len != 1 && recv_msg.hdr.len != 5) {
//TRACE(1,"SYS msg length error: %u", recv_msg.hdr.len);
errcode = ERR_LEN;
}
break;
case TYPE_READ:
if (recv_msg.hdr.len != 4) {
//TRACE(1,"READ msg length error: %u", recv_msg.hdr.len);
errcode = ERR_LEN;
}
break;
case TYPE_WRITE:
if (recv_msg.hdr.len <= 4 || recv_msg.hdr.len > 20) {
//TRACE(1,"WRITE msg length error: %u", recv_msg.hdr.len);
errcode = ERR_LEN;
}
break;
default:
break;
}
if (errcode == ERR_NONE && recv_msg.hdr.len + 1 > sizeof(recv_msg.data)) {
errcode = ERR_LEN;
}
return errcode;
}
static enum ERR_CODE handle_sys_cmd(enum SYS_CMD_TYPE cmd, unsigned char *param, unsigned int len)
{
unsigned char cret[5];
unsigned int bootmode;
cret[0] = ERR_NONE;
if (cmd == SYS_CMD_SET_BOOTMODE || cmd == SYS_CMD_CLR_BOOTMODE) {
if (len != 4) {
TRACE(2,"Invalid SYS CMD len %u for cmd: 0x%x", len, cmd);
return ERR_DATA_LEN;
}
} else {
if (len != 0) {
TRACE(2,"Invalid SYS CMD len %u for cmd: 0x%x", len, cmd);
return ERR_DATA_LEN;
}
}
switch (cmd) {
case SYS_CMD_REBOOT: {
TRACE(0,"--- Reboot---");
send_reply(cret, 1);
system_reboot();
break;
}
case SYS_CMD_SHUTDOWN: {
TRACE(0,"--- Shutdown ---");
send_reply(cret, 1);
system_shutdown();
break;
}
case SYS_CMD_SET_BOOTMODE: {
TRACE(0,"--- Set bootmode ---");
memcpy(&bootmode, param, 4);
system_set_bootmode(bootmode);
send_reply(cret, 1);
break;
}
case SYS_CMD_CLR_BOOTMODE: {
TRACE(0,"--- Clear bootmode ---");
memcpy(&bootmode, param, 4);
system_clear_bootmode(bootmode);
send_reply(cret, 1);
break;
}
case SYS_CMD_GET_BOOTMODE: {
TRACE(0,"--- Get bootmode ---");
bootmode = system_get_bootmode();
memcpy(&cret[1], &bootmode, 4);
send_reply(cret, 5);
break;
}
default: {
TRACE(1,"Invalid command: 0x%x", recv_msg.data[0]);
return ERR_SYS_CMD;
}
}
return ERR_NONE;
}
static enum ERR_CODE handle_data(unsigned char **buf, size_t *len, int *extra)
{
enum ERR_CODE errcode = ERR_NONE;
#if 0
uint32_t rlen = 0;
#endif
*extra = 0;
// Checksum
if (check_sum((unsigned char *)&recv_msg, MSG_TOTAL_LEN(&recv_msg)) != 0xFF) {
TRACE(0,"Checksum error");
return ERR_CHECKSUM;
}
switch (recv_msg.hdr.type) {
case TYPE_SYS: {
TRACE_TIME(0,"------ SYS CMD ------");
errcode = handle_sys_cmd((enum SYS_CMD_TYPE)recv_msg.data[0], &recv_msg.data[1], recv_msg.hdr.len - 1);
if (errcode != ERR_NONE) {
return errcode;
}
break;
}
case TYPE_READ: {
TRACE_TIME(0,"------ READ CMD ------");
#if 0
uint32_t addr = (recv_msg.data[0] << 16) | (recv_msg.data[1] << 8) | recv_msg.data[2];
uint8_t data[4] = {0};
rlen = read_reg(addr, data);
if(rlen == 0)
return ERR_LEN;
else {
send_reply(data, rlen);
}
#endif
break;
}
case TYPE_WRITE: {
TRACE_TIME(0,"------ WRITE CMD ------");
#if 0
uint32_t addr = (recv_msg.data[0] << 16) | (recv_msg.data[1] << 8) | recv_msg.data[2];
uint32_t wdata = (recv_msg.data[3] << 24) | (recv_msg.data[4] << 16) | (recv_msg.data[5] << 8) | recv_msg.data[6];
uint8_t data[1] = {0};
errcode = write_reg(addr, wdata);
if (errcode != ERR_NONE)
return errcode;
else
send_reply(data, 1);
#endif
break;
}
default:
break;
}
return ERR_NONE;
}
static int parse_packet(unsigned char **buf, size_t *len)
{
enum ERR_CODE errcode;
int rlen = *len;
unsigned char *data;
int i;
int extra;
unsigned char cret;
switch (parse_state) {
case PARSE_HEADER:
ASSERT(rlen > 0 && rlen <= sizeof(recv_msg.hdr), "Invalid rlen!");
if (recv_msg.hdr.prefix == PREFIX_CHAR) {
errcode = check_msg_hdr();
if (errcode != ERR_NONE) {
goto _err;
}
parse_state = PARSE_DATA;
*buf = &recv_msg.data[0];
*len = recv_msg.hdr.len + 1;
} else {
data = (unsigned char *)&recv_msg.hdr.prefix;
for (i = 1; i < rlen; i++) {
if (data[i] == PREFIX_CHAR) {
memmove(&recv_msg.hdr.prefix, &data[i], rlen - i);
break;
}
}
*buf = &data[rlen - i];
*len = sizeof(recv_msg.hdr) + i - rlen;
}
break;
case PARSE_DATA:
errcode = handle_data(buf, len, &extra);
if (errcode != ERR_NONE) {
goto _err;
}
// Receive next message
reset_parse_state(buf, len);
break;
default:
TRACE(1,"Invalid parse_state: %d", parse_state);
break;
}
return 0;
_err:
cancel_input();
cret = (unsigned char)errcode;
send_reply(&cret, 1);
return 1;
}
void comm_loop(void)
{
int ret;
unsigned char *buf = NULL;
size_t len = 0;
size_t buf_len, rlen;
_sync:
reset_transport();
reset_parse_state(&buf, &len);
while (1) {
rlen = 0;
if (parse_state == PARSE_HEADER) {
set_recv_timeout(default_recv_timeout_idle);
} else {
set_recv_timeout(default_recv_timeout_short);
}
buf_len = 0;
ret = recv_data_ex(buf, buf_len, len, &rlen);
if (ret) {
TRACE(1,"Receiving data failed: %d", ret);
goto _err;
}
if (len != rlen) {
TRACE(2,"Receiving part of the data: expect=%u real=%u", len, rlen);
goto _err;
}
ret = parse_packet(&buf, &len);
if (ret) {
TRACE(0,"Parsing packet failed");
goto _err;
}
}
_err:
ret = handle_error();
if (ret == 0) {
TRACE(0,"retry ...");
goto _sync;
}
return;
}
#endif

View file

@ -0,0 +1,17 @@
#ifndef __APP_FACTORY_CDC_COMM__H__
#define __APP_FACTORY_CDC_COMM__H__
#ifdef __USB_COMM__
#ifdef __cplusplus
extern "C" {
#endif
void comm_loop(void);
int send_reply(const unsigned char *payload, unsigned int len);
#ifdef __cplusplus
}
#endif
#endif
#endif

View file

@ -0,0 +1,229 @@
#ifdef __USB_COMM__
#include "sys_api_cdc_comm.h"
#include "app_factory_cdc_comm.h"
#include "hal_bootmode.h"
#include "hwtimer_list.h"
#include "pmu.h"
#ifdef CHIP_HAS_USB
#include "usb_cdc.h"
#endif
#define TIMEOUT_INFINITE ((uint32_t)-1)
const unsigned int default_recv_timeout_short = MS_TO_TICKS(500);
const unsigned int default_recv_timeout_idle = TIMEOUT_INFINITE; //MS_TO_TICKS(10 * 60 * 1000);
const unsigned int default_recv_timeout_4k_data = MS_TO_TICKS(500);
const unsigned int default_send_timeout = MS_TO_TICKS(500);
static uint32_t send_timeout;
static uint32_t recv_timeout;
static volatile bool cancel_xfer = false;
static uint32_t xfer_err_time = 0;
static uint32_t xfer_err_cnt = 0;
static HWTIMER_ID xfer_timer;
static const struct USB_SERIAL_CFG_T cdc_cfg = {
.mode = USB_SERIAL_API_NONBLOCKING,
};
void reset_transport(void)
{
cancel_xfer = false;
if (xfer_timer) {
hwtimer_stop(xfer_timer);
} else {
xfer_timer = hwtimer_alloc(NULL, NULL);
}
usb_serial_flush_recv_buffer();
usb_serial_init_xfer();
set_recv_timeout(default_recv_timeout_short);
set_send_timeout(default_send_timeout);
}
void set_recv_timeout(unsigned int timeout)
{
recv_timeout = timeout;
}
void set_send_timeout(unsigned int timeout)
{
send_timeout = timeout;
}
static void usb_send_timeout(void *param)
{
usb_serial_cancel_send();
}
static void usb_send_timer_start(void)
{
if (send_timeout == TIMEOUT_INFINITE) {
return;
}
if (xfer_timer) {
hwtimer_update_then_start(xfer_timer, usb_send_timeout, NULL, send_timeout);
}
}
static void usb_send_timer_stop(void)
{
if (xfer_timer) {
hwtimer_stop(xfer_timer);
}
}
static int usb_send_data(const unsigned char *buf, size_t len)
{
int ret;
usb_send_timer_start();
ret = usb_serial_send(buf, len);
usb_send_timer_stop();
return ret;
}
int send_data(const unsigned char *buf, size_t len)
{
if (cancel_xfer) {
return -1;
}
return usb_send_data(buf, len);
}
static void usb_recv_timeout(void *param)
{
usb_serial_cancel_recv();
}
static void usb_recv_timer_start(void)
{
if (recv_timeout == TIMEOUT_INFINITE) {
return;
}
if (xfer_timer) {
hwtimer_update_then_start(xfer_timer, usb_recv_timeout, NULL, recv_timeout);
}
}
static void usb_recv_timer_stop(void)
{
if (xfer_timer) {
hwtimer_stop(xfer_timer);
}
}
static int usb_recv_data(unsigned char *buf, size_t len, size_t *rlen)
{
int ret;
usb_recv_timer_start();
ret = usb_serial_recv(buf, len);
usb_recv_timer_stop();
if (ret == 0) {
*rlen = len;
}
return ret;
}
int recv_data_ex(unsigned char *buf, size_t len, size_t expect, size_t *rlen)
{
if (cancel_xfer) {
return -1;
}
return usb_recv_data(buf, expect, rlen);
}
static int usb_handle_error(void)
{
int ret;
TRACE(0,"****** Send break ******");
// Send break signal, to tell the peer to reset the connection
ret = usb_serial_send_break();
if (ret) {
TRACE(1,"Sending break failed: %d", ret);
}
return ret;
}
int handle_error(void)
{
int ret = 0;
uint32_t err_time;
hal_sys_timer_delay(MS_TO_TICKS(50));
if (!cancel_xfer) {
ret = usb_handle_error();
}
err_time = hal_sys_timer_get();
if (xfer_err_cnt == 0 || err_time - xfer_err_time > MS_TO_TICKS(5000)) {
xfer_err_cnt = 0;
xfer_err_time = err_time;
}
xfer_err_cnt++;
if (xfer_err_cnt < 3) {
hal_sys_timer_delay(MS_TO_TICKS(100));
} else if (xfer_err_cnt < 5) {
hal_sys_timer_delay(MS_TO_TICKS(500));
} else {
hal_sys_timer_delay(MS_TO_TICKS(2000));
}
return ret;
}
static int usb_cancel_input(void)
{
return usb_serial_flush_recv_buffer();
}
int cancel_input(void)
{
return usb_cancel_input();
}
void system_reboot(void)
{
hal_sys_timer_delay(MS_TO_TICKS(10));
hal_cmu_sys_reboot();
}
void system_shutdown(void)
{
#if 0
if (dld_transport == TRANSPORT_USB) {
// Avoid PC usb serial driver hanging
usb_serial_close();
}
#endif
hal_sys_timer_delay(MS_TO_TICKS(10));
pmu_shutdown();
}
void system_set_bootmode(unsigned int bootmode)
{
bootmode &= ~(HAL_SW_BOOTMODE_READ_ENABLED | HAL_SW_BOOTMODE_WRITE_ENABLED);
hal_sw_bootmode_set(bootmode);
}
void system_clear_bootmode(unsigned int bootmode)
{
bootmode &= ~(HAL_SW_BOOTMODE_READ_ENABLED | HAL_SW_BOOTMODE_WRITE_ENABLED);
hal_sw_bootmode_clear(bootmode);
}
unsigned int system_get_bootmode(void)
{
return hal_sw_bootmode_get();
}
#endif

View file

@ -0,0 +1,41 @@
#ifndef __SYS_API_USB_CDC_H__
#define __SYS_API_USB_CDC_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "tool_msg.h"
#include "hal_trace.h"
#include "hal_timer.h"
#define TRACE_TIME(num,str, ...) TRACE(num+1,"[%05u] " str, TICKS_TO_MS(hal_sys_timer_get()), ##__VA_ARGS__)
extern const unsigned int default_recv_timeout_short;
extern const unsigned int default_recv_timeout_idle;
extern const unsigned int default_recv_timeout_4k_data;
extern const unsigned int default_send_timeout;
void reset_transport(void);
void set_recv_timeout(unsigned int timeout);
void set_send_timeout(unsigned int timeout);
int send_data(const unsigned char *buf, size_t len);
int recv_data_ex(unsigned char *buf, size_t len, size_t expect, size_t *rlen);
int handle_error(void);
int cancel_input(void);
void system_reboot(void);
void system_shutdown(void);
void system_flash_boot(void);
void system_set_bootmode(unsigned int bootmode);
void system_clear_bootmode(unsigned int bootmode);
unsigned int system_get_bootmode(void);
#ifdef __cplusplus
}
#endif
#endif

8
apps/key/Makefile Normal file
View file

@ -0,0 +1,8 @@
cur_dir := $(dir $(lastword $(MAKEFILE_LIST)))
obj-y := $(patsubst $(cur_dir)%,%,$(wildcard $(cur_dir)*.c $(cur_dir)*.cpp $(cur_dir)*.S))
obj-y := $(obj-y:.c=.o)
obj-y := $(obj-y:.cpp=.o)
obj-y := $(obj-y:.S=.o)
subdir-ccflags-y += -Iutils/list

Some files were not shown because too many files have changed in this diff Show more