playing audio
parent
15980d347c
commit
b11c4ac0b8
|
@ -1,2 +1,3 @@
|
||||||
/target
|
/target
|
||||||
|
*.m4a
|
||||||
*.opus
|
*.opus
|
||||||
|
|
|
@ -88,6 +88,12 @@ version = "3.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
|
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -421,6 +427,7 @@ name = "music_player"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"byteorder",
|
||||||
"cpal",
|
"cpal",
|
||||||
"ffmpeg-next",
|
"ffmpeg-next",
|
||||||
]
|
]
|
||||||
|
|
|
@ -7,5 +7,6 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.45"
|
anyhow = "1.0.45"
|
||||||
|
byteorder = "1.4.3"
|
||||||
cpal = "0.13.4"
|
cpal = "0.13.4"
|
||||||
ffmpeg-next = "4.4.0"
|
ffmpeg-next = "4.4.0"
|
||||||
|
|
78
src/main.rs
78
src/main.rs
|
@ -1,4 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
io::Cursor,
|
||||||
sync::{
|
sync::{
|
||||||
Arc,
|
Arc,
|
||||||
Condvar,
|
Condvar,
|
||||||
|
@ -13,6 +14,11 @@ use anyhow::{
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use byteorder::{
|
||||||
|
LittleEndian,
|
||||||
|
ReadBytesExt,
|
||||||
|
};
|
||||||
|
|
||||||
use cpal::traits::{
|
use cpal::traits::{
|
||||||
DeviceTrait,
|
DeviceTrait,
|
||||||
HostTrait,
|
HostTrait,
|
||||||
|
@ -74,25 +80,35 @@ fn main () -> Result <()> {
|
||||||
let pair2 = Arc::clone (&pair);
|
let pair2 = Arc::clone (&pair);
|
||||||
|
|
||||||
let thread_decoder = thread::spawn (move|| {
|
let thread_decoder = thread::spawn (move|| {
|
||||||
|
/*
|
||||||
|
Pipeline:
|
||||||
|
- demuxer
|
||||||
|
- decoder
|
||||||
|
- resampler
|
||||||
|
- cpal
|
||||||
|
*/
|
||||||
|
|
||||||
let (lock, cvar) = &*pair2;
|
let (lock, cvar) = &*pair2;
|
||||||
|
|
||||||
let freq = 75;
|
let mut input_ctx = ffmpeg_next::format::input (&"test.m4a")?;
|
||||||
let period = SAMPLE_RATE / freq;
|
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 {
|
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");
|
// eprintln! ("decode thread parking");
|
||||||
|
|
||||||
let mut pcm_buffers = cvar.wait_while (lock.lock ().unwrap (), |pcm_buffers| {
|
let mut pcm_buffers = cvar.wait_while (lock.lock ().unwrap (), |pcm_buffers| {
|
||||||
|
@ -100,8 +116,38 @@ fn main () -> Result <()> {
|
||||||
pcm_buffers.samples_available () >= 48_000
|
pcm_buffers.samples_available () >= 48_000
|
||||||
}).unwrap ();
|
}).unwrap ();
|
||||||
|
|
||||||
// dbg! (pcm_buffers.samples_available ());
|
let mut did_anything = false;
|
||||||
pcm_buffers.produce (buffer);
|
|
||||||
|
|
||||||
|
|
||||||
|
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> (())
|
Ok::<_, anyhow::Error> (())
|
||||||
|
|
Loading…
Reference in New Issue