Rust библиотека rodio не запускает mp3, ogg файлы
Хочу запускать музыку через программу на rust. При вводе файла с расширением .wav все прекрасно работает, но вот если это будет mp3, ogg, то выдает такую ошибку:
Введите путь до файла
muse.ogg
thread 'main' panicked at library/core/src/panicking.rs:218:5:
unsafe precondition(s) violated: slice::get_unchecked_mut requires that the index is within the slice
This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread caused non-unwinding panic. aborting.
[1] 10663 IOT instruction (core dumped) cargo run src/main.rs
use rodio::{Decoder, OutputStream, Source};
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::thread;
use std::time::Duration;
fn main() {
create_device();
}
fn create_device() {
let (_stream, stream_handle) =
OutputStream::try_default().expect("Не удалось найти поток вывода");
println!("Введите путь до файла");
let path = get_file_path();
let source = listen_file(&path);
let duration = duration_to_u64(get_audio_duration(&source));
match stream_handle.play_raw(source.convert_samples()) {
Ok(()) => {
println!("Длина композиции: {:?} секунд", duration);
}
Err(e) => {
eprintln!("Ошибка воспроизведения {}", e);
}
}
thread::sleep(Duration::from_secs(duration));
}
fn get_audio_duration(file: &Decoder<BufReader<File>>) -> Option<Duration> {
file.total_duration()
}
fn duration_to_u64(opt: Option<Duration>) -> u64 {
match opt {
Some(dur) => dur.as_secs() as u64,
None => 0,
}
}
fn listen_file(path: &str) -> Decoder<BufReader<File>> {
let file = File::open(path).expect("Файл не найден");
rodio::Decoder::new(BufReader::new(file)).expect("Ошибка декодирования")
}
fn get_file_path() -> String {
let mut path = String::new();
io::stdin()
.read_line(&mut path)
.expect("Что ты блять ввел?");
path.trim().to_string()
}
Не понимаю, что с этим вообще делать
Ответы (1 шт):
У меня не получилось воспроизвести вашу проблему.
Я собрал приложение с rustc 1.78.0 и rodio v0.20.1
код не работает, но не по той причине, по которой вы пишете.
- декодер для OGG возвращает длительность None.
- получается что в
thread::sleep(Duration::from_secs(duration));стоит 0 секунд и приложение завершается раньше, чем издаёт хотя бы один звук.
Я заменил длительность на фиксированное значение, и файл заиграл. Я скачал из интернета простой бип-бип, и приложение его успешно вопроизвело
use rodio::{Decoder, OutputStream, Source};
use std::fs::File;
use std::{io};
use std::io::BufReader;
use std::thread;
use std::time::Duration;
fn main() {
let path = get_path();
create_device(path.as_str());
}
fn get_path() -> String {
let args: Vec<String> = std::env::args().collect();
if args.len() > 1 {
return args[1].clone();
}
println!("Введите путь до файла");
return read_file_path();
}
fn create_device(path: &str) {
let (_stream, stream_handle) =
OutputStream::try_default().expect("Не удалось найти поток вывода");
let source = listen_file(&path);
// let duration = (get_audio_duration(&source));
let duration = 123;
match stream_handle.play_raw(source.convert_samples()) {
Ok(()) => {
println!("Длина композиции: {:?} секунд", duration);
}
Err(e) => {
eprintln!("Ошибка воспроизведения {}", e);
}
}
thread::sleep(Duration::from_secs(duration));
}
fn get_audio_duration(file: &Decoder<BufReader<File>>) -> Option<Duration> {
file.total_duration()
}
fn duration_to_u64(opt: Option<Duration>) -> u64 {
match opt {
Some(dur) => dur.as_secs() as u64,
None => 0,
}
}
fn listen_file(path: &str) -> Decoder<BufReader<File>> {
let file = BufReader::new(File::open(path).unwrap());
rodio::Decoder::new(file).expect("Ошибка декодирования")
}
fn read_file_path() -> String {
let mut path = String::new();
io::stdin()
.read_line(&mut path)
.expect("Что ты блять ввел?");
path.trim().to_string()
}
Затем я посмотрел, зачем вы используете duration, погуглил немного и обнаружил тип Sink, в котором есть метод sleep_until_end, чтобы дождаться конца воспроизведения.
С Sink всё получилось легко и непринуждённо
use rodio::{Decoder, OutputStream, Sink};
use std::fs::File;
use std::{io};
use std::io::BufReader;
fn main() {
let path = get_path();
play_file(path.as_str());
}
fn play_file(path: &str) {
let (_stream, stream_handle) =
OutputStream::try_default().expect("Не удалось найти поток вывода");
let source = new_decoder(&path);
let sink = Sink::try_new(&stream_handle).expect("Не удалось создать sink");
sink.append(source);
sink.sleep_until_end();
}
fn new_decoder(path: &str) -> Decoder<BufReader<File>> {
let file = BufReader::new(File::open(path).unwrap());
rodio::Decoder::new(file).expect("Ошибка декодирования")
}
fn get_path() -> String {
let args: Vec<String> = std::env::args().collect();
if args.len() > 1 {
return args[1].clone();
}
println!("Введите путь до файла");
let mut path = String::new();
io::stdin()
.read_line(&mut path)
.expect("?");
path.trim().to_string()
}
Работает, не падает.