2024-08-31 18:00:23 +08:00
|
|
|
#include "OpusEncoder.h"
|
|
|
|
|
#include "esp_err.h"
|
|
|
|
|
#include "esp_log.h"
|
|
|
|
|
|
|
|
|
|
#define TAG "OpusEncoder"
|
|
|
|
|
|
|
|
|
|
OpusEncoder::OpusEncoder() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OpusEncoder::~OpusEncoder() {
|
|
|
|
|
if (audio_enc_ != nullptr) {
|
|
|
|
|
opus_encoder_destroy(audio_enc_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OpusEncoder::Configure(int sample_rate, int channels, int duration_ms) {
|
|
|
|
|
if (audio_enc_ != nullptr) {
|
|
|
|
|
opus_encoder_destroy(audio_enc_);
|
|
|
|
|
audio_enc_ = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int error;
|
|
|
|
|
audio_enc_ = opus_encoder_create(sample_rate, channels, OPUS_APPLICATION_VOIP, &error);
|
|
|
|
|
if (audio_enc_ == nullptr) {
|
|
|
|
|
ESP_LOGE(TAG, "Failed to create audio encoder, error code: %d", error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set DTX
|
|
|
|
|
opus_encoder_ctl(audio_enc_, OPUS_SET_DTX(1));
|
2024-09-04 13:36:20 +08:00
|
|
|
SetComplexity(5);
|
2024-08-31 18:00:23 +08:00
|
|
|
|
|
|
|
|
frame_size_ = sample_rate / 1000 * duration_ms;
|
2024-09-01 10:37:02 +08:00
|
|
|
out_buffer_.resize(sample_rate * channels * sizeof(int16_t));
|
2024-08-31 18:00:23 +08:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 13:36:20 +08:00
|
|
|
void OpusEncoder::SetComplexity(int complexity) {
|
|
|
|
|
if (audio_enc_ != nullptr) {
|
|
|
|
|
opus_encoder_ctl(audio_enc_, OPUS_SET_COMPLEXITY(complexity));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-01 10:37:02 +08:00
|
|
|
void OpusEncoder::Encode(const iovec pcm, std::function<void(const iovec opus)> handler) {
|
2024-08-31 18:00:23 +08:00
|
|
|
if (audio_enc_ == nullptr) {
|
|
|
|
|
ESP_LOGE(TAG, "Audio encoder is not configured");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-01 10:37:02 +08:00
|
|
|
auto pcm_data = (int16_t*)pcm.iov_base;
|
|
|
|
|
in_buffer_.insert(in_buffer_.end(), pcm_data, pcm_data + pcm.iov_len / sizeof(int16_t));
|
2024-08-31 18:00:23 +08:00
|
|
|
|
2024-09-01 10:37:02 +08:00
|
|
|
while (in_buffer_.size() >= frame_size_) {
|
|
|
|
|
auto ret = opus_encode(audio_enc_, in_buffer_.data(), frame_size_, out_buffer_.data(), out_buffer_.size());
|
2024-08-31 18:00:23 +08:00
|
|
|
if (ret < 0) {
|
|
|
|
|
ESP_LOGE(TAG, "Failed to encode audio, error code: %ld", ret);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (handler != nullptr) {
|
2024-09-01 10:37:02 +08:00
|
|
|
handler(iovec { out_buffer_.data(), (size_t)ret });
|
2024-08-31 18:00:23 +08:00
|
|
|
}
|
|
|
|
|
|
2024-09-01 10:37:02 +08:00
|
|
|
in_buffer_.erase(in_buffer_.begin(), in_buffer_.begin() + frame_size_);
|
2024-08-31 18:00:23 +08:00
|
|
|
}
|
|
|
|
|
}
|
2024-09-04 13:36:20 +08:00
|
|
|
|
|
|
|
|
void OpusEncoder::ResetState() {
|
|
|
|
|
if (audio_enc_ != nullptr) {
|
|
|
|
|
opus_encoder_ctl(audio_enc_, OPUS_RESET_STATE);
|
|
|
|
|
}
|
|
|
|
|
in_buffer_.clear();
|
|
|
|
|
}
|