无法使用 cpal 录制音频并使用 opus 进行编码。总是创建不正确的文件
Unable to record audio with cpal and encode with opus. Always creates improper file
我已经工作了几个小时,试图简单地从我的麦克风录制音频并用 opus 对其进行编码,以便我最终可以将其流式传输并在其他地方播放。目前,我正在努力尝试让它简单地播放一个文件。我在很大程度上基于 cpal 示例以及 libopus c 示例。目前,它只是输出一个 VLC 甚至无法读取的无意义文件。但是,如果我在编码时打印原始字节,我可以肯定地知道发生了什么。我也试过弄乱字节序,但它根本不起作用。我也一直在使用 rubato 将原始输出重新采样为作品可以使用的方式。
fn main() -> Result<(), anyhow::Error> {
let mut encoder = opus::Encoder::new(48000, opus::Channels::Stereo, opus::Application::Voip).unwrap();
let mut resampler = rubato::FftFixedInOut::<f32>::new(44100, 48000, 896, 2);
let host = cpal::default_host();
let device = host.default_input_device().unwrap();
println!("Input device: {}", device.name()?);
let config = device
.default_input_config()
.expect("Failed to get default input config");
println!("Default input config: {:?}", config);
println!("Begin recording...");
let err_fn = move |err| {
eprintln!("an error occurred on stream: {}", err);
};
let sample_format = config.sample_format();
// let socket = std::net::UdpSocket::bind("192.168.1.82:1337")?;
const PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/recorded.pcm");
let socket = std::fs::File::create(PATH).unwrap();
let mut socket = BufWriter::new(socket);
let stream = device
.build_input_stream_raw(
&config.into(),
sample_format,
move |data, _: &_| write_input_data_f32(data, &mut encoder, &mut resampler, &mut socket),
err_fn,
)
.unwrap();
stream.play()?;
std::thread::sleep(std::time::Duration::from_secs(10));
drop(stream);
Ok(())
}
type ResamplerHandle = rubato::FftFixedInOut<f32>;
// type SocketHandle = std::net::UdpSocket;
type SocketHandle = BufWriter<std::fs::File>;
fn write_input_data_f32(
input: &Data,
encoder: &mut Encoder,
resampler: &mut ResamplerHandle,
socket: &mut SocketHandle,
) {
let mut inp = input.as_slice::<f32>().unwrap().to_vec();
inp.truncate(resampler.nbr_frames_needed());
if inp.len() < resampler.nbr_frames_needed() {
inp.append(&mut vec![0f32; resampler.nbr_frames_needed() - inp.len()]);
}
let mut wave_out = resampler.process(&vec![Vec::from(inp); 2]).unwrap();//[0].to_owned();
use itertools::interleave;
let v1 = wave_out[0].to_owned();
let v2 = wave_out[1].to_owned();
let v = interleave(v1.chunks(1), v2.chunks(1)).flatten().copied().collect::<Vec<f32>>();
let buff = encoder.encode_vec_float(v.as_slice(), 960).unwrap();
use std::io::Write;
socket.write(&buff);
}
您似乎正在将原始音频帧写入文件,这很可能不是您要查找的文件。大多数音频文件不仅仅是原始数据,它们使用具有 header 和其他功能的音频容器。对于 Opus,您很可能希望使用 Ogg container 来简单地将音频保存到文件中(而不是例如流式传输)。
我发现这个问题是对 opus 工作方式的误解。它似乎在块中明显工作,而不是输入流。所以我继续并开始通过网络流式传输它们,当我输入准确的输出块时,它完美地工作了!
我已经工作了几个小时,试图简单地从我的麦克风录制音频并用 opus 对其进行编码,以便我最终可以将其流式传输并在其他地方播放。目前,我正在努力尝试让它简单地播放一个文件。我在很大程度上基于 cpal 示例以及 libopus c 示例。目前,它只是输出一个 VLC 甚至无法读取的无意义文件。但是,如果我在编码时打印原始字节,我可以肯定地知道发生了什么。我也试过弄乱字节序,但它根本不起作用。我也一直在使用 rubato 将原始输出重新采样为作品可以使用的方式。
fn main() -> Result<(), anyhow::Error> {
let mut encoder = opus::Encoder::new(48000, opus::Channels::Stereo, opus::Application::Voip).unwrap();
let mut resampler = rubato::FftFixedInOut::<f32>::new(44100, 48000, 896, 2);
let host = cpal::default_host();
let device = host.default_input_device().unwrap();
println!("Input device: {}", device.name()?);
let config = device
.default_input_config()
.expect("Failed to get default input config");
println!("Default input config: {:?}", config);
println!("Begin recording...");
let err_fn = move |err| {
eprintln!("an error occurred on stream: {}", err);
};
let sample_format = config.sample_format();
// let socket = std::net::UdpSocket::bind("192.168.1.82:1337")?;
const PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/recorded.pcm");
let socket = std::fs::File::create(PATH).unwrap();
let mut socket = BufWriter::new(socket);
let stream = device
.build_input_stream_raw(
&config.into(),
sample_format,
move |data, _: &_| write_input_data_f32(data, &mut encoder, &mut resampler, &mut socket),
err_fn,
)
.unwrap();
stream.play()?;
std::thread::sleep(std::time::Duration::from_secs(10));
drop(stream);
Ok(())
}
type ResamplerHandle = rubato::FftFixedInOut<f32>;
// type SocketHandle = std::net::UdpSocket;
type SocketHandle = BufWriter<std::fs::File>;
fn write_input_data_f32(
input: &Data,
encoder: &mut Encoder,
resampler: &mut ResamplerHandle,
socket: &mut SocketHandle,
) {
let mut inp = input.as_slice::<f32>().unwrap().to_vec();
inp.truncate(resampler.nbr_frames_needed());
if inp.len() < resampler.nbr_frames_needed() {
inp.append(&mut vec![0f32; resampler.nbr_frames_needed() - inp.len()]);
}
let mut wave_out = resampler.process(&vec![Vec::from(inp); 2]).unwrap();//[0].to_owned();
use itertools::interleave;
let v1 = wave_out[0].to_owned();
let v2 = wave_out[1].to_owned();
let v = interleave(v1.chunks(1), v2.chunks(1)).flatten().copied().collect::<Vec<f32>>();
let buff = encoder.encode_vec_float(v.as_slice(), 960).unwrap();
use std::io::Write;
socket.write(&buff);
}
您似乎正在将原始音频帧写入文件,这很可能不是您要查找的文件。大多数音频文件不仅仅是原始数据,它们使用具有 header 和其他功能的音频容器。对于 Opus,您很可能希望使用 Ogg container 来简单地将音频保存到文件中(而不是例如流式传输)。
我发现这个问题是对 opus 工作方式的误解。它似乎在块中明显工作,而不是输入流。所以我继续并开始通过网络流式传输它们,当我输入准确的输出块时,它完美地工作了!