11use std:: mem:: MaybeUninit ;
22use std:: sync:: { Arc , Mutex } ;
3+ use std:: time:: Duration ;
34
45use cpal:: traits:: { DeviceTrait , HostTrait , StreamTrait } ;
56use cpal:: Stream ;
67use opus:: Decoder ;
8+ use ringbuf:: ring_buffer:: RbBase ;
79use ringbuf:: { LocalRb , Rb } ;
810use tokio:: sync:: mpsc;
11+ use tokio:: time:: { Instant , Interval } ;
912
1013use 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
243252impl 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}
0 commit comments