经过仔细阅读algorithm_stream的低版本源码和升级注释后搞明白。algorithm_stream只能处理 sample_rate=16000的采样频率,超过这个频率的会报内存错误。现在把i2c_stream的采样改为sample_rate=16000程序可以正常运行了,唯一遗憾就是algo_config.input_type = ALGORITHM_STREAM_INPUT_TYPE2的这种模式,回音消除几乎没有用,不知道哪儿还需要调整。
............................................... +-----------+
............................................... | |
............................................... | TYPE 2 |
............................................... | |
................ +--------------------------------------+-----------+----------------------------------------+
................ | |
................ | |
+-----------+ | +-----------+ +-----------+ +-----------+ +-----------+ +-----------+ |
| | | | | | | | | | | | | |
| I2S read |-------|->| Resample |--->| rec signal|--->| AEC |--->| NS |--->| AGC | |
| | | | | | | | | | | | | |
+-----------+ | +-----------+ +-----------+ +-----^-----+ +-----------+ +-----------+ |
................| | ^ |
+-----------+ | +-----------+ +-----------+ | | |
| | | | | | | | | |
| input_rb |-------|->| Resample |--->| ref signal|----------+| |
| | | | | | | |
+-----------+ | +-----------+ +-----------+ |
................| |
................ +-------------------------------------------------------------------------------------------+
下为完整voip源代码
#include <string.h>
#include "raw_stream.h"
#include "filter_resample.h"
#include "audio_element.h"
#include "audio_pipeline.h"
#include "i2s_stream.h"
#include "esp_sip.h"
#include "g711_decoder.h"
#include "g711_encoder.h"
#include "algorithm_stream.h"
#include "lwip/ip4_addr.h"
#include "esp_log.h"
#include "doVOIP.h"
#include "doMP3.h"
#include "tcpip_adapter.h"
#include "tcpip_adapter_types.h"
#include "zmgccs_main.h"
char *TAG_VOIP = "zmg-VOIP";
static char * wifi_ip ;
QueueHandle_t voip_evt_queue = NULL;
sip_handle_t voip_sip = NULL;
audio_element_handle_t voip_raw_read=NULL, voip_raw_write=NULL;
audio_pipeline_handle_t voip_recorder=NULL, voip_player=NULL;
int voip_started = 0 ;
int voip_state = 0;
uint32_t voip_connect_timeout = 0; //wifi连接超时,超时后进行处理
// ringbuf_handle_t input_rb = algo_stream_get_multi_input_rb(element_algo);
// audio_element_set_multi_output_ringbuf(i2s_stream_writer, input_rb, 0);
esp_err_t recorder_play_pipeline_open()
{
audio_element_handle_t i2s_stream_reader=NULL , sip_encoder = NULL, filter_in=NULL;
audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
voip_recorder = audio_pipeline_init(&pipeline_cfg);
AUDIO_NULL_CHECK(TAG_VOIP, voip_recorder, return ESP_FAIL);
i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
i2s_cfg.type = AUDIO_STREAM_READER;
i2s_cfg.task_core =0;
i2s_cfg.task_prio =Priority_voip;
i2s_cfg.uninstall_drv = false;
i2s_cfg.i2s_config.sample_rate = I2S_SAMPLE_RATE;
i2s_cfg.volume = 30;
i2s_cfg.stack_in_ext = true;
i2s_stream_reader = i2s_stream_init(&i2s_cfg);
i2s_stream_set_clk(i2s_stream_reader,I2S_SAMPLE_RATE,16,2);
algorithm_stream_cfg_t algo_config = ALGORITHM_STREAM_CFG_DEFAULT();
//algo_config.task_core = 0;
algo_config.task_prio = Priority_voip;
algo_config.task_stack = 8*1024;
//algo_config.input_type = ALGORITHM_STREAM_INPUT_TYPE1;
algo_config.input_type = ALGORITHM_STREAM_INPUT_TYPE2;
audio_element_handle_t element_algo = algo_stream_init(&algo_config);
rsp_filter_cfg_t rsp_cfg = DEFAULT_RESAMPLE_FILTER_CONFIG();
rsp_cfg.src_rate = I2S_SAMPLE_RATE;
rsp_cfg.src_ch = I2S_CHANNELS;
rsp_cfg.dest_rate = CODEC_SAMPLE_RATE;
rsp_cfg.dest_ch = CODEC_CHANNELS;
rsp_cfg.complexity = 5;
rsp_cfg.task_core = 0;
rsp_cfg.task_prio = Priority_voip;
filter_in = rsp_filter_init(&rsp_cfg);
g711_encoder_cfg_t g711_cfg = DEFAULT_G711_ENCODER_CONFIG();
g711_cfg.task_core = 0;
g711_cfg.task_prio = Priority_voip;
g711_cfg.enc_mode =1;
sip_encoder = g711_encoder_init(&g711_cfg);
raw_stream_cfg_t raw_cfg = RAW_STREAM_CFG_DEFAULT();
raw_cfg.type = AUDIO_STREAM_READER;
voip_raw_read = raw_stream_init(&raw_cfg);
audio_element_set_output_timeout(voip_raw_read, portMAX_DELAY);
ESP_LOGI(TAG_VOIP, "SIP recorder register");
AUDIO_NULL_CHECK(TAG_VOIP, i2s_stream_reader, return ESP_FAIL);
audio_pipeline_register(voip_recorder, i2s_stream_reader, "i2s");
audio_pipeline_register(voip_recorder, element_algo, "algo");
audio_pipeline_register(voip_recorder, filter_in, "filter");
audio_pipeline_register(voip_recorder, sip_encoder, "sip_enc");
audio_pipeline_register(voip_recorder, voip_raw_read, "raw");
const char *link_tag[5] = {"i2s","algo", "filter", "sip_enc", "raw"};
audio_pipeline_link(voip_recorder, &link_tag[0], 5);
audio_element_handle_t i2s_stream_writer=NULL, sip_decoder=NULL ,filter_out=NULL;
voip_player = audio_pipeline_init(&pipeline_cfg);
AUDIO_NULL_CHECK(TAG_VOIP, voip_player, return ESP_FAIL);
raw_cfg.type = AUDIO_STREAM_WRITER;
voip_raw_write = raw_stream_init(&raw_cfg);
g711_decoder_cfg_t g711_cfg2 = DEFAULT_G711_DECODER_CONFIG();
g711_cfg2.task_core = 0;
g711_cfg2.task_prio = Priority_voip;
g711_cfg2.dec_mode = 1;
sip_decoder = g711_decoder_init(&g711_cfg2);
rsp_filter_cfg_t rsp_cfg2 = DEFAULT_RESAMPLE_FILTER_CONFIG();
rsp_cfg2.src_rate = CODEC_SAMPLE_RATE;
rsp_cfg2.src_ch = CODEC_CHANNELS;
rsp_cfg2.dest_rate = I2S_SAMPLE_RATE;
rsp_cfg2.dest_ch = I2S_CHANNELS;
rsp_cfg2.complexity = 5;
rsp_cfg2.task_core = 0;
rsp_cfg2.task_prio = Priority_voip;
filter_out = rsp_filter_init(&rsp_cfg2);
//i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
i2s_cfg.type = AUDIO_STREAM_WRITER;
i2s_cfg.uninstall_drv = false;
i2s_cfg.i2s_config.sample_rate = I2S_SAMPLE_RATE;
i2s_cfg.task_core =0;
i2s_cfg.task_prio =Priority_voip;
i2s_cfg.volume = 30;
i2s_cfg.stack_in_ext = true;
i2s_stream_writer = i2s_stream_init(&i2s_cfg);
i2s_stream_set_clk(i2s_stream_writer,I2S_SAMPLE_RATE,16,2);
AUDIO_NULL_CHECK(TAG_VOIP, i2s_stream_writer, return ESP_FAIL);
audio_pipeline_register(voip_player, voip_raw_write, "raw");
audio_pipeline_register(voip_player, sip_decoder, "sip_dec");
audio_pipeline_register(voip_player, filter_out, "filter");
audio_pipeline_register(voip_player, i2s_stream_writer, "i2s");
const char *link_tag2[4] = {"raw", "sip_dec", "filter", "i2s"};
audio_pipeline_link(voip_player, &link_tag2[0], 4);
//重点代码 input_rb流的配置 回音消除的ref来源
ringbuf_handle_t input_rb = audio_element_get_multi_input_ringbuf(element_algo,0);
audio_element_set_multi_output_ringbuf(i2s_stream_writer, input_rb, 0);
audio_pipeline_run(voip_player);
ESP_LOGI(TAG_VOIP, "SIP player has been created");
audio_pipeline_run(voip_recorder);
ESP_LOGI(TAG_VOIP, "SIP recorder has been created");
return ESP_OK;
}
ip4_addr_t _get_network_ip()
{
tcpip_adapter_ip_info_t ip;
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip);
return ip.ip;
}
int _sip_event_handler(sip_event_msg_t *event)
{
ip4_addr_t ip;
switch ((int)event->type) {
case SIP_EVENT_REQUEST_NETWORK_STATUS:
ESP_LOGD(TAG_VOIP, "SIP_EVENT_REQUEST_NETWORK_STATUS");
ip = _get_network_ip();
if (ip.addr) {
return true;
}
return ESP_OK;
case SIP_EVENT_REQUEST_NETWORK_IP:
ESP_LOGD(TAG_VOIP, "SIP_EVENT_REQUEST_NETWORK_IP");
ip = _get_network_ip();
int ip_len = sprintf((char *)event->data, "%s", ip4addr_ntoa(&ip));
return ip_len;
case SIP_EVENT_REGISTERED:
ESP_LOGI(TAG_VOIP, "SIP_EVENT_REGISTERED");
//vTaskDelay(200);
//if (voip_state != SIP_EVENT_REGISTERED)//voip 在没断网的情况下过一定时间自动会触发此时间,避免重复提示
{
player_mp3_attention((uint16_t)voice_voip_connected);
voip_state = SIP_EVENT_REGISTERED;
}
break;
case SIP_EVENT_UNREGISTERED:
ESP_LOGI(TAG_VOIP, "SIP_EVENT_UNREGISTERED");
voip_state = SIP_EVENT_UNREGISTERED;
player_mp3_attention((uint16_t)voice_voip_disconnected);
break;
case SIP_EVENT_RINGING:
ESP_LOGI(TAG_VOIP, "ringing... RemotePhoneNum %s,PLAYER PAUSE", (char *)event->data);
//呼叫接入,自动接听
player_mp3_pause(); //停止并中断所以播放播放
esp_sip_uas_answer(voip_sip,true);
break;
case SIP_EVENT_INVITING:
ESP_LOGI(TAG_VOIP, "SIP_EVENT_INVITING Remote Ring...");
break;
case SIP_EVENT_BUSY:
ESP_LOGI(TAG_VOIP, "SIP_EVENT_BUSY");
break;
case SIP_EVENT_HANGUP:
ESP_LOGI(TAG_VOIP, "SIP_EVENT_HANGUP,PLAYER ENABLE");
player_mp3_enable(); //允许语音播放
break;
case SIP_EVENT_AUDIO_SESSION_BEGIN:
ESP_LOGI(TAG_VOIP, "SIP_EVENT_AUDIO_SESSION_BEGIN");
// vTaskDelay(1);
// player_pipeline_open();
// vTaskDelay(1);
// recorder_pipeline_open();
recorder_play_pipeline_open();
player_mp3_pause(); //停止并中断所以播放播放
break;
case SIP_EVENT_AUDIO_SESSION_END:
ESP_LOGI(TAG_VOIP, "SIP_EVENT_AUDIO_SESSION_END");
audio_pipeline_stop(voip_player);
audio_pipeline_wait_for_stop(voip_player);
audio_pipeline_deinit(voip_player);
audio_pipeline_stop(voip_recorder);
audio_pipeline_wait_for_stop(voip_recorder);
audio_pipeline_deinit(voip_recorder);
player_mp3_enable(); //允许语音播放
break;
case SIP_EVENT_READ_AUDIO_DATA:
return raw_stream_read(voip_raw_read, (char *)event->data, event->data_len);
break;
case SIP_EVENT_WRITE_AUDIO_DATA:
return raw_stream_write(voip_raw_write, (char *)event->data, event->data_len);
break;
case SIP_EVENT_READ_DTMF:
//ESP_LOGI(TAG_VOIP, "SIP_EVENT_READ_DTMF ID : %d ", ((char *)event->data)[0]);
break;
}
return 0;
}
int voip_set_stat(bool active,char * wifi_curr_ip,char * voip_url)
{
//char URL[150];
//bzero(URL,sizeof(URL));
//strcpy(URL,voip_url);
char tmp1[30];
bzero(tmp1,sizeof(tmp1));
wifi_ip = wifi_curr_ip;
sip_config_t sip_cfg ;
sip_state_t sip_state;
if (strlen(voip_url)<10)
{
ESP_LOGI(TAG_VOIP, "[ xx ] voip url error set format :udp//usernum:password@sip_server_ip:port/path ");
return -1;
}
if (active)
{
sip_cfg.uri = voip_url;
sip_cfg.event_handler = _sip_event_handler;
sip_cfg.send_options = true;
sip_cfg.acodec_type = SIP_ACODEC_G711U;
sip_cfg.cert_pem = tmp1;
sip_cfg.client_cert_pem = tmp1;
sip_cfg.client_key_pem = tmp1;
if (voip_started == 0)
{
voip_started = 1;
ESP_LOGI(TAG_VOIP, "[ 5 ] Create SIP Service url:%s ",voip_url);
voip_sip = esp_sip_init(&sip_cfg);
esp_sip_start(voip_sip);
//sip_messages_info_t sip_msg;
//esp_sip_set_invite_info(voip_sip,);
} else { //判断状态
voip_connect_timeout ++;
if(voip_connect_timeout>1800*100) //8分钟 10ms一次
{
sip_state = esp_sip_get_state(voip_sip);
if (!(sip_state == SIP_STATE_CALLING || sip_state == SIP_STATE_RINGING || sip_state == SIP_STATE_ON_CALL))
{
voip_connect_timeout=0;
esp_sip_destroy(voip_sip);
voip_sip = esp_sip_init(&sip_cfg);
esp_sip_start(voip_sip);
ESP_LOGE(TAG_VOIP, "Re Create SIP Service url");
}
}
}
} else{
if (voip_started == 1)
{
voip_started = 0;
ESP_LOGI(TAG_VOIP, "[ 5 ] STOP SIP Service ");
esp_sip_destroy(voip_sip);
voip_state = 0;
}
}
return 1;
}
求助:当algorithm_stream的配置为ALGORITHM_STREAM_INPUT_TYPE2 时用法
求助:当algorithm_stream的配置为ALGORITHM_STREAM_INPUT_TYPE2 时用法
Last edited by qinli198 on Mon Jun 13, 2022 3:55 am, edited 1 time in total.
Re: 求助:当algorithm_stream的配置为ALGORITHM_STREAM_INPUT_TYPE2 时用法
自己顶一下修改采用频率
i2s_cfg.i2s_config.sample_rate=16000,程序已经能够正常运行,但是回音没有消除。
i2s_cfg.i2s_config.sample_rate=16000,程序已经能够正常运行,但是回音没有消除。
Re: 求助:当algorithm_stream的配置为ALGORITHM_STREAM_INPUT_TYPE2 时用法
通过源代码阅读最后终于解决问题,voip系统可以正常对讲了,回音杂音都满足了需要。唯一遗憾是es8388贴片时选错为es8388s需要自己全部手动更换,好在只有100片。
最后重点:voip系统播放和录音只能是单声道,并且播放和录音i2s_stream的sample_rate最好是16000。
最后重点:voip系统播放和录音只能是单声道,并且播放和录音i2s_stream的sample_rate最好是16000。
-
- Posts: 184
- Joined: Fri Dec 15, 2017 2:45 am
Re: 求助:当algorithm_stream的配置为ALGORITHM_STREAM_INPUT_TYPE2 时用法
请问,最后回声消除是怎么处理的,我也遇到这个问题
-
- Posts: 135
- Joined: Tue Apr 24, 2018 5:54 am
Re: 求助:当algorithm_stream的配置为ALGORITHM_STREAM_INPUT_TYPE2 时用法
其实 对讲 这种 单入单出 即可的应用不建议用 ES8388 ,建议用 ES8311
1. 单 MIC 而言,8311 更恰当,价格合适
2. 对于 AEC 算法而言,type1 硬件回采效果更好,type2 软件回采有时延问题,而 ES8311 支持硬件回采
https://github.com/espressif/esp-adf/bl ... 311.c#L651
ret I= es8311 write_reg (ES8311 _GPIO_REG44, 0x50) ;
1. 单 MIC 而言,8311 更恰当,价格合适
2. 对于 AEC 算法而言,type1 硬件回采效果更好,type2 软件回采有时延问题,而 ES8311 支持硬件回采
https://github.com/espressif/esp-adf/bl ... 311.c#L651
ret I= es8311 write_reg (ES8311 _GPIO_REG44, 0x50) ;
Who is online
Users browsing this forum: No registered users and 80 guests