bluetoothappprofiles/avrcp/playerinformation/src/playerinformation.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 18 Jan 2010 20:28:57 +0200
changeset 0 f63038272f30
permissions -rw-r--r--
Revision: 201001 Kit: 201003

// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

/**
 @file
 @publishedAll
 @released
*/

#include <bluetooth/logger.h>
#include <playerinformationtarget.h>
#include <e32property.h> 
#include <hwrmpowerstatesdkpskeys.h>

#include "playerapplicationsetting.h"
#include "eventsmask.h"
#include "playerinformation.h"

#ifdef __FLOG_ACTIVE
_LIT8(KLogComponent, LOG_COMPONENT_AVRCP_PLAYER_INFO);
#endif

EXPORT_C CPlayerInfoTarget* CPlayerInfoTarget::NewL(CRemConInterfaceSelector& aInterfaceSelector,
										MPlayerCapabilitiesObserver*& aPlayerCapabilitiesObserver,
										MPlayerApplicationSettingsObserver*& aPlayerApplicationSettingsObserver,
										MPlayerEventsObserver*& aPlayerEventsObserver,
										MPlayerApplicationSettingsNotify& aApplicationSettingNotifier )
	{
	LOG_STATIC_FUNC

	CPlayerInfoTarget* self = new(ELeave) CPlayerInfoTarget(aInterfaceSelector, aApplicationSettingNotifier);
	CleanupStack::PushL(self);
	self->ConstructL( aPlayerCapabilitiesObserver, aPlayerApplicationSettingsObserver, aPlayerEventsObserver );
	CleanupStack::Pop(self);
	return self;
	}
	
/** 
Constructs this interface.
@param aInterfaceSelector An interface selector for use with this interface.
@internalComponent
@released
*/
CPlayerInfoTarget::CPlayerInfoTarget(CRemConInterfaceSelector& aInterfaceSelector, MPlayerApplicationSettingsNotify& aApplicationSettingNotifier)
:	CRemConInterfaceBase(TUid::Uid(KRemConPlayerInformationUid), 
						 KMaxLengthPlayerInformationMsg,
						 aInterfaceSelector,
						 ERemConClientTypeTarget),
	iApplicationSettingNotifier(aApplicationSettingNotifier),
	iPlaybackStatusUpdatePending(EFalse)
	{
	}
	
		
void CPlayerInfoTarget::ConstructL(MPlayerCapabilitiesObserver*& aPlayerCapabilitiesObserver,
										MPlayerApplicationSettingsObserver*& aPlayerApplicationSettingsObserver,
										MPlayerEventsObserver*& aPlayerEventsObserver )
	{
	// reserve two AV/C frames, for this reasoning:
	// GetCapabilities (PDU 0x10) can generate a response
	// which is (255 * 3 bytes) + 2 bytes = 767 total and
	// will fit into two AVC frames. Other PDUs generate
	// less than this, except for PDUs 0x15 and 0x16 which
	// use their own buffer pre-allocated by calling Size()
	iOutBuf.CreateL(KAVCFrameMaxLength * 2);
	
	BaseConstructL();
	
	aPlayerCapabilitiesObserver = this;
	aPlayerApplicationSettingsObserver = this;
	aPlayerEventsObserver = this;
	
	// default values for event notifiers
	iPlayBackStatus = EStopped;
	
	// If no track currently selected
	iTrackId = KNoTrackSelected;
	
	iLengthInMilliseconds = 0;
	iTrackPosition = EStart;
	
	// If no track currently selected, then return KPlaybackPositionUnknown
	iPlaybackPositionInMilliseconds = KPlaybackPositionUnknown;
	iLastNotifiedPlaybackPositionInMilliseconds	= KPlaybackPositionUnknown;

	// The time interval used for playback position notification
	iPlayBackIntervalInMilliseconds = 0;

	// Try to detect battery status from hardware P&S properties	
	iBatteryStatus = DetectBatteryStatus();

	// The Bluetooth SIG vendor id must always be present
	// See AVRCP 1.3 Specification, section 5.5.1, table 5.4
	iCompanyIdList.AppendL(KBluetoothSIGVendorId);
 
	// AVRCP 1.3 specification, Appendix H says that PlaybackStatusChanged
	// and TrackChanged event notification support is mandatory, so add these
	iSupportedNotificationEventList = new (ELeave) TEventsMask();
	iSupportedNotificationEventList->Append(ERegisterNotificationPlaybackStatusChanged);
	iSupportedNotificationEventList->Append(ERegisterNotificationTrackChanged);
	}

EXPORT_C CPlayerInfoTarget::~CPlayerInfoTarget()
	{
	iPendingNotificationEventList.Close();
	iCompanyIdList.Close();
	iOutBuf.Close();

	// Free up all the settings memory
	THashMapIter<TInt, CPlayerApplicationSettings*> iter(iPlayerApplicationSettings);
	CPlayerApplicationSettings* const* setting = iter.NextValue();
	while ( setting != NULL )
		{
		delete *setting;
		setting = iter.NextValue();
		}

	// Now close the hash table itself
	iPlayerApplicationSettings.Close();
	delete iSupportedNotificationEventList;
	}
	
		
