[Slim-Checkins] r33680 - in /7.7/trunk/server/Slim: Player/ Player/Protocols/ Plugin/LastFM/ Plugin/Sounds/

[email protected]
Newsgroups gmane.music.equipment.slimdevices.cvs
Message-ID <[email protected]>
Author: ayoung
Date: Thu Nov 10 01:55:01 2011
New Revision: 33680

URL: http://svn.slimdevices.com/slim?rev=33680&view=rev
Log:
bug 17692: Stream proxy capability for SqueezePlay 
On SN, when using direct streaming (should be always), when synchronized, and when one of the players in the sync-group supports proxy streaming, then use the proxy streaming capability of a player so that only a single stream is fetched from the source and synchronization is possible.
Only use this capability if the stream duration is unknown (radio). Individual protocol handlers can override this in either direction; this is used for LastFM.

Modified:
    7.7/trunk/server/Slim/Player/Client.pm
    7.7/trunk/server/Slim/Player/Protocols/SqueezePlayDirect.pm
    7.7/trunk/server/Slim/Player/SongStreamController.pm
    7.7/trunk/server/Slim/Player/SqueezePlay.pm
    7.7/trunk/server/Slim/Player/Squeezebox.pm
    7.7/trunk/server/Slim/Player/StreamingController.pm
    7.7/trunk/server/Slim/Plugin/LastFM/ProtocolHandler.pm
    7.7/trunk/server/Slim/Plugin/Sounds/ProtocolHandler.pm

Modified: 7.7/trunk/server/Slim/Player/Client.pm
URL: http://svn.slimdevices.com/slim/7.7/trunk/server/Slim/Player/Client.pm?rev=33680&r1=33679&r2=33680&view=diff
==============================================================================
--- 7.7/trunk/server/Slim/Player/Client.pm (original)
+++ 7.7/trunk/server/Slim/Player/Client.pm Thu Nov 10 01:55:01 2011
@@ -1446,6 +1446,8 @@
 
 sub canImmediateCrossfade { 0 };
 
+sub proxyAddress { undef };
+
 sub hidden { 0 }
 
 sub hasScrolling { 0 }

Modified: 7.7/trunk/server/Slim/Player/Protocols/SqueezePlayDirect.pm
URL: http://svn.slimdevices.com/slim/7.7/trunk/server/Slim/Player/Protocols/SqueezePlayDirect.pm?rev=33680&r1=33679&r2=33680&view=diff
==============================================================================
--- 7.7/trunk/server/Slim/Player/Protocols/SqueezePlayDirect.pm (original)
+++ 7.7/trunk/server/Slim/Player/Protocols/SqueezePlayDirect.pm Thu Nov 10 01:55:01 2011
@@ -24,6 +24,8 @@
 sub isRemote { 1 }
 
 sub isAudio { 1 }
+
+sub usePlayerProxyStreaming { 0 } # 0 => do not use player-proxy-streaming
 
 sub contentType { 'spdr' }
 

Modified: 7.7/trunk/server/Slim/Player/SongStreamController.pm
URL: http://svn.slimdevices.com/slim/7.7/trunk/server/Slim/Player/SongStreamController.pm?rev=33680&r1=33679&r2=33680&view=diff
==============================================================================
--- 7.7/trunk/server/Slim/Player/SongStreamController.pm (original)
+++ 7.7/trunk/server/Slim/Player/SongStreamController.pm Thu Nov 10 01:55:01 2011
@@ -77,5 +77,10 @@
 	return shift->{'song'}->currentTrack();
 }
 
+sub playerProxyStreaming {
+	my $self = shift;
+	$self->{'playerProxyStreaming'} = shift if @_;
+	return $self->{'playerProxyStreaming'};
+}
 
 1;

Modified: 7.7/trunk/server/Slim/Player/SqueezePlay.pm
URL: http://svn.slimdevices.com/slim/7.7/trunk/server/Slim/Player/SqueezePlay.pm?rev=33680&r1=33679&r2=33680&view=diff
==============================================================================
--- 7.7/trunk/server/Slim/Player/SqueezePlay.pm (original)
+++ 7.7/trunk/server/Slim/Player/SqueezePlay.pm Thu Nov 10 01:55:01 2011
@@ -45,6 +45,7 @@
 		hasPreAmp
 		hasDisableDac
 		spDirectHandlers
