Skip to content

Commit 074b111

Browse files
committed
fix: play until the end more correctly
1 parent 1dbca52 commit 074b111

2 files changed

Lines changed: 131 additions & 85 deletions

File tree

player/src/audio.rs

Lines changed: 128 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
use std::mem::MaybeUninit;
22
use std::sync::{Arc, Mutex};
3+
use std::time::Duration;
34

45
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
56
use cpal::Stream;
67
use opus::Decoder;
8+
use ringbuf::ring_buffer::RbBase;
79
use ringbuf::{LocalRb, Rb};
810
use tokio::sync::mpsc;
11+
use tokio::time::{Instant, Interval};
912

1013
use protocol::AudioData;
1114

@@ -112,16 +115,9 @@ impl Player {
112115
self.last_frame = None;
113116
}
114117

115-
pub fn finish(&mut self) -> bool {
116-
{
117-
let buffer = self.buffer.lock().unwrap();
118-
if buffer.len() > 1024 {
119-
// we will lose a tiny bit but
120-
return false;
121-
}
122-
}
123-
self.pause();
124-
true
118+
pub fn is_empty(&mut self) -> bool {
119+
let buffer = self.buffer.lock().unwrap();
120+
buffer.is_empty()
125121
}
126122

127123
pub fn is_started(&self) -> bool {
@@ -189,16 +185,20 @@ fn write_audio(
189185
) {
190186
let mut buffer = buffer_mutex.lock().unwrap();
191187
let vol = volume_mutex.lock().unwrap();
192-
if out_data.len() < buffer.len() {
193-
buffer.pop_slice(out_data);
194188

195-
for sample in out_data.iter_mut() {
196-
*sample = *sample * *vol; // lol
197-
}
198-
} else {
199-
// uhhhh
200-
println!("write_audio: buffer underrun!! (but no panic)");
189+
let fill_zeros = out_data.len().saturating_sub(buffer.len());
190+
if fill_zeros > 0 {
191+
println!("write_audio: buffer underrun, filling with zeros");
192+
193+
buffer.push_slice(&vec![0.0; fill_zeros]);
194+
}
195+
196+
buffer.pop_slice(out_data);
197+
198+
for sample in out_data.iter_mut() {
199+
*sample = *sample * *vol; // lol
201200
}
201+
202202
if buffer.len() < 12000 {
203203
// TODO: actually fix this......
204204
println!("write_audio: buffer has {} left", buffer.len());
@@ -238,6 +238,15 @@ pub struct AudioThread {
238238

239239
wants_play: bool,
240240
paused: bool,
241+
242+
finish_interval: Option<Interval>,
243+
}
244+
245+
async fn maybe_interval_tick(maybe_interval: &mut Option<Interval>) -> Option<Instant> {
246+
match maybe_interval {
247+
Some(interval) => Some(interval.tick().await),
248+
None => None,
249+
}
241250
}
242251

243252
impl AudioThread {
@@ -250,8 +259,14 @@ impl AudioThread {
250259
let audio_status_tx = audio_status_tx.to_owned();
251260

252261
std::thread::spawn(move || {
262+
let rt = tokio::runtime::Builder::new_current_thread()
263+
.enable_time()
264+
.build()
265+
.unwrap();
266+
253267
let mut t = AudioThread::new(audio_rx, audio_status_tx);
254-
t.run();
268+
269+
rt.block_on(t.run());
255270
});
256271

257272
AudioThreadHandle { tx: audio_tx }
@@ -268,86 +283,124 @@ impl AudioThread {
268283

269284
wants_play: false,
270285
paused: false,
286+
287+
finish_interval: None,
271288
}
272289
}
273290

274-
fn run(&mut self) {
275-
while let Some(data) = self.rx.blocking_recv() {
276-
match data {
277-
AudioCommand::AudioData(d) => match d {
278-
AudioData::Frame(frame) => {
279-
if frame.frame % 10 == 0 {
280-
let _ = self
281-
.tx
282-
.send(AudioStatus::Elapsed(self.p.get_seconds_elapsed()));
283-
let _ = self.tx.send(AudioStatus::Buffer(self.p.buffer_status()));
291+
async fn run(&mut self) {
292+
loop {
293+
tokio::select! {
294+
Some(command) = self.rx.recv() => {
295+
match command {
296+
AudioCommand::Shutdown => {
297+
break;
284298
}
299+
_ => self.handle_command(command).await,
300+
}
301+
302+
if self.p.is_ready() && self.wants_play && !self.paused {
303+
self.wants_play = false;
285304

286-
self.p.receive(frame.data, frame.frame);
305+
let _ = self.tx.send(AudioStatus::Buffering(false));
287306

288-
if let Some(samples) = self.p.get_visualizer_buffer() {
289-
let bars = calculate_visualizer(&samples);
290-
let _ = self.tx.send(AudioStatus::Visualizer(bars));
307+
if !self.p.is_started() {
308+
self.p.start()
309+
} else {
310+
self.p.resume()
291311
}
292312
}
293-
AudioData::Start => {
294-
self.wants_play = true;
295-
296-
// if we don't have enough buffer yet, wait
297-
// otherwise we had extra so we can just keep playing i guess?
298-
// TODO: maybe this threshold should be lower so we can catch up only when we're actually low instead of every time we get a little low??
299-
if !self.p.is_ready() {
300-
let _ = self.tx.send(AudioStatus::Buffering(true));
301-
302-
// if we're continuing from another song, pause until we have enough
303-
if self.p.is_started() {
304-
self.p.pause();
305-
}
306-
}
313+
}
314+
315+
Some(_) = maybe_interval_tick(&mut self.finish_interval) => {
316+
// fake tick the frame count at the same rate
317+
if let Some(prev) = self.p.last_frame {
318+
self.p.last_frame = Some(prev + 1);
307319
}
308-
AudioData::Finish => {
309-
// TODO: we probably shouldnt do this
310-
while !self.p.finish() {
311-
std::thread::sleep(std::time::Duration::from_millis(20));
312-
}
320+
321+
let _ = self
322+
.tx
323+
.send(AudioStatus::Elapsed(self.p.get_seconds_elapsed()));
324+
let _ = self.tx.send(AudioStatus::Buffer(self.p.buffer_status()));
325+
326+
if self.p.is_empty() {
327+
self.finish_interval = None;
328+
313329
self.p.pause();
330+
314331
let _ = self.tx.send(AudioStatus::Finished);
315332
}
316-
},
317-
AudioCommand::Clear => {
318-
let _ = self.tx.send(AudioStatus::Elapsed(0));
319-
self.p.clear();
320-
self.p.pause();
321333
}
322-
AudioCommand::Volume(val) => {
323-
self.p.volume(val);
334+
335+
else => {
336+
break
324337
}
325-
AudioCommand::Pause(paused) => {
326-
self.paused = paused;
327-
if paused {
338+
}
339+
}
340+
}
341+
342+
async fn handle_command(&mut self, data: AudioCommand) {
343+
match data {
344+
AudioCommand::AudioData(d) => match d {
345+
AudioData::Frame(frame) => {
346+
if frame.frame % 10 == 0 {
347+
let _ = self
348+
.tx
349+
.send(AudioStatus::Elapsed(self.p.get_seconds_elapsed()));
350+
let _ = self.tx.send(AudioStatus::Buffer(self.p.buffer_status()));
351+
}
352+
353+
self.p.receive(frame.data, frame.frame);
354+
355+
if let Some(samples) = self.p.get_visualizer_buffer() {
356+
let bars = calculate_visualizer(&samples);
357+
let _ = self.tx.send(AudioStatus::Visualizer(bars));
358+
}
359+
}
360+
AudioData::Start => {
361+
self.wants_play = true;
362+
self.finish_interval = None;
363+
364+
// if we don't have enough buffer yet, wait
365+
// otherwise we had extra so we can just keep playing i guess?
366+
// TODO: maybe this threshold should be lower so we can catch up only when we're actually low instead of every time we get a little low??
367+
if !self.p.is_ready() {
368+
let _ = self.tx.send(AudioStatus::Buffering(true));
369+
370+
// if we're continuing from another song, pause until we have enough
328371
if self.p.is_started() {
329372
self.p.pause();
330373
}
331-
} else {
332-
self.wants_play = true;
333374
}
334375
}
335-
AudioCommand::Shutdown => {
336-
break;
376+
377+
// start an interval to finish playing stuff
378+
AudioData::Finish => {
379+
let mut interval = tokio::time::interval(Duration::from_millis(10));
380+
// consume the first immediate tick
381+
interval.tick().await;
382+
self.finish_interval = Some(interval);
337383
}
384+
},
385+
AudioCommand::Clear => {
386+
let _ = self.tx.send(AudioStatus::Elapsed(0));
387+
self.p.clear();
388+
self.p.pause();
338389
}
339-
340-
if self.p.is_ready() && self.wants_play && !self.paused {
341-
self.wants_play = false;
342-
343-
let _ = self.tx.send(AudioStatus::Buffering(false));
344-
345-
if !self.p.is_started() {
346-
self.p.start()
390+
AudioCommand::Volume(val) => {
391+
self.p.volume(val);
392+
}
393+
AudioCommand::Pause(paused) => {
394+
self.paused = paused;
395+
if paused {
396+
if self.p.is_started() {
397+
self.p.pause();
398+
}
347399
} else {
348-
self.p.resume()
400+
self.wants_play = true;
349401
}
350402
}
403+
AudioCommand::Shutdown => unreachable!(),
351404
}
352405
}
353406
}

player/src/connection.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -278,16 +278,7 @@ impl ConnectionActor {
278278
match msg {
279279
AudioStatus::Elapsed(elapsed) => {
280280
let s = self.state.read().await;
281-
let conn = s.connection.as_ref().unwrap();
282-
let room = conn.room.as_ref().expect("lol");
283-
284-
let total = match &room.playback_state {
285-
PlaybackState::Playing | PlaybackState::Paused => {
286-
s.current_track().expect("weird state").metadata.duration
287-
},
288-
PlaybackState::Stopped => 0.0,
289-
};
290-
281+
let total = s.current_track().expect("weird state").metadata.duration;
291282
ui_update!(UIUpdateEvent::SetTime(elapsed as f32, total));
292283
}
293284
AudioStatus::Buffering(is_buffering) => {
@@ -297,6 +288,8 @@ impl ConnectionActor {
297288
ui_update!(UIUpdateEvent::Status);
298289
}
299290
AudioStatus::Finished => {
291+
ui_update!(UIUpdateEvent::SetTime(0.0, 0.0));
292+
300293
ui_update!(UIUpdateEvent::Status);
301294
}
302295
AudioStatus::Visualizer(bars) => {

0 commit comments

Comments
 (0)