/*************************************************************************** * * 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) { 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 #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; ix[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;jjdata_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; iout[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