upnpavcontroller/upnprenderingstatemachine/src/upnpvolumestatemachine.cpp
branchIOP_Improvements
changeset 40 08b5eae9f9ff
equal deleted inserted replaced
39:6369bfd1b60d 40:08b5eae9f9ff
       
     1 /*
       
     2 * Copyright (c) 2007,2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Implementation of generic upnp volume state machine
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 // INCLUDES
       
    20 // avcontroller api
       
    21 #include <upnpavrenderingsession.h>
       
    22 #include <upnpavdevice.h> // for device.VolumeCapability()
       
    23 // volume state machine
       
    24 #include "upnprenderingstatemachineconstants.h" // option flags
       
    25 #include "upnpvolumestatemachineobserver.h"
       
    26 #include "upnpvolumestatemachine.h"
       
    27 
       
    28 _LIT( KComponentLogfile, "upnprenderingengine.txt");
       
    29 #include "upnplog.h"
       
    30 
       
    31 // CONSTANTS
       
    32 const TInt KCancelTimeMaximum = 3000000;
       
    33 const TInt KCancelTimeResolution = 500000;
       
    34 
       
    35 // ======== MEMBER FUNCTIONS ========
       
    36 
       
    37 
       
    38 TUpnpVSMQueueItem::TUpnpVSMQueueItem( 
       
    39     const TUpnpVSMQueueItem::TPropertyType aProperty, const TInt aValue )
       
    40     : iProperty( aProperty )
       
    41     , iValue( aValue )
       
    42     {    
       
    43     }
       
    44 
       
    45 TUpnpVSMQueueItem::TPropertyType TUpnpVSMQueueItem::Property() const
       
    46     {
       
    47     return iProperty;
       
    48     }
       
    49     
       
    50 TInt TUpnpVSMQueueItem::Value() const
       
    51     {
       
    52     return iValue;
       
    53     }
       
    54 
       
    55 // --------------------------------------------------------------------------
       
    56 // CUpnpVolumeStateMachine::NewL
       
    57 // Static constructor.
       
    58 // --------------------------------------------------------------------------
       
    59 // 
       
    60 EXPORT_C CUpnpVolumeStateMachine* CUpnpVolumeStateMachine::NewL( 
       
    61     MUPnPAVRenderingSession& aSession )
       
    62     {
       
    63     CUpnpVolumeStateMachine* self =
       
    64         new (ELeave) CUpnpVolumeStateMachine( aSession );
       
    65     // no 2nd phase construction needed
       
    66     return self;
       
    67     }
       
    68 
       
    69 // --------------------------------------------------------------------------
       
    70 // CUpnpVolumeStateMachine::CUpnpVolumeStateMachine
       
    71 // Default constructor.
       
    72 // --------------------------------------------------------------------------
       
    73 // 
       
    74 CUpnpVolumeStateMachine::CUpnpVolumeStateMachine( 
       
    75     MUPnPAVRenderingSession& aSession )
       
    76     : iSession( aSession )
       
    77     {
       
    78     __LOG( "VolumeStateMachine: constructor" );
       
    79     iVolumeCapability = iSession.Device().VolumeCapability();
       
    80     iMuteCapability = iSession.Device().MuteCapability();
       
    81     iState = EOffSync;
       
    82     iCurrentVolume = KErrNotFound;
       
    83     iVolumeToSetAfterMute = KErrNotFound;
       
    84     iCurrentMute = KErrNotFound;
       
    85     iMuteRequestedByClient = EFalse;
       
    86     iCachedVolume = KErrNotFound;
       
    87     iCachedMute = KErrNotFound;
       
    88     }
       
    89 
       
    90 
       
    91 // --------------------------------------------------------------------------
       
    92 // CUpnpVolumeStateMachine::~CUpnpVolumeStateMachine
       
    93 // Destructor.
       
    94 // --------------------------------------------------------------------------
       
    95 //
       
    96 EXPORT_C CUpnpVolumeStateMachine::~CUpnpVolumeStateMachine()
       
    97     {
       
    98     __LOG( "VolumeStateMachine: destructor" );
       
    99     }
       
   100 
       
   101 
       
   102 // --------------------------------------------------------------------------
       
   103 // CUpnpVolumeStateMachine::SetOptions
       
   104 // sets the option flags for this state machine
       
   105 // --------------------------------------------------------------------------
       
   106 //
       
   107 EXPORT_C void CUpnpVolumeStateMachine::SetOptions( TInt aOptions )
       
   108     {
       
   109     iOptions = aOptions;
       
   110     }
       
   111 
       
   112 // --------------------------------------------------------------------------
       
   113 // CUpnpVolumeStateMachine::Options
       
   114 // --------------------------------------------------------------------------
       
   115 //
       
   116 EXPORT_C TInt CUpnpVolumeStateMachine::Options() const
       
   117     {
       
   118     return iOptions;
       
   119     }
       
   120 
       
   121 // --------------------------------------------------------------------------
       
   122 // CUpnpVolumeStateMachine::SetObserver
       
   123 // --------------------------------------------------------------------------
       
   124 //
       
   125 EXPORT_C void CUpnpVolumeStateMachine::SetObserver(
       
   126     MUpnpVolumeStateMachineObserver& aObserver )
       
   127     {
       
   128     iObserver = &aObserver;
       
   129     }
       
   130 
       
   131 // --------------------------------------------------------------------------
       
   132 // CUpnpVolumeStateMachine::RemoveObserver
       
   133 // --------------------------------------------------------------------------
       
   134 //
       
   135 EXPORT_C void CUpnpVolumeStateMachine::RemoveObserver()
       
   136     {
       
   137     iObserver = NULL;
       
   138     }
       
   139 
       
   140 // --------------------------------------------------------------------------
       
   141 // CUpnpVolumeStateMachine::SyncL
       
   142 // Synchronises this state machine with the renderer
       
   143 // --------------------------------------------------------------------------
       
   144 //
       
   145 EXPORT_C void CUpnpVolumeStateMachine::SyncL()
       
   146     {
       
   147     __LOG( "VolumeStateMachine: SyncL" );
       
   148     
       
   149     if ( iState != EOffSync && iState != EIdle )
       
   150         {
       
   151         __LOG( "VolumeStateMachine: not synchronizing" );
       
   152         return;
       
   153         }
       
   154     
       
   155     if ( !iVolumeCapability )
       
   156         {
       
   157         User::Leave( KErrNotSupported );
       
   158         }
       
   159 
       
   160     iSession.GetVolumeL();
       
   161     iState = ESyncing;
       
   162     }
       
   163 
       
   164 // --------------------------------------------------------------------------
       
   165 // CUpnpVolumeStateMachine::SetOffSync
       
   166 // Forces the state machine off sync
       
   167 // --------------------------------------------------------------------------
       
   168 //
       
   169 EXPORT_C void CUpnpVolumeStateMachine::SetOffSync()
       
   170     {
       
   171     __ASSERTD( !IsBusy(), __FILE__, __LINE__ );
       
   172     iState = EOffSync;
       
   173     iCurrentVolume = KErrNotFound;
       
   174     iVolumeToSetAfterMute = KErrNotFound;
       
   175     iCurrentMute = KErrNotFound;
       
   176     iMuteRequestedByClient = EFalse;
       
   177     }
       
   178 
       
   179 // --------------------------------------------------------------------------
       
   180 // CUpnpVolumeStateMachine::IsInSync
       
   181 // --------------------------------------------------------------------------
       
   182 //
       
   183 EXPORT_C TBool CUpnpVolumeStateMachine::IsInSync() const
       
   184     {
       
   185     return iState != EOffSync;
       
   186     }
       
   187 
       
   188 // --------------------------------------------------------------------------
       
   189 // CUpnpVolumeStateMachine::SetVolumeL
       
   190 // --------------------------------------------------------------------------
       
   191 //
       
   192 EXPORT_C void CUpnpVolumeStateMachine::SetVolumeL( TInt aVolume )
       
   193     {
       
   194     __LOG1( "VolumeStateMachine: SetVolumeL %d", aVolume );
       
   195     __ASSERTD( IsInSync(), __FILE__, __LINE__ );
       
   196     if ( !iVolumeCapability )
       
   197         {
       
   198         User::Leave( KErrNotSupported );
       
   199         }
       
   200     
       
   201     if ( IsBusy() )
       
   202         {
       
   203         PushIntoQueueL( TUpnpVSMQueueItem::EVolume, aVolume );
       
   204         return;
       
   205         }
       
   206 
       
   207     // check volume is between given limits
       
   208     aVolume = Max( aVolume, KVolumeMin );
       
   209     aVolume = Min( aVolume, KVolumeMax );
       
   210 
       
   211     if ( aVolume == KVolumeMin && iCurrentVolume > 0 &&
       
   212         iMuteCapability && iCurrentMute == KMuteOff &&
       
   213         iOptions & Upnp::EConvertVolumeZeroToMute )
       
   214         {
       
   215         // adjust volume to zero (using mute)
       
   216         iSession.SetMuteL( ETrue );
       
   217         iState = EAdjustingVolumeToZero;
       
   218         }
       
   219     else if ( aVolume == KVolumeMin && iCurrentMute == KMuteOn )
       
   220         {
       
   221         // no need to change volume. Call back directly.
       
   222         if ( iObserver )
       
   223             {
       
   224             iObserver->VolumeChanged(
       
   225                 KErrNone, iCurrentVolume, ETrue );
       
   226             }
       
   227         }
       
   228     else if ( aVolume > KVolumeMin && iCurrentMute == KMuteOn &&
       
   229         !iMuteRequestedByClient )
       
   230         {
       
   231         // volume is at zero, and renderer is muted.
       
   232         // unmute and after that change volume if needed
       
   233         iVolumeToSetAfterMute = aVolume;
       
   234         iSession.SetMuteL( EFalse );
       
   235         iState = EAdjustingVolumeFromZero;
       
   236         }
       
   237     else if ( aVolume != iCurrentVolume )
       
   238         {
       
   239         // adjust volume normally
       
   240         iSession.SetVolumeL( aVolume );
       
   241         iState = EAdjustingVolume;
       
   242         }
       
   243     else
       
   244         {
       
   245         // no need to change volume. Call back directly.
       
   246         if ( iObserver )
       
   247             {
       
   248             iObserver->VolumeChanged(
       
   249                 KErrNone, iCurrentVolume, ETrue );
       
   250             }
       
   251         }
       
   252     }
       
   253 
       
   254 // --------------------------------------------------------------------------
       
   255 // CUpnpVolumeStateMachine::Volume
       
   256 // --------------------------------------------------------------------------
       
   257 //
       
   258 EXPORT_C TInt CUpnpVolumeStateMachine::Volume() const
       
   259     {
       
   260     __ASSERTD( IsInSync(), __FILE__, __LINE__ );
       
   261     TInt vol = iCurrentVolume;
       
   262     if ( iCurrentMute && (iOptions & Upnp::EConvertVolumeZeroToMute) )
       
   263         {
       
   264         vol = KVolumeMin;
       
   265         }
       
   266     return vol;
       
   267     }
       
   268 
       
   269 // --------------------------------------------------------------------------
       
   270 // CUpnpVolumeStateMachine::SetMuteL
       
   271 // --------------------------------------------------------------------------
       
   272 //
       
   273 EXPORT_C void CUpnpVolumeStateMachine::SetMuteL( TBool aMuteState )
       
   274     {
       
   275     __LOG1( "VolumeStateMachine: SetMuteL", aMuteState );
       
   276     __ASSERTD( IsInSync(), __FILE__, __LINE__ );
       
   277     if ( !iMuteCapability )
       
   278         {
       
   279         // Could implement here FAKE MUTE SUPPORT by converting mute
       
   280         // to Volume(0). However there is no need to that since no clients
       
   281         // use the mute feature.
       
   282         User::Leave( KErrNotSupported );
       
   283         }
       
   284     if ( IsBusy() )
       
   285         {
       
   286         PushIntoQueueL( TUpnpVSMQueueItem::EMute, aMuteState );
       
   287         return;
       
   288         }
       
   289 
       
   290     // check mute state is between given limits
       
   291     aMuteState = Max( aMuteState, KMuteOff );
       
   292     aMuteState = Min( aMuteState, KMuteOn );
       
   293 
       
   294     if ( aMuteState && !iCurrentMute )
       
   295         {
       
   296         // mute
       
   297         iSession.SetMuteL( ETrue );
       
   298         iState = EAdjustingMute;
       
   299         }
       
   300     else if ( !aMuteState && iCurrentMute )
       
   301         {
       
   302         // unmute
       
   303         iSession.SetMuteL( EFalse );
       
   304         iState = EAdjustingMute;
       
   305         }
       
   306     else
       
   307         {
       
   308         // no change in mute state. Call back directly.
       
   309         if ( iObserver )
       
   310             {
       
   311             iObserver->MuteChanged(
       
   312                 KErrNone, iCurrentMute, ETrue );
       
   313             }
       
   314         }
       
   315     }
       
   316 
       
   317 // --------------------------------------------------------------------------
       
   318 // CUpnpVolumeStateMachine::Mute
       
   319 // --------------------------------------------------------------------------
       
   320 //
       
   321 EXPORT_C TBool CUpnpVolumeStateMachine::Mute() const
       
   322     {
       
   323     __ASSERTD( IsInSync(), __FILE__, __LINE__ );
       
   324     return ( (iCurrentMute == KMuteOn) ? KMuteOn : KMuteOff );
       
   325     }
       
   326 
       
   327 // --------------------------------------------------------------------------
       
   328 // CUpnpVolumeStateMachine::IsBusy
       
   329 // --------------------------------------------------------------------------
       
   330 //
       
   331 EXPORT_C TBool CUpnpVolumeStateMachine::IsBusy() const
       
   332     {
       
   333     return iState != EIdle;
       
   334     }
       
   335 
       
   336 // --------------------------------------------------------------------------
       
   337 // CUpnpVolumeStateMachine::HasVolumeCapability
       
   338 // tests if renderer has volume capability
       
   339 // --------------------------------------------------------------------------
       
   340 //
       
   341 EXPORT_C TBool CUpnpVolumeStateMachine::HasVolumeCapability() const
       
   342     {
       
   343     return iVolumeCapability;
       
   344     }
       
   345 
       
   346 // --------------------------------------------------------------------------
       
   347 // CUpnpVolumeStateMachine::Cancel
       
   348 // --------------------------------------------------------------------------
       
   349 //
       
   350 EXPORT_C void CUpnpVolumeStateMachine::Cancel()
       
   351     {
       
   352     // actually we can not cancel anything, but providing the interface for
       
   353     // future purposes
       
   354     if ( iState != EIdle )
       
   355         {
       
   356         __LOG1( "VolumeStateMachine: Canceling in state %d", iState );
       
   357         iState = ECancelled;
       
   358         for ( TInt t = KCancelTimeMaximum;
       
   359             t > 0 && iState != EIdle;
       
   360             t -= KCancelTimeResolution )
       
   361             {
       
   362             User::After( TTimeIntervalMicroSeconds32(
       
   363                 KCancelTimeResolution ) );
       
   364             }
       
   365         __LOG1( "VolumeStateMachine: state after cancel: %d", iState );
       
   366         }
       
   367     }
       
   368 
       
   369 void CUpnpVolumeStateMachine::HandleVolumeResultInSyncState(
       
   370     TInt aError, TInt aVolumeLevel, TBool /*aActionResponse*/ )
       
   371     {
       
   372     if ( aError == KErrNone )
       
   373         {
       
   374         iCurrentVolume = aVolumeLevel;
       
   375         if ( iMuteCapability )
       
   376             {
       
   377             // continue to sync mute
       
   378             TRAPD( muteError, iSession.GetMuteL() );
       
   379             if ( muteError != KErrNone )
       
   380                 {
       
   381                 // error syncing mute - callback
       
   382                 iState = EIdle;
       
   383                 if ( iObserver )
       
   384                     {
       
   385                     iObserver->VolumeSyncReady( muteError );
       
   386                     }
       
   387                 }
       
   388             }
       
   389         else
       
   390             {
       
   391             // mute not needed - callback
       
   392             iCurrentMute = KMuteOff; // assume always off
       
   393             iState = EIdle;
       
   394             // notify sync initially and volume if changed
       
   395             if ( iObserver && iCachedVolume == KErrNotFound )
       
   396                 {
       
   397                 iObserver->VolumeSyncReady( KErrNone );
       
   398                 }
       
   399             else if ( iObserver && iCachedVolume != iCurrentVolume )
       
   400                 {
       
   401                 iObserver->VolumeChanged(
       
   402                     aError, iCurrentVolume, EFalse );
       
   403                 }
       
   404             }
       
   405         }
       
   406     else
       
   407         {
       
   408         // error callback
       
   409         iState = EIdle;
       
   410         if ( iObserver )
       
   411             {
       
   412             iObserver->VolumeSyncReady( aError );
       
   413             }
       
   414         }
       
   415     
       
   416     }
       
   417 
       
   418 
       
   419 
       
   420 // --------------------------------------------------------------------------
       
   421 // CUpnpVolumeStateMachine::VolumeResult
       
   422 // --------------------------------------------------------------------------
       
   423 //
       
   424 EXPORT_C void CUpnpVolumeStateMachine::VolumeResult(
       
   425     TInt aError, TInt aVolumeLevel, TBool aActionResponse )
       
   426     {
       
   427     __LOG3( "VolumeStateMachine: VolumeResult %d, %d state=%d",
       
   428         aError, aVolumeLevel, iState );
       
   429 
       
   430     //
       
   431     // RESPONSE TO A REQUEST
       
   432     //
       
   433     if ( aActionResponse )
       
   434         {
       
   435         //
       
   436         // SYNC
       
   437         //
       
   438         if( iState == ESyncing )
       
   439             {
       
   440             HandleVolumeResultInSyncState(aError, aVolumeLevel, aActionResponse);            
       
   441             }
       
   442         //
       
   443         // VOLUME ADJUST
       
   444         //
       
   445         else if ( iState == EAdjustingVolume ||
       
   446             iState == EAdjustingVolumeFromZero )
       
   447             {
       
   448             if ( aError == KErrNone )
       
   449                 {
       
   450                 iCurrentVolume = aVolumeLevel;
       
   451                 }
       
   452             iState = EIdle;
       
   453             // volume adjust done, call back
       
   454             if ( iObserver )
       
   455                 {
       
   456                 iObserver->VolumeChanged(
       
   457                     aError, iCurrentVolume, ETrue );
       
   458                 }
       
   459             }
       
   460         //
       
   461         // CANCEL
       
   462         //
       
   463         else if( iState == ECancelled )
       
   464             {
       
   465             iState = EIdle;
       
   466             }
       
   467         }
       
   468 
       
   469     //
       
   470     // UNSOLICTED VOLUME EVENT
       
   471     //
       
   472     else
       
   473         {
       
   474         if ( iState == EIdle )
       
   475             {
       
   476             if ( aVolumeLevel != iCurrentVolume )
       
   477                 {
       
   478                 if ( iCurrentMute == KMuteOn )
       
   479                     {
       
   480                     __LOG("unsolicted volume event during muted");
       
   481                     }
       
   482                 iCurrentVolume = aVolumeLevel;
       
   483                 if ( iObserver )
       
   484                     {
       
   485                     iObserver->VolumeChanged(
       
   486                         KErrNone, iCurrentVolume, EFalse );
       
   487                     }
       
   488                 }
       
   489             }
       
   490         else
       
   491             {
       
   492             __LOG("ignoring unsolicted volume event in this state");
       
   493             }
       
   494         }
       
   495 
       
   496     iCachedVolume = iCurrentVolume;
       
   497     ProcessNextQueuedProperty();
       
   498     }
       
   499 
       
   500 // --------------------------------------------------------------------------
       
   501 // CUpnpVolumeStateMachine::MuteResult
       
   502 // --------------------------------------------------------------------------
       
   503 //
       
   504 EXPORT_C void CUpnpVolumeStateMachine::MuteResult(
       
   505     TInt aError, TBool aMute, TBool aActionResponse )
       
   506     {
       
   507     __LOG3( "VolumeStateMachine: MuteResult %d, %d, %d",
       
   508         aError, aMute, aActionResponse );
       
   509     __LOG1( "VolumeStateMachine: MuteResult in state=%d", iState );
       
   510 
       
   511     //
       
   512     // RESPONSE TO A REQUEST
       
   513     //
       
   514     if( aActionResponse )
       
   515         {
       
   516         //
       
   517         // SYNC
       
   518         //
       
   519         if ( iState == ESyncing )
       
   520             {
       
   521             if ( aError == KErrNone )
       
   522                 {
       
   523                 iCurrentMute = aMute;
       
   524                 iMuteRequestedByClient = EFalse;
       
   525                 }
       
   526             iState = EIdle;
       
   527             // notify sync initially and volume and mute if changed
       
   528             if ( iObserver && iCachedMute == KErrNotFound )
       
   529                 {
       
   530                 iObserver->VolumeSyncReady( aError );
       
   531                 }
       
   532             else if ( iObserver )
       
   533                 {
       
   534                 if( iCachedVolume != iCurrentVolume )
       
   535                     {
       
   536                     iObserver->VolumeChanged(
       
   537                             aError, iCurrentVolume, EFalse );
       
   538                     }
       
   539                 if( iCachedMute != iCurrentMute )
       
   540                     {
       
   541                     iObserver->MuteChanged(
       
   542                             aError, iCurrentMute, EFalse );
       
   543                     }
       
   544                 }
       
   545             }
       
   546         //
       
   547         // MUTE ADJUST
       
   548         //
       
   549         if ( iState == EAdjustingMute )
       
   550             {
       
   551             if ( aError == KErrNone )
       
   552                 {
       
   553                 iCurrentMute = aMute;
       
   554                 iMuteRequestedByClient = aMute;
       
   555                 }
       
   556             iState = EIdle;
       
   557             if ( iObserver )
       
   558                 {
       
   559                 iObserver->MuteChanged(
       
   560                     aError, iCurrentMute, ETrue );
       
   561                 }
       
   562             }
       
   563         //
       
   564         // VOLUME ADJUST -> 0
       
   565         //
       
   566         if ( iState == EAdjustingVolumeToZero )
       
   567             {
       
   568             if ( aError == KErrNone )
       
   569                 {
       
   570                 iCurrentMute = aMute;
       
   571                 iMuteRequestedByClient = EFalse;
       
   572                 }
       
   573             iState = EIdle;
       
   574             if ( iObserver )
       
   575                 {
       
   576                 iObserver->VolumeChanged(
       
   577                     aError, KVolumeMin, ETrue );
       
   578                 }
       
   579             }
       
   580         //
       
   581         // VOLUME ADJUST 0 -> up
       
   582         //
       
   583         if ( iState == EAdjustingVolumeFromZero )
       
   584             {
       
   585             if ( aError == KErrNone )
       
   586                 {
       
   587                 iCurrentMute = aMute;
       
   588                 iMuteRequestedByClient = EFalse;
       
   589                 TRAP( aError, iSession.SetVolumeL(
       
   590                     iVolumeToSetAfterMute ) );
       
   591                 }
       
   592             if ( aError != KErrNone )
       
   593                 {
       
   594                 // error callback
       
   595                 iVolumeToSetAfterMute = KErrNotFound;
       
   596                 iState = EIdle;
       
   597                 if ( iObserver )
       
   598                     {
       
   599                     iObserver->VolumeChanged(
       
   600                         aError, iCurrentVolume, ETrue );
       
   601                     }
       
   602                 }
       
   603             }
       
   604         //
       
   605         // CANCEL
       
   606         //
       
   607         else if( iState == ECancelled )
       
   608             {
       
   609             iState = EIdle;
       
   610             }
       
   611         }
       
   612 
       
   613     //
       
   614     // UNSOLICITED MUTE EVENT
       
   615     //
       
   616     else
       
   617         {
       
   618         HandleUnsolicitedMuteEvent(aError, aMute, aActionResponse );
       
   619         }
       
   620     
       
   621     iCachedMute = iCurrentMute;
       
   622     ProcessNextQueuedProperty();
       
   623     }
       
   624 
       
   625 void CUpnpVolumeStateMachine::HandleUnsolicitedMuteEvent(
       
   626     TInt aError, TBool aMute, TBool aActionResponse )
       
   627     {
       
   628     if ( iState == EIdle )
       
   629         {
       
   630         HandleUnsolicitedMuteEventInIdle(aError, aMute, aActionResponse);
       
   631         }
       
   632     else
       
   633         {
       
   634         __LOG("ignoring unsolicted mute event in this state");
       
   635         }
       
   636     
       
   637     }
       
   638 
       
   639 void CUpnpVolumeStateMachine::HandleUnsolicitedMuteEventInIdle(
       
   640     TInt /*aError*/, TBool aMute, TBool /*aActionResponse*/ )
       
   641     {
       
   642     __LOG3( "VolumeStateMachine: HandleUnsolicitedMuteEventInIdle %d, %d, %d",
       
   643         aMute, iCurrentMute, iMuteRequestedByClient );
       
   644 
       
   645     if ( iCurrentMute && !aMute && iMuteRequestedByClient )
       
   646         {
       
   647         // client has requested mute, renderer unmuted
       
   648         iCurrentMute = aMute;
       
   649         // check if client has changed volume during mute
       
   650         if ( iVolumeToSetAfterMute > 0 &&
       
   651             iVolumeToSetAfterMute != iCurrentVolume )
       
   652             {
       
   653             TRAP_IGNORE(
       
   654                 iSession.SetVolumeL( iVolumeToSetAfterMute );
       
   655                 iVolumeToSetAfterMute = KErrNotFound;
       
   656                 iState = EAdjustingVolume;
       
   657                 );
       
   658             }
       
   659         // notify observer about mute state change
       
   660         if ( iObserver )
       
   661             {
       
   662             iObserver->MuteChanged(
       
   663                 KErrNone, KMuteOff, EFalse );
       
   664             }
       
   665         }
       
   666     else if ( iCurrentMute && !aMute ||
       
   667         !iCurrentMute && aMute )
       
   668         {
       
   669         // renderer unmuted - notify volume state back
       
   670         iCurrentMute = aMute;
       
   671         // check if client has changed volume during mute
       
   672         if ( iVolumeToSetAfterMute > 0 &&
       
   673             iVolumeToSetAfterMute != iCurrentVolume &&
       
   674             !aMute &&
       
   675             ( ( (iOptions & Upnp::EConvertVolumeZeroToMute) == 0 ) ||
       
   676               iMuteRequestedByClient ) )
       
   677             {
       
   678             __LOG2( "After unmute adjusting volume %d->%d",
       
   679                 iCurrentVolume, iVolumeToSetAfterMute );
       
   680             TRAP_IGNORE(
       
   681                 iSession.SetVolumeL( iVolumeToSetAfterMute );
       
   682                 iVolumeToSetAfterMute = KErrNotFound;
       
   683                 iState = EAdjustingVolume;
       
   684                 );
       
   685             }
       
   686         // notify observer
       
   687         if ( iObserver )
       
   688             {
       
   689             NotifyObserver(aMute);            
       
   690             }
       
   691         }
       
   692     else
       
   693         {
       
   694         // no need to report status change
       
   695         }    
       
   696     }
       
   697 
       
   698 void CUpnpVolumeStateMachine::NotifyObserver(TBool aMute)
       
   699     {
       
   700     __LOG2( "VolumeStateMachine: NotifyObserver %d, %d",
       
   701         aMute, iOptions );
       
   702 
       
   703     if ( ( (iOptions & Upnp::EConvertVolumeZeroToMute) == 0 ) ||
       
   704          iMuteRequestedByClient )
       
   705         {
       
   706         // client prefers to use mute, or client has 
       
   707         // explicitely requested this mute session.
       
   708         iObserver->MuteChanged(
       
   709             KErrNone, aMute, EFalse );
       
   710         }
       
   711     else
       
   712         {
       
   713         // convert mute signal to volume callback
       
   714         TInt givenvol = 
       
   715                 ( aMute ? KVolumeMin : iCurrentVolume );
       
   716         iObserver->VolumeChanged(
       
   717             KErrNone, givenvol, EFalse );
       
   718         }
       
   719     }
       
   720 
       
   721 
       
   722 
       
   723 // --------------------------------------------------------------------------
       
   724 // CUpnpVolumeStateMachine::CopyValues
       
   725 // --------------------------------------------------------------------------
       
   726 //
       
   727 EXPORT_C void CUpnpVolumeStateMachine::CopyValues(
       
   728     const CUpnpVolumeStateMachine& aOther )
       
   729     {
       
   730     iCurrentVolume = aOther.Volume();
       
   731     iCurrentMute = aOther.Mute();
       
   732     }
       
   733 
       
   734 // --------------------------------------------------------------------------
       
   735 // CUpnpVolumeStateMachine::PushIntoQueueL
       
   736 // --------------------------------------------------------------------------
       
   737 //
       
   738 void CUpnpVolumeStateMachine::PushIntoQueueL( 
       
   739     const TUpnpVSMQueueItem::TPropertyType aPropery, const TInt aValue )
       
   740     {
       
   741     __LOG( "VolumeStateMachine: PushIntoQueueL" );
       
   742     TUpnpVSMQueueItem queued( aPropery, aValue ); 
       
   743     iQueue.AppendL( queued );    
       
   744     
       
   745     CompressQueue();
       
   746     }
       
   747 
       
   748 // --------------------------------------------------------------------------
       
   749 // CUpnpVolumeStateMachine::CompressQueueL
       
   750 // --------------------------------------------------------------------------
       
   751 //
       
   752 void CUpnpVolumeStateMachine::CompressQueue()
       
   753     {
       
   754     TInt queueCount( iQueue.Count() );  
       
   755     
       
   756     if( queueCount > 1 )
       
   757         {
       
   758         __LOG1( "VolumeStateMachine: CompressQueue (queue count: %d)", queueCount );
       
   759         
       
   760         TInt lastIndex( queueCount - 1 );
       
   761         
       
   762         if( iQueue[lastIndex].Property() == TUpnpVSMQueueItem::EVolume )
       
   763             {
       
   764             // remove all other except the last 'set volume' request
       
   765             for( TInt i( queueCount - 2 ); i >= 0; --i )
       
   766                 {
       
   767                 __LOG2( "VolumeStateMachine Queue: Removing %d from queue index %d",
       
   768                        iQueue[i].Property(), i );   
       
   769                 
       
   770                 iQueue.Remove( i );
       
   771                 }
       
   772             }
       
   773         else
       
   774             {
       
   775             // remove all other except (the last 'set volume' request and)
       
   776             // the last 'set mute' request
       
   777             TBool setVolumeFound( EFalse );
       
   778             TBool setMuteFound( EFalse );
       
   779             for( TInt i( queueCount - 1 ); i >= 0; --i )
       
   780                 {                          
       
   781                 if( iQueue[i].Property() == TUpnpVSMQueueItem::EVolume &&
       
   782                     !setVolumeFound )                        
       
   783                     {
       
   784                     setVolumeFound = ETrue;
       
   785                     }
       
   786                 else if( iQueue[i].Property() == TUpnpVSMQueueItem::EMute &&
       
   787                          !setMuteFound )               
       
   788                     {
       
   789                     setMuteFound = ETrue;
       
   790                     }
       
   791                 else
       
   792                     {
       
   793                     __LOG2( "VolumeStateMachine Queue: Removing %d from queue index %d",
       
   794                         iQueue[i].Property(), i );
       
   795                     
       
   796                     iQueue.Remove( i );
       
   797                     }
       
   798                 }
       
   799             }
       
   800         }
       
   801     }
       
   802 
       
   803 // --------------------------------------------------------------------------
       
   804 // CUpnpVolumeStateMachine::ProcessNextQueuedProperty
       
   805 // --------------------------------------------------------------------------
       
   806 //
       
   807 void CUpnpVolumeStateMachine::ProcessNextQueuedProperty()
       
   808     {
       
   809     if( iQueue.Count() > 0 )
       
   810         {        
       
   811         __LOG( "VolumeStateMachine: ProcessNextQueuedPropertyL" );
       
   812         
       
   813         TUpnpVSMQueueItem queuedItem( iQueue[0] );
       
   814         iQueue.Remove( 0 );
       
   815         
       
   816         if( queuedItem.Property() == TUpnpVSMQueueItem::EVolume )
       
   817             {
       
   818             TRAPD( err, SetVolumeL( queuedItem.Value() ) );
       
   819             if( err )
       
   820                 {
       
   821                 iObserver->VolumeChanged( err, iCurrentVolume, ETrue ); 
       
   822                 }
       
   823             }
       
   824         else
       
   825             {
       
   826             TRAPD( err, SetMuteL( queuedItem.Value() ) );
       
   827             if( err )
       
   828                 {
       
   829                 iObserver->MuteChanged( err, iCurrentMute, ETrue ); 
       
   830                 }            
       
   831             }
       
   832         }
       
   833     }
       
   834 
       
   835 // end of file