+		proxyAddress
 	));
 }
 
@@ -66,6 +67,7 @@
 		hasPreAmp               => 0,
 		hasDisableDac           => 0,
 		spDirectHandlers        => undef,
+		proxyAddress            => undef,
 	);
 
 	return $client;
@@ -86,6 +88,7 @@
 	HasDisableDac           => 'hasDisableDac',
 	SyncgroupID             => undef,
 	Spdirect                => 'spDirectHandlers',
+	Proxy                   => 'proxyAddress',
 
 	# deprecated
 	model                   => '_model',

Modified: 7.7/trunk/server/Slim/Player/Squeezebox.pm
URL: http://svn.slimdevices.com/slim/7.7/trunk/server/Slim/Player/Squeezebox.pm?rev=33680&r1=33679&r2=33680&view=diff
==============================================================================
--- 7.7/trunk/server/Slim/Player/Squeezebox.pm (original)
+++ 7.7/trunk/server/Slim/Player/Squeezebox.pm Thu Nov 10 01:55:01 2011
@@ -560,7 +560,7 @@
 #               //      0x01 - polarity inversion left
 #				
 #	u8_t output_threshold`;	// [1]	Amount of output buffer data before playback starts in tenths of second.
-#	u8_t reserved;		// [1]	reserved
+#	u8_t slaves;		// [1]	number of proxy stream connections to serve
 #	u32_t replay_gain;	// [4]	replay gain in 16.16 fixed point, 0 means none
 #	u16_t server_port;	// [2]	server's port
 #	u32_t server_ip;	// [4]	server's IP
@@ -796,6 +796,14 @@
 		main::INFOLOG && logger('player.streaming.direct')->info("SqueezePlay direct stream: $url");
 
 		$request_string = $handler->requestString($client, $url, undef, $params->{'seekdata'});  
