playing audio
parent
15980d347c
commit
b11c4ac0b8
|
@ -1,2 +1,3 @@
|
|||
/target
|
||||
*.m4a
|
||||
*.opus
|
||||
|
|
|
@ -88,6 +88,12 @@ version = "3.8.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.1.0"
|
||||
|
@ -421,6 +427,7 @@ name = "music_player"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"byteorder",
|
||||
"cpal",
|
||||
"ffmpeg-next",
|
||||
]
|
||||
|
|
|
@ -7,5 +7,6 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "1.0.45"
|
||||
byteorder = "1.4.3"
|
||||
cpal = "0.13.4"
|
||||
ffmpeg-next = "4.4.0"
|
||||
|
|
76
src/main.rs
76
src/main.rs
|
@ -1,4 +1,5 @@
|
|||
use std::{
|
||||
io::Cursor,
|
||||
sync::{
|
||||
Arc,
|
||||
Condvar,
|
||||
|
@ -13,6 +14,11 @@ use anyhow::{
|
|||
Result,
|
||||
};
|
||||
|
||||
use byteorder::{
|
||||
LittleEndian,
|
||||
ReadBytesExt,
|
||||
};
|
||||
|
||||
use cpal::traits::{
|
||||
DeviceTrait,
|
||||
HostTrait,
|
||||
|
@ -74,25 +80,35 @@ fn main () -> Result <()> {
|
|||
let pair2 = Arc::clone (&pair);
|
||||
|
||||
let thread_decoder = thread::spawn (move|| {
|
||||
/*
|
||||
Pipeline:
|
||||
- demuxer
|
||||
- decoder
|
||||
- resampler
|
||||
- cpal
|
||||
*/
|
||||
|
||||
let (lock, cvar) = &*pair2;
|
||||
|
||||
let freq = 75;
|
||||
let period = SAMPLE_RATE / freq;
|
||||
let mut input_ctx = ffmpeg_next::format::input (&"test.m4a")?;
|
||||
let stream = input_ctx
|
||||
.streams ()
|
||||
.best (ffmpeg_next::media::Type::Audio)
|
||||
.ok_or_else (|| anyhow! ("can't find good audio stream"))?;
|
||||
let best_stream_idx = stream.index ();
|
||||
|
||||
let mut saw_counter = 0;
|
||||
let mut decoder = stream.codec ().decoder ().audio ()?;
|
||||
let mut resampler = decoder.resampler (
|
||||
ffmpeg_next::util::format::sample::Sample::F32 (
|
||||
ffmpeg_next::util::format::sample::Type::Packed,
|
||||
),
|
||||
ffmpeg_next::util::channel_layout::ChannelLayout::STEREO,
|
||||
48000,
|
||||
)?;
|
||||
let mut frame = ffmpeg_next::util::frame::Audio::empty ();
|
||||
let mut packets = input_ctx.packets ();
|
||||
|
||||
loop {
|
||||
let mut buffer = vec! [0.0f32; 4000];
|
||||
|
||||
for x in &mut buffer {
|
||||
*x = 0.25 * (saw_counter as f32 * 2.0 / period as f32 - 1.0);
|
||||
|
||||
saw_counter += 1;
|
||||
if saw_counter >= period {
|
||||
saw_counter = 0
|
||||
}
|
||||
}
|
||||
|
||||
// eprintln! ("decode thread parking");
|
||||
|
||||
let mut pcm_buffers = cvar.wait_while (lock.lock ().unwrap (), |pcm_buffers| {
|
||||
|
@ -100,10 +116,40 @@ fn main () -> Result <()> {
|
|||
pcm_buffers.samples_available () >= 48_000
|
||||
}).unwrap ();
|
||||
|
||||
// dbg! (pcm_buffers.samples_available ());
|
||||
let mut did_anything = false;
|
||||
|
||||
|
||||
|
||||
while decoder.receive_frame (&mut frame).is_ok () {
|
||||
did_anything = true;
|
||||
let mut buffer = vec! [0.0f32; frame.plane::<f32> (0).len () * 2];
|
||||
|
||||
let mut rdr_left = frame.plane::<f32> (0).iter ();
|
||||
let mut rdr_right = frame.plane::<f32> (1).iter ();
|
||||
|
||||
for x in buffer.chunks_mut (2) {
|
||||
x [0] = *rdr_left.next ().unwrap ();
|
||||
x [1] = *rdr_right.next ().unwrap ();
|
||||
}
|
||||
|
||||
pcm_buffers.produce (buffer);
|
||||
}
|
||||
|
||||
match packets.next () {
|
||||
None => {},
|
||||
Some ((stream, packet)) => {
|
||||
did_anything = true;
|
||||
if stream.index () == best_stream_idx {
|
||||
decoder.send_packet (&packet)?;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
if ! did_anything {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok::<_, anyhow::Error> (())
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue