remotecontrol/avrcp/remconbeareravrcp/src/avrcpplayerinfomanager.cpp
changeset 51 20ac952a623c
equal deleted inserted replaced
48:22de2e391156 51:20ac952a623c
       
     1 // Copyright (c) 2008-2010 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 
       
    17 
       
    18 /**
       
    19  @file
       
    20  @internalComponent
       
    21  @released
       
    22 */
       
    23 
       
    24 #include <avctpservices.h> // for AVCTP protocol version
       
    25 #include <bt_sock.h> // for PSM values
       
    26 #include <remcon/clientid.h>
       
    27 #include <absolutevolumeapi.h>
       
    28 #include <remcon/remconbearerbulkobserver.h>
       
    29 
       
    30 #include "avrcp.h"
       
    31 #include "avrcpplayerinfomanager.h"
       
    32 #include "avrcpsdputils.h"
       
    33 #include "playerbitmasks.h"
       
    34 #include "avrcputils.h"
       
    35 #include "avrcplog.h"
       
    36 #include "mediabrowse.h"
       
    37 #include "nowplaying.h"
       
    38 #include "playerinformation.h"
       
    39 #include "remcongroupnavigation.h"
       
    40 
       
    41 #ifdef _DEBUG
       
    42 PANICCATEGORY("playerinfo");
       
    43 #endif // _DEBUG
       
    44 
       
    45 static TBool PlayerCompare(const TRemConClientId* aId, const TAvrcpMediaPlayerItem& aItem)
       
    46 	{
       
    47 	LOG_STATIC_FUNC
       
    48 	return (aId && *aId == aItem.iId);
       
    49 	}
       
    50 
       
    51 enum TFirstAbsVolSupport { EFirstAbsVolSupport };
       
    52 static TBool FirstAbsVolSupport(const TFirstAbsVolSupport*, const TAvrcpMediaPlayerItem& aItem)
       
    53 	{
       
    54 	LOG_STATIC_FUNC
       
    55 	return aItem.iId != KNullClientId && aItem.iAbsoluteVolumeSupport;
       
    56 	}
       
    57 
       
    58 enum TFirstBrowsingSupport { EFirstBrowsingSupport };
       
    59 static TBool FirstBrowsingSupport(const TFirstBrowsingSupport*, const TAvrcpMediaPlayerItem& aItem)
       
    60 	{
       
    61 	LOG_STATIC_FUNC
       
    62 	return aItem.iId != KNullClientId && (aItem.iSdpFeatures & AvrcpSdp::EBrowsing);
       
    63 	}
       
    64 
       
    65 CAvrcpPlayerInfoManager* CAvrcpPlayerInfoManager::NewL(MRemConBearerObserver& aObserver, MRemConCommandInterface& aCommandInterface)
       
    66 	{
       
    67 	LOG_STATIC_FUNC
       
    68 	CAvrcpPlayerInfoManager* info = new(ELeave) CAvrcpPlayerInfoManager(aObserver);
       
    69 	CleanupStack::PushL(info);
       
    70 	info->ConstructL(aCommandInterface);
       
    71 	CleanupStack::Pop(info);
       
    72 	return info;
       
    73 	}
       
    74 
       
    75 void CAvrcpPlayerInfoManager::ConstructL(MRemConCommandInterface& aCommandInterface)
       
    76 	{
       
    77 	LOG_FUNC
       
    78 	LEAVEIFERRORL(iLock.CreateLocal());
       
    79 	LEAVEIFERRORL(iSdp.Connect());
       
    80 	LEAVEIFERRORL(iSdpDatabase.Open(iSdp));
       
    81 	
       
    82 	iPlayStatusWatcher = CPlayStatusWatcher::NewL(*this, aCommandInterface);
       
    83 	
       
    84 	TCallBack cb(PlayerUpdateCallBack, this);
       
    85 	iControlThreadCallBack.Create(cb, CActive::EPriorityStandard);
       
    86 	iControlThreadCallBack.Start();
       
    87 	}
       
    88 
       
    89 CAvrcpPlayerInfoManager::~CAvrcpPlayerInfoManager()
       
    90 	{
       
    91 	LOG_FUNC
       
    92 	ASSERT_CONTROL_THREAD
       
    93 	iLock.Wait();// serialise access...
       
    94 	iLock.Close();
       
    95 	delete iPlayStatusWatcher;
       
    96 	ASSERT_DEBUG(!iUidWatcher); // created in bulk thread context...
       
    97 	iControlThreadCallBack.Close();
       
    98 	iObservers.Close();
       
    99 	iPlayers.Close();
       
   100 	iSdpDatabase.Close();
       
   101 	iSdp.Close();
       
   102 	}
       
   103 
       
   104 CAvrcpPlayerInfoManager::CAvrcpPlayerInfoManager(MRemConBearerObserver& aObserver)
       
   105 	: iControlBearerObserver(aObserver)
       
   106 	{
       
   107 	LOG_FUNC
       
   108 	}
       
   109 
       
   110 /**
       
   111 This function sets up the handling in the bulk thread.  This involves creating the 
       
   112 player state watcher, which maintains an up to date view of the UID counter values
       
   113 for each player with a bulk interface.  It does this by acting as an internal
       
   114 command handler.  The bulk bearer expects the player info manager to provide it
       
   115 with a command handling interface for commands on internal interfaces, so we provide
       
   116 it with the interface for the state watcher, which is where all our internal commands
       
   117 come from.
       
   118 */
       
   119 MIncomingCommandHandler* CAvrcpPlayerInfoManager::BulkStartedL(MRemConCommandInterface& aCommandInterface)
       
   120 	{
       
   121 	LOG_FUNC;
       
   122 	ASSERT_BULK_THREAD;
       
   123 
       
   124 	iUidWatcher = CUidWatcher::NewL(*this, aCommandInterface);
       
   125 	return iUidWatcher;
       
   126 	}
       
   127 
       
   128 void CAvrcpPlayerInfoManager::BulkStopped()
       
   129 	{
       
   130 	LOG_FUNC;
       
   131 	ASSERT_BULK_THREAD;
       
   132 	delete iUidWatcher;
       
   133 	iUidWatcher = NULL;
       
   134 	}
       
   135 
       
   136 // Helper function for ClientAvailable and TargetFeaturesUpdated
       
   137 TInt CAvrcpPlayerInfoManager::SetItemDetails(TAvrcpMediaPlayerItem& aItem, TPlayerType aPlayerType, TPlayerSubType aPlayerSubType, const TDesC8& aName)
       
   138 	{
       
   139 	aItem.iPlayerType = aPlayerType;
       
   140 	aItem.iPlayerSubType = aPlayerSubType;
       
   141 	aItem.iName.Set(aName);
       
   142 	aItem.iFeatureBitmask = TPlayerFeatureBitmask();
       
   143 	return SetPlayerFeatures(aItem.iId, aItem.iFeatureBitmask, aItem.iSdpFeatures, aItem.iAbsoluteVolumeSupport);
       
   144 	}
       
   145 
       
   146 // Helper function for ClientAvailable and TargetFeaturesUpdated
       
   147 void CAvrcpPlayerInfoManager::UpdateTargetSdpRecord()
       
   148 	{
       
   149 	// Update SDP record, if this fails we carry on, it's non-fatal
       
   150 	TInt sdpErr = KErrNone;
       
   151 	if(!iTargetRecord)
       
   152 		{
       
   153 		TRAP(sdpErr, AvrcpSdpUtils::CreateTargetServiceRecordL(iSdpDatabase, iTargetRecord));
       
   154 		}
       
   155 	if(sdpErr == KErrNone)
       
   156 		{
       
   157 		TRAP_IGNORE(UpdateTgServiceRecordL());
       
   158 		}
       
   159 	}
       
   160 
       
   161 void CAvrcpPlayerInfoManager::ClientAvailable(const TRemConClientId& aId, TPlayerType aPlayerType, TPlayerSubType aPlayerSubType, const TDesC8& aName)
       
   162 	{
       
   163 	LOG_FUNC;
       
   164 	ASSERT_CONTROL_THREAD;
       
   165 	iLock.Wait();
       
   166 	// Add this to our client list, using any holes in the client id array
       
   167 	TInt index = NextPlayerIndex();
       
   168 	if(index < 0)
       
   169 		{
       
   170 		// Couldn't allocate memory to store this player, remote will just
       
   171 		// have to make do with the current set
       
   172 		iLock.Signal();
       
   173 		return;
       
   174 		}
       
   175 	
       
   176 	TAvrcpMediaPlayerItem& item = iPlayers[index];
       
   177 	item.iId = aId;
       
   178 	item.iBulkClientAvailable = EFalse;
       
   179 	item.iUidCounter = 0;
       
   180 	item.iLastUpdatedUidCounter = 0;
       
   181 	item.iPlaybackStatus = MPlayerEventsObserver::EStopped;
       
   182 	TInt err = SetItemDetails(item, aPlayerType, aPlayerSubType, aName);
       
   183 
       
   184 	// Release lock before calling out of player info manager in case
       
   185 	// anyone needs to call back in - we're finished updating the
       
   186 	// info now.
       
   187 	iLock.Signal();
       
   188 
       
   189 	if(!err)
       
   190 		{
       
   191 		TRAP(err, iPlayStatusWatcher->StartWatchingPlayerL(aId));
       
   192 		if(!err)
       
   193 			{
       
   194 			UpdateTargetSdpRecord();
       
   195 		     for(TInt i = 0; i<iObservers.Count(); i++)
       
   196 				{
       
   197 				iObservers[i]->MpcoAvailablePlayersChanged();
       
   198 				}
       
   199 			}
       
   200 		  else    
       
   201 			{
       
   202 			iLock.Wait();
       
   203 			// We know that the player array is only modified from the control thread
       
   204 			// so it's valid to use index now even though coverity thinks its stale
       
   205 			// coverity[use]
       
   206 			iPlayers[index].iId = KNullClientId;
       
   207 			iLock.Signal();
       
   208 			}
       
   209 		}
       
   210 	}
       
   211 
       
   212 void CAvrcpPlayerInfoManager::ClientNotAvailable(const TRemConClientId& aId)
       
   213 	{
       
   214 	LOG_FUNC
       
   215 	ASSERT_CONTROL_THREAD
       
   216 	iLock.Wait();
       
   217 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   218 	if(index < 0)
       
   219 		{
       
   220 		// May not be here if we couldn't allocate memory to store this
       
   221 		// when we were first told about it
       
   222 		iLock.Signal();
       
   223 		return;
       
   224 		}
       
   225 	
       
   226 	iPlayStatusWatcher->StopWatchingPlayer(aId);
       
   227 	iPlayers[index].iId = KNullClientId;
       
   228 	
       
   229 	//Release lock as soon as we've stopped fiddling
       
   230 	iLock.Signal();
       
   231 	
       
   232 	for(TInt i = 0; i<iObservers.Count(); i++)
       
   233 		{
       
   234 		iObservers[i]->MpcoAvailablePlayersChanged();
       
   235 		}
       
   236 	
       
   237 	// Don't put requirement on ordering of ClientNotAvailable/ClientStatus calls
       
   238 	if(iTargetRecord)
       
   239 		{
       
   240 		TRAP_IGNORE(UpdateTgServiceRecordL());
       
   241 		}
       
   242 	}
       
   243 
       
   244 void CAvrcpPlayerInfoManager::ClientStatus(TBool aControllerPresent, TBool aTargetPresent)
       
   245 	{
       
   246 	LOG_FUNC
       
   247 	ASSERT_CONTROL_THREAD
       
   248 	// SDP only used in the control thread
       
   249 	
       
   250 	//If we have gone from 1->0 on either of these we can remove the record now,
       
   251 	// otherwise wait for more detail on ClientAvailable or ControllerFeaturesUpdatedL
       
   252 	if(!aControllerPresent && iControllerRecord)
       
   253 		{
       
   254 		iSdpDatabase.DeleteRecord(iControllerRecord);
       
   255 		iControllerRecord = 0;
       
   256 		}
       
   257 			
       
   258 	if(!aTargetPresent && iTargetRecord)
       
   259 		{
       
   260 		iSdpDatabase.DeleteRecord(iTargetRecord);
       
   261 		iTargetRecord = 0;
       
   262 		}
       
   263 	}
       
   264 
       
   265 TInt CAvrcpPlayerInfoManager::SetLocalAddressedClient(const TRemConClientId& aId)
       
   266 	{
       
   267 	LOG_FUNC
       
   268 	ASSERT_CONTROL_THREAD
       
   269 
       
   270 	TUint16 playerId = 0;
       
   271 	TRAPD(err, playerId = PlayerL(aId));
       
   272 	static_cast<void>(playerId==playerId); // We only want to check if the bearer knows about the client.
       
   273 	if(err == KErrNone)
       
   274 		{
       
   275 		for(TInt i = 0; i<iObservers.Count(); i++)
       
   276 			{
       
   277 			iObservers[i]->MpcoAddressedPlayerChangedLocally(aId);
       
   278 			}
       
   279 		}
       
   280 	
       
   281 	return err;
       
   282 	}
       
   283 
       
   284 void CAvrcpPlayerInfoManager::ControllerFeaturesUpdatedL(RArray<TUid>& aSupportedInterfaces)
       
   285 	{
       
   286 	LOG_FUNC
       
   287 	ASSERT_CONTROL_THREAD
       
   288 	// SDP only used in the control thread
       
   289 
       
   290 	TUint16 avrcpVersion = AvrcpSdp::KAvrcpProfileVersion13; 
       
   291 	TUint16 avctpVersion = AvrcpSdp::KAvctpProtocolVersion12; 
       
   292 
       
   293 	if(aSupportedInterfaces.Find(TUid::Uid(KRemConAbsoluteVolumeControllerApiUid)) >= 0)
       
   294 		{
       
   295 		avrcpVersion = AvrcpSdp::KAvrcpProfileVersion14;
       
   296 		avctpVersion = AvrcpSdp::KAvctpProtocolVersion13;
       
   297 		}
       
   298 
       
   299 	if(!iControllerRecord)
       
   300 		{
       
   301 		AvrcpSdpUtils::CreateControllerServiceRecordL(iSdpDatabase, iControllerRecord, avrcpVersion);
       
   302 		}
       
   303 	else
       
   304 		{
       
   305 		AvrcpSdpUtils::UpdateControllerServiceClassListL(iSdpDatabase, iControllerRecord, avrcpVersion);
       
   306 		}
       
   307 
       
   308 	AvrcpSdpUtils::UpdateProtocolDescriptorListL(iSdpDatabase, iControllerRecord, avctpVersion);
       
   309 	AvrcpSdpUtils::UpdateProfileDescriptorListL(iSdpDatabase, iControllerRecord, avrcpVersion);
       
   310 	AvrcpSdpUtils::UpdateSupportedFeaturesL(iSdpDatabase, iControllerRecord, AvrcpSdp::ERemoteControl, AvrcpSdp::KAvrcpBaseCtFeatures);
       
   311 	}
       
   312 
       
   313 void CAvrcpPlayerInfoManager::TargetFeaturesUpdated(const TRemConClientId& aId, TPlayerType aPlayerType, TPlayerSubType aPlayerSubType, const TDesC8& aName)
       
   314 	{
       
   315 	LOG_FUNC;
       
   316 	ASSERT_CONTROL_THREAD;
       
   317 	iLock.Wait();
       
   318 	// Find this client in our client list
       
   319 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   320 	if(index < 0)
       
   321 		{
       
   322 		// Couldn't find client in client list, maybe we removed it after an earlier failure
       
   323 		iLock.Signal();
       
   324 		return;
       
   325 		}
       
   326 
       
   327 	TAvrcpMediaPlayerItem& item = iPlayers[index];
       
   328 	TInt err = SetItemDetails(item, aPlayerType, aPlayerSubType, aName);
       
   329 
       
   330 	if(!err)
       
   331 		{
       
   332 		UpdateTargetSdpRecord();
       
   333 		}
       
   334 	else
       
   335 		{
       
   336 		// There was an error updating the features so remove this client from the client list
       
   337 		iPlayers[index].iId = KNullClientId;
       
   338 		}
       
   339 
       
   340 	// Release lock before calling out of player info manager in case
       
   341 	// anyone needs to call back in - we're finished updating the
       
   342 	// info now.
       
   343 	iLock.Signal();
       
   344 
       
   345 	for(TInt i = 0; i<iObservers.Count(); i++)
       
   346 		{
       
   347 		iObservers[i]->MpcoAvailablePlayersChanged();
       
   348 		}
       
   349 	}
       
   350 
       
   351 MIncomingCommandHandler& CAvrcpPlayerInfoManager::InternalCommandHandler()
       
   352 	{
       
   353 	LOG_FUNC
       
   354 	ASSERT_CONTROL_THREAD
       
   355 
       
   356 	return *iPlayStatusWatcher;
       
   357 	}
       
   358 
       
   359 void CAvrcpPlayerInfoManager::BulkClientAvailable(const TRemConClientId& aId)
       
   360 	{
       
   361 	LOG_FUNC
       
   362 	ASSERT_BULK_THREAD
       
   363 	iLock.Wait();
       
   364 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   365 	if(index < 0)
       
   366 		{
       
   367 		iLock.Signal();
       
   368 		return;
       
   369 		}
       
   370 	ASSERT(!iPlayers[index].iBulkClientAvailable);
       
   371 	
       
   372 	TRAPD(err, iUidWatcher->StartWatchingPlayerL(aId));
       
   373 	
       
   374 	if(!err)
       
   375 		{
       
   376 		iPlayers[index].iBulkClientAvailable = ETrue;
       
   377 		}
       
   378 	
       
   379 	iLock.Signal();
       
   380 	}
       
   381 
       
   382 void CAvrcpPlayerInfoManager::BulkClientNotAvailable(const TRemConClientId& aId)
       
   383 	{
       
   384 	LOG_FUNC
       
   385 	ASSERT_BULK_THREAD
       
   386 	iLock.Wait();
       
   387 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   388 	if(index >= 0)
       
   389 		{
       
   390 		ASSERT(iPlayers[index].iBulkClientAvailable);
       
   391 		iPlayers[index].iBulkClientAvailable = EFalse;
       
   392 		}
       
   393 	iLock.Signal();
       
   394 	iUidWatcher->StopWatchingPlayer(aId);
       
   395 	}
       
   396 
       
   397 void CAvrcpPlayerInfoManager::AddObserverL(MPlayerChangeObserver& aObserver)
       
   398 	{
       
   399 	LOG_FUNC
       
   400 	ASSERT_CONTROL_THREAD
       
   401 	iObservers.AppendL(&aObserver);
       
   402 	}
       
   403 
       
   404 void CAvrcpPlayerInfoManager::RemoveObserver(MPlayerChangeObserver& aObserver)
       
   405 	{
       
   406 	LOG_FUNC
       
   407 	ASSERT_CONTROL_THREAD
       
   408 	TInt index = iObservers.Find(&aObserver);
       
   409 	if(index >= 0)
       
   410 		{
       
   411 		iObservers.Remove(index);
       
   412 		}
       
   413 	}
       
   414 
       
   415 TRemConClientId CAvrcpPlayerInfoManager::ClientL(TUint16 aAvrcpPlayerId) const
       
   416 	{
       
   417 	LOG_FUNC
       
   418 	// THREAD - Bulk and Control
       
   419 	
       
   420 	iLock.Wait();
       
   421 	CleanupSignalPushL(iLock);
       
   422 	
       
   423 	TRemConClientId clientId = KNullClientId;
       
   424 	if(ValidPlayer(aAvrcpPlayerId))
       
   425 		{
       
   426 		clientId = iPlayers[aAvrcpPlayerId].iId;
       
   427 		}
       
   428 	else
       
   429 		{
       
   430 		LEAVEL(KErrNotFound);
       
   431 		}
       
   432 	
       
   433 	CleanupStack::PopAndDestroy(&iLock);
       
   434 	
       
   435 	return clientId;
       
   436 	}
       
   437 
       
   438 TRemConClientId CAvrcpPlayerInfoManager::Client(TUint16 aAvrcpPlayerId) const
       
   439 	{
       
   440 	LOG_FUNC
       
   441 	// THREAD - Bulk and Control
       
   442 	
       
   443 	iLock.Wait();
       
   444 	
       
   445 	TRemConClientId clientId = KNullClientId;
       
   446 	__ASSERT_DEBUG(ValidPlayer(aAvrcpPlayerId), AvrcpUtils::Panic(EInvalidPlayerId));
       
   447 	
       
   448 	clientId = iPlayers[aAvrcpPlayerId].iId;
       
   449 	
       
   450 	iLock.Signal();
       
   451 	return clientId;
       
   452 	}
       
   453 
       
   454 TUint16 CAvrcpPlayerInfoManager::PlayerL(const TRemConClientId& aClientId) const
       
   455 	{
       
   456 	LOG_FUNC
       
   457 	// THREAD - Bulk and Control
       
   458 	
       
   459 	iLock.Wait();
       
   460 	
       
   461 	TUint16 player = 0;
       
   462 	TBool found = EFalse;
       
   463 	for(TInt i = 0; i < iPlayers.Count(); i++)
       
   464 		{
       
   465 		if(PlayerCompare(&aClientId, iPlayers[i]))
       
   466 			{
       
   467 			player = i;
       
   468 			found = ETrue;
       
   469 			}
       
   470 		}
       
   471 
       
   472 	iLock.Signal();
       
   473 	
       
   474 	if(!found)
       
   475 		{
       
   476 		LEAVEL(KErrNotFound);
       
   477 		}
       
   478 	
       
   479 	return player;
       
   480 	}
       
   481 
       
   482 TInt CAvrcpPlayerInfoManager::PlayerListing(TUint aStartItem, TUint aEndItem, RArray<TUint>& aPlayers)
       
   483 	{
       
   484 	LOG_FUNC
       
   485 	ASSERT_BULK_THREAD
       
   486 
       
   487 	if(aStartItem > aEndItem)
       
   488 		{
       
   489 		return KErrArgument;
       
   490 		}
       
   491 	
       
   492 	iLock.Wait();
       
   493 	if(aStartItem >= iPlayers.Count())
       
   494 		{
       
   495 		iLock.Signal();
       
   496 		return KErrArgument;
       
   497 		}
       
   498 	
       
   499 	TInt err = KErrNone;
       
   500 	for(TUint i = aStartItem; i <= aEndItem && i < iPlayers.Count() && err == KErrNone; i++)
       
   501 		{
       
   502 		if(iPlayers[i].iId != KNullClientId)
       
   503 			{
       
   504 			err = aPlayers.Append(i);
       
   505 			}
       
   506 		}
       
   507 	
       
   508 	iLock.Signal();
       
   509 	return err;
       
   510 	}
       
   511 
       
   512 TInt CAvrcpPlayerInfoManager::PlayerListing(RArray<TUint>& aPlayers)
       
   513 	{
       
   514 	LOG_FUNC
       
   515 	ASSERT_CONTROL_THREAD
       
   516 	iLock.Wait();
       
   517 	TInt err = KErrNone;
       
   518 	for(TInt i = 0; i < iPlayers.Count() && err == KErrNone; i++)
       
   519 		{
       
   520 		if(iPlayers[i].iId != KNullClientId)
       
   521 			{
       
   522 			err = aPlayers.Append(i);
       
   523 			}
       
   524 		}
       
   525 	
       
   526 	iLock.Signal();
       
   527 	return err;
       
   528 	}
       
   529 
       
   530 void CAvrcpPlayerInfoManager::MediaPlayerItemL(const TUint16& aAvrcpPlayerId, RMediaPlayerItem& aItem)
       
   531 	{
       
   532 	LOG_FUNC
       
   533 	ASSERT_BULK_THREAD
       
   534 	iLock.Wait();
       
   535 	CleanupSignalPushL(iLock);
       
   536 	
       
   537 	if(ValidPlayer(aAvrcpPlayerId))
       
   538 		{
       
   539 		aItem.iType = AvrcpBrowsing::EMediaPlayer;
       
   540 		aItem.iPlayerId = aAvrcpPlayerId;
       
   541 		aItem.iPlayerType = iPlayers[aAvrcpPlayerId].iPlayerType;
       
   542 		aItem.iPlayerSubType = iPlayers[aAvrcpPlayerId].iPlayerSubType;
       
   543 		aItem.iPlayStatus = iPlayers[aAvrcpPlayerId].iPlaybackStatus;
       
   544 		aItem.iFeatureBitmask = iPlayers[aAvrcpPlayerId].iFeatureBitmask.FeatureBitmask();
       
   545 		aItem.iCharset = KUtf8MibEnum;
       
   546 		aItem.iNameLength = iPlayers[aAvrcpPlayerId].iName.Length();
       
   547 		// Takes a copy of media player name
       
   548 		aItem.iName.CreateL(iPlayers[aAvrcpPlayerId].iName);
       
   549 		
       
   550 		aItem.iLength = 28 + aItem.iNameLength;
       
   551 		}
       
   552 	else
       
   553 		{
       
   554 		LEAVEL(KErrNotFound);
       
   555 		}
       
   556 	
       
   557 	CleanupStack::PopAndDestroy(&iLock);
       
   558 	}
       
   559 
       
   560 TBool CAvrcpPlayerInfoManager::ValidPlayer(const TUint16& aAvrcpPlayerId) const
       
   561 	{
       
   562 	LOG_FUNC
       
   563 
       
   564 	if(aAvrcpPlayerId >= iPlayers.Count() || iPlayers[aAvrcpPlayerId].iId == KNullClientId)
       
   565 		{
       
   566 		return EFalse;
       
   567 		}
       
   568 	else
       
   569 		{
       
   570 		return ETrue;
       
   571 		}
       
   572 	}
       
   573 
       
   574 TInt CAvrcpPlayerInfoManager::NextPlayerIndex()
       
   575 	{
       
   576 	LOG_FUNC
       
   577 
       
   578 	TRemConClientId nullId = KNullClientId;
       
   579 	TInt index = iPlayers.Find(nullId, PlayerCompare);
       
   580 
       
   581 	if(index < 0)
       
   582 		{
       
   583 		// No gaps to fill, add another item to the player list
       
   584 		TAvrcpMediaPlayerItem item;
       
   585 		TInt err = iPlayers.Append(item);
       
   586 		if(!err)
       
   587 			{
       
   588 			index = iPlayers.Count() - 1;
       
   589 			}
       
   590 		}
       
   591 	
       
   592 	return index;
       
   593 	}
       
   594 
       
   595 void CAvrcpPlayerInfoManager::MuoUidChanged(TRemConClientId aId, TUint16 aUidCounter)
       
   596 	{
       
   597 	LOG_FUNC;
       
   598 	ASSERT_BULK_THREAD
       
   599 	iLock.Wait();
       
   600 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   601 	if(index >= 0)
       
   602 		{
       
   603 		iPlayers[index].iUidCounter = aUidCounter;
       
   604 		}
       
   605 	iLock.Signal();
       
   606 	
       
   607 	iControlThreadCallBack.CallBack();
       
   608 	}
       
   609 
       
   610 void CAvrcpPlayerInfoManager::MuoError(TRemConClientId aId)
       
   611 	{
       
   612 	// Narg.  Tell everyone we can't use this player anymore
       
   613 	BulkClientNotAvailable(aId);
       
   614 	}
       
   615 
       
   616 void CAvrcpPlayerInfoManager::MpsoPlayStatusChanged(TRemConClientId aId, MPlayerEventsObserver::TPlaybackStatus aPlaybackStatus)
       
   617 	{
       
   618 	LOG_FUNC
       
   619 	ASSERT_CONTROL_THREAD
       
   620 	iLock.Wait();
       
   621 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   622 	if(index >= 0)
       
   623 		{
       
   624 		iPlayers[index].iPlaybackStatus = static_cast<MPlayerEventsObserver::TPlaybackStatus>(aPlaybackStatus);
       
   625 		}
       
   626 	iLock.Signal();
       
   627 	}
       
   628 
       
   629 void CAvrcpPlayerInfoManager::MpsoError(TRemConClientId aId)
       
   630 	{
       
   631 	LOG_FUNC
       
   632 	ASSERT_CONTROL_THREAD
       
   633 	iLock.Wait();
       
   634 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   635 	if(index >= 0)
       
   636 		{
       
   637 		iPlayers[index].iPlaybackStatus = MPlayerEventsObserver::EError;
       
   638 		}
       
   639 	iLock.Signal();
       
   640 	}
       
   641 
       
   642 TUint16 CAvrcpPlayerInfoManager::UidCounterL(const TRemConClientId& aClientId) const
       
   643 	{
       
   644 	LOG_FUNC
       
   645 	ASSERT_CONTROL_THREAD
       
   646 	iLock.Wait();
       
   647 	CleanupSignalPushL(iLock);
       
   648 	TUint16 uidCounter = KErrNone;
       
   649 	TInt index = iPlayers.Find(aClientId, PlayerCompare);
       
   650 	if(index < 0)
       
   651 		{
       
   652 		LEAVEL(KErrNotFound);
       
   653 		}
       
   654 	uidCounter = iPlayers[index].iUidCounter;
       
   655 	CleanupStack::PopAndDestroy(&iLock);
       
   656 	return uidCounter;
       
   657 	}
       
   658 
       
   659 TInt CAvrcpPlayerInfoManager::SetPlayerFeatures(const TRemConClientId& aId, TPlayerFeatureBitmask& aBitmask, TUint8& aSdpFeatures, TBool& aAbsoluteVolumeSupported)
       
   660 	{
       
   661 	LOG_FUNC
       
   662 	ASSERT_CONTROL_THREAD
       
   663 
       
   664 	TInt err;
       
   665 	RArray<TUint> operations;
       
   666 	
       
   667 	aAbsoluteVolumeSupported = EFalse;
       
   668 	aSdpFeatures = 0;
       
   669 	err = iControlBearerObserver.SupportedOperations(aId, TUid::Uid(KRemConCoreApiUid), operations);
       
   670 	if(!err)
       
   671 		{
       
   672 		aBitmask.SetCoreApiFeatures(operations);
       
   673 		}
       
   674 	else if(err != KErrNotSupported)
       
   675 		{
       
   676 		operations.Close();
       
   677 		return err;
       
   678 		}
       
   679 	
       
   680 	err = iControlBearerObserver.SupportedOperations(aId, TUid::Uid(KRemConPlayerInformationUid), operations);
       
   681 	if(!err)
       
   682 		{
       
   683 		aSdpFeatures |= AvrcpSdp::EPlayer;
       
   684 		}
       
   685 	else if(err != KErrNotSupported)
       
   686 		{
       
   687 		operations.Close();
       
   688 		return err;
       
   689 		}
       
   690 	
       
   691 	err = iControlBearerObserver.SupportedOperations(aId, TUid::Uid(KRemConGroupNavigationApiUid), operations);
       
   692 	if(!err)
       
   693 		{
       
   694 		aSdpFeatures |= AvrcpSdp::EGroupNavigation;
       
   695 		aBitmask.SetGroupNavigationApiFeatures(operations);
       
   696 		}
       
   697 	else if(err != KErrNotSupported)
       
   698 		{
       
   699 		return err;
       
   700 		}
       
   701 	
       
   702 	err = iControlBearerObserver.SupportedOperations(aId, TUid::Uid(KRemConAbsoluteVolumeTargetApiUid), operations);
       
   703 	if(!err)
       
   704 		{
       
   705 		aBitmask.SetAbsoluteVolumeApiFeatures(operations);
       
   706 		aAbsoluteVolumeSupported = ETrue;
       
   707 		}
       
   708 	else if(err != KErrNotSupported)
       
   709 		{
       
   710 		operations.Close();
       
   711 		return err;
       
   712 		}
       
   713 	
       
   714 	err = iControlBearerObserver.SupportedOperations(aId, TUid::Uid(KRemConNowPlayingApiUid), operations);
       
   715 	if(!err)
       
   716 		{
       
   717 		aBitmask.SetNowPlayingApiFeatures(operations);
       
   718 		}
       
   719 	else if(err != KErrNotSupported)
       
   720 		{
       
   721 		operations.Close();
       
   722 		return err;
       
   723 		}
       
   724 	
       
   725 	err = iControlBearerObserver.SupportedOperations(aId, TUid::Uid(KRemConMediaBrowseApiUid), operations);
       
   726 	if(!err)
       
   727 		{
       
   728 		aSdpFeatures |= AvrcpSdp::EBrowsing;
       
   729 		aBitmask.SetMediaBrowseApiFeatures(operations);
       
   730 		}
       
   731 	
       
   732 	operations.Close();
       
   733 	return err == KErrNotSupported ? KErrNone : err;
       
   734 	}
       
   735 
       
   736 void CAvrcpPlayerInfoManager::UpdateTgServiceRecordL()
       
   737 	{
       
   738 	LOG_FUNC
       
   739 	ASSERT_CONTROL_THREAD
       
   740 
       
   741 	TUint16 features, avrcpVersion, avctpVersion;
       
   742 	CurrentTargetVersionAndFeatures(avrcpVersion, avctpVersion, features);
       
   743 	
       
   744 	AvrcpSdpUtils::UpdateProtocolDescriptorListL(iSdpDatabase, iTargetRecord, avctpVersion);
       
   745 	if(avrcpVersion == AvrcpSdp::KAvrcpProfileVersion14)
       
   746 		{
       
   747 		AvrcpSdpUtils::UpdateAdditionalProtocolDescriptorListL(iSdpDatabase, iTargetRecord);
       
   748 		}
       
   749 	
       
   750 	AvrcpSdpUtils::UpdateProfileDescriptorListL(iSdpDatabase, iTargetRecord, avrcpVersion);
       
   751 	AvrcpSdpUtils::UpdateSupportedFeaturesL(iSdpDatabase, iTargetRecord, AvrcpSdp::ERemoteControlTarget, features);
       
   752 	}
       
   753 
       
   754 void CAvrcpPlayerInfoManager::CurrentTargetVersionAndFeatures(TUint16& aAvrcpVersion, TUint16& aAvctpVersion, TUint16& aSdpFeatures)
       
   755 	{
       
   756 	aSdpFeatures = AvrcpSdp::KAvrcpBaseTgFeatures;
       
   757 	for(TInt i=0; i<iPlayers.Count(); i++)
       
   758 		{
       
   759 		if(ValidPlayer(i))
       
   760 			{
       
   761 			aSdpFeatures |= iPlayers[i].iSdpFeatures;
       
   762 			}
       
   763 		}
       
   764 	
       
   765 	aAvrcpVersion = (aSdpFeatures & AvrcpSdp::EBrowsing) ? AvrcpSdp::KAvrcpProfileVersion14 : AvrcpSdp::KAvrcpProfileVersion13;
       
   766 	aAvctpVersion = (aAvrcpVersion == AvrcpSdp::KAvrcpProfileVersion14) ? AvrcpSdp::KAvctpProtocolVersion13 : AvrcpSdp::KAvctpProtocolVersion12;
       
   767 	
       
   768 	// Only indicate support for multiple players if advertising support for AVRCP 1.4
       
   769 	if(aAvrcpVersion == AvrcpSdp::KAvrcpProfileVersion14)
       
   770 		{
       
   771 		aSdpFeatures |= AvrcpSdp::EMultiplePlayers;
       
   772 		}
       
   773 	}
       
   774 
       
   775 void CAvrcpPlayerInfoManager::UidCounterUpdate()
       
   776 	{
       
   777 	LOG_FUNC
       
   778 	ASSERT_CONTROL_THREAD
       
   779 	
       
   780 	for(TInt i=0; i<iPlayers.Count(); i++)
       
   781 		{
       
   782 		if(ValidPlayer(i))
       
   783 			{
       
   784 			iLock.Wait();
       
   785 			TUint16 currentUidCounter = iPlayers[i].iUidCounter;
       
   786 			TUint16 lastUpdate = iPlayers[i].iLastUpdatedUidCounter;
       
   787 			iPlayers[i].iLastUpdatedUidCounter = currentUidCounter;
       
   788 			TRemConClientId clientId = iPlayers[i].iId;
       
   789 			iLock.Signal();
       
   790 			
       
   791 			if(currentUidCounter != lastUpdate)
       
   792 				{
       
   793 				for(TInt j=0; j<iObservers.Count(); j++)
       
   794 					{
       
   795 					// Observer can request most up to date value if it wants it
       
   796 					iObservers[j]->MpcoUidCounterChanged(clientId);
       
   797 					}
       
   798 				}
       
   799 			}
       
   800 		}
       
   801 	}
       
   802 
       
   803 /**
       
   804 If the client ID is set to a valid ID then we shall return the support
       
   805 status for the specific player referenced by the ID.
       
   806 Otherwise we shall return generic support which will indicate support across
       
   807 the device.
       
   808 @return whether absolute volume control is supported either by the specific player
       
   809 associated with a client ID, or generally by the device if an invalid client ID is
       
   810 provided.
       
   811  */
       
   812 TBool CAvrcpPlayerInfoManager::AbsoluteVolumeSupportedL(const TRemConClientId& aClientId) const
       
   813 	{
       
   814 	LOG_FUNC
       
   815 	ASSERT_CONTROL_THREAD
       
   816 
       
   817 	iLock.Wait();
       
   818 	CleanupSignalPushL(iLock);
       
   819 	
       
   820 	TBool supported = EFalse;
       
   821 	// If we receive a "NULL" client ID then it means that we should 
       
   822 	// return whether abs vol is generically supported by the device.
       
   823 	if(aClientId == KNullClientId)
       
   824 		{
       
   825 		// Try to find the first player supporting abs vol, if there is one then it is supported 
       
   826 		TInt index = iPlayers.Find(EFirstAbsVolSupport, FirstAbsVolSupport);
       
   827 		supported = (index >= 0);
       
   828 		}
       
   829 	else
       
   830 		{
       
   831 		// The abs vol support for a specific player is required, so return that.
       
   832 		TInt index = iPlayers.Find(aClientId, PlayerCompare);
       
   833 		if(index < 0)
       
   834 			{
       
   835 			LEAVEL(KErrNotFound);
       
   836 			}
       
   837 		supported = iPlayers[index].iAbsoluteVolumeSupport;
       
   838 		}
       
   839 	
       
   840 	CleanupStack::PopAndDestroy(&iLock);
       
   841 	
       
   842 	return supported;
       
   843 	}
       
   844 
       
   845 TBool CAvrcpPlayerInfoManager::BrowsingSupportedL(const TRemConClientId& aClientId) const
       
   846 	{
       
   847 	LOG_FUNC
       
   848 	ASSERT_CONTROL_THREAD
       
   849 
       
   850 	iLock.Wait();
       
   851 	CleanupSignalPushL(iLock);
       
   852 	
       
   853 	TBool supported = EFalse;
       
   854 	// If we receive a "NULL" client ID then it means that we should 
       
   855 	// return whether browsing is generically supported by the device.
       
   856 	if(aClientId == KNullClientId)
       
   857 		{
       
   858 		// Try to find the first player supporting browsing, if there is one then it is supported 
       
   859 		TInt index = iPlayers.Find(EFirstBrowsingSupport, FirstBrowsingSupport);
       
   860 		supported = (index >= 0);
       
   861 		}
       
   862 	else
       
   863 		{
       
   864 		// The browsing support for a specific player is required, so return that.
       
   865 		TInt index = iPlayers.Find(aClientId, PlayerCompare);
       
   866 		if(index < 0)
       
   867 			{
       
   868 			LEAVEL(KErrNotFound);
       
   869 			}
       
   870 		supported = iPlayers[index].iSdpFeatures & AvrcpSdp::EBrowsing;
       
   871 		}
       
   872 	
       
   873 	CleanupStack::PopAndDestroy(&iLock);
       
   874 	
       
   875 	return supported;
       
   876 	}
       
   877 
       
   878 TInt CAvrcpPlayerInfoManager::PlayerUpdateCallBack(TAny* aPlayerInfoMgr)
       
   879 	{
       
   880 	static_cast<CAvrcpPlayerInfoManager*>(aPlayerInfoMgr)->UidCounterUpdate();
       
   881 	return KErrNone;
       
   882 	}
       
   883