commonappservices/alarmserver/Server/Source/ASSrvSoundController.cpp
changeset 0 2e3d3ce01487
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "ASSrvSoundController.h"
       
    17 
       
    18 // System includes
       
    19 
       
    20 // User includes
       
    21 #include "ASSrvAlarm.h"
       
    22 #include "ASSrvAlarmQueue.h"
       
    23 #include "ASSrvStaticUtils.h"
       
    24 #include "ASSrvSoundSettings.h"
       
    25 #include "ASSrvServerWideData.h"
       
    26 #include "ASSrvAnyEventManager.h"
       
    27 #include "ASSrvSoundControllerObserver.h"
       
    28 #include "ASSrvEnvironmentChangeManager.h"
       
    29 
       
    30 #include "ASSrvIteratorByState.h"
       
    31 #include "ASSrvNotificationCoordinator.h"
       
    32 
       
    33 
       
    34 //
       
    35 // ----> CASSrvSoundController (source)
       
    36 //
       
    37 
       
    38 	/**
       
    39 	 * Indicates that the Sound Controller is disabled (ie. no sounds
       
    40 	 * intervals configured in the rsc file)
       
    41 	 */
       
    42 TBool CASSrvSoundController::IsSoundControllerDisabled() const
       
    43 	{
       
    44 	return 0==ServerData().SoundSettings().SoundIntervalCount();
       
    45 	}
       
    46 
       
    47 //*************************************************************************************
       
    48 CASSrvSoundController::CASSrvSoundController(CASSrvServerWideData& aServerWideData, MASSrvSoundControllerObserver& aObserver)
       
    49 :	CTimer(CActive::EPriorityUserInput), iServerWideData(aServerWideData), iObserver(aObserver)
       
    50 	{
       
    51 	iPreviousSoundEvent = MASSrvSoundControllerObserver::ESoundControllerEventPlayNothing;
       
    52 	CActiveScheduler::Add(this);
       
    53 	}
       
    54 
       
    55 
       
    56 //*************************************************************************************
       
    57 CASSrvSoundController::~CASSrvSoundController()
       
    58 	{
       
    59 	Cancel();
       
    60 
       
    61 	// It's ok to Cancel these even if we didn't register for the them:
       
    62 	ServerData().EnvironmentChangeManager().RequestEnvironmentChangesCancel(*this);
       
    63 	ServerData().SoundSettings().NotifySoundSettingsChangeCancel(*this);
       
    64 	ServerData().Queue().RequestAlarmObservationEventsCancel(*this);
       
    65 	ServerData().Queue().NotificationPoolChangeCancel(*this);
       
    66 	}
       
    67 
       
    68 
       
    69 //*************************************************************************************
       
    70 void CASSrvSoundController::ConstructL()
       
    71 	{
       
    72 	CTimer::ConstructL();
       
    73 
       
    74 	if( !IsSoundControllerDisabled() )
       
    75 		{
       
    76 		ServerData().Queue().NotificationPoolChangeL(*this);
       
    77 		ServerData().Queue().RequestAlarmObservationEventsL(*this);
       
    78 		ServerData().SoundSettings().NotifySoundSettingsChangeL(*this);
       
    79 		ServerData().EnvironmentChangeManager().RequestEnvironmentChangesL(*this);
       
    80 		iPreviousUTCOffset = User::UTCOffset();
       
    81 		iSoundControllerFlags.Set(ESoundControllerFlagsIsFixed);
       
    82 		}
       
    83 	}
       
    84 
       
    85 
       
    86 //*************************************************************************************
       
    87 CASSrvSoundController* CASSrvSoundController::NewL(CASSrvServerWideData& aServerWideData, MASSrvSoundControllerObserver& aObserver)
       
    88 	{
       
    89 	CASSrvSoundController* self = new(ELeave) CASSrvSoundController(aServerWideData, aObserver);
       
    90 	CleanupStack::PushL(self);
       
    91 	self->ConstructL();
       
    92 	CleanupStack::Pop(self);
       
    93 	return self;
       
    94 	}
       
    95 
       
    96 
       
    97 //
       
    98 //
       
    99 //
       
   100 
       
   101 
       
   102 //*************************************************************************************
       
   103 /**
       
   104  * @see MASSrvAlarmObserver
       
   105  *
       
   106  * When an alarm expires, we should start timing the alarm sound intervals. Note that
       
   107  * no sound is played directly by the alarm server - it's all handled by proxy in the
       
   108  * EikSrv thread (Alarm Alert Server).
       
   109  * 
       
   110  * We only ever receive one notification that an alarm has expired (unless its snoozed
       
   111  * and then the snooze expires). Therefore, the sound controller has to perform cycle
       
   112  * management for the alerting (notifying) head alarm in the queue).
       
   113  */
       
   114 void CASSrvSoundController::MASSrvAlarmObsHandleEvent(TObserverEvent aEvent, const TASSrvAlarm& aAlarm, TInt aEventSpecificData)
       
   115 	{
       
   116 	// Get a modifiable version of the alarm
       
   117 	TASSrvAlarm* alarm = ServerData().Queue().QueueAlarmById(aAlarm.Id());
       
   118 
       
   119 	if	(aEvent == EAlarmObserverStateChanged)
       
   120 		{
       
   121 		// Notifying / snoozed / notified / etc
       
   122 		const TAlarmState oldState = static_cast<TAlarmState>(aEventSpecificData);
       
   123 		if	(oldState == EAlarmStateNotifying && IdOfNotifyingAlarm() == aAlarm.Id())
       
   124 			{
       
   125 			// If the alarm was notifying, but now it's back in the queue
       
   126 			// then we need to cancel any sound playing in preparation for
       
   127 			// the new notifying alarm
       
   128 			if	(!InQuietPeriod())
       
   129 				{
       
   130 				Cancel();
       
   131 				}
       
   132 				
       
   133 			if (SoundIsPausedForAlarm())
       
   134 				{
       
   135 				iSoundControllerFlags.Clear(ESoundControllerFlagsPausing);
       
   136 				}					
       
   137 
       
   138 			// Reset this now
       
   139 			IdOfNotifyingAlarm() = KNullAlarmId;
       
   140 			}
       
   141 		//
       
   142 		switch(aAlarm.State())
       
   143 			{
       
   144 		case EAlarmStateNotifying:
       
   145 			{
       
   146 			// The only thing we really care about is that the new notifying alarm is not null.
       
   147 			__ASSERT_DEBUG(aAlarm.Id() != KNullAlarmId, 
       
   148 				ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicQueueAlarmIdNull));
       
   149 
       
   150 			// Ensure Alarm Disabled status change didn't slip in ahead in server queue
       
   151 			if (alarm->Status() == EAlarmStatusEnabled)
       
   152 				{
       
   153 				if	(InQuietPeriod())
       
   154 					{
       
   155 					// delay any sound playing until the quiet period ends
       
   156 					alarm->SetSoundState(TASSrvAlarm::ESoundStatePlayingNothing);
       
   157 					IdOfNotifyingAlarm() = aAlarm.Id();
       
   158 					}
       
   159 				else
       
   160 					{
       
   161 					Cancel();
       
   162 
       
   163 					// Work out when we should start playing the sound
       
   164 					IdOfNotifyingAlarm() = aAlarm.Id();
       
   165 					WorkOutAndScheduleForNextSoundCycle();
       
   166 					}
       
   167 				}
       
   168  
       
   169 			break;
       
   170 			}
       
   171 
       
   172 		case EAlarmStateWaitingToNotify:
       
   173 		case EAlarmStateSnoozed:
       
   174 		case EAlarmStateNotified:
       
   175 			// An alarm is no longer notifying, this is handle above already
       
   176 			break;
       
   177 		
       
   178 		// We're not interested in these kind of events
       
   179 		case EAlarmStateQueued:
       
   180 		case EAlarmStateInPreparation:
       
   181 			return;
       
   182 			}
       
   183 		}
       
   184 	else if (aEvent == EAlarmObserverStatusChanged)
       
   185 		{
       
   186 		// Enabled / disabled
       
   187 		if	(aAlarm.Id() == IdOfNotifyingAlarm() && alarm->Status() == EAlarmStatusDisabled)
       
   188 			{
       
   189 			// Cancel sound & timer
       
   190 			if	(!InQuietPeriod())
       
   191 				{
       
   192 				Cancel();
       
   193 				}
       
   194 
       
   195 			// Reset this now
       
   196 			IdOfNotifyingAlarm() = KNullAlarmId;
       
   197 			}
       
   198 		}
       
   199 		
       
   200 	// If there is no alarm playing (b/c the previous playing alarm is snoozed,
       
   201 	// notified, disabled etc), but there are multiple notifying alarms, 
       
   202 	// restart sound playing sequence for another notifying alarm
       
   203 	if (IdOfNotifyingAlarm() == KNullAlarmId && !InQuietPeriod())
       
   204 		{
       
   205 		PlayPreviousNotifyingAlarm();
       
   206 		}
       
   207 	}
       
   208 
       
   209 
       
   210 //
       
   211 //
       
   212 //
       
   213 
       
   214 
       
   215 //*************************************************************************************
       
   216 /**
       
   217  * @see MASSrvSoundSettingsObserver
       
   218  */
       
   219 void CASSrvSoundController::MASSoundSettingsHandleChangeEvent(TSoundSettingsEvent aEvent)
       
   220 	{
       
   221 	CASSrvSoundSettings& soundSettings = ServerData().SoundSettings();
       
   222 	//
       
   223 	switch(aEvent)
       
   224 		{
       
   225 	case ESoundSettingsEventGlobalSoundState:
       
   226 		if	(soundSettings.GlobalSoundState() == EAlarmGlobalSoundStateOff)
       
   227 			{
       
   228 			// Stop playing anything right now
       
   229 			CancelAllSounds();
       
   230 			}
       
   231 		else
       
   232 			{
       
   233 			// Resume sound timing from now
       
   234 			iTimeToReturnToNormalSoundTimingBehaviour = ASSrvStaticUtils::UtcTimeNow();
       
   235 			
       
   236 			StartSoundTimingForAnyWaitingAlarmAfterPausingOrQuietPeriod();
       
   237 			}
       
   238 
       
   239 		break;
       
   240 
       
   241 	case ESoundSettingsEventSoundIntervals:
       
   242 		// Resume sound timing from now
       
   243 		CancelAllSounds();
       
   244 		iTimeToReturnToNormalSoundTimingBehaviour = ASSrvStaticUtils::UtcTimeNow();
       
   245 		
       
   246 		StartSoundTimingForAnyWaitingAlarmAfterPausingOrQuietPeriod();
       
   247 		break;
       
   248 
       
   249 	case ESoundSettingsClearPauseFlag:
       
   250 		iSoundControllerFlags.Clear(ESoundControllerFlagsPausing);
       
   251 		break;
       
   252 
       
   253 	default:
       
   254 		ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicInvalidTSoundSettingsEvent);
       
   255 		break;
       
   256 		}
       
   257 	}
       
   258 
       
   259 
       
   260 //
       
   261 //
       
   262 //
       
   263 
       
   264 
       
   265 //*************************************************************************************
       
   266 /**
       
   267  * @see MASSrvAlarmQueueObserver
       
   268  */
       
   269 void CASSrvSoundController::MAlarmQueueObserverHandleEvent(TASSrvAlarmQueueEvent aEvent, TAlarmId aAlarmId)
       
   270 	{
       
   271 	/* If a notifying alarm is deleted stop playing alarm sound.
       
   272 	 * Looking for either:
       
   273 	 * 1. The currently Notifying alarm is deleted.
       
   274 	 * 2. Alarm Queue Internalize starts whilst any alarm is notifying
       
   275 	 */
       
   276 	if ((aEvent == EASSrvAlarmQueueEventAlarmDeleted) && (aAlarmId == IdOfNotifyingAlarm()))
       
   277 		{
       
   278 		// Cancel the sound and timer, and clear the id of the alarm (we're
       
   279 		// no longer notifying about anything).
       
   280 		// Cancel sound & timer
       
   281 		if (!InQuietPeriod())
       
   282 			{
       
   283 			Cancel();
       
   284 			}
       
   285 		
       
   286 		IdOfNotifyingAlarm() = KNullAlarmId;
       
   287 		
       
   288 		// If a notifying alarm is deleted, look for the previous notifying alarm.
       
   289 		// The following function is called even if we are in quiet period 
       
   290 		// because we want the appropriate alarm to be played when quite period end.
       
   291 		PlayPreviousNotifyingAlarm();
       
   292 		}
       
   293 	else if ((aEvent == EASSrvAlarmQueueEventAlarmStartInternalize) && (KNullAlarmId != IdOfNotifyingAlarm()))
       
   294 		{
       
   295 		// Cancel the sound and timer, and clear the id of the alarm (we're
       
   296 		// no longer notifying about anything).
       
   297 		// Cancel sound & timer
       
   298 		if	(!InQuietPeriod())
       
   299 			{
       
   300 			Cancel();
       
   301 			}
       
   302 
       
   303 		IdOfNotifyingAlarm() = KNullAlarmId;
       
   304 		}
       
   305 	}
       
   306 
       
   307 //*************************************************************************************
       
   308 /**
       
   309  * @see MASSrvEnvironmentChangeObserver
       
   310  */
       
   311 
       
   312 void CASSrvSoundController::MEnvChangeHandleEvent(TInt aChanges, TUint /*aWorkdays*/, TBool /*aWorkdaysChanged*/)
       
   313 	{
       
   314 	if (aChanges & EChangesSystemTime || (aChanges & EChangesLocale && (iPreviousUTCOffset != User::UTCOffset())) )
       
   315 		{
       
   316 		// UTC offset might have changed we need to redo the CTimer::AtUTC with a new UTC offset computed
       
   317 
       
   318 		if (!iSoundControllerFlags.IsSet(ESoundControllerFlagsIsFixed)) //  if floating period
       
   319 			{
       
   320 			iTimeToReturnToNormalSoundTimingBehaviour -= TTimeIntervalSeconds(User::UTCOffset().Int() - iPreviousUTCOffset.Int());
       
   321 			}
       
   322 		else  //if fixed period
       
   323 			{
       
   324 			//cancel silent period because we can't recalculate it
       
   325 			iTimeToReturnToNormalSoundTimingBehaviour = ASSrvStaticUtils::UtcTimeNow();
       
   326 			}
       
   327 
       
   328 		if (InQuietPeriod() || SoundIsPausedForAlarm())
       
   329 			{
       
   330 			Cancel();
       
   331 
       
   332 			if(iTimeToReturnToNormalSoundTimingBehaviour <= ASSrvStaticUtils::UtcTimeNow()) 
       
   333 				{
       
   334 				ReactToSoundTimerExpiry(); // Silent period expired
       
   335 				}
       
   336 			else 
       
   337 				{
       
   338 				AtUTC(iTimeToReturnToNormalSoundTimingBehaviour);
       
   339 				}
       
   340 			}
       
   341 		else if (IdOfNotifyingAlarm() != KNullAlarmId)
       
   342 			{
       
   343 			// resume sound timing from now because of changed system time
       
   344 			StartSoundTimingForAnyWaitingAlarmAfterPausingOrQuietPeriod();
       
   345 			}
       
   346 
       
   347 		// And update the UTC offset			
       
   348 		iPreviousUTCOffset = User::UTCOffset();
       
   349 		}
       
   350 	}
       
   351 
       
   352 
       
   353 //
       
   354 //
       
   355 //
       
   356 
       
   357 
       
   358 //*************************************************************************************
       
   359 /**
       
   360  * Stops any sound from playing and resets the sound timer to an idle state.
       
   361  */
       
   362 void CASSrvSoundController::CancelAllSounds()
       
   363 	{
       
   364 	// Tell observer to stop
       
   365 	if( !IsSoundControllerDisabled() )
       
   366 		{
       
   367 		NotifySoundEvent(MASSrvSoundControllerObserver::ESoundControllerEventPlayNothing, IdOfNotifyingAlarm());
       
   368 		}
       
   369 	}
       
   370 
       
   371 
       
   372 //*************************************************************************************
       
   373 /**
       
   374  * Stop playing any sounds until the specified time.
       
   375  */
       
   376 void CASSrvSoundController::MakeAllSoundsQuietUntil(const TTime& aTime)
       
   377 	{
       
   378 	if( IsSoundControllerDisabled() )
       
   379 		{
       
   380 		return;
       
   381 		}
       
   382 
       
   383 	Cancel();
       
   384 
       
   385 	// Update the flags
       
   386 	iSoundControllerFlags.Set(ESoundControllerFlagsInQuietPeriod);
       
   387 
       
   388 	// set global sound state
       
   389 	ServerData().SoundSettings().SetGlobalSoundState(EAlarmGlobalSoundStateOff);
       
   390 	
       
   391 	// Wake up when sounds are to start again
       
   392 	iTimeToReturnToNormalSoundTimingBehaviour = aTime;
       
   393 	AtUTC(iTimeToReturnToNormalSoundTimingBehaviour);
       
   394 	
       
   395 	// Notify change
       
   396 	ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventSoundSilence, KNullAlarmId);
       
   397 	}
       
   398 	
       
   399 //*************************************************************************************
       
   400 /**
       
   401  * Stop playing the sound (for just this alarm) until the specified time.
       
   402  */
       
   403 void CASSrvSoundController::CurrentAlarmSoundPausedUntil(const TTime& aTime)
       
   404 	{
       
   405 	if( IsSoundControllerDisabled() )
       
   406 		{
       
   407 		return;
       
   408 		}
       
   409 
       
   410 	Cancel();
       
   411 
       
   412 	// Save the time we're supposed to wake up at and reset
       
   413 	// the alarm's sound state so that it can start over
       
   414 	// again when we're due to run.
       
   415 	TASSrvAlarm* alarm = ServerData().Queue().QueueAlarmById(IdOfNotifyingAlarm());
       
   416 
       
   417 	// We have a new baseline for all sound timing calculations. The next set of
       
   418 	// cycle calcs must be based upon the time at which the quiet period ends
       
   419 	// rather than the original due time.
       
   420 	alarm->ReinitializeSoundState(aTime);
       
   421 
       
   422 	// Update the flags
       
   423 	iSoundControllerFlags.Set(ESoundControllerFlagsPausing);
       
   424 	
       
   425 	// Wake up when sounds are to start again
       
   426 	iTimeToReturnToNormalSoundTimingBehaviour = aTime;
       
   427 	
       
   428 	AtUTC(aTime);
       
   429 
       
   430 	// Notify change
       
   431 	ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventSoundSilence, KNullAlarmId);
       
   432 	}
       
   433 
       
   434 
       
   435 //*************************************************************************************
       
   436 /**
       
   437  * Returns a boolean indicating whether or not the alarm server is currently
       
   438  * in a quiet period.
       
   439  */
       
   440 TBool CASSrvSoundController::InQuietPeriod() const
       
   441 	{
       
   442 	if( IsSoundControllerDisabled() )
       
   443 		{
       
   444 		return ETrue;
       
   445 		}
       
   446 	return Flags().IsSet(ESoundControllerFlagsInQuietPeriod);
       
   447 	}
       
   448 
       
   449 
       
   450 //*************************************************************************************
       
   451 /**
       
   452  * Return a boolean indicating whether sound is currently
       
   453  * paused within the alarm server.
       
   454  */
       
   455 TBool CASSrvSoundController::SoundIsPausedForAlarm() const
       
   456 	{
       
   457 	if( IsSoundControllerDisabled() )
       
   458 		{
       
   459 		return EFalse;
       
   460 		}
       
   461 	return Flags().IsSet(ESoundControllerFlagsPausing);
       
   462 	}
       
   463 
       
   464 
       
   465 //*************************************************************************************
       
   466 /**
       
   467  * Cancel a previously enabled silent period
       
   468  */
       
   469 void CASSrvSoundController::CancelSilence()
       
   470 	{
       
   471 	if( IsSoundControllerDisabled() )
       
   472 		{
       
   473 		return;
       
   474 		}
       
   475 
       
   476 	if	(iSoundControllerFlags.IsSet(ESoundControllerFlagsPausing) || iSoundControllerFlags.IsSet(ESoundControllerFlagsInQuietPeriod))
       
   477 		{
       
   478 		Cancel();
       
   479 
       
   480 		// Update the time to use as a baseline for the next bout of sounds
       
   481 		iTimeToReturnToNormalSoundTimingBehaviour = ASSrvStaticUtils::UtcTimeNow();
       
   482 		
       
   483 		// Update the flags
       
   484 		iSoundControllerFlags.Clear(ESoundControllerFlagsPausing);
       
   485 		iSoundControllerFlags.Clear(ESoundControllerFlagsInQuietPeriod);
       
   486 
       
   487 		// set global sound state
       
   488 		ServerData().SoundSettings().SetGlobalSoundState(EAlarmGlobalSoundStateOn);
       
   489 
       
   490 		// Notify change
       
   491 		ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventSoundSilence, KNullAlarmId);
       
   492 		}
       
   493 	}
       
   494 
       
   495 
       
   496 //
       
   497 //
       
   498 //
       
   499 
       
   500 
       
   501 //*************************************************************************************
       
   502 /**
       
   503  * @see CActive
       
   504  */
       
   505 void CASSrvSoundController::RunL()
       
   506 	{
       
   507 	const TInt statusValue = iStatus.Int();
       
   508 
       
   509 	// When the user changes the system time, then the timer's request status
       
   510 	// is completed with KErrAbort. If we don't gracefully trap this here, then
       
   511 	// lots of strange thing start to happen (dialogs don't get dismissed in EikSrv etc).
       
   512 	if	(statusValue == KErrAbort || statusValue == KErrCancel || statusValue == KErrOverflow)
       
   513 		return;
       
   514 
       
   515 	// Handle the timer expiry
       
   516 	ReactToSoundTimerExpiry();
       
   517 	}
       
   518 
       
   519 
       
   520 //*************************************************************************************
       
   521 /**
       
   522  * Replacement of CActive::Cancel function
       
   523  */
       
   524 void CASSrvSoundController::Cancel()
       
   525 	{
       
   526 	// If we're currently timing an event, Cancel the timer and send
       
   527 	// a StopSound command. Otherwise, don't pollute the Alert Server
       
   528 	// with an extra message.
       
   529 	if( IsActive() )
       
   530 		{
       
   531 		CTimer::Cancel();
       
   532 		CancelAllSounds();
       
   533 		}
       
   534 	}
       
   535 
       
   536 
       
   537 //
       
   538 //
       
   539 //
       
   540 
       
   541 
       
   542 //*************************************************************************************
       
   543 void CASSrvSoundController::ReactToSoundTimerExpiry()
       
   544 	{
       
   545 	__ASSERT_DEBUG(!IsSoundControllerDisabled(), ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicUnexpectedEventSoundControllerDisabled));
       
   546 
       
   547 	if	(InQuietPeriod())
       
   548 		{
       
   549 		// If we're in a quiet period, and the sound timer has expired,
       
   550 		// then we should now start to play sound for any currently notifying
       
   551 		// alarm.
       
   552 		iSoundControllerFlags.Clear(ESoundControllerFlagsInQuietPeriod);
       
   553 		ServerData().SoundSettings().SetGlobalSoundState(EAlarmGlobalSoundStateOn);
       
   554 		}
       
   555 	else if (SoundIsPausedForAlarm())
       
   556 		{
       
   557 		iSoundControllerFlags.Clear(ESoundControllerFlagsPausing);
       
   558 		StartSoundTimingForAnyWaitingAlarmAfterPausingOrQuietPeriod();
       
   559 		}
       
   560 	else
       
   561 		{
       
   562 		// ensure notifying Alarm hasn't been disabled, etc... between Timer expiry and this function running
       
   563 		if(IdOfNotifyingAlarm() != KNullAlarmId)
       
   564 			{
       
   565 			WorkOutAndScheduleForNextSoundCycle();
       
   566 			}
       
   567 		else
       
   568 			{
       
   569 			// stop any sound currently playing 
       
   570 			CancelAllSounds();
       
   571 			}
       
   572 		}
       
   573 	}
       
   574 
       
   575 
       
   576 //*************************************************************************************
       
   577 void CASSrvSoundController::NotifySoundEvent(MASSrvSoundControllerObserver::TSoundControllerEvent aEvent, TAlarmId aAlarmId)
       
   578 	{
       
   579 	__ASSERT_DEBUG(!IsSoundControllerDisabled(), ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicUnexpectedEventSoundControllerDisabled));
       
   580 
       
   581 	if	(aEvent == MASSrvSoundControllerObserver::ESoundControllerEventPlaySound && 
       
   582 		(InQuietPeriod() || SoundIsPausedForAlarm()))
       
   583 		{
       
   584 		// If we're in a quiet period, then we should ignore play sound requests...
       
   585 		return;
       
   586 		}
       
   587 	else if (ServerData().SoundSettings().GlobalSoundState() == EAlarmGlobalSoundStateOff)
       
   588 		{
       
   589 		// Also ignore sounds requests if all sounds are disabled
       
   590 		return;
       
   591 		}
       
   592 
       
   593 	// In an effort to minimise the polution passed to the Alert Server, let's
       
   594 	// keep track of what message was last sent, except the SoundStopAll events.
       
   595 	if ( MASSrvSoundControllerObserver::ESoundControllerEventPlayNothing == aEvent && aAlarmId == KNullAlarmId )
       
   596 		{
       
   597 		iObserver.MASHandleSoundControllerEvent(aEvent, aAlarmId);
       
   598 		}
       
   599 	else if ( iPreviousSoundEvent != aEvent )
       
   600 		{
       
   601 		iPreviousSoundEvent = aEvent;
       
   602 		iObserver.MASHandleSoundControllerEvent(aEvent, aAlarmId);
       
   603 		}
       
   604 	}
       
   605 
       
   606 
       
   607 //*************************************************************************************
       
   608 void CASSrvSoundController::StartSoundTimingForAnyWaitingAlarmAfterPausingOrQuietPeriod()
       
   609 	{
       
   610 	__ASSERT_DEBUG(!IsSoundControllerDisabled(), ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicUnexpectedEventSoundControllerDisabled));
       
   611 
       
   612 	const TAlarmId id = IdOfNotifyingAlarm();
       
   613 	if	(id != KNullAlarmId)
       
   614 		{
       
   615 		// Cancel function of this object is overridden and sends 
       
   616 		// ESoundControllerEventPlayNothing message as well as Cancels the timer.
       
   617 		// The situation that the timer is pending is very unlikely, so we check 
       
   618 		// if it is Active to prevent unnecessary message pollution.
       
   619 		if (IsActive())
       
   620 			{
       
   621 			Cancel();
       
   622 			}
       
   623 
       
   624 		// Save the time we're supposed to wake up at and reset
       
   625 		// the alarm's sound state so that it can start over
       
   626 		// again when we're due to run.
       
   627 		TASSrvAlarm* alarm = ServerData().Queue().QueueAlarmById(id);
       
   628 
       
   629 		// Clear the sound paused flag for the notifying alarm
       
   630 		alarm->ClearSoundPausedFlag();
       
   631 
       
   632 		// We have a new baseline for all sound timing calculations. The next set of
       
   633 		// cycle calcs must be based upon the time at which the quiet period ends
       
   634 		// rather than the original due time.
       
   635 		alarm->ReinitializeSoundState(iTimeToReturnToNormalSoundTimingBehaviour);
       
   636 
       
   637 		// Is a fixed value, should not be recomputed if offset changes.
       
   638 		iSoundControllerFlags.Set(ESoundControllerFlagsIsFixed);
       
   639 
       
   640 		// Run again straight away - this will start the sound again immediately.
       
   641 		AtUTC(iTimeToReturnToNormalSoundTimingBehaviour);
       
   642 		}
       
   643 	}
       
   644 
       
   645 
       
   646 //*************************************************************************************
       
   647 void CASSrvSoundController::WorkOutAndScheduleForNextSoundCycle()
       
   648 	{
       
   649 	__ASSERT_DEBUG(!IsSoundControllerDisabled(), ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicUnexpectedEventSoundControllerDisabled));
       
   650 
       
   651 	__ASSERT_ALWAYS(IdOfNotifyingAlarm() != KNullAlarmId, ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicNotifyingAboutWrongAlarm));
       
   652 
       
   653 	const TAlarmId id = IdOfNotifyingAlarm();
       
   654 
       
   655 
       
   656 	// Get the alarm which we are monitoring...
       
   657 	TASSrvAlarm* alarm = ServerData().Queue().QueueAlarmById(id);
       
   658  
       
   659 
       
   660 	// Tell observer what to do
       
   661 	MASSrvSoundControllerObserver::TSoundControllerEvent event = MASSrvSoundControllerObserver::ESoundControllerEventPlaySound;
       
   662 	if	(alarm->SoundState() == TASSrvAlarm::ESoundStatePlayingNothing)
       
   663 		event = MASSrvSoundControllerObserver::ESoundControllerEventPlayNothing;
       
   664 	NotifySoundEvent(event, id);
       
   665 
       
   666 	// Work out when we're next due to play [sound/silence]
       
   667 	const TTime nextTimePeriod = alarm->CalculateAndPrepareNextSoundCycle();
       
   668 	
       
   669 	if (nextTimePeriod == Time::NullTTime())
       
   670 		{
       
   671 		// We've reached the end of the Sound Interval sequence, with the 
       
   672 		// Sound Setting Repeat option set to EAlarmSoundRepeatSettingStop.
       
   673 		// Reset the Alarm Id and *don't* start the timer.
       
   674 		IdOfNotifyingAlarm() = KNullAlarmId;
       
   675 		}
       
   676 	else
       
   677 		{
       
   678 		// Toggle the alarm's sound state so that when we wake up, we do the right thing
       
   679 		alarm->ToggleSoundState();
       
   680 
       
   681 		// Next time to react is a fixed offset to UTC
       
   682 		iSoundControllerFlags.Set(ESoundControllerFlagsIsFixed);
       
   683 
       
   684 		// Wait for the next time to react
       
   685 		AtUTC(nextTimePeriod);
       
   686 		}
       
   687 	}
       
   688 
       
   689 
       
   690 /**
       
   691 Silent sound if the given alarm id is the currently playing alarm.
       
   692 Handles EASAltAlertServerResponseSilence.
       
   693 */
       
   694 void CASSrvSoundController::CancelSound(TAlarmId aAlarmId)
       
   695 	{
       
   696 	// Don't notify anyone if we're disabled.
       
   697 	if( IsSoundControllerDisabled() )
       
   698 		{
       
   699 		return;
       
   700 		}
       
   701 	
       
   702 	if ( aAlarmId == KNullAlarmId )
       
   703 		{
       
   704 		NotifySoundEvent(MASSrvSoundControllerObserver::ESoundControllerEventPlayNothing, aAlarmId);
       
   705 		}
       
   706 	else if ( aAlarmId == IdOfNotifyingAlarm() )
       
   707 		{
       
   708 		NotifySoundEvent(MASSrvSoundControllerObserver::ESoundControllerEventPlayNothing, aAlarmId);
       
   709 		}
       
   710 	}
       
   711 
       
   712 /**
       
   713 If there are other alarm in the notifying alarm list, start sound play
       
   714 sequence for the previous notifying alarm. If we are in quite period, this previous
       
   715 alarm will be played after quite period ends
       
   716 */
       
   717 void CASSrvSoundController::PlayPreviousNotifyingAlarm()
       
   718 	{
       
   719 	CASSrvAlarmQueue& queue = ServerData().Queue();
       
   720 	
       
   721 	TASSrvAlarm* lastAlarm = NULL;
       
   722 	RASSrvIteratorByState iterator(queue, EAlarmStateNotifying);
       
   723 	iterator.Open();
       
   724 	if (!iterator.NextAlarmAvailable())
       
   725 		{
       
   726 		return;
       
   727 		}
       
   728 
       
   729 	// look for a the latest alarm
       
   730 	while (iterator.NextAlarmAvailable())
       
   731 		{
       
   732 		lastAlarm = &iterator.NextAlarm();
       
   733 		}
       
   734 	
       
   735 	IdOfNotifyingAlarm() = lastAlarm->Id();
       
   736 	
       
   737 	if (!InQuietPeriod())
       
   738 		{
       
   739 		// reset the baseline for all sound timing calculations.
       
   740 		TTime now(ASSrvStaticUtils::UtcTimeNow());			
       
   741 		lastAlarm->ReinitializeSoundState(now);
       
   742 		WorkOutAndScheduleForNextSoundCycle();
       
   743 		}
       
   744 	}
       
   745