toy-Kapi_Rtc/main/audio/simple_pipeline.cc
2026-01-20 16:55:17 +08:00

124 lines
4.5 KiB
C++

#include "simple_pipeline.h"
#include "boards/common/board.h"
#include "audio_codecs/audio_codec.h"
#include <vector>
#include <cstring>
static inline int16_t lrint16(float v){ if(v>32767.f) return 32767; if(v<-32768.f) return -32768; return (int16_t)v; }
static void resample_mono_nearest(const int16_t* in, int in_samples, int in_rate, int16_t* out, int out_samples, int out_rate){
if(in_rate==out_rate){ for(int i=0;i<out_samples;i++) out[i]=in[i]; return; }
float ratio = (float)in_rate/(float)out_rate;
for(int i=0;i<out_samples;i++){ int idx = (int)(i*ratio); if(idx>=in_samples) idx=in_samples-1; out[i]=in[idx]; }
}
recorder_pipeline_handle_t recorder_pipeline_open(){
auto h = (recorder_pipeline_handle_t)pvPortMalloc(sizeof(recorder_pipeline_t));
h->task = nullptr;
h->dest_rate = 16000;
auto codec = Board::GetInstance().GetAudioCodec();
h->src_rate = codec->input_sample_rate();
h->channels = 1;
h->block_bytes = (h->dest_rate/50)*sizeof(int16_t);
codec->EnableInput(true);
return h;
}
void recorder_pipeline_run(recorder_pipeline_handle_t){ }
void recorder_pipeline_close(recorder_pipeline_handle_t h){
if(!h) return;
if (h->task) {
vTaskDelete(h->task);
}
auto codec = Board::GetInstance().GetAudioCodec();
codec->EnableInput(false);
vPortFree(h);
}
int recorder_pipeline_get_default_read_size(recorder_pipeline_handle_t h){ return h? h->block_bytes: 0; }
int recorder_pipeline_read(recorder_pipeline_handle_t h, char *buffer, int buf_size){
if(!h || !buffer) return 0;
auto codec = Board::GetInstance().GetAudioCodec();
int out_samples = h->dest_rate/50;
std::vector<int16_t> tmp;
if(h->src_rate==h->dest_rate){ tmp.resize(out_samples); }
else{ tmp.resize((int)((float)out_samples*h->src_rate/h->dest_rate)); }
if(!codec->InputData(tmp)) return 0;
std::vector<int16_t> out(out_samples);
resample_mono_nearest(tmp.data(), (int)tmp.size(), h->src_rate, out.data(), out_samples, h->dest_rate);
int bytes = out_samples*sizeof(int16_t);
if(bytes>buf_size) bytes=buf_size;
memcpy(buffer, out.data(), bytes);
return bytes;
}
player_pipeline_handle_t player_pipeline_open(){
auto h = (player_pipeline_handle_t)pvPortMalloc(sizeof(player_pipeline_t));
h->task = nullptr;
h->src_rate = 16000;
auto codec = Board::GetInstance().GetAudioCodec();
h->dest_rate = codec->output_sample_rate();
h->channels = codec->output_channels();
h->block_bytes = (h->src_rate/50)*sizeof(int16_t);
h->fade_total = h->dest_rate / 10; // 100ms淡入
h->fade_done = 0;
codec->EnableOutput(true);
return h;
}
void player_pipeline_run(player_pipeline_handle_t){ }
void player_pipeline_close(player_pipeline_handle_t h){
if(!h) return;
if (h->task) {
vTaskDelete(h->task);
}
auto codec = Board::GetInstance().GetAudioCodec();
codec->EnableOutput(false);
vPortFree(h);
}
int player_pipeline_get_default_read_size(player_pipeline_handle_t h){ return h? h->block_bytes: 0; }
int player_pipeline_write(player_pipeline_handle_t h, char *buffer, int buf_size){
if(!h || !buffer || buf_size<=0) return 0;
int in_samples = buf_size/sizeof(int16_t);
std::vector<int16_t> in(in_samples);
memcpy(in.data(), buffer, buf_size);
int out_samples = (int)((float)in_samples*h->dest_rate/h->src_rate);
std::vector<int16_t> out(out_samples);
resample_mono_nearest(in.data(), in_samples, h->src_rate, out.data(), out_samples, h->dest_rate);
if (h->fade_done < h->fade_total) {
int n = out_samples;
for (int i = 0; i < n; ++i) {
int done = h->fade_done + i;
float g = done < h->fade_total ? (float)done / (float)h->fade_total : 1.0f;
out[i] = lrint16((float)out[i] * g);
}
h->fade_done += n;
if (h->fade_done > h->fade_total) h->fade_done = h->fade_total;
}
auto codec = Board::GetInstance().GetAudioCodec();
if (h->channels == 2) {
std::vector<int16_t> stereo(out_samples * 2);
for (int i = 0, j = 0; i < out_samples; ++i) {
stereo[j++] = out[i];
stereo[j++] = out[i];
}
codec->OutputData(stereo);
} else {
codec->OutputData(out);
}
return buf_size;
}
void player_pipeline_write_play_buffer_flag(player_pipeline_handle_t){ }
void player_pipeline_set_src_rate(player_pipeline_handle_t h, int rate){
if (!h || rate <= 0) return;
h->src_rate = rate;
h->block_bytes = (h->src_rate/50)*sizeof(int16_t);
}