diff -r 22de2e391156 -r 20ac952a623c remotecontrol/avrcp/playerinformation/src/playersettings.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remotecontrol/avrcp/playerinformation/src/playersettings.cpp Wed Oct 13 16:20:29 2010 +0300 @@ -0,0 +1,685 @@ +// 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 +#include + +#include "playerapplicationsetting.h" +#include "playerinformation.h" +#include "playersettingsutils.h" + + +void CPlayerInfoTarget::SendError(TInt aError, TInt aOperationId) + { + TInt error = 0; + RAvrcpIPCError response; + response.iError = aError; + TRAP(error, response.WriteL(iOutBuf)); // Try to send internal error if OOM + if (error == KErrNone) + { + InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid), + aOperationId, ERemConResponse, iOutBuf); + } + } + + +// PDU 0x11 +void CPlayerInfoTarget::ProcessListPlayerApplicationAttributes(TInt aOperationId) + { + RRemConPlayerListOfAttributes response; + response.iNumberAttributes = iPlayerApplicationSettings.Count(); + + THashMapIter iter(iPlayerApplicationSettings); + const TInt* attribute = iter.NextKey(); + while ( attribute != NULL ) + { + if (response.iAttributes.Append(*attribute) != KErrNone) + { + response.Close(); + return SendError(KErrAvrcpMetadataInternalError, aOperationId); // Try to send internal error if OOM + } + attribute = iter.NextKey(); + } + + // send the response back to the CT + TInt error = 0; + TRAP(error, response.WriteL(iOutBuf)); // Try to send internal error if OOM + response.Close(); + if (error != KErrNone) + { + return SendError(KErrAvrcpMetadataInternalError, aOperationId); + } + + InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid), + EListPlayerApplicationSettingAttributes, ERemConResponse, iOutBuf ); + } + +// PDU 0x12 +void CPlayerInfoTarget::ProcessListPlayerApplicationValues(const TDesC8& aData, TInt aOperationId) + { + TInt error =0; + RDesReadStream readStream; + readStream.Open(aData); + TInt attributeID = 0; + TRAP(error, attributeID = readStream.ReadUint8L()); + readStream.Close(); + if (error != KErrNone) + { + return SendError(KErrAvrcpMetadataParameterNotFound, aOperationId); // Nothing in packet + } + + // Send the number of values for this attribute (1 byte), + // followed by the defined values themselves (n x 1byte) + CPlayerApplicationSettings* thisSetting = GetSetting(attributeID); + if (thisSetting == NULL) + { + // Attribute Id not found + return SendError(KErrAvrcpMetadataInvalidParameter, aOperationId); + } + + RRemConPlayerListOfAttributes response; + RArray* values = thisSetting->GetValues(); + TInt numValues = values->Count(); + response.iNumberAttributes = numValues; + + // Make sure that we always have at least one result to return + // Table 5.18 says that the number of results provided has an + // allowed value of 1-255, so we cannot return zero results. + if (response.iNumberAttributes == 0) + { + return SendError(KErrAvrcpMetadataParameterNotFound, aOperationId); // No attributes matched + } + + for ( TInt i = 0; i < numValues; i++ ) + { + TInt value = (*values)[i]; + if (response.iAttributes.Append(value) != KErrNone) + { + response.Close(); + return SendError(KErrAvrcpMetadataInternalError, aOperationId); // Try to send internal error if OOM + } + } + + // send the response back to the CT + TRAP(error, response.WriteL(iOutBuf)); // Try to send internal error if OOM + response.Close(); + if (error != KErrNone) + { + return SendError(KErrAvrcpMetadataInternalError, aOperationId); + } + + InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid), + aOperationId, ERemConResponse, iOutBuf ); + } + +// PDU 0x15 +void CPlayerInfoTarget::ProcessGetPlayerApplicationAttributeText(const TDesC8& aData, TInt aOperationId) + { + TInt error =0; + + // If we can't parse the request, then return an error + RRemConPlayerListOfAttributes request; + TRAP(error, request.ReadL(aData)); + if (error != KErrNone) + { + request.Close(); + return SendError(KErrAvrcpMetadataInvalidCommand, aOperationId); + } + + // Iterate through requested attributes and remove + // those which we don't have any settings for. + for (TInt i = 0; i < request.iNumberAttributes; i++) + { + if (! AttributeSettingExists(request.iAttributes[i])) + { + request.iAttributes.Remove(i); + request.iNumberAttributes--; + i--; + } + } + + // Make sure that we always have at least one result to return + // Table 5.18 says that the number of results provided has an + // allowed value of 1-255, so we cannot return zero results. + RRemConGetPlayerApplicationTextResponse response; + response.iNumberAttributes = request.iNumberAttributes; + if (response.iNumberAttributes == 0) + { + request.Close(); + return SendError(KErrAvrcpMetadataInvalidParameter, aOperationId); // No attributes matched + } + + // for every attribute text requested + for (TInt i = 0; i < request.iNumberAttributes; i++) + { + // start with the attribute id requested and the character set + RSettingWithCharset setting; + TInt attId = request.iAttributes[i]; + CPlayerApplicationSettings* thisSetting = GetSetting(attId); + setting.iAttributeId = attId; + setting.iCharset = KUtf8MibEnum; + const TPtrC8 text = thisSetting->GetAttributeText(); + setting.iStringLen = text.Length(); + setting.iString = text.Alloc(); + + // If OOM, try to return an internal error. + if (setting.iString == NULL) + { + request.Close(); + response.Close(); + return SendError(KErrAvrcpMetadataInternalError, aOperationId); + } + + // If OOM, try to return an internal error. + if (response.iAttributes.Append(setting) != KErrNone) + { + setting.Close(); + request.Close(); + response.Close(); + return SendError(KErrAvrcpMetadataInternalError, aOperationId); + } + } + request.Close(); + + // Allocate a buffer for the formatted message + RBuf8 messageBuffer; + if ( messageBuffer.Create(response.Size()) != KErrNone ) + { + // On OOM drop the message + response.Close(); + return; + } + + // send the response back to the CT + TRAP(error, response.WriteL(messageBuffer)); // Try to send internal error if OOM + response.Close(); + if (error != KErrNone) + { + messageBuffer.Close(); + return SendError(KErrAvrcpMetadataInternalError, aOperationId); + } + + InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid), + aOperationId, ERemConResponse, messageBuffer ); + + messageBuffer.Close(); + } + +// PDU 0x14 +void CPlayerInfoTarget::ProcessSetPlayerApplicationValue(const TDesC8& aData, TInt aOperationId) + { + RRemConPlayerAttributeIdsAndValues request; + TInt error = 0; + + // If we can't parse the request, then return an error + TRAP(error, request.ReadL(aData)); + if (error != KErrNone) + { + request.Close(); + return SendError(KErrAvrcpMetadataInvalidCommand, aOperationId); + } + + // Iterate through all the settings we're sent to update and set them + for (TInt i = 0; i < request.iNumberAttributes; i++) + { + if (! AttributeValueCanBeSet(request.iAttributeId[i], request.iAttributeValue[i])) + { + // remove this setting + request.iAttributeId.Remove(i); + request.iAttributeValue.Remove(i); + request.iNumberAttributes--; + i--; + } + } + __ASSERT_DEBUG(request.iAttributeId.Count() == request.iAttributeValue.Count(), PlayerSettingsUtils::Panic(EPlayerSettingsFunnyLengthData)); + + // Section 5.7 of the AVRCP specification (page 56) says: + // If CT sent a PDU with nonexistent PDU ID or a PDU containing + // only one parameter with nonexistent parameter ID, TG shall return + // REJECTED response with Error Status Code. If CT sent a PDU with + // multiple parameters where at least one ID is existent and the + // others are nonexistent, TG shall proceed with the existent ID and + // ignore the non-existent IDs. + // + // This means we return REJECTED if we have nothing to set + if (request.iNumberAttributes == 0) + { + request.Close(); + return SendError(KErrAvrcpMetadataInvalidParameter, aOperationId); + } + + // If an application setting notifier has been requested then notify it + // If the notification succeeds, then set all the values + + TRAP(error, iApplicationSettingNotifier.MpasnSetPlayerApplicationValueL(request.iAttributeId, request.iAttributeValue)); + if ( error == KErrNone ) + { + for (TInt i = 0; i < request.iNumberAttributes; i++) + { + CPlayerApplicationSettings* thisSetting = GetSetting(request.iAttributeId[i]); + thisSetting->SetCurrentValue(request.iAttributeValue[i]); + } + } + else + { + // Return an AVRCP internal error via RemCon. See section 5.7.1 of specification. + request.Close(); + return SendError(KErrAvrcpMetadataInternalError, aOperationId); + } + + request.Close(); + // Send a notification if one has been registered + if ( KErrNotFound != iPendingNotificationEventList.Find( ERegisterNotificationPlayerApplicationSettingChanged )) + { + SendNotificationResponse( ERegisterNotificationPlayerApplicationSettingChanged, ERemConNotifyResponseChanged ); + } + + + // SendError KErrNone is used to send a valid response + SendError(KErrNone, aOperationId); + } + +// PDU 0x13 +void CPlayerInfoTarget::ProcessGetCurrentPlayerApplicationValue(const TDesC8& aData, TInt aOperationId) + { + TInt error = 0; + + // If we can't parse the request, then return an error + RRemConPlayerListOfAttributes request; + TRAP(error, request.ReadL(aData)); + if (error != KErrNone) + { + request.Close(); + return SendError(KErrAvrcpMetadataInvalidCommand, aOperationId); + } + + // Look through requested attributes, and assemble a response + // for those which we posess. If none are found, return an error + RRemConPlayerAttributeIdsAndValues response; + response.iNumberAttributes = 0; + request.iAttributes.Sort(); + + for (TInt i = 0; i < request.iNumberAttributes; i++) + { + TInt attToSend = request.iAttributes[i]; + if (AttributeSettingExists(attToSend)) + { + TInt ret1 = response.iAttributeId.Append(attToSend); + TInt ret2 = response.iAttributeValue.Append(GetSetting(attToSend)->GetCurrentValue()); + if (ret1 != KErrNone || ret2 != KErrNone) + { + request.Close(); + response.Close(); + return SendError(KErrAvrcpMetadataInternalError, aOperationId); // Try to send internal error if OOM + } + response.iNumberAttributes++; + } + } + request.Close(); + + // Make sure that we always have at least one result to return + // Table 5.18 says that the number of results provided has an + // allowed value of 1-255, so we cannot return zero results. + if (response.iNumberAttributes == 0) + { + response.Close(); + return SendError(KErrAvrcpMetadataInvalidParameter, aOperationId); // No attributes matched + } + + // send the response back to the CT + TRAP(error, response.WriteL(iOutBuf)); // Try to send internal error if OOM + response.Close(); + if (error != KErrNone) + { + return SendError(KErrAvrcpMetadataInternalError, aOperationId); + } + + InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid), + aOperationId, ERemConResponse, iOutBuf ); + } + +// PDU 0x16 +void CPlayerInfoTarget::ProcessGetPlayerApplicationValueText(const TDesC8& aData, TInt aOperationId) + { + RDesReadStream readStream; + readStream.Open(aData); + + TInt error = 0; + TInt reqAttribute = 0; + + // Read the attribute id + TRAP(error, reqAttribute = readStream.ReadUint8L()); + if (error != KErrNone) + { + readStream.Close(); + return SendError(KErrAvrcpMetadataParameterNotFound, aOperationId); // Nothing in packet + } + + // If we don't have settings for this attribute, return an error + CPlayerApplicationSettings* thisSetting = GetSetting(reqAttribute); + if (thisSetting == NULL) + { + readStream.Close(); + return SendError(KErrAvrcpMetadataInvalidParameter, aOperationId); // Attribute not found + } + + // Read the number of PAS values + TInt numSettings = 0; + TRAP(error, numSettings = readStream.ReadUint8L()); + if (error != KErrNone) + { + readStream.Close(); + return SendError(KErrAvrcpMetadataParameterNotFound, aOperationId); // Nothing in packet + } + + RArray valueTextsRequested; + for (TInt i = 0; i < numSettings; i++) + { + TInt requestedValueText = 0; + TRAP(error, requestedValueText = readStream.ReadUint8L()); + if (error == KErrNone) + { + if (valueTextsRequested.Append(requestedValueText) != KErrNone) + { + readStream.Close(); + return SendError(KErrAvrcpMetadataInternalError, aOperationId); // Try to send internal error if OOM + } + } + } + + readStream.Close(); + + // format the response in a RRemConGetPlayerApplicationTextResponse + RRemConGetPlayerApplicationTextResponse response; + response.iNumberAttributes = 0; + + // for every attribute text requested + RPointerArray* textValues = thisSetting->GetValuesTexts(); + RArray* values = thisSetting->GetValues(); + TInt numRequested = valueTextsRequested.Count(); + for (TInt i = 0; i < numRequested; i++) + { + // start with the attribute id requested and the character set + RSettingWithCharset setting; + TInt valueToSend = valueTextsRequested[i]; + setting.iAttributeId = valueToSend; + setting.iCharset = KUtf8MibEnum; + + // text length followed by the text + TInt found = values->Find(valueToSend); + if (found != KErrNotFound) + { + HBufC8* text = (*textValues)[found]; + setting.iStringLen = text->Length(); + setting.iString = text->Alloc(); + + // If OOM, try to return an internal error. + if (setting.iString == NULL) + { + response.Close(); + valueTextsRequested.Close(); + return SendError(KErrAvrcpMetadataInternalError, aOperationId); + } + + // If OOM, try to return an internal error. Of course, this could fail too + if (response.iAttributes.Append(setting) != KErrNone) + { + response.Close(); + setting.Close(); + valueTextsRequested.Close(); + return SendError(KErrAvrcpMetadataInternalError, aOperationId); + } + + response.iNumberAttributes++; + } + } + valueTextsRequested.Close(); + + // Make sure that we always have at least one result to return + // Table 5.18 says that the number of results provided has an + // allowed value of 1-255, so we cannot return zero results. + if (response.iNumberAttributes == 0) + { + response.Close(); + return SendError(KErrAvrcpMetadataInvalidParameter, aOperationId); + } + + // Allocate a buffer for the formatted message + RBuf8 messageBuffer; + if ( messageBuffer.Create(response.Size()) != KErrNone ) + { + // On OOM drop the message + response.Close(); + return; + } + + // send the response back to the CT + TRAP(error, response.WriteL(messageBuffer)); // Try to send internal error if OOM + response.Close(); + if (error != KErrNone) + { + messageBuffer.Close(); + return SendError(KErrAvrcpMetadataInternalError, aOperationId); + } + + InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid), + aOperationId, ERemConResponse, messageBuffer ); + messageBuffer.Close(); + } + +TBool CPlayerInfoTarget::AttributeSettingExists(TUint anAttributeID) + { + if (GetSetting(anAttributeID) == NULL) + { + return EFalse; + } + else + { + return ETrue; + } + } + +TBool CPlayerInfoTarget::IsValidAttributeValue(TUint anAttributeID, TUint anAttributeValue) + { + // As defined in Appendix F of the AVRCP specification, page 81 + // Attribute 0x01 - range 0x01 to 0x02 + // Attribute 0x02 - range 0x01 to 0x04 + // Attribute 0x03 - range 0x01 to 0x03 + // Attribute 0x04 - range 0x01 to 0x03 + // Attribute 0x05 - 0x7f -- invalid; reserved for future use + // Attribute 0x80 - 0xff -- vendor dependent + if (anAttributeID >= 0x80 && anAttributeID <= 0xff && anAttributeValue <= 0xff ) + { + return ETrue; + } + + if (anAttributeID == 0x01 && anAttributeValue >= 0x01 && anAttributeValue <= 0x02) + { + return ETrue; + } + + if (anAttributeID == 0x02 && anAttributeValue >= 0x01 && anAttributeValue <= 0x04) + { + return ETrue; + } + + if ((anAttributeID == 0x03 || anAttributeID == 0x04) + && anAttributeValue >= 0x01 && anAttributeValue <= 0x03) + { + return ETrue; + } + + // Everything else is invalid, as defined by the specification + return EFalse; + } + +// Check that anAttributeValue is in the valid value list for anAttributeID +TBool CPlayerInfoTarget::AttributeValueCanBeSet(TUint anAttributeID, TUint anAttributeValue) + { + CPlayerApplicationSettings* thisSetting = GetSetting(anAttributeID); + if (thisSetting == NULL) + { + return EFalse; + } + + RArray* values = thisSetting->GetValues(); + if (values == NULL) + { + return EFalse; + } + + if (values->Find(anAttributeValue) == KErrNotFound) + { + return EFalse; + } + + // This attribute id and value has been already defined by the RSS + // file, and checked that it conforms to the specification when the + // RSS file was loaded. Now allow this value to be set over the air. + return ETrue; + } + +CPlayerApplicationSettings* CPlayerInfoTarget::GetSetting(TUint anAttributeID) + { + // Will return NULL if anAttributeID is not found + CPlayerApplicationSettings** settings = iPlayerApplicationSettings.Find(anAttributeID); + if (settings == NULL) + { + return NULL; + } + + return *settings; + } + + +// from MPlayerApplicationSettingsObserver +// exported function wrapper for internal pure virtual +EXPORT_C void MPlayerApplicationSettingsObserver::DefineAttributeL(TUint aAttributeID, + TDesC8& aAttributeText, + RArray& aValues, + RArray& aValueTexts, + TUint aInitialValue) + { + DoDefineAttributeL(aAttributeID, aAttributeText, aValues, aValueTexts, aInitialValue); + } + +EXPORT_C void MPlayerApplicationSettingsObserver::SetAttributeL(TUint aAttributeID, TUint aValue) + { + DoSetAttributeL(aAttributeID, aValue ); + } + +void CPlayerInfoTarget::DoDefineAttributeL(TUint aAttributeID, + TDesC8& aAttributeText, + RArray& aValues, + RArray& aValueTexts, + TUint aInitialValue) + { + //Check Length of the player application setting attribute string is 1-255 + if(aAttributeText.Length() > KMaxPlayerApplicationSettingsValue || + aAttributeText.Length() < KMinPlayerApplicationSettingsValue ) + { + User::Leave(KErrNotSupported); + } + + //Check the number of player application setting values is 1-255 + if(aValues.Count() > KMaxPlayerApplicationSettingsValue || + aValues.Count() < KMinPlayerApplicationSettingsValue ) + { + User::Leave(KErrNotSupported); + } + + //Check the numbers of player application setting values and + //player application setting value texts are equal + if(aValues.Count() != aValueTexts.Count()) + { + User::Leave(KErrNotSupported); + } + + //Check Length of the player application setting value string is 1-255 + for(TInt i = 0; i < aValueTexts.Count(); i++ ) + { + if(aValueTexts[i].Length() > KMaxPlayerApplicationSettingsValue || + aValueTexts[i].Length() < KMinPlayerApplicationSettingsValue ) + { + User::Leave (KErrNotSupported); + } + } + + for (TInt i = 0; i < aValues.Count(); i++) + { + // The user cannot define certain attribute ids or values; see Appendix F + if ( ! IsValidAttributeValue(aAttributeID, aValues[i])) + { + User::Leave(KErrNotSupported); + } + } + + // Check the initial value, too + if ( ! IsValidAttributeValue(aAttributeID, aInitialValue)) + { + User::Leave(KErrNotSupported); + } + + // check that aInitialValue is in aValues + if (aValues.Find(aInitialValue) == KErrNotFound) + { + User::Leave(KErrNotSupported); + } + + // create a new TPlayerApplicationSettings + CPlayerApplicationSettings* newSetting = CPlayerApplicationSettings::NewL(aAttributeID, aAttributeText, aValues, aValueTexts, aInitialValue); + CleanupStack::PushL(newSetting); + + // Backup the settings of aAttributeID if they exist, return NULL if the attribute ID cannot be found + CPlayerApplicationSettings* backupSetting = GetSetting(aAttributeID); + + // and save it + iPlayerApplicationSettings.InsertL(aAttributeID, newSetting); + + //Delete backupSetting, as the InsertL will replace the old objects by the provided objects + delete backupSetting; + + CleanupStack::Pop(newSetting); + } + +void CPlayerInfoTarget::DoSetAttributeL(TUint aAttributeID, TUint aValue) + { + // Will return NULL if the attribute ID cannot be found + CPlayerApplicationSettings* setting = GetSetting(aAttributeID); + if (setting == NULL) + { + User::Leave(KErrNotFound); + } + + if ( ! IsValidAttributeValue(aAttributeID, aValue)) + { + User::Leave(KErrNotSupported); + } + + setting->SetCurrentValue(aValue); + + if ( KErrNotFound != iPendingNotificationEventList.Find( ERegisterNotificationPlayerApplicationSettingChanged )) + { + // send response + SendNotificationResponse( ERegisterNotificationPlayerApplicationSettingChanged, ERemConNotifyResponseChanged ); + } + } +