callcontinuity/vcchotrigger/src/vcccchmonitor.cpp
changeset 0 a4daefaec16c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/callcontinuity/vcchotrigger/src/vcccchmonitor.cpp	Mon Jan 18 20:12:36 2010 +0200
@@ -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 <cch.h>
+#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;
+    }