+		$autostart += 2; # will be 2 for direct streaming with no autostart, or 3 for direct with autostart
+
+	} elsif (my $proxy = $params->{'proxyStream'}) {
+
+		$request_string = ' ';	# need at least a byte to keep ip3k happy
+		my ($pserver, $pport) = split (/:/, $proxy);
+		$server_port = $pport;
+		$server_ip = Slim::Utils::Network::intip($pserver);
 		$autostart += 2; # will be 2 for direct streaming with no autostart, or 3 for direct with autostart
 
 	} elsif ($isDirect) {
@@ -998,7 +1006,7 @@
 		$transitionType,
 		$flags,		# flags	     
 		$outputThreshold,
-		0,		# reserved
+		($params->{'slaveStreams'} || 0),
 		$replayGain,	
 		$server_port || $prefs->get('httpport'),  # use slim server's IP
 		$server_ip || 0,

Modified: 7.7/trunk/server/Slim/Player/StreamingController.pm
URL: http://svn.slimdevices.com/slim/7.7/trunk/server/Slim/Player/StreamingController.pm?rev=33680&r1=33679&r2=33680&view=diff
==============================================================================
--- 7.7/trunk/server/Slim/Player/StreamingController.pm (original)
+++ 7.7/trunk/server/Slim/Player/StreamingController.pm Thu Nov 10 01:55:01 2011
@@ -1255,6 +1255,56 @@
 	# bug 10438
 	$self->resetFrameData();
 	
+	my $proxy;
+	if (main::SLIM_SERVICE) {
+		# Player-supplied proxy streaming (bug 17692)
+		if (   scalar @{$self->{'players'}} > 1
+			&& $songStreamController->isDirect() )
+		{
+			my $use;
+			if ($song->currentTrackHandler()->can('usePlayerProxyStreaming')) {
+				# The API for usePlayerProxyStreaming() allows the following return values:
+				#	0 => do not use player-supplier proxy streaming
+				#	1 => use player-supplier proxy streaming if possible
+				#	2 => player-supplier proxy streaming is optional
+				#
+				# Currently, option 2 is treated equivalently to option 0. 
+				# The trade-off is between potential overload of the WAN, supplying multiple
+				# copies of the same remote stream, and overload of the (proxy) player's 
+				# network link (and its capability to service it).
+				$use = $song->currentTrackHandler()->usePlayerProxyStreaming($song);
+			} elsif (!$song->duration) {
+				$use = 1;
+			} else {
+				$use = 0;
+			}
+			
+			if ($use == 1) {
+				my @candidates;
+				foreach (@{$self->{'players'}}) {
+					# find players which supports proxying.
+					if ($_->proxyAddress()) {
+						push @candidates, [$_, ($_->signalStrength || 200) * 1000
+												+ (($_->deviceid == 9 && $_->model eq 'fab4') ? 10 : 0)];
+					}
+				}
+				if (@candidates) {
+					# Prefer wired over wireless
+					# Prefer best signal-strength if wireless
+					# Prefer Fab4 over everything else if more than one wired (or same signal-strength)
+					my $p = (sort {$b->[1] <=> $a->[1]} @candidates)[0]->[0];
+					$proxy = $p->proxyAddress();
+					$songStreamController->playerProxyStreaming($p);
+				}
+			}
+		}
+		if ($proxy) {
+			main::INFOLOG && $synclog->info('Will use player-supplied proxy streaming via ', $songStreamController->playerProxyStreaming()->id);
+		} else {
+			$songStreamController->playerProxyStreaming(undef);
+		}
+	}
+	
 	foreach my $player (@{$self->{'players'}}) {
 		if ($setVolume) {
 			# Bug 10310: Make sure volume is synced if necessary
@@ -1275,7 +1325,7 @@
 			$song->currentTrackHandler()->onStream($player, $song);
 		}
 		
-		$startedPlayers += $player->play( { 
+		my %params = ( 
 			'paused'      => $paused, 
 			'format'      => $song->streamformat(), 
 			'controller'  => $songStreamController,
@@ -1285,7 +1335,19 @@
 			'seekdata'    => $seekdata,
 			'fadeIn'      => $myFadeIn,
 			# we never set the 'loop' parameter
-		} );
+		);
+		
+		if (main::SLIM_SERVICE) {
+			if ($proxy) {
+				if ($songStreamController->playerProxyStreaming() == $player) {
+					$params{'slaveStreams'} = scalar @{$self->{'players'}} - 1;
+				} else {
+					$params{'proxyStream'} = $proxy;
+				}
+			}
+		}
+
+		$startedPlayers += $player->play( \%params );
 		
 		$reportsTrackStart ||= $player->reportsTrackStart();
 	}	
@@ -1927,6 +1989,22 @@
 	if (@{$self->{'allPlayers'}} < 2) {return;}
 	
 	main::INFOLOG && $synclog->info($self->{'masterId'} . " unsync " . $player->id()); # bt();
+	
+	my $restartTime;
+	if (main::SLIM_SERVICE) {
+		# Check if the player that is being unsynced is the master proxy streaming one
+		if (!$self->isStopped() && $self->{'songStreamController'} && @{$self->{'players'}} > 1) {
+			my $proxy = $self->{'songStreamController'}->playerProxyStreaming();
+			if ($proxy && $proxy == $player) {
+				if ($self->isPlaying()) {
+					$restartTime = playingSongElapsed($self);
+				} elsif ($self->isPaused() && $self->playingSong()) {
+					# make sure that the streaming is disconnected, so that any unpause will be by _JumpToTime
+					_pauseStreaming($self, $self->playingSong());
+				}
+			}
+		}
+	}
 		
 	# remove player from the lists
 	my $i = 0;
@@ -1981,6 +2059,11 @@
 		$synclog->info($self->{'masterId'} . " sync group now has: " . join(',', map { $_->id } @{$self->{'allPlayers'}}));
 		$synclog->info($self->{'masterId'} . " active players are: " . join(',', map { $_->id } @{$self->{'players'}}));
 	}
