关于边录边播的问题

ethan_xie
Posts: 4
Joined: Thu Nov 22, 2018 1:27 pm

关于边录边播的问题

Postby ethan_xie » Thu Nov 22, 2018 2:57 pm

刚刚接触esp32,想要实现边录边播,想法是通过两个I2S,分别控制录音和播放。
我的代码实现如下:
公共部分的初始化
  1.     esp_log_level_set("*", ESP_LOG_WARN);
  2.     esp_log_level_set(TAG, ESP_LOG_INFO);
  3.  
  4.     esp_periph_config_t periph_cfg = { 0 };
  5.     esp_periph_init(&periph_cfg);
  6.  
  7.     periph_sdcard_cfg_t sdcard_cfg = {
  8.         .root = "/sdcard",
  9.         .card_detect_pin = SD_CARD_INTR_GPIO, //GPIO_NUM_34
  10.     };
  11.     esp_periph_handle_t sdcard_handle = periph_sdcard_init(&sdcard_cfg);
  12.     esp_periph_start(sdcard_handle);
  13.    
  14.     while (!periph_sdcard_is_mounted(sdcard_handle)) {
  15.         vTaskDelay(100 / portTICK_PERIOD_MS);
  16.     }
  17.  
  18.     periph_touch_cfg_t touch_cfg = {
  19.         .touch_mask = TOUCH_SEL_SET | TOUCH_SEL_PLAY | TOUCH_SEL_VOLUP | TOUCH_SEL_VOLDWN,
  20.         .tap_threshold_percent = 70,
  21.     };
  22.     touch_periph = periph_touch_init(&touch_cfg);
  23.  
  24.     esp_periph_start(touch_periph);
  25.    
  26.     audio_hal_codec_config_t audio_hal_codec_cfg =  AUDIO_HAL_ES8388_DEFAULT();
  27.     audio_hal_codec_cfg.i2s_iface.samples = AUDIO_HAL_44K_SAMPLES;
  28.     hal = audio_hal_init(&audio_hal_codec_cfg, 0);
  29.     audio_hal_ctrl_codec(hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);
播放部分的初始化
  1.     audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
  2.     pipeline_mp3 = audio_pipeline_init(&pipeline_cfg);
  3.     mem_assert(pipeline_mp3);
  4.  
  5.     i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
  6.     i2s_cfg.i2s_port = I2S_NUM_0;
  7.     i2s_cfg.type = AUDIO_STREAM_WRITER;
  8.     i2s_stream_writer = i2s_stream_init(&i2s_cfg);
  9.  
  10.     mp3_decoder_cfg_t mp3_cfg = DEFAULT_MP3_DECODER_CONFIG();
  11.     mp3_decoder = mp3_decoder_init(&mp3_cfg);
  12.     audio_element_set_read_cb(mp3_decoder, my_sdcard_read_cb, NULL);
  13.  
  14.     audio_pipeline_register(pipeline_mp3, mp3_decoder, "mp3");
  15.     audio_pipeline_register(pipeline_mp3, i2s_stream_writer, "i2s_mp3");
  16.  
  17.     ESP_LOGI(TAG, "Link it together [my_sdcard_read_cb]-->mp3_decoder-->i2s_stream-->[codec_chip]");
  18.     audio_pipeline_link(pipeline_mp3, (const char *[]) {"mp3", "i2s_mp3"}, 2);
  19.  
  20.     audio_event_iface_cfg_t evt_mp3_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
  21.     evt_mp3 = audio_event_iface_init(&evt_mp3_cfg);
  22.  
  23.     audio_pipeline_set_listener(pipeline_mp3, evt_mp3);
  24.     audio_event_iface_set_listener(esp_periph_get_event_iface(), evt_mp3);
录音部分的初始化
  1.     audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
  2.     pipeline_rec = audio_pipeline_init(&pipeline_cfg);
  3.     mem_assert(pipeline_rec);
  4.    
  5.     fatfs_stream_cfg_t fatfs_cfg = FATFS_STREAM_CFG_DEFAULT();
  6.     fatfs_cfg.type = AUDIO_STREAM_WRITER;
  7.     fatfs_stream_writer = fatfs_stream_init(&fatfs_cfg);
  8.  
  9.     i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
  10.  
  11.     i2s_cfg.i2s_port = I2S_NUM_1;
  12.     i2s_cfg.task_core = 1;
  13.     i2s_cfg.i2s_config.sample_rate = 8000;
  14.     i2s_cfg.i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
  15.     i2s_cfg.type = AUDIO_STREAM_READER;
  16.     i2s_stream_reader = i2s_stream_init(&i2s_cfg);
  17.    
  18.     amrnb_encoder_cfg_t amr_enc_cfg = DEFAULT_AMRNB_ENCODER_CONFIG();
  19.     amr_encoder = amrnb_encoder_init(&amr_enc_cfg);
  20.    
  21.     audio_pipeline_register(pipeline_rec, i2s_stream_reader, "i2s_rec");
  22.     audio_pipeline_register(pipeline_rec, amr_encoder, "amr");
  23.     audio_pipeline_register(pipeline_rec, fatfs_stream_writer, "file");
  24.  
  25.     audio_pipeline_link(pipeline_rec, (const char *[]) {"i2s_rec", "amr", "file"}, 3);
  26.  
  27.     audio_element_set_uri(fatfs_stream_writer, "/sdcard/rec.amr");
  28.  
  29.     audio_event_iface_cfg_t evt_rec_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
  30.     evt_rec = audio_event_iface_init(&evt_rec_cfg);
  31.  
  32.     audio_pipeline_set_listener(pipeline_rec, evt_rec);
