Edit: I updated the example to include both mic and speaker that have been confirmed to work. It should also be a complete example with UDP send and receive code.
It’s a bit of a hack, using the microphone event to read and feed the speaker data, but it works.
…
I have been able to stream audio out of the microphone using this configuration:
i2s_audio:
- id: i2s_in
i2s_lrclk_pin: GPIO2
i2s_bclk_pin: GPIO15
- id: i2s_out
i2s_lrclk_pin: GPIO38
i2s_bclk_pin: GPIO48
#i2s_mclk_pin: GPIO21
microphone:
- platform: i2s_audio
id: i2s_microphone
i2s_audio_id: i2s_in
i2s_din_pin: GPIO39
adc_type: external
pdm: false
channel: right
sample_rate: 16000
bits_per_sample: 16bit
on_data:
- lambda: |-
static std::vector<int16_t> send_buffer;
static std::vector<uint8_t> recv_buffer(1024);
static struct sockaddr_in destination = {
.sin_family = AF_INET,
.sin_port = htons(12345),
.sin_addr = { .s_addr = inet_addr("192.168.1.165") }
};
static struct sockaddr_in source = {
.sin_family = AF_INET,
.sin_port = htons(12346),
.sin_addr = { .s_addr = INADDR_ANY }
};
static int send_sock = ::socket(AF_INET, SOCK_DGRAM, 0);
static int recv_sock = ::socket(AF_INET, SOCK_DGRAM, 0);
static bool bound = false;
if (!bound) {
int flags = fcntl(recv_sock, F_GETFL, 0);
fcntl(recv_sock, F_SETFL, flags | O_NONBLOCK);
bind(recv_sock, (const sockaddr*)&source, sizeof(source));
bound = true;
}
for (uint16_t byte : x) {
send_buffer.push_back(byte);
}
int send_cnt = send_buffer.size();
if(send_cnt >= 256) {
::sendto(send_sock, send_buffer.data(), send_cnt * 2, 0, reinterpret_cast<sockaddr*>(&destination), sizeof(destination));
send_buffer.clear();
}
socklen_t fromlen = sizeof(source);
int recv_cnt = ::recvfrom(recv_sock, recv_buffer.data(), recv_buffer.size(), 0, reinterpret_cast<sockaddr*>(&source), &fromlen);
if (recv_cnt > 0) {
id(i2s_speaker).play(recv_buffer.data(), recv_cnt, 0);
}
button:
- platform: template
name: "Enable Microphone"
on_press:
- microphone.capture: i2s_microphone
- delay: 10s
- microphone.stop_capture: i2s_microphone
speaker:
- platform: i2s_audio
id: i2s_speaker
i2s_audio_id: i2s_out
i2s_dout_pin: GPIO47
dac_type: external
sample_rate: 16000
bits_per_sample: 16bit
channel: mono
I suspect the problem that I was having previously was not knowing that I needed to start capture, which is what the button is for.
I got most of this from here: Is there a way to stream audio from one ESPHome to another? - #9 by haforum
I’m currently trying to figure out how to do something similar for the speaker to test it.