Fixed AVController, it was accidentally set to search only for renderers. Now also servers are added to device list. Also some minor changes in package definition xml and platform API xml definition files.
/*
* Copyright (c) 2007 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: Utility for parsing upnp items
*
*/
// INCLUDE FILES
// System
#include <e32std.h>
// dlnasrv / mediaserver api
#include <upnpitem.h>
#include <upnpdlnaprotocolinfo.h>
// dlnasrv / avcontroller helper api
#include "upnpconstantdefs.h" // for KValueNotImplemented
#include "upnpitemutility.h"
_LIT( KComponentLogfile, "upnpavcontrollerhelper.txt");
#include "upnplog.h"
// CONSTANTS
const TInt KDateStringLength = 10;
const TInt KDateTimeStringLength = 19;
const TInt KMaxDateStringLength = 30;
const TInt KCodeSemicolon = 58;
_LIT( KSeparator, ":" );
_LIT( KNullTime, "000000" );
_LIT8( KHttp, "http://" );
_LIT8( KCiParam, "DLNA.ORG_CI" );
/* removed due to M-DMC CTT test case 7.3.26.2
_LIT8( KAudioSupport, "audio/" );
_LIT8( KImageSupport, "image/" );
_LIT8( KVideoSupport, "video/" );
*/
// ============================ LOCAL FUNCTIONS =============================
// --------------------------------------------------------------------------
// UPnPItemUtility::BelongsToClass
//---------------------------------------------------------------------------
EXPORT_C TBool UPnPItemUtility::BelongsToClass(
const CUpnpObject& aObject,
const TDesC8& aClass )
{
TBool beginsWith =
( aObject.ObjectClass().Find( aClass ) == 0 );
return beginsWith;
}
// --------------------------------------------------------------------------
// UPnPItemUtility::GetResElements
//---------------------------------------------------------------------------
EXPORT_C void UPnPItemUtility::GetResElements(
const CUpnpObject& aObject,
RUPnPElementsArray& aResElementsArray )
{
const RUPnPElementsArray& array =
const_cast<CUpnpObject&>(aObject).GetElements();
for( TInt i = 0; i < array.Count(); i++ )
{
if( array[ i ]->Name() == KElementRes() )
{
aResElementsArray.Append( array[ i ] );
}
}
}
// --------------------------------------------------------------------------
// UPnPItemUtility::ResourceFromItemL
//---------------------------------------------------------------------------
EXPORT_C const CUpnpElement& UPnPItemUtility::ResourceFromItemL(
const CUpnpItem& aItem )
{
__LOG( "UpnpItemUtility:ResourceFromItemL" );
// Obtain list of item's res elements
RUPnPElementsArray elms;
GetResElements( aItem, elms );
TInt count = elms.Count();
CUpnpDlnaProtocolInfo* pInfo = NULL;
TBool found = EFalse;
TInt i(0);
// bestCandidate is an index of some res element in the list. This res
// will be considered as the best candidate for desired res and that
// candidate will be returned if no res element contains false CI-flag.
const CUpnpElement* bestCandidate = 0;
// determine which resource is the original one
// 1. In DLNA 1.5 case, parse protocolInfo attribute and see if some res
// element has CI-flag false (=not converted so that is what we want)
// 2. In non-DLNA 1.5 case and in DLNA 1.5 case where CI-flag does not
// exist, do the following:
// o filter out other than HTTP GET resources (internal uri's, RTP)
// o filter out resources that do not match itemtype (mime type of
// audio file resources should start with "audio/" etc.)
for( i = 0 ; i < count; i++ )
{
// Make sure that it is a HTTP GET resource. Otherwise continue.
if( elms[ i ]->Value().Left( KHttp.iTypeLength ).Compare( KHttp() )
!= 0 )
{
continue;
}
// Obtain protocolInfo of the res element.
const CUpnpAttribute* attr = FindAttributeByName(
*elms[i], KAttributeProtocolInfo() );
if ( attr )
{
TRAP_IGNORE( pInfo = CUpnpDlnaProtocolInfo::NewL( attr->Value() ) );
if( !pInfo )
{
//if pInfo, start next one!
continue;
}
// check if CI parameter is false or it doesn't have CI parameters at all.
//for upnp item, always the first res element is the best, resolution
// should be checked in the future
if ( ( attr->Value().Find( KCiParam() ) != KErrNotFound &&
pInfo->CiParameter() == EFalse ) ||
attr->Value().Find( KCiParam() ) == KErrNotFound )
{
// end loop, we found what we were looking for.
found = ETrue;
delete pInfo; pInfo = NULL;
break;
}
/* removed due to M-DMC CTT test case 7.3.26.2
// check that mimetype corresponds to objectType
TPtrC8 mime = pInfo->ThirdField();
TPtrC8 objectClass = aItem.ObjectClass();
if ( objectClass.Compare( KClassAudio ) == 0 )
{
if ( mime.Left( KAudioSupport().Length() ).CompareF(
KAudioSupport() ) != 0 )
{
// if mime type does not match to object type, this is
// not the correct resource.
delete pInfo; pInfo = NULL;
continue;
}
}
else if ( objectClass.Compare( KClassVideo ) == 0 )
{
if ( mime.Left( KVideoSupport().Length() ).CompareF(
KVideoSupport() ) != 0 )
{
// if mime type does not match to object type, this is
// not the correct resource.
delete pInfo; pInfo = NULL;
continue;
}
}
else if ( objectClass.Compare( KClassImage ) == 0 )
{
if ( mime.Left( KImageSupport().Length() ).CompareF(
KImageSupport() ) != 0 )
{
// if mime type does not match to object type, this is
// not the correct resource.
delete pInfo; pInfo = NULL;
continue;
}
}
*/
// use the first suitable res field as candidate which will be
// returned if better is not found.
// More sophisticated solution would be to compare resolution
// etc. attributes to determine the best candidate,
if ( 0 == bestCandidate )
{
bestCandidate = elms[i];
}
delete pInfo; pInfo = NULL;
}
else
{
// No mandatory protocolinfo attribute. This is not what we want.
}
}
if ( found )
{
bestCandidate = elms[i];
}
// close the elements array
elms.Close();
if( bestCandidate == 0 )
{
User::Leave( KErrNotFound );
}
return *bestCandidate;
}
// --------------------------------------------------------------------------
// UPnPItemUtility::FindElementByName
//---------------------------------------------------------------------------
EXPORT_C const CUpnpElement* UPnPItemUtility::FindElementByName(
const CUpnpObject& aObject, const TDesC8& aName )
{
__LOG( "UpnpItemUtility:FindElementByName" );
CUpnpElement* element = NULL;
const RUPnPElementsArray& array =
const_cast<CUpnpObject&>(aObject).GetElements();
for( TInt i = 0; i < array.Count(); i++ )
{
if( array[ i ]->Name() == aName )
{
element = array[ i ];
i = array.Count();
}
}
return element;
}
// --------------------------------------------------------------------------
// UPnPItemUtility::FindElementByNameL
//---------------------------------------------------------------------------
EXPORT_C const CUpnpElement& UPnPItemUtility::FindElementByNameL(
const CUpnpObject& aObject, const TDesC8& aName )
{
__LOG( "UpnpItemUtility:FindElementByNameL" );
const CUpnpElement* element = FindElementByName(
aObject, aName );
if( !element )
{
User::Leave( KErrNotFound );
}
return *element;
}
// --------------------------------------------------------------------------
// UPnPItemUtility::FindAttributeByName
//---------------------------------------------------------------------------
EXPORT_C const CUpnpAttribute* UPnPItemUtility::FindAttributeByName(
const CUpnpElement& aElement, const TDesC8& aName )
{
__LOG( "UpnpItemUtility:FindAttributeByName" );
CUpnpAttribute* attribute = NULL;
const RUPnPAttributesArray& array =
const_cast<CUpnpElement&>(aElement).GetAttributes();
for( TInt i = 0; i < array.Count(); i++ )
{
TBufC8<255> buf(array[ i ]->Name());
if( array[ i ]->Name() == aName )
{
attribute = array[ i ];
i = array.Count();
}
}
return attribute;
}
// --------------------------------------------------------------------------
// UPnPItemUtility::FindAttributeByNameL
//---------------------------------------------------------------------------
EXPORT_C const CUpnpAttribute& UPnPItemUtility::FindAttributeByNameL(
const CUpnpElement& aElement, const TDesC8& aName )
{
__LOG( "UpnpItemUtility:FindAttributeByNameL" );
const CUpnpAttribute* attribute = FindAttributeByName(
aElement, aName );
if( !attribute )
{
User::Leave( KErrNotFound );
}
return *attribute;
}
// --------------------------------------------------------------------------
// UPnPItemUtility::UpnpDateAsTTime
//---------------------------------------------------------------------------
EXPORT_C TInt UPnPItemUtility::UPnPDateAsTTime(
const TDesC8& aUpnpDate, TTime& aTime )
{
__LOG( "UpnpItemUtility:UpnpDateAsTTime" );
TRAPD( err, UPnPItemUtility::UPnPDateAsTTimeL( aUpnpDate, aTime ) );
return err;
}
// --------------------------------------------------------------------------
// UPnPItemUtility::UpnpDurationAsMilliseconds
//---------------------------------------------------------------------------
EXPORT_C TInt UPnPItemUtility::UPnPDurationAsMilliseconds(
const TDesC8& aDuration, TInt& aMilliseconds )
{
__LOG( "UpnpItemUtility:UpnpDurationAsMilliseconds" );
TInt retVal = KErrNone;
if( aDuration.Length() > 0 )
{
// Check if information is actually returned by the device
if( aDuration.Compare( KValueNotImplemented ) != 0 )
{
TInt time = 0;
TChar separator( KCodeSemicolon );
TInt lposit = aDuration.Locate( separator );
if ( lposit != KErrNotFound )
{
TInt rposit = aDuration.LocateReverse( separator );
if( rposit != lposit )
{
// Hours
TLex8 lex( aDuration.Left( lposit ) );
retVal = lex.Val( time );
if( retVal == KErrNone )
{
// Convert to ms and add
aMilliseconds += time * 3600 * 1000;
// Minutes
lex.Assign( aDuration.Mid(
lposit + 1, rposit - lposit - 1 ) );
retVal = lex.Val( time );
if( retVal == KErrNone )
{
// Convert to ms and add
aMilliseconds += time * 60* 1000;
// Seconds
lex.Assign( aDuration.Mid(
rposit + 1, 2 ) );
retVal = lex.Val( time );
if( retVal == KErrNone )
{
// Convert to ms and add
aMilliseconds += time * 1000;
}
}
}
}
else
{
retVal = KErrNotSupported;
}
}
else
{
retVal = KErrNotSupported;
}
}
else
{
retVal = KErrNotSupported;
}
}
else
{
retVal = KErrNotSupported;
}
return retVal;
}
void UPnPItemUtility::UPnPDateAsTTimeL( const TDesC8& aUpnpDate,
TTime& aTime )
{
// This method is capable of handling the most common dc:date formats:
// CCYY-MM-DD and CCYY-MM-DDThh:mm:ss
// Rest of the dc:date formats are handled as well, but they might not
// be converted precisely
TBuf<KMaxDateStringLength> formatDateString;
HBufC* dateString = HBufC::NewL( aUpnpDate.Length() );
dateString->Des().Copy( aUpnpDate );
if( aUpnpDate.Length() >= KDateStringLength )
{
// CCYY-MM-DD --> CCYYMMDD
formatDateString.Copy( dateString->Des().Left( 4 ) ); // Year
formatDateString.Append( dateString->Des().Mid( 5,2 ) ); // Month
formatDateString.Append( dateString->Des().Mid( 8,2 ) ); // Day
if( aUpnpDate.Length() >= KDateTimeStringLength )
{
// hh:mm:ss --> hhmmss
formatDateString.Append( KSeparator );
// Hours
formatDateString.Append( dateString->Des().Mid( 11, 2 ) );
// Minutes
formatDateString.Append( dateString->Des().Mid( 14, 2 ) );
// Seconds
formatDateString.Append( dateString->Des().Mid( 17, 2 ) );
}
else
{
// hh:mm:ss --> 000000
formatDateString.Append( KSeparator );
formatDateString.Append( KNullTime );
}
}
delete dateString;
User::LeaveIfError( aTime.Set( formatDateString ) );
}