bluetoothappprofiles/avrcp/playerinformation/src/playerevents.cpp
changeset 0 f63038272f30
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothappprofiles/avrcp/playerinformation/src/playerevents.cpp	Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,477 @@
+// 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:
+// This file contains the events part of the PlayerInformation API.
+// 
+//
+
+/**
+ @file
+ @publishedAll
+ @released
+*/
+
+#include <bluetooth/logger.h>
+#include <remconinterfaceselector.h>
+#include <remconbeareravrcp.h>
+#include <playerinformationtarget.h>
+#include <playerinformationtargetobserver.h>
+
+#include "playerapplicationsetting.h"
+#include "eventsmask.h"
+#include "playereventsutils.h"
+#include "playerinformation.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_AVRCP_PLAYER_INFO);
+#endif
+
+EXPORT_C void MPlayerEventsObserver::PlaybackStatusChanged(TPlaybackStatus aStatus)
+	{
+	DoPlaybackStatusChanged(aStatus);
+	}
+
+EXPORT_C void MPlayerEventsObserver::TrackChanged(TUint64 aTrackId, TUint32 aLengthInMilliseconds) 
+	{
+	DoTrackChanged(aTrackId, aLengthInMilliseconds); 
+	}
+
+EXPORT_C void MPlayerEventsObserver::TrackReachedEnd() 
+	{
+	DoTrackReachedEnd();
+	}
+
+EXPORT_C void MPlayerEventsObserver::TrackReachedStart()
+	{
+	DoTrackReachedStart();
+	}
+
+EXPORT_C void MPlayerEventsObserver::SetPlaybackPosition(TUint32 aMilliseconds) 
+	{
+	DoSetPlaybackPosition(aMilliseconds); 
+	}
+	
+EXPORT_C void MPlayerEventsObserver::SetBatteryStatus(TTargetBatteryStatus aBatteryStatus) 
+	{
+	DoSetBatteryStatus(aBatteryStatus); 
+	}
+
+void CPlayerInfoTarget::ProcessGetStatusAndBeginObserving( const TUint aOperationId, TRegisterNotificationEvent aEventId, const TDesC8& aData)
+	{
+	// check the event is in the supported list
+	if (!iSupportedNotificationEventList->Find(aEventId))
+		{
+		// Not supported so return error
+		SendError(KErrAvrcpMetadataInvalidParameter, aOperationId, ERemConNotifyResponseInterim);
+		return;
+		}
+		
+	// if the event is EPlaybackPosChanged then the timeinterval is included in the RegisterNofication
+	if (aEventId == ERegisterNotificationPlaybackPosChanged)
+		{
+		// decode the playback interval from aData
+		TInt error = 0;
+		RRemConPlayerInformation32BitResponse request;
+		TRAP(error, request.ReadL(aData));
+		
+		if (error != KErrNone)
+			{
+			// Not supported so return error
+			SendError(KErrAvrcpMetadataParameterNotFound, aOperationId, ERemConNotifyResponseInterim);
+			return;
+			}
+		
+		// save the playback interval
+		iPlayBackIntervalInMilliseconds = request.iValue * 1000;
+		
+		// and the current position
+		iLastNotifiedPlaybackPositionInMilliseconds = iPlaybackPositionInMilliseconds;
+		}
+		
+	// and request another notification (if there is not one already pending)
+	// on the next state change  
+	if (KErrNotFound ==iPendingNotificationEventList.Find(aEventId))
+		{
+		if (iPendingNotificationEventList.Append(aEventId) != KErrNone)
+			{
+			return SendError(KErrAvrcpMetadataInternalError, aOperationId);   // Try to send internal error if OOM
+			}
+		}
+		
+	// send the current status
+	SendNotificationResponse(aEventId, ERemConNotifyResponseInterim );
+	}
+
+void CPlayerInfoTarget::ProcessGetStatus( const TUint aOperationId, TRegisterNotificationEvent aEventId)
+	{
+	// send the current value
+	if (iSupportedNotificationEventList->Find(aEventId))
+		{
+		SendNotificationResponse(aEventId, ERemConNotifyResponseChanged );
+		}
+	else
+		{
+		// Not found so return error
+		SendError(KErrAvrcpMetadataInvalidParameter, aOperationId, ERemConNotifyResponseChanged);
+		}
+	}
+		
+/* ProcessGetPlayStatus This returns the current values of SongLength, 
+   SongPosition and PlayStatus.
+   Note if SongLength and SongPosition are not supported KPlaybackPositionUnknown is returned
+ */
+void CPlayerInfoTarget::ProcessGetPlayStatus()
+	{
+	LOG_FUNC
+
+	TInt error =0;
+
+	// format the response in a RRemConPlayerInformationGetPlayStatusResponse
+	RRemConPlayerInformationGetPlayStatusResponse response;
+	response.iTrackLength = iLengthInMilliseconds;
+	response.iPlayPos = iPlaybackPositionInMilliseconds;
+	response.iStatus = iPlayBackStatus;
+	
+	TRAP(error, response.WriteL(iOutBuf));
+	if (error == KErrNone)
+		{
+		// send the response back to the CT
+		error = InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid),
+												EGetPlayStatus, ERemConResponse, iOutBuf );
+		}
+	}
+
+/* ProcessGetPlayStatusUpdate returns the current play status if it has changed
+ * relative to the provided play status, otherwise the request is queued until
+ * the play status changes.
+ */
+void CPlayerInfoTarget::ProcessGetPlayStatusUpdate(const TDesC8& aData)
+	{
+	LOG_FUNC
+
+	// Bearer should never send us more than one of these in parallel
+	__ASSERT_DEBUG(!iPlaybackStatusUpdatePending, PlayerEventsUtils::Panic(ETwoGetPlayStatusUpdatesQueued));
+	
+	TInt error =0;
+	RRemConPlayerInformationGetPlayStatusUpdateRequest request;
+	TRAP(error, request.ReadL(aData));
+	__ASSERT_DEBUG(error == KErrNone, PlayerEventsUtils::Panic(EBadlyFormattedInternalData));
+
+	if(request.iStatus != iPlayBackStatus)
+		{
+		// format the response in a RRemConPlayerInformationGetPlayStatusResponse
+		RRemConPlayerInformationGetPlayStatusUpdateResponse response;
+		response.iStatus = iPlayBackStatus;
+		
+		TRAP(error, response.WriteL(iOutBuf));
+		if (error == KErrNone)
+			{
+			// send the response back to the CT
+			error = InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid),
+													EGetPlayStatusUpdate, ERemConResponse, iOutBuf );
+			if(error != KErrNone)
+				{
+				// We will try and send the response again next time we get an update
+				iPlaybackStatusUpdatePending = ETrue;
+				}
+			}
+		}
+	else
+		{
+		iPlaybackStatusUpdatePending = ETrue;
+		}
+	}
+
+// Send a Notification message for aEventID 
+void CPlayerInfoTarget::SendNotificationResponse( TRegisterNotificationEvent aEventId, TRemConMessageSubType aMsgSubType )
+	{
+	LOG_FUNC
+
+	TInt error = 0;
+	iOutBuf.Zero();
+
+	if (!iSupportedNotificationEventList->Find(aEventId))
+		{
+		return SendError(KErrAvrcpMetadataInvalidParameter, 
+						 RAvrcpIPC::SetIPCOperationIdFromEventId(aEventId), aMsgSubType);
+		}
+		
+	switch (aEventId)
+		{
+		case ERegisterNotificationTrackReachedEnd:
+		case ERegisterNotificationTrackReachedStart:
+			{
+			// no extra data for reached start or end 
+			RAvrcpIPCError response;
+			response.iError = KErrNone;
+			TRAP(error, response.WriteL(iOutBuf));
+			break;
+			}
+
+		case ERegisterNotificationPlaybackStatusChanged:
+			{
+			// 8bit response -- current playback status 
+			RRemConPlayerInformation8BitResponse response;
+			response.iValue = iPlayBackStatus;
+			TRAP(error, response.WriteL(iOutBuf));
+			break;
+			}
+
+		case ERegisterNotificationBatteryStatusChanged:
+			{
+			// 8bit response -- current battery status
+			RRemConPlayerInformation8BitResponse response;
+			response.iValue = iBatteryStatus;
+			TRAP(error, response.WriteL(iOutBuf));
+			break;
+			}
+
+		case ERegisterNotificationPlaybackPosChanged:
+			{
+			// 32bit response -- current playback position in millisecond 
+			RRemConPlayerInformation32BitResponse response;
+			response.iValue = iPlaybackPositionInMilliseconds;
+			TRAP(error, response.WriteL(iOutBuf));
+			break;
+			}
+
+		case ERegisterNotificationTrackChanged:
+			{
+			// 64bit response -- index of the current track 
+			RRemConPlayerInformation64BitResponse response;
+			response.iValue = iTrackId;
+			TRAP(error, response.WriteL(iOutBuf));
+			break;
+			}
+
+		case ERegisterNotificationPlayerApplicationSettingChanged:
+			{
+			// Send a list of the settings that have changed followed by their value 
+			// starting with the number of attributes to be sent 
+			RRemConPlayerAttributeIdsAndValues response;
+			response.iNumberAttributes = 0;
+		
+			// for every entry in the list
+			THashMapIter<TInt, CPlayerApplicationSettings*> iter(iPlayerApplicationSettings);
+			CPlayerApplicationSettings* const* setting = iter.NextValue();
+			while ( setting != NULL )
+				{
+				TUint8 value = (*setting)->GetCurrentValue();
+				TInt ret1 = response.iAttributeValue.Append(value);
+				TInt ret2 = response.iAttributeId.Append((*setting)->GetAttributeID());
+				if (ret1 != KErrNone || ret2 != KErrNone)
+					{
+					response.Close();
+					return SendError(KErrAvrcpMetadataInternalError, 
+									 RAvrcpIPC::SetIPCOperationIdFromEventId(aEventId),
+									 aMsgSubType);   // Try to send internal error if OOM
+					}
+				response.iNumberAttributes++;
+				setting = iter.NextValue();
+				}
+				
+			TRAP(error, response.WriteL(iOutBuf));
+			response.Close();
+			break;
+			}
+		default:
+			return;
+		}
+	
+	if (error == KErrNone)
+		{
+		// send the response back to the CT
+		TUint operationId = RAvrcpIPC::SetIPCOperationIdFromEventId(aEventId);
+		error = InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid),
+												operationId, ERemConResponse, aMsgSubType, iOutBuf);
+		}
+	}
+	 
+// from MPlayerEventsObserver
+ void CPlayerInfoTarget::DoPlaybackStatusChanged(TPlaybackStatus  aStatus)
+	{
+	LOG_FUNC
+
+	iPlayBackStatus = aStatus;
+	
+	// if the playback status is in the current event list
+	TInt pos = iPendingNotificationEventList.Find( ERegisterNotificationPlaybackStatusChanged );
+	if (pos != KErrNotFound)
+		{
+		iPendingNotificationEventList.Remove( pos );
+		SendNotificationResponse( ERegisterNotificationPlaybackStatusChanged, ERemConNotifyResponseChanged);
+		}
+	
+	pos = iPendingNotificationEventList.Find( ERegisterNotificationPlaybackPosChanged );
+	if (pos != KErrNotFound)
+		{
+		iPendingNotificationEventList.Remove( pos );
+		SendNotificationResponse(ERegisterNotificationPlaybackPosChanged, ERemConNotifyResponseChanged);
+		}
+	
+	if(iPlaybackStatusUpdatePending)
+		{
+		// format the response in a RRemConPlayerInformationGetPlayStatusResponse
+		RRemConPlayerInformationGetPlayStatusUpdateResponse response;
+		response.iStatus = iPlayBackStatus;
+		
+		TRAPD(error, response.WriteL(iOutBuf));
+		if (error == KErrNone)
+			{
+			// send the response back to the CT
+			error = InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid),
+													EGetPlayStatusUpdate, ERemConResponse, iOutBuf );
+			if(error == KErrNone)
+				{
+				iPlaybackStatusUpdatePending = EFalse;
+				}
+			// if we did error we will try and respond again next time the client's play status
+			// changes
+			}
+		}
+	}
+	
+void CPlayerInfoTarget::DoTrackChanged(TUint64 aTrackId, TUint32 aLengthInMilliseconds)
+	{
+	LOG_FUNC
+
+	iTrackId = aTrackId;
+	iLengthInMilliseconds = aLengthInMilliseconds;
+
+	// if the playback status is in the current event list 
+	TInt pos = iPendingNotificationEventList.Find( ERegisterNotificationTrackChanged );
+	if (pos != KErrNotFound)
+		{
+		iPendingNotificationEventList.Remove( pos );
+		SendNotificationResponse(ERegisterNotificationTrackChanged, ERemConNotifyResponseChanged);
+		}
+
+	pos = iPendingNotificationEventList.Find( ERegisterNotificationPlaybackPosChanged );
+	if (pos != KErrNotFound)
+		{
+		iPendingNotificationEventList.Remove( pos );
+		iPlaybackPositionInMilliseconds = 0;	//set 0 to current position for new track
+		SendNotificationResponse(ERegisterNotificationPlaybackPosChanged, ERemConNotifyResponseChanged);
+		}
+	}
+
+void CPlayerInfoTarget::DoTrackReachedEnd()
+	{
+	LOG_FUNC
+	
+	iTrackPosition = EEnd;
+
+	// if the ETrackReachedEnd status is in the current event list 
+	TInt pos = iPendingNotificationEventList.Find( ERegisterNotificationTrackReachedEnd );
+	if (pos != KErrNotFound)
+		{
+		iPendingNotificationEventList.Remove( pos );
+		SendNotificationResponse(ERegisterNotificationTrackReachedEnd, ERemConNotifyResponseChanged);
+		}
+	
+	pos = iPendingNotificationEventList.Find( ERegisterNotificationPlaybackPosChanged );
+	if (pos != KErrNotFound)
+		{
+		iPendingNotificationEventList.Remove( pos );
+		iPlaybackPositionInMilliseconds = iLengthInMilliseconds;
+		SendNotificationResponse(ERegisterNotificationPlaybackPosChanged, ERemConNotifyResponseChanged);
+		}
+	}
+
+void CPlayerInfoTarget::DoTrackReachedStart()
+	{
+	LOG_FUNC
+
+	iTrackPosition = EStart;
+
+	// if the ETrackReachedStart status is in the current event list 
+	TInt pos = iPendingNotificationEventList.Find( ERegisterNotificationTrackReachedStart );
+	if (pos != KErrNotFound)
+		{
+		iPendingNotificationEventList.Remove( pos );
+		SendNotificationResponse(ERegisterNotificationTrackReachedStart, ERemConNotifyResponseChanged);
+		}
+	
+	pos = iPendingNotificationEventList.Find( ERegisterNotificationPlaybackPosChanged );
+	if (pos != KErrNotFound)
+		{
+		iPendingNotificationEventList.Remove( pos );
+		iPlaybackPositionInMilliseconds = 0;
+		SendNotificationResponse(ERegisterNotificationPlaybackPosChanged, ERemConNotifyResponseChanged);
+		}
+	}
+
+void CPlayerInfoTarget::DoSetPlaybackPosition(TUint32 aMilliseconds)		
+	{
+	LOG_FUNC
+	
+	iPlaybackPositionInMilliseconds = aMilliseconds;
+
+	// if the playback position is in the current Notification event list 
+	TInt pos = iPendingNotificationEventList.Find( ERegisterNotificationPlaybackPosChanged );
+	if (pos != KErrNotFound)
+		{
+		// a notification has been requested, now check if it is due
+
+		TUint32 difference = (iPlaybackPositionInMilliseconds > iLastNotifiedPlaybackPositionInMilliseconds) ?
+        	iPlaybackPositionInMilliseconds - iLastNotifiedPlaybackPositionInMilliseconds:
+        	iLastNotifiedPlaybackPositionInMilliseconds - iPlaybackPositionInMilliseconds;
+
+		if (difference >= iPlayBackIntervalInMilliseconds)
+			{
+			// Due now so send
+			iPendingNotificationEventList.Remove( pos );
+			SendNotificationResponse(ERegisterNotificationPlaybackPosChanged, ERemConNotifyResponseChanged);			
+			}	
+		}
+	}
+
+void CPlayerInfoTarget::DoSetBatteryStatus(TTargetBatteryStatus aBatteryStatus)
+	{
+	LOG_FUNC
+
+	TBool validStatus = ETrue;
+	if (aBatteryStatus < MPlayerEventsObserver::ENormal || 
+		aBatteryStatus > MPlayerEventsObserver::EFullCharge)
+		{
+		LOG1(_L("Invalid battery status: %d"),aBatteryStatus);
+		validStatus = EFalse;
+		}
+	else
+		{
+		iBatteryStatus = aBatteryStatus;
+		}
+
+	// if the battery status is in the current event list
+	TInt pos = iPendingNotificationEventList.Find( ERegisterNotificationBatteryStatusChanged );
+	if (pos != KErrNotFound)
+		{
+		iPendingNotificationEventList.Remove( pos );
+		if (validStatus)
+			{
+			SendNotificationResponse(ERegisterNotificationBatteryStatusChanged, ERemConNotifyResponseChanged);
+			}
+		}
+	}
+	
+void CPlayerInfoTarget::SendError(TInt aError, TInt aOperationId, TRemConMessageSubType aSubType)
+	{
+	TInt error = 0;
+	RAvrcpIPCError response;
+	response.iError = aError;
+	TRAP(error, response.WriteL(iOutBuf));   // Don't send error if OOM
+	if (error == KErrNone)
+		InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid),
+										aOperationId, ERemConResponse, aSubType, iOutBuf);
+	}
+