-
-
Notifications
You must be signed in to change notification settings - Fork 309
CodecOpusOgg encoded data cannot be played #2043
-
Problem Description
hi, bro. First of all, thank you very much for your project. He did me a big favor! 🌹
Now I want to send the opus
data to the server via ws
, and the server will save it as record.opus
.
It was found that the saved file has no length. The reason should be that there is no correct ending.
My Arduino code is in a mess! I hope you can help me answer this.
Arduino Code
#include <WiFi.h>
#include <WebSocketsClient.h>
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecOpusOgg.h"
#include <driver/i2s.h>
// 聆听模式
bool LISTENING = true;
bool ended = false;
// WEBSOCKET
SemaphoreHandle_t wsMutex;
WebSocketsClient webSocket;
// AUDIO INPUT SETTINGS
class WebsocketStream : public Print
{
public:
virtual size_t write(uint8_t b) override
{
if (!webSocket.isConnected())
{
return 1;
}
if (xSemaphoreTake(wsMutex, pdMS_TO_TICKS(100)) == pdTRUE)
{
webSocket.sendBIN(&b, 1);
xSemaphoreGive(wsMutex);
return 1;
}
return 1;
}
virtual size_t write(const uint8_t *buffer, size_t size) override
{
if (size == 0 || !webSocket.isConnected())
{
return size;
}
if (xSemaphoreTake(wsMutex, pdMS_TO_TICKS(100)) == pdTRUE)
{
Serial.print("发送大小:");
Serial.println(size);
webSocket.sendBIN(buffer, size);
xSemaphoreGive(wsMutex);
return size;
}
return size;
}
};
WebsocketStream wsStream;
I2SStream i2sInput;
// VolumeStream volume(i2sInput);
// StreamCopy micToWsCopier(wsStream, volume);
OpusOggEncoder encoder;
EncodedAudioStream out(&wsStream, &encoder);
StreamCopy micToWsCopier(out, i2sInput);
const int MIC_COPY_SIZE = 1024; // 或更高
void micTask(void *parameter)
{
// Configure and start I2S input stream.
auto i2sConfig = i2sInput.defaultConfig(RX_MODE);
i2sConfig.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
i2sConfig.sample_rate = 16000;
i2sConfig.channels = 1;
i2sConfig.i2s_format = I2S_LEFT_JUSTIFIED_FORMAT;
i2sConfig.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
// Configure your I2S input pins appropriately here:
i2sConfig.pin_bck = 4;
i2sConfig.pin_ws = 5;
i2sConfig.pin_data = 6;
i2sConfig.port_no = 0;
i2sInput.begin(i2sConfig);
// auto vcfg = volume.defaultConfig();
// vcfg.copyFrom(i2sConfig);
// vcfg.allow_boost = true;
// volume.begin(vcfg);
// volume.setVolume(12);
// 配置 Opus 编码器
OpusEncoderSettings cfg;
cfg.sample_rate = i2sConfig.sample_rate;
cfg.channels = i2sConfig.channels;
// configure additinal parameters
cfg.application = OPUS_APPLICATION_RESTRICTED_LOWDELAY;
cfg.frame_sizes_ms_x2 = OPUS_FRAMESIZE_100_MS;
// enc.config().complexity = 5; // 支持的范围是0-10,其中10代表最高的复杂度。
if (!encoder.begin(cfg))
{
Serial.println("❌ Opus encoder failed to initialize!");
while (true)
{
delay(1000); // 或根据你项目逻辑退出
}
}
out.begin(i2sConfig);
long start_time = millis();
while (1)
{
if (webSocket.isConnected())
{
if ((millis() - start_time) > 6000)
{
micToWsCopier.end();
i2sInput.end(); // 停止 I2S 输入
out.flush(); // 刷新剩余数据
vTaskDelay(100); // 等待数据发出
encoder.end(); // 结束编码器,写入最后封包(EOS)
vTaskDelay(1000); // 给 websocket 一点时间发送完最后一包
Serial.println("----");
ended = true;
Serial.println("结束");
webSocket.disconnect();
}
else
{
// Use smaller chunk size to avoid blocking too long
// micToWsCopier.copyBytes(MIC_COPY_SIZE);
micToWsCopier.copy();
// Yield more frequently
vTaskDelay(50);
}
}
else
{
vTaskDelay(100);
}
}
}
// I2S 配置见上面
void setup()
{
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Debug);
// AudioLogger::instance().begin(Serial, AudioLogger::Info);
wsMutex = xSemaphoreCreateMutex();
delay(2000);
Serial.println("开始连接wifi");
WiFi.begin("联域科技", "lykj987654321");
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(500);
}
Serial.println("wifi连接成功");
webSocket.begin("192.168.3.16", 8988, "/");
webSocket.onEvent(webSocketEvent);
webSocket.setReconnectInterval(5000);
xTaskCreatePinnedToCore(
micTask, // Function
"Microphone Task", // Name
1024 * 8, // Stack size
NULL, // Parameters
4, // Priority
NULL, // Handle
1 // Core 1 (application core)
);
}
void loop()
{
if (!ended)
{
webSocket.loop();
}
}
void webSocketEvent(WStype_t type, uint8_t *payload, size_t length)
{
switch (type)
{
case WStype_DISCONNECTED:
Serial.println("WebSocket Disconnected");
break;
case WStype_CONNECTED:
Serial.println("WebSocket Connected");
break;
case WStype_TEXT:
Serial.printf("Received Text: %s\n", payload);
break;
case WStype_BIN:
break;
}
}
Node Code
const WebSocket = require('ws')
var fs = require('fs')
// 和 esp32 连接的 ws 服务
let wss;
// 与 esp32 的通信
function wss_start() {
wss = new WebSocket.Server({ port: 8988 });
wss.on('connection', function connection(ws) {
console.log('\n\n esp32 连接成功');
const output = fs.createWriteStream('record.opus');
ws.on('message', data => {
console.log(data.length)
output.write(data)
});
// 处理WebSocket断开
ws.on('close', () => {
console.log("服务断开");
// 保险:延迟关闭文件,确保缓冲区刷新完成
setTimeout(() => {
output.end();
console.log("文件写入完成");
}, 300); // 等待 300ms
});
});
console.log('WebSocket server is running on ws://localhost:8988');
}
wss_start();
Device Description
ESP32s3
Sketch
-
Other Steps to Reproduce
No response
What is your development environment (incl. core version info)
No response
I have checked existing issues, discussions and online documentation
- I confirm I have checked existing issues, discussions and online documentation
Beta Was this translation helpful? Give feedback.
All reactions
Please follow the advice give in this Wiki and build and test your sketch in steps.
I would suggest to start to with a very simple sketch that just outputs the i2s data to a CSVOutput, if this is working replace the output with a HexDumpOutput. As the next step add the encoding. Only if this is working replace the output class.
Test each step separatley and advance only when you have the confirmation that it is wokring.
Also test your WebsocketStream class separatly by sending some defined data.
Replies: 2 comments
-
This is the detailed information of the audio:
Input #0, ogg, from './record.opus':KB vq= 0KB sq= 0B
Duration: 00:00:00.05, start: -0.009604, bitrate: 1562 kb/s
Stream #0:0: Audio: opus, 48000 Hz, mono, fltp
-0.07 M-A: 0.000 fd= 0 aq= 0KB vq= 0KB sq= 0B
Beta Was this translation helpful? Give feedback.
All reactions
-
Please follow the advice give in this Wiki and build and test your sketch in steps.
I would suggest to start to with a very simple sketch that just outputs the i2s data to a CSVOutput, if this is working replace the output with a HexDumpOutput. As the next step add the encoding. Only if this is working replace the output class.
Test each step separatley and advance only when you have the confirmation that it is wokring.
Also test your WebsocketStream class separatly by sending some defined data.
Beta Was this translation helpful? Give feedback.