Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve retries for non-live remote streams. #786

Open
wants to merge 8 commits into
base: public/8.3
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 50 additions & 21 deletions Slim/Player/StreamingController.pm
Original file line number Diff line number Diff line change
Expand Up @@ -916,11 +916,23 @@ sub _RetryOrNext { # -> Idle; IF [shouldretry && canretry] THEN continue
&& $song->isRemote()
&& $elapsed > 10) # have we managed to play at least 10s?
{
if (!$song->duration() && $song->isLive()) { # unknown duration => assume radio
if (!$song->duration() || $song->isLive()) { # unknown duration => assume radio
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we are going there as soon as a track as no duration, which might not be just remote. Would have to check but when playing local track from directory browsing, we might not have scanned it yet. Might not be a big deal, but that's a key change of logic

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not mateirial to the change. Reverting.

main::INFOLOG && $log->is_info && $log->info('Attempting to re-stream ', $song->currentTrack()->url, ' after time ', $elapsed);
$song->retryData({ count => 0, start => Time::HiRes::time()});
_Stream($self, $event, {song => $song});
return;
} else {
if ($song->duration() - $elapsed < 10) # check we have more than 10 seconds left to play.
{
if ( main::DEBUGLOG && $log->is_debug ) {$log->debug("Will not retry - track is within 10 seconds of end.")};
} else {
# get seek data from protocol handler.
if ( main::DEBUGLOG && $log->is_debug ) {$log->debug("Getting seek data from protocol handler.")};
my $seekdata = $song->getSeekData($elapsed);
main::INFOLOG && $log->is_info && $log->info("Restarting playback at time offset: ". $elapsed);
_Stream($self, undef, {song => $song, seekdata => $seekdata, reconnect => 1});
return;
}
}
}

Expand Down Expand Up @@ -948,8 +960,6 @@ sub _Continue {
$song->setStatus(Slim::Player::Song::STATUS_PLAYING);
}
} else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for removing that comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. Reverting.

# This handles resuming after reboot with the caveat that if connection has been lost (no reboot)
# while playing and before reception of next song's 1st byte, we'll resume the current song
main::INFOLOG && $log->is_info && $log->info("Restarting playback at time offset: ". $self->playingSongElapsed());
_JumpToTime($self, $event, {newtime => $self->playingSongElapsed(), restartIfNoSeek => 1});
}
Expand Down Expand Up @@ -1404,50 +1414,69 @@ sub _willRetry {
$song ||= streamingSong($self);
return 0 if !$song;

my $retry = $song->retryData();
if (!$retry) {
# $song->retryData() will be undef is we are not retrying already.
if (!$song->retryData()) {
$log->info('no retry data');
return 0;
$song->retryData({ count => 0, start => Time::HiRes::time()});
}

$song->retryData->{'count'} += 1;

# Have we managed to play at least 10 seconds of a track and retried fewer times than there are intervals?
my $elapsed = $self->playingSongElapsed();
if ($song->retryData->{'count'} > scalar @retryIntervals || $elapsed < 10 || ($song->duration() - $elapsed < 10)) {
if ( main::DEBUGLOG && $log->is_debug ) {$log->debug("Will not retry - too many retries already or track is within 10 seconds of start or end.")};
return 0;
}


# Define $limit as the time until which a retry is allowed.
my $limit;
my $next = nextsong($self);
if (defined $next && $next != $song->index) {
$limit = RETRY_LIMIT_PLAYLIST;
} else {
$limit = RETRY_LIMIT;
}

my $interval = $retryIntervals[$retry->{'count'} > $#retryIntervals ? -1 : $retry->{'count'}];

# Setting $interval to -1 causes retryTime to be in the past so no retry will be attempted.
my $interval = $retryIntervals[$song->retryData->{'count'} > $#retryIntervals ? -1 : $song->retryData->{'count'}];
my $retryTime = time() + $interval;

if ($retry->{'start'} + $limit < $retryTime) {
# $retryTime is when we will next retry.
# $retry->{'start'} + $limit is the time before which it is okay to retry.
if ($song->retryData->{'start'} + $limit < $retryTime) {
if ( main::DEBUGLOG && $synclog->is_debug ) {$log->debug("too late, give up")};
# too late, give up
$song->retryData(undef);
_errorOpening($self, $song->currentTrack()->url, 'RETRY_LIMIT_EXCEEDED');
_Stop($self);
$self->{'consecutiveErrors'} = 1; # the failed retry counts as one error
$self->{'consecutiveErrors'}++; # the failed retry counts as one error
return 0;
}

$retry->{'count'} += 1;
my $id = ++$self->{'nextTrackCallbackId'};
$self->{'nextTrack'} = undef;
_setStreamingState($self, TRACKWAIT);



my $queue = $self->{'songqueue'};
$queue->[0]->setStatus(Slim::Player::Song::STATUS_READY) if scalar @$queue;
Slim::Utils::Timers::setTimer(
$self,
$retryTime,
sub {
$song->setStatus(Slim::Player::Song::STATUS_READY);
$self->{'consecutiveErrors'} = 0;
_nextTrackReady($self, $id, $song);
_playersMessage($self, $song->currentTrack()->url, undef, 'RETRYING', undef, undef, 1);
if (!$song->duration() || $song->isLive()) { # unknown duration => assume radio
main::INFOLOG && $log->is_info && $log->info("Restarting playback at time offset: 0");
_Stream($self, undef, {song => $song, reconnect => 1});
} else {
# get seek data from protocol handler.
if ( main::DEBUGLOG && $log->is_debug ) {$log->debug("Getting seek data from protocol handler.")};
my $seekdata = $song->getSeekData($elapsed);
main::INFOLOG && $log->is_info && $log->info("Restarting playback at time offset: ". $elapsed);
_Stream($self, undef, {song => $song, seekdata => $seekdata, reconnect => 1});
}
},
undef
);

_playersMessage($self, $song->currentTrack()->url, undef, 'RETRYING', undef, 0, $interval + 1);

return 1;
}

Expand Down