mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Limit number of prefetch requests.
This commit is contained in:
parent
05b281f085
commit
db0e4a0422
1 changed files with 34 additions and 18 deletions
|
@ -49,13 +49,13 @@ pub const READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS: f64 = 2.0;
|
||||||
// Note: the calculations are done using the nominal bitrate of the file. The actual amount
|
// Note: the calculations are done using the nominal bitrate of the file. The actual amount
|
||||||
// of audio data may be larger or smaller.
|
// of audio data may be larger or smaller.
|
||||||
|
|
||||||
pub const READ_AHEAD_DURING_PLAYBACK_SECONDS: f64 = 1.0;
|
pub const READ_AHEAD_DURING_PLAYBACK_SECONDS: f64 = 5.0;
|
||||||
// While playing back, this many seconds of data ahead of the current read position are
|
// While playing back, this many seconds of data ahead of the current read position are
|
||||||
// requested.
|
// requested.
|
||||||
// Note: the calculations are done using the nominal bitrate of the file. The actual amount
|
// Note: the calculations are done using the nominal bitrate of the file. The actual amount
|
||||||
// of audio data may be larger or smaller.
|
// of audio data may be larger or smaller.
|
||||||
|
|
||||||
pub const READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS: f64 = 2.0;
|
pub const READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS: f64 = 10.0;
|
||||||
// Same as READ_AHEAD_DURING_PLAYBACK_SECONDS, but the time is taken as a factor of the ping
|
// Same as READ_AHEAD_DURING_PLAYBACK_SECONDS, but the time is taken as a factor of the ping
|
||||||
// time to the Spotify server.
|
// time to the Spotify server.
|
||||||
// Note: the calculations are done using the nominal bitrate of the file. The actual amount
|
// Note: the calculations are done using the nominal bitrate of the file. The actual amount
|
||||||
|
@ -77,6 +77,13 @@ const FAST_PREFETCH_THRESHOLD_FACTOR: f64 = 1.5;
|
||||||
// performed while downloading. Values smaller than 1 cause the download rate to collapse and effectively
|
// performed while downloading. Values smaller than 1 cause the download rate to collapse and effectively
|
||||||
// only PREFETCH_THRESHOLD_FACTOR is in effect. Thus, set to zero if bandwidth saturation is not wanted.
|
// only PREFETCH_THRESHOLD_FACTOR is in effect. Thus, set to zero if bandwidth saturation is not wanted.
|
||||||
|
|
||||||
|
const MAX_PREFETCH_REQUESTS: usize = 4;
|
||||||
|
// Limit the number of requests that are pending simultaneously before pre-fetching data. Pending
|
||||||
|
// requests share bandwidth. Thus, havint too many requests can lead to the one that is needed next
|
||||||
|
// for playback to be delayed leading to a buffer underrun. This limit has the effect that a new
|
||||||
|
// pre-fetch request is only sent if less than MAX_PREFETCH_REQUESTS are pending.
|
||||||
|
|
||||||
|
|
||||||
pub enum AudioFile {
|
pub enum AudioFile {
|
||||||
Cached(fs::File),
|
Cached(fs::File),
|
||||||
Streaming(AudioFileStreaming),
|
Streaming(AudioFileStreaming),
|
||||||
|
@ -726,10 +733,11 @@ impl AudioFileFetch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pre_fetch_more_data(&mut self, bytes: usize) {
|
fn pre_fetch_more_data(&mut self, bytes: usize, max_requests_to_send: usize) {
|
||||||
let mut bytes_to_go = bytes;
|
let mut bytes_to_go = bytes;
|
||||||
|
let mut requests_to_go = max_requests_to_send;
|
||||||
|
|
||||||
while bytes_to_go > 0 {
|
while bytes_to_go > 0 && requests_to_go > 0 {
|
||||||
// determine what is still missing
|
// determine what is still missing
|
||||||
let mut missing_data = RangeSet::new();
|
let mut missing_data = RangeSet::new();
|
||||||
missing_data.add_range(&Range::new(0, self.shared.file_size));
|
missing_data.add_range(&Range::new(0, self.shared.file_size));
|
||||||
|
@ -750,6 +758,7 @@ impl AudioFileFetch {
|
||||||
let offset = range.start;
|
let offset = range.start;
|
||||||
let length = min(range.length, bytes_to_go);
|
let length = min(range.length, bytes_to_go);
|
||||||
self.download_range(offset, length);
|
self.download_range(offset, length);
|
||||||
|
requests_to_go -=1;
|
||||||
bytes_to_go -= length;
|
bytes_to_go -= length;
|
||||||
} else if !missing_data.is_empty() {
|
} else if !missing_data.is_empty() {
|
||||||
// ok, the tail is downloaded, download something fom the beginning.
|
// ok, the tail is downloaded, download something fom the beginning.
|
||||||
|
@ -757,6 +766,7 @@ impl AudioFileFetch {
|
||||||
let offset = range.start;
|
let offset = range.start;
|
||||||
let length = min(range.length, bytes_to_go);
|
let length = min(range.length, bytes_to_go);
|
||||||
self.download_range(offset, length);
|
self.download_range(offset, length);
|
||||||
|
requests_to_go -=1;
|
||||||
bytes_to_go -= length;
|
bytes_to_go -= length;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
|
@ -899,23 +909,29 @@ impl Future for AudioFileFetch {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let DownloadStrategy::Streaming() = self.get_download_strategy() {
|
if let DownloadStrategy::Streaming() = self.get_download_strategy() {
|
||||||
let bytes_pending: usize = {
|
|
||||||
let download_status = self.shared.download_status.lock().unwrap();
|
|
||||||
download_status.requested.minus(&download_status.downloaded).len()
|
|
||||||
};
|
|
||||||
|
|
||||||
let ping_time_seconds =
|
let number_of_open_requests = self.shared.number_of_open_requests.load(atomic::Ordering::SeqCst);
|
||||||
0.001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64;
|
let max_requests_to_send = MAX_PREFETCH_REQUESTS - min(MAX_PREFETCH_REQUESTS, number_of_open_requests);
|
||||||
let download_rate = self.session.channel().get_download_rate_estimate();
|
|
||||||
|
|
||||||
let desired_pending_bytes = max(
|
if (max_requests_to_send > 0) {
|
||||||
(PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * self.shared.stream_data_rate as f64)
|
let bytes_pending: usize = {
|
||||||
as usize,
|
let download_status = self.shared.download_status.lock().unwrap();
|
||||||
(FAST_PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * download_rate as f64) as usize,
|
download_status.requested.minus(&download_status.downloaded).len()
|
||||||
);
|
};
|
||||||
|
|
||||||
if bytes_pending < desired_pending_bytes {
|
let ping_time_seconds =
|
||||||
self.pre_fetch_more_data(desired_pending_bytes - bytes_pending);
|
0.001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64;
|
||||||
|
let download_rate = self.session.channel().get_download_rate_estimate();
|
||||||
|
|
||||||
|
let desired_pending_bytes = max(
|
||||||
|
(PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * self.shared.stream_data_rate as f64)
|
||||||
|
as usize,
|
||||||
|
(FAST_PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * download_rate as f64) as usize,
|
||||||
|
);
|
||||||
|
|
||||||
|
if bytes_pending < desired_pending_bytes {
|
||||||
|
self.pre_fetch_more_data(desired_pending_bytes - bytes_pending, max_requests_to_send);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue