--- /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);
+ }
+