@@ -18,70 +18,70 @@ use tokio::sync::{mpsc, oneshot};
1818use self :: receive:: { audio_file_fetch, request_range} ;
1919use crate :: range_set:: { Range , RangeSet } ;
2020
21+ /// The minimum size of a block that is requested from the Spotify servers in one request.
22+ /// This is the block size that is typically requested while doing a `seek()` on a file.
23+ /// Note: smaller requests can happen if part of the block is downloaded already.
2124const MINIMUM_DOWNLOAD_SIZE : usize = 1024 * 16 ;
22- // The minimum size of a block that is requested from the Spotify servers in one request.
23- // This is the block size that is typically requested while doing a seek() on a file.
24- // Note: smaller requests can happen if part of the block is downloaded already.
2525
26+ /// The amount of data that is requested when initially opening a file.
27+ /// Note: if the file is opened to play from the beginning, the amount of data to
28+ /// read ahead is requested in addition to this amount. If the file is opened to seek to
29+ /// another position, then only this amount is requested on the first request.
2630const INITIAL_DOWNLOAD_SIZE : usize = 1024 * 16 ;
27- // The amount of data that is requested when initially opening a file.
28- // Note: if the file is opened to play from the beginning, the amount of data to
29- // read ahead is requested in addition to this amount. If the file is opened to seek to
30- // another position, then only this amount is requested on the first request.
31-
32- const INITIAL_PING_TIME_ESTIMATE_SECONDS : f64 = 0.5 ;
33- // The pig time that is used for calculations before a ping time was actually measured.
34-
35- const MAXIMUM_ASSUMED_PING_TIME_SECONDS : f64 = 1.5 ;
36- // If the measured ping time to the Spotify server is larger than this value, it is capped
37- // to avoid run-away block sizes and pre-fetching.
38-
39- pub const READ_AHEAD_BEFORE_PLAYBACK_SECONDS : f64 = 1.0 ;
40- // Before playback starts, this many seconds of data must be present.
41- // Note: the calculations are done using the nominal bitrate of the file. The actual amount
42- // of audio data may be larger or smaller.
43-
44- pub const READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS : f64 = 2.0 ;
45- // Same as READ_AHEAD_BEFORE_PLAYBACK_SECONDS, but the time is taken as a factor of the ping
46- // time to the Spotify server.
47- // Both, READ_AHEAD_BEFORE_PLAYBACK_SECONDS and READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS are
48- // obeyed.
49- // Note: the calculations are done using the nominal bitrate of the file. The actual amount
50- // of audio data may be larger or smaller.
51-
52- pub const READ_AHEAD_DURING_PLAYBACK_SECONDS : f64 = 5.0 ;
53- // While playing back, this many seconds of data ahead of the current read position are
54- // requested.
55- // Note: the calculations are done using the nominal bitrate of the file. The actual amount
56- // of audio data may be larger or smaller.
57-
58- pub const READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS : f64 = 10.0 ;
59- // Same as READ_AHEAD_DURING_PLAYBACK_SECONDS, but the time is taken as a factor of the ping
60- // time to the Spotify server.
61- // Note: the calculations are done using the nominal bitrate of the file. The actual amount
62- // of audio data may be larger or smaller.
63-
64- const PREFETCH_THRESHOLD_FACTOR : f64 = 4.0 ;
65- // If the amount of data that is pending (requested but not received) is less than a certain amount,
66- // data is pre-fetched in addition to the read ahead settings above. The threshold for requesting more
67- // data is calculated as
68- // <pending bytes> < PREFETCH_THRESHOLD_FACTOR * <ping time> * <nominal data rate>
69-
70- const FAST_PREFETCH_THRESHOLD_FACTOR : f64 = 1.5 ;
71- // Similar to PREFETCH_THRESHOLD_FACTOR, but it also takes the current download rate into account.
72- // The formula used is
73- // <pending bytes> < FAST_PREFETCH_THRESHOLD_FACTOR * <ping time> * <measured download rate>
74- // This mechanism allows for fast downloading of the remainder of the file. The number should be larger
75- // than 1 so the download rate ramps up until the bandwidth is saturated. The larger the value, the faster
76- // the download rate ramps up. However, this comes at the cost that it might hurt ping-time if a seek is
77- // performed while downloading. Values smaller than 1 cause the download rate to collapse and effectively
78- // only PREFETCH_THRESHOLD_FACTOR is in effect. Thus, set to zero if bandwidth saturation is not wanted.
7931
32+ /// The ping time that is used for calculations before a ping time was actually measured.
33+ const INITIAL_PING_TIME_ESTIMATE : Duration = Duration :: from_millis ( 500 ) ;
34+
35+ /// If the measured ping time to the Spotify server is larger than this value, it is capped
36+ /// to avoid run-away block sizes and pre-fetching.
37+ const MAXIMUM_ASSUMED_PING_TIME : Duration = Duration :: from_millis ( 1500 ) ;
38+
39+ /// Before playback starts, this many seconds of data must be present.
40+ /// Note: the calculations are done using the nominal bitrate of the file. The actual amount
41+ /// of audio data may be larger or smaller.
42+ pub const READ_AHEAD_BEFORE_PLAYBACK : Duration = Duration :: from_secs ( 1 ) ;
43+
44+ /// Same as `READ_AHEAD_BEFORE_PLAYBACK`, but the time is taken as a factor of the ping
45+ /// time to the Spotify server. Both `READ_AHEAD_BEFORE_PLAYBACK` and
46+ /// `READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS` are obeyed.
47+ /// Note: the calculations are done using the nominal bitrate of the file. The actual amount
48+ /// of audio data may be larger or smaller.
49+ pub const READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS : f32 = 2.0 ;
50+
51+ /// While playing back, this many seconds of data ahead of the current read position are
52+ /// requested.
53+ /// Note: the calculations are done using the nominal bitrate of the file. The actual amount
54+ /// of audio data may be larger or smaller.
55+ pub const READ_AHEAD_DURING_PLAYBACK : Duration = Duration :: from_secs ( 5 ) ;
56+
57+ /// Same as `READ_AHEAD_DURING_PLAYBACK`, but the time is taken as a factor of the ping
58+ /// time to the Spotify server.
59+ /// Note: the calculations are done using the nominal bitrate of the file. The actual amount
60+ /// of audio data may be larger or smaller.
61+ pub const READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS : f32 = 10.0 ;
62+
63+ /// If the amount of data that is pending (requested but not received) is less than a certain amount,
64+ /// data is pre-fetched in addition to the read ahead settings above. The threshold for requesting more
65+ /// data is calculated as `<pending bytes> < PREFETCH_THRESHOLD_FACTOR * <ping time> * <nominal data rate>`
66+ const PREFETCH_THRESHOLD_FACTOR : f32 = 4.0 ;
67+
68+ /// Similar to `PREFETCH_THRESHOLD_FACTOR`, but it also takes the current download rate into account.
69+ /// The formula used is `<pending bytes> < FAST_PREFETCH_THRESHOLD_FACTOR * <ping time> * <measured download rate>`
70+ /// This mechanism allows for fast downloading of the remainder of the file. The number should be larger
71+ /// than `1.0` so the download rate ramps up until the bandwidth is saturated. The larger the value, the faster
72+ /// the download rate ramps up. However, this comes at the cost that it might hurt ping time if a seek is
73+ /// performed while downloading. Values smaller than `1.0` cause the download rate to collapse and effectively
74+ /// only `PREFETCH_THRESHOLD_FACTOR` is in effect. Thus, set to `0.0` if bandwidth saturation is not wanted.
75+ const FAST_PREFETCH_THRESHOLD_FACTOR : f32 = 1.5 ;
76+
77+ /// Limit the number of requests that are pending simultaneously before pre-fetching data. Pending
78+ /// requests share bandwidth. Thus, havint too many requests can lead to the one that is needed next
79+ /// for playback to be delayed leading to a buffer underrun. This limit has the effect that a new
80+ /// pre-fetch request is only sent if less than `MAX_PREFETCH_REQUESTS` are pending.
8081const MAX_PREFETCH_REQUESTS : usize = 4 ;
81- // Limit the number of requests that are pending simultaneously before pre-fetching data. Pending
82- // requests share bandwidth. Thus, havint too many requests can lead to the one that is needed next
83- // for playback to be delayed leading to a buffer underrun. This limit has the effect that a new
84- // pre-fetch request is only sent if less than MAX_PREFETCH_REQUESTS are pending.
82+
83+ /// The time we will wait to obtain status updates on downloading.
84+ const DOWNLOAD_TIMEOUT : Duration = Duration :: from_secs ( 1 ) ;
8585
8686pub enum AudioFile {
8787 Cached ( fs:: File ) ,
@@ -131,10 +131,10 @@ impl StreamLoaderController {
131131 } )
132132 }
133133
134- pub fn ping_time_ms ( & self ) -> usize {
135- self . stream_shared . as_ref ( ) . map_or ( 0 , |shared| {
136- shared. ping_time_ms . load ( atomic:: Ordering :: Relaxed )
137- } )
134+ pub fn ping_time ( & self ) -> Duration {
135+ Duration :: from_millis ( self . stream_shared . as_ref ( ) . map_or ( 0 , |shared| {
136+ shared. ping_time_ms . load ( atomic:: Ordering :: Relaxed ) as u64
137+ } ) )
138138 }
139139
140140 fn send_stream_loader_command ( & self , command : StreamLoaderCommand ) {
@@ -170,7 +170,7 @@ impl StreamLoaderController {
170170 {
171171 download_status = shared
172172 . cond
173- . wait_timeout ( download_status, Duration :: from_millis ( 1000 ) )
173+ . wait_timeout ( download_status, DOWNLOAD_TIMEOUT )
174174 . unwrap ( )
175175 . 0 ;
176176 if range. length
@@ -271,10 +271,10 @@ impl AudioFile {
271271 let mut initial_data_length = if play_from_beginning {
272272 INITIAL_DOWNLOAD_SIZE
273273 + max (
274- ( READ_AHEAD_DURING_PLAYBACK_SECONDS * bytes_per_second as f64 ) as usize ,
275- ( INITIAL_PING_TIME_ESTIMATE_SECONDS
274+ ( READ_AHEAD_DURING_PLAYBACK . as_secs_f32 ( ) * bytes_per_second as f32 ) as usize ,
275+ ( INITIAL_PING_TIME_ESTIMATE . as_secs_f32 ( )
276276 * READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS
277- * bytes_per_second as f64 ) as usize ,
277+ * bytes_per_second as f32 ) as usize ,
278278 )
279279 } else {
280280 INITIAL_DOWNLOAD_SIZE
@@ -368,7 +368,7 @@ impl AudioFileStreaming {
368368
369369 let read_file = write_file. reopen ( ) . unwrap ( ) ;
370370
371- //let (seek_tx, seek_rx) = mpsc::unbounded();
371+ // let (seek_tx, seek_rx) = mpsc::unbounded();
372372 let ( stream_loader_command_tx, stream_loader_command_rx) =
373373 mpsc:: unbounded_channel :: < StreamLoaderCommand > ( ) ;
374374
@@ -405,17 +405,19 @@ impl Read for AudioFileStreaming {
405405 let length_to_request = match * ( self . shared . download_strategy . lock ( ) . unwrap ( ) ) {
406406 DownloadStrategy :: RandomAccess ( ) => length,
407407 DownloadStrategy :: Streaming ( ) => {
408- // Due to the read-ahead stuff, we potentially request more than the actual reqeust demanded.
409- let ping_time_seconds =
410- 0.0001 * self . shared . ping_time_ms . load ( atomic:: Ordering :: Relaxed ) as f64 ;
408+ // Due to the read-ahead stuff, we potentially request more than the actual request demanded.
409+ let ping_time_seconds = Duration :: from_millis (
410+ self . shared . ping_time_ms . load ( atomic:: Ordering :: Relaxed ) as u64 ,
411+ )
412+ . as_secs_f32 ( ) ;
411413
412414 let length_to_request = length
413415 + max (
414- ( READ_AHEAD_DURING_PLAYBACK_SECONDS * self . shared . stream_data_rate as f64 )
415- as usize ,
416+ ( READ_AHEAD_DURING_PLAYBACK . as_secs_f32 ( )
417+ * self . shared . stream_data_rate as f32 ) as usize ,
416418 ( READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS
417419 * ping_time_seconds
418- * self . shared . stream_data_rate as f64 ) as usize ,
420+ * self . shared . stream_data_rate as f32 ) as usize ,
419421 ) ;
420422 min ( length_to_request, self . shared . file_size - offset)
421423 }
@@ -449,7 +451,7 @@ impl Read for AudioFileStreaming {
449451 download_status = self
450452 . shared
451453 . cond
452- . wait_timeout ( download_status, Duration :: from_millis ( 1000 ) )
454+ . wait_timeout ( download_status, DOWNLOAD_TIMEOUT )
453455 . unwrap ( )
454456 . 0 ;
455457 }
0 commit comments