初始化完成后,起两个线程分别捕捉播放及录音的事件通知。

播放事件
  1.         int player_volume = 50;
  2.     audio_hal_set_volume(hal, player_volume);
  3.     audio_pipeline_run(pipeline_mp3);
  4.     while (1) {
  5.         /* Handle event interface messages from pipeline
  6.            to set music info and to advance to the next song
  7.         */
  8.         audio_event_iface_msg_t msg;
  9.         esp_err_t ret = audio_event_iface_listen(evt_mp3, &msg, portMAX_DELAY);
  10.         if (ret != ESP_OK) {
  11.             ESP_LOGE(TAG, "[ * ] Event interface error : %d", ret);
  12.             continue;
  13.         }
  14.         if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT){
  15.             // Set music info for a new song to be played
  16.             if (msg.source == (void *) mp3_decoder
  17.                 && msg.cmd == AEL_MSG_CMD_REPORT_MUSIC_INFO) {
  18.                 audio_element_info_t music_info = {0};
  19.                 audio_element_getinfo(mp3_decoder, &music_info);
  20.                 ESP_LOGI(TAG, "[ * ] Received music info from mp3 decoder, sample_rates=%d, bits=%d, ch=%d",
  21.                     music_info.sample_rates, music_info.bits, music_info.channels);
  22.                 audio_element_setinfo(i2s_stream_writer, &music_info);
  23.                 i2s_stream_set_clk(i2s_stream_writer, music_info.sample_rates, music_info.bits, music_info.channels);
  24.                 continue;
  25.             }
  26.             // Advance to the next song when previous finishes
  27.             if (msg.source == (void *) i2s_stream_writer
  28.                 && msg.cmd == AEL_MSG_CMD_REPORT_STATUS) {
  29.                 audio_element_state_t el_state = audio_element_get_state(i2s_stream_writer);
  30.                 if (el_state == AEL_STATE_FINISHED) {
  31.                     ESP_LOGI(TAG, "[ * ] Finished, advancing to the next song");
  32.                     audio_pipeline_stop(pipeline_mp3);
  33.                     audio_pipeline_wait_for_stop(pipeline_mp3);
  34.                     get_file(NEXT);
  35.                     audio_pipeline_run(pipeline_mp3);
  36.                 }
  37.                 continue;
  38.             }
  39.         }
录音事件
  1.     audio_pipeline_run(pipeline_rec);
  2.     int second_recorded = 0;
  3.     while (1) {
  4.         audio_event_iface_msg_t msg;
  5.         if (audio_event_iface_listen(evt_rec, &msg, 1000 / portTICK_RATE_MS) != ESP_OK) {
  6.             second_recorded++;
  7.             ESP_LOGI(TAG, "[ * ] Recording ... %d", second_recorded);
  8.             if (second_recorded >= 5) {
  9.                 ESP_LOGI(TAG, "Finishing amr recording");
  10.                 break;
  11.             }
  12.             continue;
  13.         }
  14.  
  15.         /* Stop when the last pipeline element (i2s_stream_reader in this case) receives stop event */
  16.         if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *)i2s_stream_reader && msg.cmd ==
  17.             AEL_MSG_CMD_REPORT_STATUS && (int)msg.data == AEL_STATUS_STATE_STOPPED) {
  18.             ESP_LOGW(TAG, "[ * ] Stop event received");
  19.             break;
  20.         }
  21.     }
两个线程单独运行ok,如果同步运行的话,会出现播放卡顿,录音出来的声音是很尖锐的噪音。
请问是不是我的处理思路有问题,或是配置有问题?烦请解答,不胜感激!

llx4186041
Posts: 3
Joined: Fri Jul 10, 2020 7:11 am

Re: 关于边录边播的问题

Postby llx4186041 » Tue Jul 13, 2021 2:21 am

板子只有一个8388,只能连接一个i2s,播放和录音要用同一个i2S端口,采样率也要一致。

Who is online

Users browsing this forum: No registered users and 38 guests