diff --git a/Slim/Player/Playlist.pm b/Slim/Player/Playlist.pm index 7e19b7294c0..565d7603708 100644 --- a/Slim/Player/Playlist.pm +++ b/Slim/Player/Playlist.pm @@ -190,6 +190,10 @@ sub addTracks { my $playlist = playList($client); my $maxPlaylistLength = $prefs->get('maxPlaylistLength'); + + # do we need to plan for restart of streaming? + my $restart = (Slim::Player::Source::playingSongIndex($client) == Slim::Player::Source::streamingSongIndex($client)) && + (Slim::Player::Source::playingSongIndex($client) == count($client) - 1); # How many tracks might we need to remove to make space? my $need = $maxPlaylistLength ? (scalar @{$playlist} + scalar @{$tracksRef}) - $maxPlaylistLength : 0; @@ -245,17 +249,25 @@ sub addTracks { }); } + if ($insert) { _insert_done($client, $canAdd); } + # if we are adding a track while we are playing the last one, might + # need to relaunch the process if it has been streamed fully. + if ($restart) { + $log->info("adding track while playing last, check if streaming needs relaunch"); + $client->controller->nextIfStreamed($client); + } + return $canAdd; } sub _insert_done { my ($client, $size, $callbackf, $callbackargs) = @_; - my $playlistIndex = Slim::Player::Source::streamingSongIndex($client)+1; + my $playlistIndex = Slim::Player::Source::playingSongIndex($client) + 1; my $moveFrom = count($client) - $size; if (shuffle($client)) { @@ -266,6 +278,11 @@ sub _insert_done { } else { push @{$client->shufflelist}, @reshuffled; } + # need to flush if we are changing streaming song + if (Slim::Player::Source::streamingSongIndex($client) == $playlistIndex % count($client)) { + main::INFOLOG && $log->info("add+replace streaming (not playing) track"); + Slim::Player::Source::flushStreamingSong($client); + } } else { if (count($client) != $size) { moveSong($client, $moveFrom, $playlistIndex, $size); @@ -382,25 +399,25 @@ sub removeTrack { } if (!$stopped) { - if (Slim::Player::Source::streamingSongIndex($client) >= $tracknum && Slim::Player::Source::streamingSongIndex($client) < $tracknum + $nTracks) { + + my $index = Slim::Player::Source::streamingSongIndex($client); + my $queue = $client->currentsongqueue(); + + # udpate index of tracks in queue but capture the streamingIndex before... + for my $song (@$queue) { + if ($tracknum < $song->index()) { + $song->index($song->index() - $nTracks); + } + } + + if ($index >= $tracknum && $index < $tracknum + $nTracks) { # If we're removing the streaming song (which is different from # the playing song), get the client to flush out the current song # from its audio pipeline. main::INFOLOG && $log->info("Removing currently streaming track."); - Slim::Player::Source::flushStreamingSong($client); + } - } else { - - my $queue = $client->currentsongqueue(); - - for my $song (@$queue) { - - if ($tracknum < $song->index()) { - $song->index($song->index() - $nTracks); - } - } - } } if ($stopped) { @@ -446,6 +463,7 @@ sub removeMultipleTracks { my $stopped = 0; my $oldMode = Slim::Player::Source::playmode($client); + my $flush = 0; my $playingTrackPos = ${shuffleList($client)}[Slim::Player::Source::playingSongIndex($client)]; my $streamingTrackPos = ${shuffleList($client)}[Slim::Player::Source::streamingSongIndex($client)]; @@ -473,7 +491,7 @@ sub removeMultipleTracks { } elsif ($streamingTrackPos == $oldCount) { - Slim::Player::Source::flushStreamingSong($client); + $flush = 1; } } else { @@ -539,6 +557,8 @@ sub removeMultipleTracks { for my $song (@{$queue}) { $song->index($oldToNewShuffled{$song->index()} || 0); } + + Slim::Player::Source::flushStreamingSong($client) if $flush; } refreshPlaylist($client); @@ -589,18 +609,10 @@ sub moveSong { splice @{$listref},$dest, 0, @item; + my $queue = $client->currentsongqueue(); + my $playingIndex = Slim::Player::Source::playingSongIndex($client); my $streamingIndex = Slim::Player::Source::streamingSongIndex($client); - # If we're streaming a different song than we're playing and - # moving either to or from the streaming song position, flush - # the streaming song, because it's no longer relevant. - if (($playingIndex != $streamingIndex) && - (($streamingIndex == $src) || ($streamingIndex == $dest) || - ($playingIndex == $src) || ($playingIndex == $dest))) { - Slim::Player::Source::flushStreamingSong($client); - } - - my $queue = $client->currentsongqueue(); for my $song (@$queue) { my $index = $song->index(); @@ -611,6 +623,26 @@ sub moveSong { $song->index(($dest>$src)? $index - 1 : $index + 1); } } + + # If we're streaming a different song than we're playing and + # moving either to or from the streaming song position, flush + # the streaming song, because it's no longer relevant. + if (($playingIndex != $streamingIndex) && + (($streamingIndex == $src) || ($streamingIndex == $dest) || + ($playingIndex == $src) || ($playingIndex == $dest))) { + $log->info("move+replace streaming (not playing) track"); + Slim::Player::Source::flushStreamingSong($client); + } + + # if we are either moving the last track or moving one after it, we + # might need to relaunch the process if it has been streamed fully. + if (($playingIndex == $streamingIndex) && + ($streamingIndex == count($client) - 1) && + ($src == $streamingIndex || $dest == $streamingIndex)) { + $log->info("moving last track itsef or another track past it"); + $client->controller->nextIfStreamed($client); + } + refreshPlaylist($client); } diff --git a/Slim/Player/Squeezebox2.pm b/Slim/Player/Squeezebox2.pm index 00f2a318b86..56335fdd813 100644 --- a/Slim/Player/Squeezebox2.pm +++ b/Slim/Player/Squeezebox2.pm @@ -389,6 +389,9 @@ sub flush { $client->stream('f'); $client->SUPER::flush(); + + # once flush, don't wait for answer, just get ready + $client->readyToStream(1); return 1; } diff --git a/Slim/Player/StreamingController.pm b/Slim/Player/StreamingController.pm index 690d23c576a..c8aa6bfd9e3 100644 --- a/Slim/Player/StreamingController.pm +++ b/Slim/Player/StreamingController.pm @@ -147,8 +147,8 @@ Flush => [ [ \&_Invalid, \&_BadState, \&_BadState, \&_Invalid], # STOPPED [ \&_BadState, \&_Invalid, \&_Invalid, \&_BadState], # BUFFERING [ \&_BadState, \&_Invalid, \&_Invalid, \&_BadState], # WAITING_TO_SYNC - [ \&_Invalid, \&_FlushGetNext,\&_FlushGetNext,\&_Invalid], # PLAYING - [ \&_Invalid, \&_FlushGetNext,\&_FlushGetNext,\&_Invalid], # PAUSED + [ \&_FlushGetNext,\&_FlushGetNext,\&_FlushGetNext,\&_FlushGetNext], # PLAYING + [ \&_FlushGetNext,\&_FlushGetNext,\&_FlushGetNext,\&_FlushGetNext], # PAUSED ], Skip => [ [ \&_StopGetNext, \&_BadState, \&_BadState, \&_NoOp], # STOPPED @@ -164,7 +164,6 @@ JumpToTime => [ \&_JumpToTime, \&_JumpToTime, \&_JumpToTime, \&_JumpToTime], # PLAYING [ \&_JumpPaused, \&_JumpPaused, \&_JumpPaused, \&_JumpPaused], # PAUSED ], - NextTrackReady => [ [ \&_NoOp, \&_BadState, \&_BadState, \&_Stream], # STOPPED [ \&_BadState, \&_Invalid, \&_Invalid, \&_BadState], # BUFFERING @@ -186,7 +185,6 @@ LocalEndOfStream => [ \&_Invalid, \&_Streamout, \&_Invalid, \&_Invalid], # PLAYING [ \&_Invalid, \&_Streamout, \&_Invalid, \&_Invalid], # PAUSED ], - BufferReady => [ [ \&_Invalid, \&_BadState, \&_BadState, \&_Invalid], # STOPPED [ \&_BadState, \&_WaitToSync, \&_WaitToSync, \&_BadState], # BUFFERING @@ -442,7 +440,7 @@ sub _CheckPaused { # only called when PAUSED } elsif (!$song->duration()) { # Bug 7620: stop remote radio streams if they have been paused long enough for the buffer to fill. - # Assume unknown duration means radio and so we shuould stop now + # Assume unknown duration means radio and so we should stop now main::INFOLOG && $log->info("Stopping remote stream upon full buffer when paused (no resume)"); _Stop(@_); @@ -979,6 +977,9 @@ sub _Skip { sub _FlushGetNext { # flush -> Idle; IF [moreTracks] THEN getNextTrack -> TrackWait ENDIF my ($self, $event, $params) = @_; + # flush means that we get rid of the streaming song + shift @{$self->{'songqueue'}}; + foreach my $player (@{$self->{'players'}}) { $player->flush(); } @@ -2112,6 +2113,21 @@ sub closeStream { $_[0]->{'songStreamController'}->close() if $_[0]->{'songStreamController'}; } +sub nextIfStreamed { + my ($self) = @_; + + # this is called when we are adding/moving another track after last one + # or moving it upper in the list. If it has been fully streamed and we + # are playing/buffering/waiting, then we need to grab next track. If we + # are paused then we'll restart the process later upon resume + if ($self->{'streamingState'} == IDLE && + $self->{'playingState'} != STOPPED && + $self->{'playingState'} != PAUSED) { + main::INFOLOG && $log->info("getting next track to re-launch streaming process"); + _getNextTrack($self); + } +} + #################################################################### # Incoming events - <> PlayControl