287 lines
9.8 KiB
C++
287 lines
9.8 KiB
C++
/***************************************************************************
|
|
*
|
|
* Copyright 2015-2019 BES.
|
|
* All rights reserved. All unpublished rights reserved.
|
|
*
|
|
* No part of this work may be used or reproduced in any form or by any
|
|
* means, or stored in a database or retrieval system, without prior written
|
|
* permission of BES.
|
|
*
|
|
* Use of this work is governed by a license granted by BES.
|
|
* This work contains confidential and proprietary information of
|
|
* BES. which is protected by copyright, trade secret,
|
|
* trademark and other intellectual property rights.
|
|
*
|
|
****************************************************************************/
|
|
#include "app_bt_stream.h"
|
|
#include "app_factory.h"
|
|
#include "app_media_player.h"
|
|
#include "cmsis_os.h"
|
|
#include "hal_trace.h"
|
|
#include "resources.h"
|
|
#include "string.h"
|
|
|
|
// for audio
|
|
#include "app_audio.h"
|
|
#include "app_utils.h"
|
|
#include "audioflinger.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) {
|
|
DUMP16("%d,", (int *)buf, 30);
|
|
|
|
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
|
|
stream_cfg.device = AUD_STREAM_USE_INT_CODEC;
|
|
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
|