Невозможно записать звук с помощью cpal и закодировать с помощью 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);
}

person user3756718    schedule 26.12.2020    source источник


Ответы (2)


Похоже, вы записываете необработанные аудиокадры в файл, что, скорее всего, не то, что вы ищете. Большинство аудиофайлов - это не просто необработанные данные, они используют аудиоконтейнер с заголовком и другими функциями. Для Opus вы, скорее всего, захотите использовать контейнер Ogg для простого сохранения звука в файл ( в отличие, например, от потоковой передачи).

person Coder-256    schedule 26.12.2020
comment
Моей конечной целью было добраться до точки, когда я могу просто отправлять аудиоданные по сети и просто воспроизводить их на другом конце. Мне все еще нужно это делать, или мне все равно понадобится контейнер ogg. - person user3756718; 27.12.2020
comment
Трудно сказать без общей картины - person Coder-256; 27.12.2020

Я обнаружил, что проблема заключается в неправильном понимании того, как работает opus. Кажется, он работает четко по частям, а не в потоке ввода. Итак, я пошел дальше и начал передавать их по сети, и когда я вставил точные выходные блоки, все заработало отлично!

person user3756718    schedule 05.01.2021