TAny* CPlayerInfoTarget::GetInterfaceIf(TUid aUid)
	{
	TAny* ret = NULL;
	if ( aUid == TUid::Uid(KRemConInterfaceIf2) )
		{
		ret = reinterpret_cast<TAny*>(
			static_cast<MRemConInterfaceIf2*>(this)
			);
		}

	return ret;	
	}

// from MRemConInterfaceIf
void CPlayerInfoTarget::MrcibNewMessage(TUint aOperationId, const TDesC8& aData, TRemConMessageSubType aMsgSubType)
	{
	LOG(_L("CPlayerInfoTarget::MrcibNewMessage"));
	LOG1(_L("\taOperationId = 0x%02x"), aOperationId);
	LOG1(_L("\taData.Length = %d"), aData.Length());
	LOG1(_L("\taMsgSubType = 0x%02x"), aMsgSubType);

	TMetadataTransferPDU currentOp = RAvrcpIPC::GetPDUIdFromIPCOperationId(aOperationId);
	
	switch (currentOp)
		{
		case EGetCapabilities:
			{
			/* process this in playercapabilities */
			ProcessGetCapabilities( aData );
			break;
			}
		case EListPlayerApplicationSettingAttributes:	
			{
			/* respond with Player Application Attributes*/
			ProcessListPlayerApplicationAttributes( aOperationId );
			break;
			}
		case EGetPlayerApplicationSettingAttributeText:	
			{
			/* respond with Player Application Attribute Text*/
			ProcessGetPlayerApplicationAttributeText( aData, aOperationId );
			break;
			}
		case EListPlayerApplicationSettingValues:
			{
			/* respond with Player Application Values*/
			ProcessListPlayerApplicationValues( aData, aOperationId );
			break;
			}
		case EGetPlayerApplicationSettingValueText:
			{
			/* respond with Application Value Text*/
			ProcessGetPlayerApplicationValueText( aData, aOperationId );
			break;
			}
		case EGetCurrentPlayerApplicationSettingValue:
			{
			/* respond with Current Player Application Value*/
			ProcessGetCurrentPlayerApplicationValue( aData, aOperationId );
			break;
			}
		case ESetPlayerApplicationSettingValue:
			{
			/* Set Player Application Value*/
			ProcessSetPlayerApplicationValue( aData, aOperationId );
			break;
			}
		case EGetPlayStatus:
			{
			// process in playerevents
			ProcessGetPlayStatus();
			break;
			}
		case ERegisterNotification:
			{
			// obtain eventId from aOperationId
			TRegisterNotificationEvent eventId = RAvrcpIPC::GetEventIdFromIPCOperationId(aOperationId);
			
			// register for Notifications
			if (aMsgSubType == ERemConNotifyCommandAwaitingInterim)
				{
				ProcessGetStatusAndBeginObserving(aOperationId, eventId, aData);
				}
			else if (aMsgSubType == ERemConNotifyCommandAwaitingChanged)
				{
				ProcessGetStatus(aOperationId, eventId);
				}
		 	break;
		 	}
		case EGetPlayStatusUpdate:
			{
			// process in playerevents
			ProcessGetPlayStatusUpdate(aData);
			break;
			}
		default:
			break;
		}
		
	}

MPlayerEventsObserver::TTargetBatteryStatus CPlayerInfoTarget::DetectBatteryStatus()
	{
	MPlayerEventsObserver::TTargetBatteryStatus status = ECritical;
	TInt err = KErrNone;
	TInt batteryStatus = EBatteryStatusUnknown;
	TInt chargingStatus = EChargingStatusNotConnected;
	err = RProperty::Get(KPSUidHWRMPowerState,KHWRMBatteryStatus,batteryStatus);
	if (!err)
		{
		err = RProperty::Get(KPSUidHWRMPowerState,KHWRMChargingStatus,chargingStatus);
		}

	switch (batteryStatus)
		{
		// Normal or Charging
		case EBatteryStatusOk:
			{
			if (chargingStatus == EChargingStatusCharging ||
				chargingStatus == EChargingStatusAlmostComplete ||
				chargingStatus == EChargingStatusChargingContinued)
				{
				iBatteryStatus = EExternal;
				}
			else
				{
				if (chargingStatus == EChargingStatusChargingComplete)
					{
					iBatteryStatus = EFullCharge;
					}
				else
					{
					iBatteryStatus = ENormal;
					}
				}
			}
			break;
		// Warning
		case EBatteryStatusLow:
			{
			iBatteryStatus = EWarning;
			}
			break;
		// Critical
		case EBatteryStatusEmpty:
			{
			iBatteryStatus = ECritical;
			}
			break;
		// Unknown state, set as ECritical
		case EBatteryStatusUnknown:
			{
			iBatteryStatus = ECritical;
			}
			break;
		}
	return status;
	}