diff -r f742655b05bf -r d38647835c2e callcontinuity/vcchotrigger/src/vcccchmonitor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/callcontinuity/vcchotrigger/src/vcccchmonitor.cpp Wed Sep 01 12:29:57 2010 +0100 @@ -0,0 +1,433 @@ +/* +* Copyright (c) 2008-2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Implementation of the CCH monitor. +* +*/ + + + +#include +#include "vcccchmonitor.h" +#include "vccsettingsreader.h" +#include "rubydebug.h" + +// --------------------------------------------------------------------------- +// Symbian OS static constructor +// --------------------------------------------------------------------------- +// +CVccCchMonitor* CVccCchMonitor::NewL( MVccCchObserver& aObserver ) + { + RUBY_DEBUG_BLOCKL( "CVccCchMonitor::NewL" ); + + CVccCchMonitor* self = new ( ELeave ) CVccCchMonitor( aObserver ); + + CleanupStack::PushL( self ); + + self->ConstructL(); + + CleanupStack::Pop( self ); + + return self; + } + +// --------------------------------------------------------------------------- +// C++ destructor +// --------------------------------------------------------------------------- +// +CVccCchMonitor::~CVccCchMonitor() + { + RUBY_DEBUG0( "CVccCchMonitor::~CVccCchMonitor START" ); + + // If we have reserved the used service, free it before disabling. + // Do not mind the return values, just keep going. + + if ( iCchService ) + { + if ( iServiceReserved ) + { + RUBY_DEBUG0( " -Free and disable service" ); + + (void) iCchService->Free( ECCHVoIPSub ); + (void) iCchService->Disable( ECCHVoIPSub ); + + // We did disabled here. + iDisableService = EFalse; + } + + // If we enabled the service, we must disable it also + // ( even if it was not reserved for us). + // Do not mind the return value, just keep going. + + if ( iDisableService ) + { + RUBY_DEBUG0( " -Disable service" ); + (void) iCchService->Disable( ECCHVoIPSub ); + } + + // Remove observer + iCchService->RemoveObserver(); + + // We DO NOT OWN the service, DO NOT DELETE IT + iCchService = NULL; + } + + // Free the CCH itself + delete iCch; + RUBY_DEBUG0( "CVccCchMonitor::~CVccCchMonitor STOP" ); + } + +// --------------------------------------------------------------------------- +// Symbian OS 2nd phase constructor +// --------------------------------------------------------------------------- +// +void CVccCchMonitor::ConstructL() + { + RUBY_DEBUG_BLOCKL( "CVccCchMonitor::ConstructL" ); + + // First we create the CCH object and get the VoIP id + // which is VCC enabled. + // + // If we don't get the VoIP id we leave since + // without the VoIP id we cannot get the right VoIP service. + // + // If everything goes well, we try to enable the service. + // All errors etc. are received thru the CCH observer interface. + // + + // Initialize some own flags. + + // Do not notify our observer (yet). + iNotifyObserver = EFalse; + + // Do not disable service when we exit. + iDisableService = EFalse; + + // Intitial CCH state. + iCurrentCchState = ECCHUninitialized; + + // No errors so far. + iLastCchError = KErrNone; + + // And service is not available (yet). + iCurrentStatus = MVccCchObserver::EServiceUnavailable; + + + // Create CCH + iCch = CCch::NewL(); + + // We do not have the service yet. + iCchService = NULL; + } + +// --------------------------------------------------------------------------- +// C++ constructor +// --------------------------------------------------------------------------- +// +CVccCchMonitor::CVccCchMonitor( MVccCchObserver& aObserver ) + : iObserver( aObserver ) + { + RUBY_DEBUG_BLOCK( "CVccCchMonitor::CVccCchMonitor" ); + } + +// --------------------------------------------------------------------------- +// Enable the VoIP service and start monitoring the state of the CCH. +// --------------------------------------------------------------------------- +// +void CVccCchMonitor::EnableServiceL() + { + RUBY_DEBUG_BLOCK( "CVccCchMonitor::EnableServiceL" ); + + // CCH must be created. + __ASSERT_DEBUG( iCch, User::Leave( KErrArgument ) ); + + // Get the Voip service id. Get it always to if the SP + // settings are chagned, we get updated values. + + iServiceId = VccSettingsReader::VoIPServiceIdL(); + + if ( iServiceId == KErrNotFound ) + { + RUBY_DEBUG1( " -VoIP service id (%d) not found - LEAVE", iServiceId ); + User::Leave( KErrNotFound ); + } + + // Get the service if not already available + + if ( !iCchService ) + { + + // Get the service. The ownership is not transfered + iCchService = iCch->GetService( iServiceId ); + + RUBY_DEBUG1( " -CCH service fetched, addr = %x (LEAVE if NULL)", + iCchService ); + + // CCH cannot find the service if it returns NULL + if ( !iCchService ) + { + User::Leave( KErrNotFound ); + } + + // We got the service. + // Set us as observer to get notifications. + + iCchService->SetObserver( *this ); + } + + + // Start sending notifications to our observer. + iNotifyObserver = ETrue; + + // And then enable the VoIP service. + DoEnableServiceL(); + } + +// --------------------------------------------------------------------------- +// Disable the service, this means that +// we stop sending notifications to our observer. +// The service is not disabled, we just do not notify our obsserver. +// The service is disabled when we exit. +// --------------------------------------------------------------------------- +// +void CVccCchMonitor::DisableService() + { + RUBY_DEBUG_BLOCK( "CVccCchMonitor::DisableService" ); + + // We do not disable the service. + // It can be done here but if we start and stop it + // many times within a short period of time, + // it does not make sense. + // + // Service is released (and disabled if needed) + // when we exit (see destructor). + // So here just flag to stop sending notifications to + // our observer. + iCchService = NULL; + iNotifyObserver = EFalse; + } + +// --------------------------------------------------------------------------- +// From MCchServiceStatusObserver +// Handles CCH service or error status changes. +// --------------------------------------------------------------------------- +// +void CVccCchMonitor::ServiceStatusChanged( + TInt aServiceId, + TCCHSubserviceType aType, + const TCchServiceStatus& aServiceStatus ) + { + RUBY_DEBUG_BLOCK( "CVccCchMonitor::ServiceStatusChanged" ); + + // The CCH sends notifications to all + // so service id and the type must be checked. + + if ( !( aServiceId == iServiceId && aType == ECCHVoIPSub ) ) + { + return; + } + + // Get the state and the error. + iCurrentCchState = aServiceStatus.State(); + iLastCchError = aServiceStatus.Error(); + + RUBY_DEBUG2( " -State = %d, error = %d", iCurrentCchState, iLastCchError ); + + + // If we are observing, notify our observer. + if ( iNotifyObserver == EFalse ) + { + return; + } + else + { + NotifyObserver(); + } + } + +// --------------------------------------------------------------------------- +// Send notifications to our observer. +// --------------------------------------------------------------------------- +// +void CVccCchMonitor::NotifyObserver() + { + RUBY_DEBUG_BLOCK( "CVccCchMonitor::NotifyObserver" ); + + + // This method should be called only when + // the state of the cch service is updated + // to iCurrentCchState member variable. + + // If CCH state != enabled or there is an error, service is not working + // + // Note that the service stays enabled until someone disables it. + + if ( ( iCurrentCchState != ECCHEnabled ) || + ( iLastCchError != KErrNone ) ) + { + RUBY_DEBUG0( " -Service unavailable" ); + iCurrentStatus = MVccCchObserver::EServiceUnavailable; + } + else + { + RUBY_DEBUG0( " -Service available" ); + iCurrentStatus = MVccCchObserver::EServiceAvailable; + } + + iObserver.CchServiceStatusChanged( iCurrentStatus ); + } + +// --------------------------------------------------------------------------- +// Enable the CCH service we are using (ECCHVoIPSub). +// --------------------------------------------------------------------------- +// +void CVccCchMonitor::DoEnableServiceL() + { + RUBY_DEBUG_BLOCK( "CVccCchMonitor::DoEnableServiceL" ); + + // Enable the service + // + // Depending of the current state of the CCH service: + // + // Do nothing if + // - ECCHConnecting + // + // + // Try to enable if + // - ECCHDisconnecting + // - ECCHDisabled + // - ECCHUninitialized + // + // Notify our observer if + // - ECCHEnabled + + + // Check the state of the service. + // The state is got from the status object of the service. + + + TCchServiceStatus serviceStatus; + TInt errorValue( KErrNone ); + + // Get the status. + errorValue = iCchService->GetStatus( ECCHVoIPSub, serviceStatus ); + + RUBY_DEBUG2( " -GetStatus returned = %d, service status = %d", + errorValue, serviceStatus.State() ); + + + // If we can't get the status, leave + + if ( errorValue != KErrNone ) + { + RUBY_DEBUG0( " -GetStatus returned error, can't enable - LEAVE" ); + + User::Leave( errorValue ); + } + + + // Okay, get the state and error (from status). + iCurrentCchState = serviceStatus.State(); + iLastCchError = serviceStatus.Error(); + + RUBY_DEBUG1( " -Service state = %d", iCurrentCchState ); + + + switch( iCurrentCchState ) + { + case ECCHUninitialized: + // Fall-through intended here + case ECCHDisabled: + // Fall-through intended here + case ECCHDisconnecting: + { + RUBY_DEBUG0( " -Try to enable service, LEAVE if error" ); + + // Enable, leave if errors, + User::LeaveIfError( iCchService->Enable( ECCHVoIPSub ) ); + + // Service should be enabled in a while, + // we must disable it upon exiting since it was not enabled + // (we are one who enabled it so must disable it). + + iDisableService = ETrue; + break; + } + + case ECCHConnecting: + { + // Service is connecting (by someone else + // or we have been called more than twice). + // We should get the notification when it is enabled + // and ready for the use. + // Do nothing. + break; + } + + case ECCHEnabled: + { + RUBY_DEBUG0( " -Service is already enabled - do nothing" ); + + // Enabled already. We can notify our observer + // with the status of the service. + + NotifyObserver(); + break; + } + + default: + { + break; + } + + } // End of switch + + + // So good so far... + // Check if we can reserve (if not done already) + // the service for us. + // This prevents someone to disable it during a call + + if ( !iServiceReserved ) + { + TBool isReserved( EFalse ); + + iCchService->IsReserved( ECCHVoIPSub, isReserved ); + + if ( !isReserved ) + { + RUBY_DEBUG0( " -Try to reserve the service for us" ); + + // It is free. Try to reserve it. + + if ( iCchService->Reserve( ECCHVoIPSub ) == KErrNone ) + { + RUBY_DEBUG0( " -Service reserved for us" ); + iServiceReserved = ETrue; + } + } + } + } + +// --------------------------------------------------------------------------- +// Return the current status of the service availability +// --------------------------------------------------------------------------- +// +MVccCchObserver::TServiceStatus CVccCchMonitor::ServiceStatus() const + { + RUBY_DEBUG_BLOCK( "CVccCchMonitor::ServiceStatus" ); + + RUBY_DEBUG1( " -Status = %d", iCurrentStatus ); + + return iCurrentStatus; + }