bluetoothappprofiles/avrcp/remconbeareravrcp/src/avrcpplayerinfomanager.cpp
changeset 70 f5508c13dfe0
parent 67 16e4b9007960
child 71 083fd884d7dd
equal deleted inserted replaced
67:16e4b9007960 70:f5508c13dfe0
     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::UpdateSdpRecord(const TAvrcpMediaPlayerItem& aItem)
       
   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::CreateServiceRecordL(iSdpDatabase, iTargetRecord, ETrue, 
       
   154 					(aItem.iSdpFeatures & AvrcpSdp::EBrowsing) ? AvrcpSdp::KAvrcpProfileVersion14 : AvrcpSdp::KAvrcpProfileVersion13));
       
   155 		}
       
   156 	if(sdpErr == KErrNone)
       
   157 		{
       
   158 		TRAP_IGNORE(UpdateTgServiceRecordL());
       
   159 		}
       
   160 	}
       
   161 
       
   162 void CAvrcpPlayerInfoManager::ClientAvailable(const TRemConClientId& aId, TPlayerType aPlayerType, TPlayerSubType aPlayerSubType, const TDesC8& aName)
       
   163 	{
       
   164 	LOG_FUNC;
       
   165 	ASSERT_CONTROL_THREAD;
       
   166 	iLock.Wait();
       
   167 	// Add this to our client list, using any holes in the client id array
       
   168 	TInt index = NextPlayerIndex();
       
   169 	if(index < 0)
       
   170 		{
       
   171 		// Couldn't allocate memory to store this player, remote will just
       
   172 		// have to make do with the current set
       
   173 		iLock.Signal();
       
   174 		return;
       
   175 		}
       
   176 	
       
   177 	TAvrcpMediaPlayerItem& item = iPlayers[index];
       
   178 	item.iId = aId;
       
   179 	item.iBulkClientAvailable = EFalse;
       
   180 	item.iUidCounter = 0;
       
   181 	item.iLastUpdatedUidCounter = 0;
       
   182 	item.iPlaybackStatus = MPlayerEventsObserver::EStopped;
       
   183 	TInt err = SetItemDetails(item, aPlayerType, aPlayerSubType, aName);
       
   184 
       
   185 	// Release lock before calling out of player info manager in case
       
   186 	// anyone needs to call back in - we're finished updating the
       
   187 	// info now.
       
   188 	iLock.Signal();
       
   189 
       
   190 	if(!err)
       
   191 		{
       
   192 		TRAP(err, iPlayStatusWatcher->StartWatchingPlayerL(aId));
       
   193 		if(!err)
       
   194 			{
       
   195 			UpdateSdpRecord(item);
       
   196 		     for(TInt i = 0; i<iObservers.Count(); i++)
       
   197 				{
       
   198 				iObservers[i]->MpcoAvailablePlayersChanged();
       
   199 				}
       
   200 			}
       
   201 		  else    
       
   202 			{
       
   203 			iLock.Wait();
       
   204 			iPlayers[index].iId = KNullClientId;
       
   205 			iLock.Signal();
       
   206 			}
       
   207 		}
       
   208 	}
       
   209 
       
   210 void CAvrcpPlayerInfoManager::ClientNotAvailable(const TRemConClientId& aId)
       
   211 	{
       
   212 	LOG_FUNC
       
   213 	ASSERT_CONTROL_THREAD
       
   214 	iLock.Wait();
       
   215 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   216 	if(index < 0)
       
   217 		{
       
   218 		// May not be here if we couldn't allocate memory to store this
       
   219 		// when we were first told about it
       
   220 		iLock.Signal();
       
   221 		return;
       
   222 		}
       
   223 	
       
   224 	iPlayStatusWatcher->StopWatchingPlayer(aId);
       
   225 	iPlayers[index].iId = KNullClientId;
       
   226 	
       
   227 	//Release lock as soon as we've stopped fiddling
       
   228 	iLock.Signal();
       
   229 	
       
   230 	for(TInt i = 0; i<iObservers.Count(); i++)
       
   231 		{
       
   232 		iObservers[i]->MpcoAvailablePlayersChanged();
       
   233 		}
       
   234 	
       
   235 	// Don't put requirement on ordering of ClientNotAvailable/ClientStatus calls
       
   236 	if(iTargetRecord)
       
   237 		{
       
   238 		TRAP_IGNORE(UpdateTgServiceRecordL());
       
   239 		}
       
   240 	}
       
   241 
       
   242 void CAvrcpPlayerInfoManager::ClientStatus(TBool aControllerPresent, TBool aTargetPresent)
       
   243 	{
       
   244 	LOG_FUNC
       
   245 	ASSERT_CONTROL_THREAD
       
   246 	// SDP only used in the control thread
       
   247 	
       
   248 	//If we have gone from 1->0 on either of these we can remove the record now,
       
   249 	// otherwise wait for more detail on ClientAvailable or ControllerFeaturesUpdatedL
       
   250 	if(!aControllerPresent && iControllerRecord)
       
   251 		{
       
   252 		iSdpDatabase.DeleteRecord(iControllerRecord);
       
   253 		iControllerRecord = 0;
       
   254 		}
       
   255 			
       
   256 	if(!aTargetPresent && iTargetRecord)
       
   257 		{
       
   258 		iSdpDatabase.DeleteRecord(iTargetRecord);
       
   259 		iTargetRecord = 0;
       
   260 		}
       
   261 	}
       
   262 
       
   263 TInt CAvrcpPlayerInfoManager::SetLocalAddressedClient(const TRemConClientId& aId)
       
   264 	{
       
   265 	LOG_FUNC
       
   266 	ASSERT_CONTROL_THREAD
       
   267 
       
   268 	TUint16 playerId = 0;
       
   269 	TRAPD(err, playerId = PlayerL(aId));
       
   270 	static_cast<void>(playerId==playerId); // We only want to check if the bearer knows about the client.
       
   271 	if(err == KErrNone)
       
   272 		{
       
   273 		for(TInt i = 0; i<iObservers.Count(); i++)
       
   274 			{
       
   275 			iObservers[i]->MpcoAddressedPlayerChangedLocally(aId);
       
   276 			}
       
   277 		}
       
   278 	
       
   279 	return err;
       
   280 	}
       
   281 
       
   282 void CAvrcpPlayerInfoManager::ControllerFeaturesUpdatedL(RArray<TUid>& aSupportedInterfaces)
       
   283 	{
       
   284 	LOG_FUNC
       
   285 	ASSERT_CONTROL_THREAD
       
   286 	// SDP only used in the control thread
       
   287 
       
   288 	TUint16 avrcpVersion = AvrcpSdp::KAvrcpProfileVersion13; 
       
   289 	TUint16 avctpVersion = AvrcpSdp::KAvctpProtocolVersion12; 
       
   290 
       
   291 	if(aSupportedInterfaces.Find(TUid::Uid(KRemConAbsoluteVolumeControllerApiUid)) >= 0)
       
   292 		{
       
   293 		avrcpVersion = AvrcpSdp::KAvrcpProfileVersion14;
       
   294 		avctpVersion = AvrcpSdp::KAvctpProtocolVersion13;
       
   295 		}
       
   296 
       
   297 	if(!iControllerRecord)
       
   298 		{
       
   299 		AvrcpSdpUtils::CreateServiceRecordL(iSdpDatabase, iControllerRecord, EFalse, avrcpVersion);		
       
   300 		AvrcpSdpUtils::UpdateBrowseListL(iSdpDatabase, iControllerRecord);
       
   301 		}
       
   302 
       
   303 	AvrcpSdpUtils::UpdateProtocolDescriptorListL(iSdpDatabase, iControllerRecord, avctpVersion);
       
   304 	AvrcpSdpUtils::UpdateProfileDescriptorListL(iSdpDatabase, iControllerRecord, avrcpVersion);
       
   305 	AvrcpSdpUtils::UpdateSupportedFeaturesL(iSdpDatabase, iControllerRecord, AvrcpSdp::ERemoteControl, AvrcpSdp::KAvrcpBaseCtFeatures);
       
   306 	}
       
   307 
       
   308 void CAvrcpPlayerInfoManager::TargetFeaturesUpdated(const TRemConClientId& aId, TPlayerType aPlayerType, TPlayerSubType aPlayerSubType, const TDesC8& aName)
       
   309 	{
       
   310 	LOG_FUNC;
       
   311 	ASSERT_CONTROL_THREAD;
       
   312 	iLock.Wait();
       
   313 	// Find this client in our client list
       
   314 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   315 	if(index < 0)
       
   316 		{
       
   317 		// Couldn't find client in client list, maybe we removed it after an earlier failure
       
   318 		iLock.Signal();
       
   319 		return;
       
   320 		}
       
   321 
       
   322 	TAvrcpMediaPlayerItem& item = iPlayers[index];
       
   323 	TInt err = SetItemDetails(item, aPlayerType, aPlayerSubType, aName);
       
   324 
       
   325 	// Release lock before calling out of player info manager in case
       
   326 	// anyone needs to call back in - we're finished updating the
       
   327 	// info now.
       
   328 	iLock.Signal();
       
   329 
       
   330 	if(!err)
       
   331 		{
       
   332 		UpdateSdpRecord(item);
       
   333 		}
       
   334 	else    
       
   335 		{
       
   336 		// There was an error updating the features so remove this client from the client list
       
   337 		iLock.Wait();
       
   338 		iPlayers[index].iId = KNullClientId;
       
   339 		iLock.Signal();
       
   340 		}
       
   341 
       
   342 	for(TInt i = 0; i<iObservers.Count(); i++)
       
   343 		{
       
   344 		iObservers[i]->MpcoAvailablePlayersChanged();
       
   345 		}
       
   346 	}
       
   347 
       
   348 MIncomingCommandHandler& CAvrcpPlayerInfoManager::InternalCommandHandler()
       
   349 	{
       
   350 	LOG_FUNC
       
   351 	ASSERT_CONTROL_THREAD
       
   352 
       
   353 	return *iPlayStatusWatcher;
       
   354 	}
       
   355 
       
   356 void CAvrcpPlayerInfoManager::BulkClientAvailable(const TRemConClientId& aId)
       
   357 	{
       
   358 	LOG_FUNC
       
   359 	ASSERT_BULK_THREAD
       
   360 	iLock.Wait();
       
   361 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   362 	if(index < 0)
       
   363 		{
       
   364 		iLock.Signal();
       
   365 		return;
       
   366 		}
       
   367 	ASSERT(!iPlayers[index].iBulkClientAvailable);
       
   368 	
       
   369 	TRAPD(err, iUidWatcher->StartWatchingPlayerL(aId));
       
   370 	
       
   371 	if(!err)
       
   372 		{
       
   373 		iPlayers[index].iBulkClientAvailable = ETrue;
       
   374 		}
       
   375 	
       
   376 	iLock.Signal();
       
   377 	}
       
   378 
       
   379 void CAvrcpPlayerInfoManager::BulkClientNotAvailable(const TRemConClientId& aId)
       
   380 	{
       
   381 	LOG_FUNC
       
   382 	ASSERT_BULK_THREAD
       
   383 	iLock.Wait();
       
   384 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   385 	if(index >= 0)
       
   386 		{
       
   387 		ASSERT(iPlayers[index].iBulkClientAvailable);
       
   388 		iPlayers[index].iBulkClientAvailable = EFalse;
       
   389 		}
       
   390 	iLock.Signal();
       
   391 	iUidWatcher->StopWatchingPlayer(aId);
       
   392 	}
       
   393 
       
   394 void CAvrcpPlayerInfoManager::AddObserverL(MPlayerChangeObserver& aObserver)
       
   395 	{
       
   396 	LOG_FUNC
       
   397 	ASSERT_CONTROL_THREAD
       
   398 	iObservers.AppendL(&aObserver);
       
   399 	}
       
   400 
       
   401 void CAvrcpPlayerInfoManager::RemoveObserver(MPlayerChangeObserver& aObserver)
       
   402 	{
       
   403 	LOG_FUNC
       
   404 	ASSERT_CONTROL_THREAD
       
   405 	TInt index = iObservers.Find(&aObserver);
       
   406 	if(index >= 0)
       
   407 		{
       
   408 		iObservers.Remove(index);
       
   409 		}
       
   410 	}
       
   411 
       
   412 TRemConClientId CAvrcpPlayerInfoManager::ClientL(TUint16 aAvrcpPlayerId) const
       
   413 	{
       
   414 	LOG_FUNC
       
   415 	// THREAD - Bulk and Control
       
   416 	
       
   417 	iLock.Wait();
       
   418 	CleanupSignalPushL(iLock);
       
   419 	
       
   420 	TRemConClientId clientId = KNullClientId;
       
   421 	if(ValidPlayer(aAvrcpPlayerId))
       
   422 		{
       
   423 		clientId = iPlayers[aAvrcpPlayerId].iId;
       
   424 		}
       
   425 	else
       
   426 		{
       
   427 		LEAVEL(KErrNotFound);
       
   428 		}
       
   429 	
       
   430 	CleanupStack::PopAndDestroy(&iLock);
       
   431 	
       
   432 	return clientId;
       
   433 	}
       
   434 
       
   435 TRemConClientId CAvrcpPlayerInfoManager::Client(TUint16 aAvrcpPlayerId) const
       
   436 	{
       
   437 	LOG_FUNC
       
   438 	// THREAD - Bulk and Control
       
   439 	
       
   440 	iLock.Wait();
       
   441 	
       
   442 	TRemConClientId clientId = KNullClientId;
       
   443 	__ASSERT_DEBUG(ValidPlayer(aAvrcpPlayerId), AvrcpUtils::Panic(EInvalidPlayerId));
       
   444 	
       
   445 	clientId = iPlayers[aAvrcpPlayerId].iId;
       
   446 	
       
   447 	iLock.Signal();
       
   448 	return clientId;
       
   449 	}
       
   450 
       
   451 TUint16 CAvrcpPlayerInfoManager::PlayerL(const TRemConClientId& aClientId) const
       
   452 	{
       
   453 	LOG_FUNC
       
   454 	// THREAD - Bulk and Control
       
   455 	
       
   456 	iLock.Wait();
       
   457 	
       
   458 	TUint16 player = 0;
       
   459 	TBool found = EFalse;
       
   460 	for(TInt i = 0; i < iPlayers.Count(); i++)
       
   461 		{
       
   462 		if(PlayerCompare(&aClientId, iPlayers[i]))
       
   463 			{
       
   464 			player = i;
       
   465 			found = ETrue;
       
   466 			}
       
   467 		}
       
   468 
       
   469 	iLock.Signal();
       
   470 	
       
   471 	if(!found)
       
   472 		{
       
   473 		LEAVEL(KErrNotFound);
       
   474 		}
       
   475 	
       
   476 	return player;
       
   477 	}
       
   478 
       
   479 TInt CAvrcpPlayerInfoManager::PlayerListing(TUint aStartItem, TUint aEndItem, RArray<TUint>& aPlayers)
       
   480 	{
       
   481 	LOG_FUNC
       
   482 	ASSERT_BULK_THREAD
       
   483 
       
   484 	if(aStartItem > aEndItem)
       
   485 		{
       
   486 		return KErrArgument;
       
   487 		}
       
   488 	
       
   489 	iLock.Wait();
       
   490 	if(aStartItem >= iPlayers.Count())
       
   491 		{
       
   492 		iLock.Signal();
       
   493 		return KErrArgument;
       
   494 		}
       
   495 	
       
   496 	TInt err = KErrNone;
       
   497 	for(TUint i = aStartItem; i <= aEndItem && i < iPlayers.Count() && err == KErrNone; i++)
       
   498 		{
       
   499 		if(iPlayers[i].iId != KNullClientId)
       
   500 			{
       
   501 			err = aPlayers.Append(i);
       
   502 			}
       
   503 		}
       
   504 	
       
   505 	iLock.Signal();
       
   506 	return err;
       
   507 	}
       
   508 
       
   509 TInt CAvrcpPlayerInfoManager::PlayerListing(RArray<TUint>& aPlayers)
       
   510 	{
       
   511 	LOG_FUNC
       
   512 	ASSERT_CONTROL_THREAD
       
   513 	iLock.Wait();
       
   514 	TInt err = KErrNone;
       
   515 	for(TInt i = 0; i < iPlayers.Count() && err == KErrNone; i++)
       
   516 		{
       
   517 		if(iPlayers[i].iId != KNullClientId)
       
   518 			{
       
   519 			err = aPlayers.Append(i);
       
   520 			}
       
   521 		}
       
   522 	
       
   523 	iLock.Signal();
       
   524 	return err;
       
   525 	}
       
   526 
       
   527 void CAvrcpPlayerInfoManager::MediaPlayerItemL(const TUint16& aAvrcpPlayerId, RMediaPlayerItem& aItem)
       
   528 	{
       
   529 	LOG_FUNC
       
   530 	ASSERT_BULK_THREAD
       
   531 	iLock.Wait();
       
   532 	CleanupSignalPushL(iLock);
       
   533 	
       
   534 	if(ValidPlayer(aAvrcpPlayerId))
       
   535 		{
       
   536 		aItem.iType = AvrcpBrowsing::EMediaPlayer;
       
   537 		aItem.iPlayerId = aAvrcpPlayerId;
       
   538 		aItem.iPlayerType = iPlayers[aAvrcpPlayerId].iPlayerType;
       
   539 		aItem.iPlayerSubType = iPlayers[aAvrcpPlayerId].iPlayerSubType;
       
   540 		aItem.iPlayStatus = iPlayers[aAvrcpPlayerId].iPlaybackStatus;
       
   541 		aItem.iFeatureBitmask = iPlayers[aAvrcpPlayerId].iFeatureBitmask.FeatureBitmask();
       
   542 		aItem.iCharset = KUtf8MibEnum;
       
   543 		aItem.iNameLength = iPlayers[aAvrcpPlayerId].iName.Length();
       
   544 		// Takes a copy of media player name
       
   545 		aItem.iName.CreateL(iPlayers[aAvrcpPlayerId].iName);
       
   546 		
       
   547 		aItem.iLength = 28 + aItem.iNameLength;
       
   548 		}
       
   549 	else
       
   550 		{
       
   551 		LEAVEL(KErrNotFound);
       
   552 		}
       
   553 	
       
   554 	CleanupStack::PopAndDestroy(&iLock);
       
   555 	}
       
   556 
       
   557 TBool CAvrcpPlayerInfoManager::ValidPlayer(const TUint16& aAvrcpPlayerId) const
       
   558 	{
       
   559 	LOG_FUNC
       
   560 
       
   561 	if(aAvrcpPlayerId >= iPlayers.Count() || iPlayers[aAvrcpPlayerId].iId == KNullClientId)
       
   562 		{
       
   563 		return EFalse;
       
   564 		}
       
   565 	else
       
   566 		{
       
   567 		return ETrue;
       
   568 		}
       
   569 	}
       
   570 
       
   571 TInt CAvrcpPlayerInfoManager::NextPlayerIndex()
       
   572 	{
       
   573 	LOG_FUNC
       
   574 
       
   575 	TRemConClientId nullId = KNullClientId;
       
   576 	TInt index = iPlayers.Find(nullId, PlayerCompare);
       
   577 
       
   578 	if(index < 0)
       
   579 		{
       
   580 		// No gaps to fill, add another item to the player list
       
   581 		TAvrcpMediaPlayerItem item;
       
   582 		TInt err = iPlayers.Append(item);
       
   583 		if(!err)
       
   584 			{
       
   585 			index = iPlayers.Count() - 1;
       
   586 			}
       
   587 		}
       
   588 	
       
   589 	return index;
       
   590 	}
       
   591 
       
   592 void CAvrcpPlayerInfoManager::MuoUidChanged(TRemConClientId aId, TUint16 aUidCounter)
       
   593 	{
       
   594 	LOG_FUNC;
       
   595 	ASSERT_BULK_THREAD
       
   596 	iLock.Wait();
       
   597 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   598 	if(index >= 0)
       
   599 		{
       
   600 		iPlayers[index].iUidCounter = aUidCounter;
       
   601 		}
       
   602 	iLock.Signal();
       
   603 	
       
   604 	iControlThreadCallBack.CallBack();
       
   605 	}
       
   606 
       
   607 void CAvrcpPlayerInfoManager::MuoError(TRemConClientId aId)
       
   608 	{
       
   609 	// Narg.  Tell everyone we can't use this player anymore
       
   610 	BulkClientNotAvailable(aId);
       
   611 	}
       
   612 
       
   613 void CAvrcpPlayerInfoManager::MpsoPlayStatusChanged(TRemConClientId aId, MPlayerEventsObserver::TPlaybackStatus aPlaybackStatus)
       
   614 	{
       
   615 	LOG_FUNC
       
   616 	ASSERT_CONTROL_THREAD
       
   617 	iLock.Wait();
       
   618 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   619 	if(index >= 0)
       
   620 		{
       
   621 		iPlayers[index].iPlaybackStatus = static_cast<MPlayerEventsObserver::TPlaybackStatus>(aPlaybackStatus);
       
   622 		}
       
   623 	iLock.Signal();
       
   624 	}
       
   625 
       
   626 void CAvrcpPlayerInfoManager::MpsoError(TRemConClientId aId)
       
   627 	{
       
   628 	LOG_FUNC
       
   629 	ASSERT_CONTROL_THREAD
       
   630 	iLock.Wait();
       
   631 	TInt index = iPlayers.Find(aId, PlayerCompare);
       
   632 	if(index >= 0)
       
   633 		{
       
   634 		iPlayers[index].iPlaybackStatus = MPlayerEventsObserver::EError;
       
   635 		}
       
   636 	iLock.Signal();
       
   637 	}
       
   638 
       
   639 TUint16 CAvrcpPlayerInfoManager::UidCounterL(const TRemConClientId& aClientId) const
       
   640 	{
       
   641 	LOG_FUNC
       
   642 	ASSERT_CONTROL_THREAD
       
   643 	iLock.Wait();
       
   644 	CleanupSignalPushL(iLock);
       
   645 	TUint16 uidCounter = KErrNone;
       
   646 	TInt index = iPlayers.Find(aClientId, PlayerCompare);
       
   647 	if(index < 0)
       
   648 		{
       
   649 		LEAVEL(KErrNotFound);
       
   650 		}
       
   651 	uidCounter = iPlayers[index].iUidCounter;
       
   652 	CleanupStack::PopAndDestroy(&iLock);
       
   653 	return uidCounter;
       
   654 	}
       
   655 
       
   656 TInt CAvrcpPlayerInfoManager::SetPlayerFeatures(const TRemConClientId& aId, TPlayerFeatureBitmask& aBitmask, TUint8& aSdpFeatures, TBool& aAbsoluteVolumeSupported)
       
   657 	{
       
   658 	LOG_FUNC
       
   659 	ASSERT_CONTROL_THREAD
       
   660 
       
   661 	TInt err;
       
   662 	RArray<TUint> operations;
       
   663 	
       
   664 	aAbsoluteVolumeSupported = EFalse;
       
   665 	aSdpFeatures = 0;
       
   666 	err = iControlBearerObserver.SupportedOperations(aId, TUid::Uid(KRemConCoreApiUid), operations);
       
   667 	if(!err)
       
   668 		{
       
   669 		aBitmask.SetCoreApiFeatures(operations);
       
   670 		}
       
   671 	else if(err != KErrNotSupported)
       
   672 		{
       
   673 		operations.Close();
       
   674 		return err;
       
   675 		}
       
   676 	
       
   677 	err = iControlBearerObserver.SupportedOperations(aId, TUid::Uid(KRemConPlayerInformationUid), operations);
       
   678 	if(!err)
       
   679 		{
       
   680 		aSdpFeatures |= AvrcpSdp::EPlayer;
       
   681 		}
       
   682 	else if(err != KErrNotSupported)
       
   683 		{
       
   684 		operations.Close();
       
   685 		return err;
       
   686 		}
       
   687 	
       
   688 	err = iControlBearerObserver.SupportedOperations(aId, TUid::Uid(KRemConGroupNavigationApiUid), operations);
       
   689 	if(!err)
       
   690 		{
       
   691 		aSdpFeatures |= AvrcpSdp::EGroupNavigation;
       
   692 		aBitmask.SetGroupNavigationApiFeatures(operations);
       
   693 		}
       
   694 	else if(err != KErrNotSupported)
       
   695 		{
       
   696 		return err;
       
   697 		}
       
   698 	
       
   699 	err = iControlBearerObserver.SupportedOperations(aId, TUid::Uid(KRemConAbsoluteVolumeTargetApiUid), operations);
       
   700 	if(!err)
       
   701 		{
       
   702 		aBitmask.SetAbsoluteVolumeApiFeatures(operations);
       
   703 		aAbsoluteVolumeSupported = ETrue;
       
   704 		}
       
   705 	else if(err != KErrNotSupported)
       
   706 		{
       
   707 		operations.Close();
       
   708 		return err;
       
   709 		}
       
   710 	
       
   711 	err = iControlBearerObserver.SupportedOperations(aId, TUid::Uid(KRemConNowPlayingApiUid), operations);
       
   712 	if(!err)
       
   713 		{
       
   714 		aBitmask.SetNowPlayingApiFeatures(operations);
       
   715 		}
       
   716 	else if(err != KErrNotSupported)
       
   717 		{
       
   718 		operations.Close();
       
   719 		return err;
       
   720 		}
       
   721 	
       
   722 	err = iControlBearerObserver.SupportedOperations(aId, TUid::Uid(KRemConMediaBrowseApiUid), operations);
       
   723 	if(!err)
       
   724 		{
       
   725 		aSdpFeatures |= AvrcpSdp::EBrowsing;
       
   726 		aBitmask.SetMediaBrowseApiFeatures(operations);
       
   727 		}
       
   728 	
       
   729 	operations.Close();
       
   730 	return err == KErrNotSupported ? KErrNone : err;
       
   731 	}
       
   732 
       
   733 void CAvrcpPlayerInfoManager::UpdateTgServiceRecordL()
       
   734 	{
       
   735 	LOG_FUNC
       
   736 	ASSERT_CONTROL_THREAD
       
   737 
       
   738 	TUint16 features = AvrcpSdp::KAvrcpBaseTgFeatures;
       
   739 	for(TInt i=0; i<iPlayers.Count(); i++)
       
   740 		{
       
   741 		if(ValidPlayer(i))
       
   742 			{
       
   743 			features |= iPlayers[i].iSdpFeatures;
       
   744 			}
       
   745 		}
       
   746 	
       
   747 	TUint16 avrcpVersion = (features & AvrcpSdp::EBrowsing) ? AvrcpSdp::KAvrcpProfileVersion14 : AvrcpSdp::KAvrcpProfileVersion13;
       
   748 	TUint16 avctpVersion = (avrcpVersion == AvrcpSdp::KAvrcpProfileVersion14) ? AvrcpSdp::KAvctpProtocolVersion13 : AvrcpSdp::KAvctpProtocolVersion12;
       
   749 	
       
   750 	AvrcpSdpUtils::UpdateProtocolDescriptorListL(iSdpDatabase, iTargetRecord, avctpVersion);
       
   751 	if(avrcpVersion == AvrcpSdp::KAvrcpProfileVersion14)
       
   752 		{
       
   753 		AvrcpSdpUtils::UpdateAdditionalProtocolDescriptorListL(iSdpDatabase, iTargetRecord);
       
   754 		}
       
   755 	
       
   756 	AvrcpSdpUtils::UpdateProfileDescriptorListL(iSdpDatabase, iTargetRecord, avrcpVersion);
       
   757 	AvrcpSdpUtils::UpdateBrowseListL(iSdpDatabase, iTargetRecord);
       
   758 	AvrcpSdpUtils::UpdateSupportedFeaturesL(iSdpDatabase, iTargetRecord, AvrcpSdp::ERemoteControlTarget, features);
       
   759 	}
       
   760 
       
   761 void CAvrcpPlayerInfoManager::UidCounterUpdate()
       
   762 	{
       
   763 	LOG_FUNC
       
   764 	ASSERT_CONTROL_THREAD
       
   765 	
       
   766 	for(TInt i=0; i<iPlayers.Count(); i++)
       
   767 		{
       
   768 		if(ValidPlayer(i))
       
   769 			{
       
   770 			iLock.Wait();
       
   771 			TUint16 currentUidCounter = iPlayers[i].iUidCounter;
       
   772 			TUint16 lastUpdate = iPlayers[i].iLastUpdatedUidCounter;
       
   773 			iPlayers[i].iLastUpdatedUidCounter = currentUidCounter;
       
   774 			TRemConClientId clientId = iPlayers[i].iId;
       
   775 			iLock.Signal();
       
   776 			
       
   777 			if(currentUidCounter != lastUpdate)
       
   778 				{
       
   779 				for(TInt j=0; j<iObservers.Count(); j++)
       
   780 					{
       
   781 					// Observer can request most up to date value if it wants it
       
   782 					iObservers[j]->MpcoUidCounterChanged(clientId);
       
   783 					}
       
   784 				}
       
   785 			}
       
   786 		}
       
   787 	}
       
   788 
       
   789 /**
       
   790 If the client ID is set to a valid ID then we shall return the support
       
   791 status for the specific player referenced by the ID.
       
   792 Otherwise we shall return generic support which will indicate support across
       
   793 the device.
       
   794 @return whether absolute volume control is supported either by the specific player
       
   795 associated with a client ID, or generally by the device if an invalid client ID is
       
   796 provided.
       
   797  */
       
   798 TBool CAvrcpPlayerInfoManager::AbsoluteVolumeSupportedL(const TRemConClientId& aClientId) const
       
   799 	{
       
   800 	LOG_FUNC
       
   801 	ASSERT_CONTROL_THREAD
       
   802 
       
   803 	iLock.Wait();
       
   804 	CleanupSignalPushL(iLock);
       
   805 	
       
   806 	TBool supported = EFalse;
       
   807 	// If we receive a "NULL" client ID then it means that we should 
       
   808 	// return whether abs vol is generically supported by the device.
       
   809 	if(aClientId == KNullClientId)
       
   810 		{
       
   811 		// Try to find the first player supporting abs vol, if there is one then it is supported 
       
   812 		TInt index = iPlayers.Find(EFirstAbsVolSupport, FirstAbsVolSupport);
       
   813 		supported = (index >= 0);
       
   814 		}
       
   815 	else
       
   816 		{
       
   817 		// The abs vol support for a specific player is required, so return that.
       
   818 		TInt index = iPlayers.Find(aClientId, PlayerCompare);
       
   819 		if(index < 0)
       
   820 			{
       
   821 			LEAVEL(KErrNotFound);
       
   822 			}
       
   823 		supported = iPlayers[index].iAbsoluteVolumeSupport;
       
   824 		}
       
   825 	
       
   826 	CleanupStack::PopAndDestroy(&iLock);
       
   827 	
       
   828 	return supported;
       
   829 	}
       
   830 
       
   831 TBool CAvrcpPlayerInfoManager::BrowsingSupportedL(const TRemConClientId& aClientId) const
       
   832 	{
       
   833 	LOG_FUNC
       
   834 	ASSERT_CONTROL_THREAD
       
   835 
       
   836 	iLock.Wait();
       
   837 	CleanupSignalPushL(iLock);
       
   838 	
       
   839 	TBool supported = EFalse;
       
   840 	// If we receive a "NULL" client ID then it means that we should 
       
   841 	// return whether browsing is generically supported by the device.
       
   842 	if(aClientId == KNullClientId)
       
   843 		{
       
   844 		// Try to find the first player supporting browsing, if there is one then it is supported 
       
   845 		TInt index = iPlayers.Find(EFirstBrowsingSupport, FirstBrowsingSupport);
       
   846 		supported = (index >= 0);
       
   847 		}
       
   848 	else
       
   849 		{
       
   850 		// The browsing support for a specific player is required, so return that.
       
   851 		TInt index = iPlayers.Find(aClientId, PlayerCompare);
       
   852 		if(index < 0)
       
   853 			{
       
   854 			LEAVEL(KErrNotFound);
       
   855 			}
       
   856 		supported = iPlayers[index].iSdpFeatures & AvrcpSdp::EBrowsing;
       
   857 		}
       
   858 	
       
   859 	CleanupStack::PopAndDestroy(&iLock);
       
   860 	
       
   861 	return supported;
       
   862 	}
       
   863 
       
   864 TInt CAvrcpPlayerInfoManager::PlayerUpdateCallBack(TAny* aPlayerInfoMgr)
       
   865 	{
       
   866 	static_cast<CAvrcpPlayerInfoManager*>(aPlayerInfoMgr)->UidCounterUpdate();
       
   867 	return KErrNone;
       
   868 	}
       
   869