Index: Slim/Player/Sync.pm =================================================================== --- Slim/Player/Sync.pm (revision 22172) +++ Slim/Player/Sync.pm (working copy) @@ -236,6 +236,12 @@ deleteSyncPrefs($lastInGroup, 1) if $lastInGroup; } + # Clear current alarm if it was inherited from the sync group + if ($client->alarmData->{currentAlarm} && $client->alarmData->{currentAlarm}->client ne $client) { + warn 'removing current alarm for ' . $client->name; + $client->alarmData->{currentAlarm} = undef; + } + if (Slim::Player::Source::playmode($client) ne 'stop') { Slim::Player::Source::playmode($client, 'stop'); Slim::Control::Request::notifyFromArray($client, ['stop']); @@ -277,6 +283,10 @@ $client->master($buddy); push (@{$client->master->slaves}, $client); + + # Copy any current alarm from the buddy to the client + warn 'Adding current alarm for ' . $client->name; + $client->alarmData->{currentAlarm} = $buddy->alarmData->{currentAlarm}; if (Slim::Player::Source::playmode($buddy) eq "play") { $buddy->execute(["stop"]); Index: Slim/Utils/Alarm.pm =================================================================== --- Slim/Utils/Alarm.pm (revision 22172) +++ Slim/Utils/Alarm.pm (working copy) @@ -80,6 +80,8 @@ }, ); +# Global count of the number of active alarms on the server +my $activeAlarms = 0; ################################################################################ =head1 INSTANCE METHODS @@ -475,15 +477,24 @@ # Sound an Alarm (HWV 63) $log->debug('Sounding alarm'); - # Stop any other current alarm - if ($client->alarmData->{currentAlarm}) { - $log->debug('Stopping other current alarm'); - $client->alarmData->{currentAlarm}->stop; + $activeAlarms++; + + my @syncGroup = Slim::Player::Sync::syncedWith($client); + push @syncGroup, $client; + + # Stop any other current alarm, including alarms on synced players and set current alarm to be this one + foreach my $buddy (@syncGroup) { + warn $buddy->name . "\n"; + if ($buddy->alarmData->{currentAlarm}) { + $log->debug('Stopping other current alarm on ' . $buddy->name); + $buddy->alarmData->{currentAlarm}->stop; + } + + $buddy->alarmData->{lastAlarmTime} = $self->{_nextDue}; + $buddy->alarmData->{currentAlarm} = $self; } - $client->alarmData->{lastAlarmTime} = $self->{_nextDue}; $self->{_active} = 1; - $client->alarmData->{currentAlarm} = $self; my $now = Time::HiRes::time(); # Bug 7818, count this as user interaction, even though it isn't really @@ -497,11 +508,13 @@ $request = $client->execute(['power', 1]); $request->source('ALARM'); - $class->pushAlarmScreensaver($client); + foreach my $buddy (@syncGroup) { + $class->pushAlarmScreensaver($buddy); - # Set analogOutMode to subwoofer to force output through main speakers even if headphones are plugged in - # This needs doing a lot more thoroughly. Bug 8146 - $client->can('setAnalogOutMode') && $client->setAnalogOutMode(1); + # Set analogOutMode to subwoofer to force output through main speakers even if headphones are plugged in + # This needs doing a lot more thoroughly. Bug 8146 + $buddy->can('setAnalogOutMode') && $buddy->setAnalogOutMode(1); + } # Set up volume my $currentVolume = $client->volume; @@ -543,12 +556,6 @@ # Allow a slight delay for things to load up then tell the user what's going on Slim::Utils::Timers::setTimer($client, Time::HiRes::time() + 2, sub { - # Show a long-lasting notification unless we've already pushed into an alarm screensaver - my $showBrieflyDur = 30; - if (Slim::Buttons::Common::mode($client) eq $class->alarmScreensaver) { - $showBrieflyDur = $SHOW_BRIEFLY_DUR; - } - my $line1 = $client->string('ALARM_NOW_PLAYING'); my $line2; @@ -571,10 +578,19 @@ $line2 = $client->string('CURRENT_PLAYLIST'); } - $client->showBriefly({ - line => [ $line1, $line2 ], - duration => $showBrieflyDur, - }); + foreach my $buddy (@syncGroup) { + # Show a long-lasting notification unless we've already pushed into an alarm screensaver + my $showBrieflyDur = 30; + if (Slim::Buttons::Common::mode($buddy) eq $class->alarmScreensaver) { + $showBrieflyDur = $SHOW_BRIEFLY_DUR; + } + + $buddy->showBriefly({ + line => [ $line1, $line2 ], + duration => $showBrieflyDur, + block => 1, + }); + } } ); # Set up subscription to end the alarm on user activity @@ -612,6 +628,9 @@ return unless $self->{_active}; my $client = $self->client; + my @syncGroup = Slim::Player::Sync::syncedWith($client); + push @syncGroup, $client; + my $class = ref $self; # don't snooze again if we're already snoozing. @@ -650,10 +669,12 @@ # Set up snooze subscription to end snooze on user activity $class->_setAlarmSubscription($client, 1); - $client->showBriefly({ - line => [$client->string('ALARM_SNOOZE')], - duration => $SHOW_BRIEFLY_DUR, - }); + foreach my $buddy (@syncGroup) { + $buddy->showBriefly({ + line => [$buddy->string('ALARM_SNOOZE')], + duration => $SHOW_BRIEFLY_DUR, + }); + } } $class->pushAlarmScreensaver($client); @@ -680,6 +701,8 @@ my $class = ref $self; my $client = $self->client; + my @syncGroup = Slim::Player::Sync::syncedWith($client); + push @syncGroup, $client; $self->{_snoozeActive} = 0; @@ -689,10 +712,12 @@ $request->source('ALARM'); } - $client->showBriefly({ - line => [$client->string('ALARM_SNOOZE_ENDED')], - duration => $SHOW_BRIEFLY_DUR, - }); + foreach my $buddy (@syncGroup) { + $buddy->showBriefly({ + line => [$buddy->string('ALARM_SNOOZE_ENDED')], + duration => $SHOW_BRIEFLY_DUR, + }); + } # Reset the subscription to end the alarm on user activity $class->_setAlarmSubscription($client); @@ -714,17 +739,27 @@ my $self = shift; my $client = $self->client; + my @syncGroup = Slim::Player::Sync::syncedWith($client); + push @syncGroup, $client; return unless $self->{_active}; - if (defined $client->alarmData->{currentAlarm} && $client->alarmData->{currentAlarm} == $self) { - $client->alarmData->{currentAlarm} = undef; + $activeAlarms --; + + foreach my $buddy (@syncGroup) { + if (defined $buddy->alarmData->{currentAlarm} && $buddy->alarmData->{currentAlarm} == $self) { + $buddy->alarmData->{currentAlarm} = undef; + } } + $self->{_active} = 0; $self->{_snoozeActive} = 0; - # Kill the subscription to automatically end this alarm on user activity - Slim::Control::Request::unsubscribe(\&_alarmEnd, $client); + # If this is the last active alarm, kill the subscription to end alarms on user activity + if (! $activeAlarms) { + $log->debug('Removing _alarmEnd subscription'); + Slim::Control::Request::unsubscribe(\&_alarmEnd); + } # Kill the callback to check for playback Slim::Utils::Timers::killTimers($self, \&_checkPlaying); @@ -735,17 +770,20 @@ $self->{_timeoutTimer} = undef; } - # Restore analogOutMode to previous setting - $client->can('setAnalogOutMode') && $client->setAnalogOutMode(); + my $class = ref $self; - my $class = ref $self; $class->popAlarmScreensaver($client); - $client->showBriefly({ - line => [$client->string('ALARM_STOPPED')], - duration => $SHOW_BRIEFLY_DUR, - }); + foreach my $buddy (@syncGroup) { + # Restore analogOutMode to previous setting + $buddy->can('setAnalogOutMode') && $buddy->setAnalogOutMode(); + $buddy->showBriefly({ + line => [$buddy->string('ALARM_STOPPED')], + duration => $SHOW_BRIEFLY_DUR, + }); + } + # Send notifications Slim::Control::Request::notifyFromArray($client, ['alarm', 'end', $self->{_id}]); } @@ -987,30 +1025,28 @@ my $snooze = shift; # Remove any subscription for this client - Slim::Control::Request::unsubscribe(\&_alarmEnd, $client); + Slim::Control::Request::unsubscribe(\&_alarmEnd); my $currentAlarm = $client->alarmData->{currentAlarm}; return unless defined $currentAlarm; - $log->debug('Adding ' . ($snooze ? 'snooze' : 'alarm') . ' subscription'); + $log->debug('Adding subscription'); - my $stopCommands; + # A snooze should be cancelled on anything the user does that results in music playing and also on any + # "off" action: + # power needs to be caught on its own as the music is paused + # pause/play when paused results in pause + # fwd/rew and (hopefully) commands that load a new playlist result in 'playlist jump' - if ($snooze) { - # The snooze should be cancelled on anything the user does that results in music playing and also on any - # "off" action: - # power needs to be caught on its own as the music is paused - # pause/play when paused results in pause - # fwd/rew and (hopefully) commands that load a new playlist result in 'playlist jump' - $stopCommands = ['power', 'pause', 'stop', 'playlist']; - } else { - # The alarm should be cancelled on anything the user does that would stop the music - # power needs to be caught on its own as the music could potentially be stopped if the alarm playlist failed - # for some reason - $stopCommands = ['pause', 'stop', 'power']; - } - Slim::Control::Request::subscribe(\&_alarmEnd, [$stopCommands], $client); + # An alarm should be cancelled on anything the user does that would stop the music + # power needs to be caught on its own as the music could potentially be stopped if the alarm playlist failed + # for some reason + my $stopCommands = ['power', 'pause', 'stop', 'playlist']; + + # There may already be an active subscription if another alarm is active, this won't matter however - only one + # will exist at once and any subscription will service all alarms. + Slim::Control::Request::subscribe(\&_alarmEnd, [$stopCommands]); } =head2 getCurrentAlarm( $client ) @@ -1507,9 +1543,10 @@ my $client = $request->client; - $log->debug(sub {'_alarmEnd called with request: ' . $request->getRequestString}); + $log->debug(sub {'_alarmEnd called with request: ' . $request->getRequestString . ' from client ' . $client->name}); my $currentAlarm = $client->alarmData->{currentAlarm}; + if (! defined $currentAlarm) { $log->debug('No current alarm. Doing nothing.'); return; @@ -1523,6 +1560,7 @@ } # power always ends the alarm, whether snoozing or not + # We only stop on playlist jump for snoozes if ($currentAlarm->{_snoozeActive} && $request->getRequest(0) ne 'power') { # When snoozing we should end on 'playlist jump' but can only filter on playlist if ($request->getRequest(0) eq 'playlist' && $request->getRequest(1) ne 'jump') { @@ -1534,9 +1572,13 @@ $log->debug('Stopping snooze'); Slim::Utils::Timers::killTimers($currentAlarm, \&stopSnooze); $currentAlarm->stopSnooze(0); - } else { - $log->debug('Stopping alarm'); - $currentAlarm->stop; + } elsif ($request->getRequest(0) ne 'playlist') { + # Only stop for power if the request turned the client off - otherwise alarms could stop when synced + # players are turned on. + if ($request->getRequest(0) ne 'power' || ! $client->power) { + $log->debug('Stopping alarm'); + $currentAlarm->stop; + } } }