Skip to content

Commit 1945c8b

Browse files
committed
feat: load audio in chunks
1 parent f44c375 commit 1945c8b

2 files changed

Lines changed: 147 additions & 83 deletions

File tree

‎player/src/audio.rs‎

Lines changed: 126 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,38 @@ use symphonia::core::errors::Error as SymphoniaError;
1111
use symphonia::core::formats::FormatOptions;
1212
use symphonia::core::io::MediaSourceStream;
1313
use symphonia::core::meta::MetadataOptions;
14-
use symphonia::core::probe::Hint;
14+
use symphonia::core::probe::{Hint, ProbeResult};
1515

1616
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
17-
use cpal::{Data, PlayStreamError, Sample, SampleFormat, Stream};
17+
use cpal::{Sample, Stream};
1818
use rubato::{FftFixedIn, Resampler};
1919

20-
pub struct Track {
21-
pub samples: Arc<Vec<f32>>,
22-
pub sample_rate: u32,
23-
pub channel_count: usize,
24-
pub position: usize,
20+
type Ringbuf<T> = LocalRb<T, Vec<MaybeUninit<T>>>;
21+
22+
pub struct AudioReader {
23+
probe_result: ProbeResult,
24+
decoder: Box<dyn symphonia::core::codecs::Decoder>,
2525
encoder: Encoder,
26+
27+
buffer: Ringbuf<f32>,
28+
29+
position: usize, // we might not actually need this for anything now?
30+
finished: bool,
31+
32+
// not read until the first packet
33+
sample_rate: Option<u32>,
34+
channel_count: Option<usize>,
2635
}
2736

28-
impl Track {
37+
impl AudioReader {
2938
pub fn load(path: &str) -> Result<Self, Box<dyn Error>> {
3039
let src = std::fs::File::open(path)?;
3140

3241
let mss = MediaSourceStream::new(Box::new(src), Default::default());
3342

34-
let mut hint = Hint::new();
35-
//hint.with_extension("mp3");
36-
37-
let mut samples_not_interleaved: Option<Vec<Vec<f32>>> = None;
38-
let mut sample_rate: u32 = 0;
39-
let mut channel_count: usize = 0;
43+
let hint = Hint::new();
4044

41-
let mut probe_result = symphonia::default::get_probe()
45+
let probe_result = symphonia::default::get_probe()
4246
.format(
4347
&hint,
4448
mss,
@@ -50,7 +54,7 @@ impl Track {
5054
)
5155
.unwrap();
5256

53-
let mut decoder = symphonia::default::get_codecs()
57+
let decoder = symphonia::default::get_codecs()
5458
.make(
5559
&probe_result
5660
.format
@@ -61,59 +65,100 @@ impl Track {
6165
)
6266
.unwrap();
6367

64-
println!("loading into memory...");
68+
let encoder =
69+
opus::Encoder::new(48000, opus::Channels::Stereo, opus::Application::Audio).unwrap();
70+
//encoder.set_bitrate(opus::Bitrate::Bits(256)).unwrap();
71+
72+
Ok(Self {
73+
probe_result,
74+
decoder,
75+
encoder,
76+
77+
buffer: Ringbuf::new(16384),
78+
79+
position: 0,
80+
finished: false,
81+
82+
sample_rate: None,
83+
channel_count: None,
84+
})
85+
}
86+
87+
// Ok(true) if there's more to read
88+
fn read_packets(&mut self) -> Result<bool, Box<dyn Error>> {
89+
println!("read_packet() called");
90+
91+
let mut has_more = true;
92+
let mut channel_samples: Vec<Vec<f32>> = vec![Vec::new(); self.channel_count.unwrap_or(0)];
93+
let mut sample_count = 0;
6594

6695
loop {
67-
match probe_result.format.next_packet() {
96+
match self.probe_result.format.next_packet() {
6897
Ok(packet) => {
69-
let decoded = decoder.decode(&packet).unwrap();
98+
let decoded = self.decoder.decode(&packet).unwrap();
7099
let spec = *decoded.spec();
71-
let song_samples = match &mut samples_not_interleaved {
72-
Some(s) => Some(s),
73-
None => {
74-
samples_not_interleaved = Some(vec![Vec::new(); spec.channels.count()]);
75-
sample_rate = spec.rate;
76-
channel_count = spec.channels.count();
77-
samples_not_interleaved.as_mut()
78-
}
100+
101+
if self.sample_rate == None {
102+
self.sample_rate = Some(spec.rate);
103+
}
104+
if self.channel_count == None {
105+
self.channel_count = Some(spec.channels.count());
106+
107+
// we probably also need to allocate channel_samples now since this is the 1st packet we're processing
108+
channel_samples = vec![Vec::new(); spec.channels.count()];
79109
}
80-
.unwrap();
81110

82111
if decoded.frames() > 0 {
83-
let mut samples: SampleBuffer<f32> =
112+
let mut sample_buffer: SampleBuffer<f32> =
84113
SampleBuffer::new(decoded.frames() as u64, spec);
85114

86-
samples.copy_interleaved_ref(decoded);
87-
for frame in samples.samples().chunks(spec.channels.count()) {
115+
sample_buffer.copy_interleaved_ref(decoded);
116+
117+
let samples = sample_buffer.samples();
118+
119+
println!("packet had {:?}", samples.len());
120+
sample_count += samples.len();
121+
122+
for frame in samples.chunks(spec.channels.count()) {
88123
for (chan, sample) in frame.iter().enumerate() {
89-
song_samples[chan].push(*sample)
124+
channel_samples[chan].push(*sample)
90125
}
91126
}
92127
} else {
93128
eprintln!("Empty packet encountered while loading song!");
94129
}
95130
}
96-
Err(SymphoniaError::IoError(_)) => break,
131+
Err(SymphoniaError::IoError(_)) => {
132+
// no more packets
133+
has_more = false;
134+
break;
135+
}
97136
Err(e) => return Err("failed to parse track".into()),
98137
}
138+
139+
// we should stop after a reasonable number of samples
140+
// (a reasonable number --> nobody knows)
141+
// we probably want more than 960 so we can resample enough at once (does that matter?)
142+
if sample_count >= 2048 {
143+
break;
144+
}
99145
}
100146

101147
println!("resampling....");
102148

103149
// resample to standard 48000 if needed
104-
let samples_correct_rate = if sample_rate != 48000 {
105-
let l = samples_not_interleaved.as_ref().unwrap()[0].len().clone();
150+
let samples_correct_rate = if self.sample_rate.unwrap() != 48000 {
151+
let l = channel_samples[0].len();
106152
let mut resampler =
107-
FftFixedIn::<f32>::new(sample_rate as usize, 48000, l, 100, 2).unwrap();
153+
FftFixedIn::<f32>::new(self.sample_rate.unwrap() as usize, 48000, l, 100, 2)
154+
.unwrap();
108155

109-
resampler
110-
.process(&samples_not_interleaved.unwrap(), None)
111-
.unwrap()
156+
resampler.process(&channel_samples, None).unwrap()
112157
} else {
113-
samples_not_interleaved.unwrap()
158+
channel_samples
114159
};
115160

116-
println!("interlacing....");
161+
println!("interleaving....");
117162

118163
// now we have to interleave it since we had to use the resampling thing
119164
let samples: Vec<f32> = samples_correct_rate[0]
@@ -123,38 +168,42 @@ impl Track {
123168
.copied()
124169
.collect();
125170

126-
// it would be really sick to do all that at once (while reading it)
127-
// but since we read like.. 2 samples at a time idk how
128-
// the way it is it's just too slow for anything realistically-sized
171+
println!(
172+
"copying {:?} samples to the buffer which has {:?} free",
173+
samples.len(),
174+
self.buffer.free_len()
175+
);
129176

130-
let mut encoder =
131-
opus::Encoder::new(48000, opus::Channels::Stereo, opus::Application::Audio).unwrap();
132-
//encoder.set_bitrate(opus::Bitrate::Bits(256)).unwrap();
133-
Ok(Self {
134-
samples: Arc::new(samples),
135-
sample_rate,
136-
channel_count,
137-
position: 0,
138-
encoder,
139-
})
177+
for sample in samples.iter() {
178+
self.buffer.push(*sample).unwrap();
179+
}
180+
181+
Ok(has_more)
140182
}
141183

142184
pub fn encode_frame(&mut self) -> Result<AudioFrame, ()> {
143-
const pcm_length: usize = 960;
144-
145-
if pcm_length * (self.position + 1) >= self.samples.len() {
146-
println!(
147-
"encode_frame was about to run out of samples at pos {}",
148-
self.position
149-
);
150-
return Err(());
185+
const PCM_LENGTH: usize = 960;
186+
187+
// we don't have enough samples buffered to encode an opus frame, read more packets
188+
if self.buffer.len() < PCM_LENGTH {
189+
if let Ok(has_more) = self.read_packets() {
190+
if !has_more {
191+
// no more packets, fill with 0s until we have a multiple of 960 frames
192+
while self.buffer.len() % 960 != 0 {
193+
self.buffer.push(0.0).unwrap();
194+
}
195+
196+
self.finished = true;
197+
}
198+
} else {
199+
// unrecoverable error?
200+
return Err(());
201+
}
151202
}
152203

153-
let mut pcm = [0.0; pcm_length];
204+
let mut pcm = [0.0; PCM_LENGTH];
154205

155-
for i in 0..pcm_length {
156-
pcm[i] = self.samples[i + pcm_length * self.position];
157-
}
206+
self.buffer.pop_slice(&mut pcm);
158207

159208
let x = self.encoder.encode_vec_float(&pcm, 256).unwrap();
160209
self.position += 1;
@@ -164,20 +213,22 @@ impl Track {
164213
data: x,
165214
})
166215
}
167-
}
168216

169-
type Ringbuf = LocalRb<f32, Vec<MaybeUninit<f32>>>;
217+
pub fn finished(&self) -> bool {
218+
self.finished
219+
}
220+
}
170221

171222
pub struct Player {
172223
decoder: Decoder,
173-
buffer: Arc<Mutex<Ringbuf>>,
224+
buffer: Arc<Mutex<Ringbuf<f32>>>,
174225
stream: Option<Stream>,
175226
}
176227
impl Player {
177228
pub fn new() -> Self {
178229
Self {
179230
decoder: Decoder::new(48000, opus::Channels::Stereo).unwrap(),
180-
buffer: Arc::new(Mutex::new(Ringbuf::new(48000 * 10))), // 10s??
231+
buffer: Arc::new(Mutex::new(Ringbuf::<f32>::new(48000 * 10))), // 10s??
181232
stream: None,
182233
}
183234
}
@@ -261,11 +312,15 @@ impl Player {
261312
fn write_audio<T: Sample>(
262313
out_data: &mut [f32],
263314
_: &cpal::OutputCallbackInfo,
264-
buffer_mutex: &Arc<Mutex<Ringbuf>>,
315+
buffer_mutex: &Arc<Mutex<Ringbuf<f32>>>,
265316
) {
266317
let mut buffer = buffer_mutex.lock().unwrap();
267318
if out_data.len() < buffer.len() {
268319
buffer.pop_slice(out_data);
320+
321+
for sample in out_data.iter_mut() {
322+
*sample = *sample * 0.1;
323+
}
269324
} else {
270325
// uhhhh
271326
println!("write_audio: buffer underrun!! (but no panic)");

‎player/src/main.rs‎

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ use tokio::time::timeout;
77
use tokio::{net::TcpStream, sync::mpsc};
88

99
mod audio;
10-
use audio::Track;
11-
12-
// use cpal::traits::{DeviceTrait, HostTrait};
13-
10+
use audio::AudioReader;
1411
struct Connection {
1512
stream: FrameStream,
1613
my_id: String,
@@ -97,8 +94,11 @@ impl Connection {
9794
None
9895
}
9996
} else if line.starts_with("c ") {
100-
let mut c = line.split_ascii_whitespace().into_iter().collect::<Vec<&str>>();
101-
if c.len() < 2{
97+
let mut c = line
98+
.split_ascii_whitespace()
99+
.into_iter()
100+
.collect::<Vec<&str>>();
101+
if c.len() < 2 {
102102
None
103103
} else {
104104
c.remove(0);
@@ -182,13 +182,11 @@ impl Connection {
182182

183183
self.play_state = PlayState::Transmitting;
184184
tokio::spawn(async move {
185-
let mut t: Track = match Track::load(&path) {
185+
let mut t: AudioReader = match AudioReader::load(&path) {
186186
Ok(t) => t,
187-
Err(_) => return
187+
Err(_) => return,
188188
};
189189

190-
191-
dbg!(&t.samples.len());
192190
audio_tx_2.send(AudioData::Clear).unwrap();
193191
audio_tx_2.send(AudioData::Start).unwrap();
194192

@@ -199,16 +197,21 @@ impl Connection {
199197
.unwrap();
200198

201199
let mut interval = tokio::time::interval(tokio::time::Duration::from_millis(200));
202-
while (t.position + 1) * 960 < t.samples.len() {
200+
loop {
203201
// ok let's actually do the math for this
204202
// each frame is 960 samples
205203
// at 48k that means it's 20ms per frame
206204
// SO we need to send a frame at least every 20ms.
207205
// i think.................
208206
// LOL OK it's two frames idk why maybe because it's stereo interleaved??????
209207
interval.tick().await;
210-
208+
211209
for _ in 0..20 {
210+
// stop in the middle of this "tick" of 20 frames
211+
if t.finished() {
212+
break;
213+
};
214+
212215
let f = t.encode_frame();
213216
if let Ok(frame) = f {
214217
audio_tx_2.send(AudioData::Frame(frame.clone())).unwrap();
@@ -217,8 +220,14 @@ impl Connection {
217220
break; // we're done i guess
218221
}
219222
}
223+
224+
// we encoded the entire file
225+
if t.finished() {
226+
break;
227+
};
220228
}
221229

230+
// TODO: should be "End"? and should finish playing without stopping immediately
222231
audio_tx_2.send(AudioData::Stop).unwrap();
223232
message_tx_2
224233
.send(Message::PlaybackState(PlaybackState {

0 commit comments

Comments
 (0)