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