+	
+	if (defined $restartTime) {
+		main::INFOLOG && $log->info($self->{'masterId'} . " restart play");
+		_JumpToTime($self, undef, {newtime => $restartTime, restartIfNoSeek => 1});
+	}
 }
 
 sub playerActive {
@@ -2016,19 +2099,35 @@
 	# Choose new master
 	_newMaster($self);
 	
-	if (main::INFOLOG && $log->is_info) {
-		$log->info($self->{'masterId'} . " sync group now has: " . join(',', map { $_->id } @{$self->{'allPlayers'}}));
-		$log->info($self->{'masterId'} . " active players are: " . join(',', map { $_->id } @{$self->{'players'}}));
+	if (main::INFOLOG && $synclog->is_info) {
+		$synclog->info($self->{'masterId'} . " sync group now has: " . join(',', map { $_->id } @{$self->{'allPlayers'}}));
+		$synclog->info($self->{'masterId'} . " active players are: " . join(',', map { $_->id } @{$self->{'players'}}));
 	}
 	
 	if (isPlaying($self)) {
-		main::INFOLOG && $log->info($self->{'masterId'} . " restart play");
+		main::INFOLOG && $synclog->info($self->{'masterId'} . " restart play");
 		_JumpToTime($self, undef, {newtime => playingSongElapsed($self), restartIfNoSeek => 1});
 	}
 }
 
 sub playerInactive {
 	my ($self, $player) = @_;
+	
+	my $restartTime;
+	if (main::SLIM_SERVICE) {
+		# Check if the player that is going inactive is the master proxy streaming one
+		if (!$self->isStopped() && $self->{'songStreamController'} && @{$self->{'players'}} > 1) {
+			my $proxy = $self->{'songStreamController'}->playerProxyStreaming();
+			if ($proxy && $proxy == $player) {
+				if ($self->isPlaying()) {
+					$restartTime = playingSongElapsed($self);
+				} elsif ($self->isPaused() && $self->playingSong()) {
+					# make sure that the streaming is disconnected, so that any unpause will be by _JumpToTime
+					_pauseStreaming($self, $self->playingSong());
+				}
+			}
+		}
+	}
 	
 	# remove player from the list
 	my $i = 0;
@@ -2059,9 +2158,14 @@
 		_newMaster($self);
 	}
 
-	if (main::INFOLOG && $log->is_info) {
-		$log->info($self->{'masterId'} . " sync group now has: " . join(',', map { $_->id } @{$self->{'allPlayers'}}));
-		$log->info($self->{'masterId'} . " active players are: " . join(',', map { $_->id } @{$self->{'players'}}));	
+	if (main::INFOLOG && $synclog->is_info) {
+		$synclog->info($self->{'masterId'} . " sync group now has: " . join(',', map { $_->id } @{$self->{'allPlayers'}}));
+		$synclog->info($self->{'masterId'} . " active players are: " . join(',', map { $_->id } @{$self->{'players'}}));	
+	}
+	
+	if (defined $restartTime) {
+		main::INFOLOG && $synclog->info($self->{'masterId'} . " restart play");
+		_JumpToTime($self, undef, {newtime => $restartTime, restartIfNoSeek => 1});
 	}
 }
 

Modified: 7.7/trunk/server/Slim/Plugin/LastFM/ProtocolHandler.pm
URL: http://svn.slimdevices.com/slim/7.7/trunk/server/Slim/Plugin/LastFM/ProtocolHandler.pm?rev=33680&r1=33679&r2=33680&view=diff
==============================================================================
--- 7.7/trunk/server/Slim/Plugin/LastFM/ProtocolHandler.pm (original)
+++ 7.7/trunk/server/Slim/Plugin/LastFM/ProtocolHandler.pm Thu Nov 10 01:55:01 2011
@@ -52,6 +52,8 @@
 
 # Don't allow looping if the tracks are short
 sub shouldLoop () { 0 }
+
+sub usePlayerProxyStreaming { 1 } # 1 => player-proxy-streaming necessary for sync
 
 sub canSeek { 0 }
 sub getSeekDataByPosition { undef }

Modified: 7.7/trunk/server/Slim/Plugin/Sounds/ProtocolHandler.pm
URL: http://svn.slimdevices.com/slim/7.7/trunk/server/Slim/Plugin/Sounds/ProtocolHandler.pm?rev=33680&r1=33679&r2=33680&view=diff
==============================================================================
--- 7.7/trunk/server/Slim/Plugin/Sounds/ProtocolHandler.pm (original)
+++ 7.7/trunk/server/Slim/Plugin/Sounds/ProtocolHandler.pm Thu Nov 10 01:55:01 2011
@@ -22,6 +22,8 @@
 # Some sounds are small, use a small buffer threshold
 sub bufferThreshold { 10 }
 
+sub usePlayerProxyStreaming { 0 } # 1 => do not use player-proxy-streaming
+
 sub canSeek { 0 }
 
 sub isAudioURL { 1 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.