【ESP32音视频传输】②通过I2S采集SPH0645麦克风音频数据并上传到服务端实时播放

您所在的位置:网站首页 jblpulse4连接麦克风 【ESP32音视频传输】②通过I2S采集SPH0645麦克风音频数据并上传到服务端实时播放

【ESP32音视频传输】②通过I2S采集SPH0645麦克风音频数据并上传到服务端实时播放

2023-11-20 21:51| 来源: 网络整理| 查看: 265

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录 前言一、I2S型麦克风SPH0645二、使用步骤1.连线图2.Arduino主文件代码3.服务端利用UDP接收音频代码 Arduino完整程序

前言

本文章基于Arduino ESP32 2.07版本,因为2.04版本开始I2S驱动被更改了,所以相同代码可能效果不太同 本文主要参考了:https://atomic14.com/2020/09/12/esp32-audio-input.html

一、I2S型麦克风SPH0645

ESP32有多种方式从外置麦克风中读取数据:

①直接从内置模数转换器 (ADC) 读取数据 这对于一次性读数很有用,但不适用于高采样率。 ②使用 I2S 通过 DMA 读取内置 ADC 适用于模拟麦克风,例如 MAX4466 和 MAX9814 ③使用 I2S 直接读取 I2S 兼容外设 适用于 SPH0645LM4H、INPM441、ICS43432 和 ICS43434 等麦克风 SPH0645

二、使用步骤 1.连线图

代码如下(示例): 在这里插入图片描述 (上图均来自:https://diyi0t.com/i2s-sound-tutorial-for-esp32/)

①位时钟线

正式名称为“连续串行时钟 (SCK)”。通常写作“位时钟(BCLK)”。

② 字时钟线

正式的“单词选择(WS)”。通常称为“左右时钟 (LRCLK)”或“帧同步 (FS)”。

0 = 左声道,1 = 右声道

③数据线

正式名称为“串行数据 (SD)”,但可以称为 SDATA、SDIN、SDOUT、DACDAT、ADCDAT 等。

我的连线图是这样的 在这里插入图片描述 引脚对应为:

// i2s pins i2s_pin_config_t i2sPins = { .bck_io_num = GPIO_NUM_15, .ws_io_num = GPIO_NUM_16, .data_out_num = I2S_PIN_NO_CHANGE, .data_in_num = GPIO_NUM_21}; 2.Arduino主文件代码

工程代码的I2S操作SPH0645参考了:https://github.com/atomic14/esp32-walkie-talkie,原工程用的是HTTP stream,本例改成了AsyncUDP 主文件代码如下:

#include #include #include "soc/soc.h" #include "soc/rtc_cntl_reg.h" #include "esp_camera.h" #include "configuration.h" #include "I2SMEMSSampler.h" #include "AsyncUDP.h" const char * ssid = "your-ssid"; //WiFi名称 const char * password = "password";//wifi密码 IPAddress serverip = IPAddress(192,168,1,108); //服务端的静态IP地址 uint16_t toport_sound = 8085; //服务端的开放端口 const int SAMPLE_SIZE = 700;//udp一次最大发送的数据包大小,UDP最大发生有限制 AsyncUDP SoundUDP; I2SSampler *i2sSampler = NULL; void InitUDP(IPAddress ip, uint16_t toport_sound){ if(SoundUDP.connect(ip, toport_sound)) { Serial.println("UDP connected"); SoundUDP.onPacket([](AsyncUDPPacket packet) { Serial.print("UDP Packet Type: "); Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast"); Serial.print(", From: "); Serial.print(packet.remoteIP()); Serial.print(":"); Serial.print(packet.remotePort()); Serial.print(", To: "); Serial.print(packet.localIP()); Serial.print(":"); Serial.print(packet.localPort()); Serial.print(", Length: "); Serial.print(packet.length()); Serial.print(", Data: "); Serial.write(packet.data(), packet.length()); Serial.println(); //reply to the client packet.printf("S2 Got %u bytes of data", packet.length()); }); //Send unicast //SoundUDP.print("This is S2 Server"); } } // i2s config for reading from left channel of I2S i2s_config_t i2sMemsConfigLeftChannel = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX), .sample_rate = 16000, .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S), .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 4, .dma_buf_len = 1024, .use_apll = false, .tx_desc_auto_clear = false, .fixed_mclk = 0}; // i2s pins i2s_pin_config_t i2sPins = { .bck_io_num = GPIO_NUM_15, .ws_io_num = GPIO_NUM_16, .data_out_num = I2S_PIN_NO_CHANGE, .data_in_num = GPIO_NUM_21}; // 发送音频数据 void sendSoundData(uint8_t *bytes, size_t count, AsyncUDP* UDPClient = &SoundUDP, uint16_t the_port = toport_sound) { // send them off to the server digitalWrite(2, HIGH); /* httpClient->begin(*wifiClient, url); httpClient->addHeader("content-type", "application/octet-stream"); httpClient->POST(bytes, count); httpClient->end(); */ //这是向局域网内所有用户广播,若只发给连接的用户,要用UDPClient.write() UDPClient->broadcastTo(bytes, count,the_port); digitalWrite(2, LOW); } // Task to write samples to our server void i2sMemsWriterTask(void *param) { I2SSampler *sampler = (I2SSampler *)param; int16_t *samples = (int16_t *)malloc(sizeof(uint16_t) * SAMPLE_SIZE); if (!samples) { Serial.println("Failed to allocate memory for samples"); return; } while (true) { int samples_read = sampler->read(samples, SAMPLE_SIZE); //sendSoundData((uint8_t *)samples, samples_read * sizeof(uint16_t)); SoundUDP.write((uint8_t *)samples, samples_read * sizeof(uint16_t)); //SoundUDP.broadcastTo((uint8_t *)samples, samples_read * sizeof(uint16_t),toport_sound); } } void setup() { WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector Serial.begin(115200); //Serial.setDebugOutput(false); // launch WiFi WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); if (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("WiFi Failed"); while(1) { delay(1000); } } // indicator LED pinMode(2, OUTPUT); InitUDP(serverip,toport_sound); // Direct i2s input from INMP441 or the SPH0645 i2sSampler = new I2SMEMSSampler(I2S_NUM_1, i2sPins, i2sMemsConfigLeftChannel, false); i2sSampler->start(); // set up the i2s sample writer task TaskHandle_t i2sMemsWriterTaskHandle; xTaskCreatePinnedToCore(i2sMemsWriterTask, "I2S Writer Task", 4096, i2sSampler, 1, &i2sMemsWriterTaskHandle, 1); // // start sampling from i2s device } void loop() { // nothing to do here - everything is taken care of by tasks }

该处使用的url网络请求的数据。

3.服务端利用UDP接收音频代码 import pyaudio import socket # 配置参数 chunk = 1400 sample_rate = 16000 duration = 5 udp_port = 8085 p = pyaudio.PyAudio() # 打开音频流 stream = p.open(format=pyaudio.paInt16, channels=1, rate=sample_rate, output=True) # 打开UDP套接字 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind(('0.0.0.0', udp_port)) # 播放PCM音频数据 while True: data, addr = sock.recvfrom(chunk) print(f"Received message ") stream.write(data) # 关闭音频流和UDP套接字 stream.stop_stream() stream.close() sock.close() p.terminate() Arduino完整程序

https://download.csdn.net/download/loveliveoil/87762126



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3