diff -r 000000000000 -r 7f85d04be362 upnpsharing/upnpcontentserver/src/upnpcontentmetadatautility.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/upnpsharing/upnpcontentserver/src/upnpcontentmetadatautility.cpp Thu Dec 17 08:52:00 2009 +0200 @@ -0,0 +1,727 @@ +/* +* Copyright (c) 2006-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: CUpnpContentMetadataUtility class implementation + * +*/ + + + + + + +// INCLUDE FILES +// System +#include +#include +#include +#include +#include +#include +#include + +// upnp stack api +#include +#include +#include + +// upnpframework / avcontroller helper api +#include "upnpfileutility.h" + +// upnpframework / internal api's +#include "upnpcommonutils.h" +#include "upnpmetadatautility.h" + +#include "upnpdlnaprofiler.h" +#include "upnpcdsreselementutility.h" + +// homeconnect internal +#include "upnpcontentmetadatautility.h" +#include "upnpcustomgrouper.h" +#include "upnppostfilter.h" + +#include "upnpcontentserverdefs.h" + +_LIT( KComponentLogfile, "contentserver.txt"); +#include "upnplog.h" + +// CONSTANTS +_LIT( KUPnPFileListSeparator, "\t" ); +const TInt KMediaTypeArrGranularity(1); + +using namespace UpnpContentServer; + +// ============================ MEMBER FUNCTIONS ============================ +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::CUpnpContentMetadataUtility() +// Default constructor +// -------------------------------------------------------------------------- +// +CUpnpContentMetadataUtility::CUpnpContentMetadataUtility() + : iRefreshOngoing( ETrue ) + { + } + +void CUpnpContentMetadataUtility::ConstructL() + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + // Create Content Listing Engine and a list model + iEngine = ContentListingFactory::NewContentListingEngineLC(); + CleanupStack::Pop(); // iEngine + iMusicModel = iEngine->CreateListModelLC( *this ); + CleanupStack::Pop(); // iMusicModel + + iImageModel = iEngine->CreateListModelLC( *this ); + CleanupStack::Pop(); // iImageModel + + iVideoModel = iEngine->CreateListModelLC( *this ); + CleanupStack::Pop(); // iVideoModel + + iCollectionModel = iEngine->CreateListModelLC( *this ); + CleanupStack::Pop(); // iCollectionModel + // Set music media type filter to CLF + RArray musicArray( KMediaTypeArrGranularity ); + + CleanupClosePushL( musicArray ); + musicArray.AppendL( ECLFMediaTypeMusic ); + iMusicModel->SetWantedMediaTypesL( musicArray.Array() ); + CleanupStack::PopAndDestroy( &musicArray ); + + // Set image media type filter to CLF + RArray imageArray( KMediaTypeArrGranularity ); + + CleanupClosePushL( imageArray ); + imageArray.AppendL( ECLFMediaTypeImage ); + iImageModel->SetWantedMediaTypesL( imageArray.Array() ); + CleanupStack::PopAndDestroy( &imageArray ); + + // Set video media type filter to CLF + RArray videoArray( KMediaTypeArrGranularity ); + CleanupClosePushL( videoArray ); + videoArray.AppendL( ECLFMediaTypeVideo ); + iVideoModel->SetWantedMediaTypesL( videoArray.Array() ); + CleanupStack::PopAndDestroy( &videoArray ); + + // Set Collection media type filter to CLF + RArray collectionArray( KMediaTypeArrGranularity ); + + CleanupClosePushL( collectionArray ); + collectionArray.AppendL( ECLFMediaTypeCollection ); + iCollectionModel->SetWantedMediaTypesL( collectionArray.Array() ); + CleanupStack::PopAndDestroy( &collectionArray ); + + // Group items by collection name + iCustomGrouper = CUpnpCustomGrouper::NewL( ECLFFieldIdCollectionName ); + iCollectionModel->SetCustomGrouper( iCustomGrouper ); + + // Start to refresh the music files (HandleOperationEventL + // callback comes when finished) + iMusicModel->RefreshL(); + + // Create metadata utility + iMetaDataUtility = CUPnPMetaDataUtility::NewL(); + + __LOG8_1( "%s end.", __PRETTY_FUNCTION__ ); + } + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::NewL() +// 2 phased constructor +// -------------------------------------------------------------------------- +// +CUpnpContentMetadataUtility* CUpnpContentMetadataUtility::NewL() + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + CUpnpContentMetadataUtility* self + = new( ELeave ) CUpnpContentMetadataUtility; + + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop(); + __LOG8_1( "%s end.", __PRETTY_FUNCTION__ ); + return self; + } + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::~CUpnpContentMetadataUtility() +// Default destructor +// -------------------------------------------------------------------------- +// +CUpnpContentMetadataUtility::~CUpnpContentMetadataUtility() + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + delete iMusicModel; + delete iImageModel; + delete iVideoModel; + delete iCollectionModel; + delete iPostFilter; + delete iCustomGrouper; + delete iEngine; + delete iMetaDataUtility; + __LOG8_1( "%s end.", __PRETTY_FUNCTION__ ); + } + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::HandleOperationEventL +// Callback implementation for MCLFOperationObserver +// -------------------------------------------------------------------------- +// +void CUpnpContentMetadataUtility::HandleOperationEventL( + TCLFOperationEvent aOperationEvent, + TInt /*aError*/ ) + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + // Waiting is stopped when an event for refresh completion is received + if( aOperationEvent == ECLFRefreshComplete ) + + { + switch ( iRefreshCounter ) + { + case 0 : + { + iVideoModel->RefreshL(); + break; + } + case 1 : + { + iImageModel->RefreshL(); + break; + } + case 2 : + { + iCollectionModel->RefreshL(); + break; + } + case 3 : + { + + iRefreshOngoing = EFalse; + iRefreshCounter = 0; + if ( iHandler ) + { + iHandler->RefreshDoneL(); + } + __LOG("CUpnpContentMetadataUtility::HandleOperationEventL: \ +Refresh done"); + break; + + } + default : + { + __LOG("CUpnpContentMetadataUtility::HandleOperationEventL: \ +default: error"); + break; + } + + } + if ( iRefreshOngoing ) + { + iRefreshCounter++; + } + } + __LOG8_1( "%s end.", __PRETTY_FUNCTION__ ); + } + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::HandleItemChangeL +// CLF content is changed --> model needs to be refreshed +// -------------------------------------------------------------------------- +// +void CUpnpContentMetadataUtility::HandleItemChangeL( + const TArray& /*aItemIDArray*/ ) + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + // Start to refresh the music files (HandleOperationEventL + // callback comes when finished) + iRefreshOngoing = ETrue; + iMusicModel->RefreshL(); + iImageModel->RefreshL(); + iVideoModel->RefreshL(); + __LOG8_1( "%s end.", __PRETTY_FUNCTION__ ); + } + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::HandleError +// Method is used to handle errors in changed item event. +// -------------------------------------------------------------------------- +// +void CUpnpContentMetadataUtility::HandleError( TInt /*aError*/ ) + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + } + + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::MusicFiles +// ( other items are commented in header ) +// -------------------------------------------------------------------------- +// +const MCLFItemListModel& CUpnpContentMetadataUtility::MusicFiles() const + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + return *iMusicModel; + } + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::ImageFiles +// ( other items are commented in header ) +// -------------------------------------------------------------------------- +// +const MCLFItemListModel& CUpnpContentMetadataUtility::ImageFiles() const + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + return *iImageModel; + } + + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::VideoFiles +// ( other items are commented in header ) +// -------------------------------------------------------------------------- +// +const MCLFItemListModel& CUpnpContentMetadataUtility::VideoFiles() const + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + return *iVideoModel; + } + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::Collections +// ( other items are commented in header ) +// -------------------------------------------------------------------------- +// +const MCLFItemListModel& CUpnpContentMetadataUtility::Collections() const + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + return *iCollectionModel; + } + + + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::GetCollectionFileNamesL +// ( other items are commented in header ) +// -------------------------------------------------------------------------- +// +void CUpnpContentMetadataUtility::GetCollectionFileNamesL( + CDesCArray& aFileArray, + const TDesC& aFiles ) const + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + + TInt collectionLength( aFiles.Length() ); + TInt position( 0 ); + TInt dataPos( 0 ); + do + { + // Put filenames from ":" separeted row to aFileArray + TPtrC data( aFiles.Right( collectionLength - position ) ); + dataPos = data.Find( KUPnPFileListSeparator ); + if( dataPos > 0 ) + { + ++position; // skip KUPnPFileListSeparator + position += dataPos; + aFileArray.AppendL( data.Left( dataPos ) ); + } + } while ( dataPos > 0 ); + __LOG8_1( "%s end.", __PRETTY_FUNCTION__ ); + } + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::CollectionItemsL() +// ( other items are commented in header ) +// -------------------------------------------------------------------------- +// +void CUpnpContentMetadataUtility::CollectionItemsL( + const TDesC& aNameOfCollection ) + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + __LOG1( "CUpnpContentMetadataUtility: collection: %S", + &aNameOfCollection ); + + //clear previous filtering + iCollectionModel->SetPostFilter( NULL ); + + // Delete old post filter if any + + delete iPostFilter; + iPostFilter = NULL; + + // Create and activate a post filter for collection filtering + // so that the model will contain only files + // from selected collection + iPostFilter = CUpnpPostFilter::NewL( ECLFFieldIdCollectionName, + aNameOfCollection, EFalse ); + iCollectionModel->SetPostFilter( iPostFilter ); + + iCollectionModel->RefreshL( ECLFRefreshPostFilter ); + __LOG8_1( "%s end.", __PRETTY_FUNCTION__ ); + } + + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::CreateItemL +// Create the item with mandatory fields +// -------------------------------------------------------------------------- +// +CUpnpItem* CUpnpContentMetadataUtility::CreateItemL( + const MCLFItem& aCLFItem, + const TDesC8& aParentId ) const + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + + TPtrC fullFileName; + TInt err( aCLFItem.GetField( ECLFFieldIdFileNameAndPath, + fullFileName )); + + TInt32 filesize( 0 ); + TInt err1( aCLFItem.GetField( ECLFFieldIdFileSize, filesize ) ); + + CUpnpItem* newItem( NULL ); + + if ( !err && !err1 && filesize ) + { + newItem = CreateItemL( fullFileName, aParentId ); + } + else + { + __LOG8_1( "MCLFItem ECLFFieldIdFileNameAndPath err= %d", err ); + __LOG8_1( "MCLFItem ECLFFieldIdFileSize err= %d", err1 ); + } + + __LOG8_1( "%s end.", __PRETTY_FUNCTION__ ); + return newItem; + } + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::CreateItemL +// Update the basic fields, based on list of filenames +// -------------------------------------------------------------------------- +// +CUpnpItem* CUpnpContentMetadataUtility::CreateItemL( + const TDesC& aFullFilename, + const TDesC8& aParentId + ) const + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + + CUpnpItem* newItem( NULL ); + + TFileName path( aFullFilename ); + TBool isProtected( EFalse ); + TRAPD( err, + isProtected = UPnPFileUtility::IsFileProtectedL( path ) ); + + if ( !isProtected && !err ) + { + // title + HBufC8* itemName( NULL ); + iMetaDataUtility->LoadTitleL( path ); + if( iMetaDataUtility->Title().Length() > 0 ) + { + itemName = UpnpString::FromUnicodeL( + iMetaDataUtility->Title() ); + } + else + { + // If does not find the title, using filename instead + TParse fileParser; + fileParser.Set( path, NULL, NULL ); + itemName = UpnpString::FromUnicodeL( fileParser.Name() ); + } + + if ( itemName ) + { + CleanupStack::PushL( itemName ); + + newItem = CUpnpItem::NewL(); + CleanupStack::PushL( newItem ); + newItem->SetTitleL( *itemName ); + newItem->SetObjectClassL( KClassItem ); + newItem->SetParentIdL( aParentId ); + CleanupStack::Pop( newItem ); + + CleanupStack::PopAndDestroy( itemName ); + } + } + else + { + __LOG8_1( "UPnPFileUtility::IsFileProtectedL err= %d", err ); + } + + __LOG8_1( "%s end.", __PRETTY_FUNCTION__ ); + return newItem; + } + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::RefreshOngoing() const +// Used to check if refresh is ongoing. +// -------------------------------------------------------------------------- +// + +TBool CUpnpContentMetadataUtility::RefreshOngoing() const + { + return iRefreshOngoing; + } + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::UpdateMetaDataL +// Updates meta data for the item +// -------------------------------------------------------------------------- +// +TBool CUpnpContentMetadataUtility::UpdateMetadataL( + const TUpnpMediaType& aMediaType, + CUpnpItem* aItem, + const TDesC& aFileName ) + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + + // 1st use correct model according to item type + MCLFItemListModel* model = NULL; + switch( aMediaType ) + { + case EMusicFile : + { + model = iMusicModel; + break; + } + case EVideoFile : + { + model = iVideoModel; + break; + } + case EPhotoFile : + { + model = iImageModel; + break; + } + default: + { + break; + } + } + // Then find the CLF item and update data from it + TBool found = EFalse; + TBool end = EFalse; + TInt beginLoop = iClfIndex; + + // increment. If passed item count, start from beginning. + iClfIndex = 0; + beginLoop = -1; + + while ( model->ItemCount() && + !found && + !end ) + { + // Get the item + const MCLFItem& myItem = model->Item( iClfIndex ); + TPtrC fileName; + TInt error = myItem.GetField( ECLFFieldIdFileNameAndPath, + fileName ); + + // if there was no error and file name matched + if ( !error && aFileName.CompareF( fileName ) == 0 ) + { + found = ETrue; + + // Get the mediatype + TInt32 mediaType; + TInt errorType = myItem.GetField( ECLFFieldIdMediaType, + mediaType ); + // If it is music file, fill the meta data for it + if ( !errorType && mediaType == ECLFMediaTypeMusic ) + { + // Get title, artist, album & genre tag info of the item + // Test update the class as it is in 1.x + aItem->SetObjectClassL( + KClassAudioMusicTrack ); + + TPtrC songArtist; + TInt errorArtist( myItem.GetField( ECLFFieldIdArtist, + songArtist ) ); + if ( !errorArtist ) + { + CUpnpElement* elArtist = CUpnpElement::NewL( + KElementArtist ); + CleanupStack::PushL( elArtist ); + HBufC8* artist = UpnpString::FromUnicodeL( + songArtist ); + CleanupStack::PushL( artist ); + elArtist->SetValueL( *artist ); + // UPnP stack needs filepath + elArtist->SetFilePathL( aFileName ); + CleanupStack::PopAndDestroy( artist ); + aItem->AddElementL( elArtist ); // transfer own.. + CleanupStack::Pop( elArtist ); + } + TPtrC songAlbum; + TInt errorAlbum( myItem.GetField( ECLFFieldIdAlbum, + songAlbum ) ); + if ( !errorAlbum ) + { + CUpnpElement* elAlbum = CUpnpElement::NewL( + KElementAlbum ); + CleanupStack::PushL( elAlbum ); + HBufC8* album = UpnpString::FromUnicodeL( songAlbum ); + + CleanupStack::PushL( album ); + elAlbum->SetValueL( *album ); + // UPnP stack needs filepath + elAlbum->SetFilePathL( aFileName ); + CleanupStack::PopAndDestroy( album ); + aItem->AddElementL( elAlbum ); // transfer own.. + CleanupStack::Pop( elAlbum ); + } + TPtrC songGenre; + TInt errorGenre( myItem.GetField( ECLFFieldIdGenre, + songGenre ) ); + if ( !errorGenre ) + { + CUpnpElement* elGenre = CUpnpElement::NewL( + KElementGenre ); + CleanupStack::PushL( elGenre ); + HBufC8* genre = UpnpString::FromUnicodeL( songGenre ); + + CleanupStack::PushL( genre ); + elGenre->SetValueL( *genre ); + // UPnP stack needs filepath + elGenre->SetFilePathL( aFileName ); + CleanupStack::PopAndDestroy( genre ); + aItem->AddElementL( elGenre ); // transfer own.. + CleanupStack::Pop( elGenre ); + + } + } + else if ( !errorType && mediaType == ECLFMediaTypeImage ) + { + // Just set correct object class + aItem->SetObjectClassL( KImageItemObjectClass ); + } + else if ( !errorType && mediaType == ECLFMediaTypeVideo ) + { + // Just set correct object class + aItem->SetObjectClassL( KVideoItemObjectClass ); + } + + // Below this happens to ALL media types + TTime dateTime; + TInt errorDate( myItem.GetField( ECLFFieldIdFileDate, + dateTime ) ); + + if ( !errorDate ) + { + HBufC* date = NULL; + TRAP( errorDate, date = + UPnPCommonUtils::TTimeToUPnPDateL(dateTime)); + + + if(date && errorDate == KErrNone) + { + CleanupStack::PushL( date ); + + CUpnpElement* elDate = CUpnpElement::NewL( + KElementDate ); + CleanupStack::PushL( elDate ); + + + HBufC8* date8 = UpnpString::FromUnicodeL( *date ); + CleanupStack::PushL( date8 ); + elDate->SetValueL( *date8 ); + + CleanupStack::PopAndDestroy( date8 ); + + elDate->SetFilePathL( aFileName ); + aItem->AddElementL( elDate ); // transfer own.. + + CleanupStack::Pop( elDate ); + CleanupStack::Pop( date ); + } + + + if(date) + { + delete date; + date = NULL; + } + } + + } + else + { + // The item was not found + if ( iClfIndex != beginLoop ) + { + if ( ++iClfIndex >= model->ItemCount() ) + { + iClfIndex = 0; + end = ETrue; + } + } + else + { + end = ETrue; + __LOG("end=ETRue"); + } + } + } // while + if( found ) + { + __LOG("CUpnpContentMetadataUtility:: item found"); + } + else + { + __LOG("CUpnpContentMetadataUtility:: item not found"); + } + + __LOG8_1( "%s end.", __PRETTY_FUNCTION__ ); + return found; + } + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::ClearPostFiltersL +// ( other items are commented in header ) +// -------------------------------------------------------------------------- +void CUpnpContentMetadataUtility::ClearPostFiltersL() + { + __LOG8_1( "%s begin.", __PRETTY_FUNCTION__ ); + //clear previous filtering + iCollectionModel->SetPostFilter( NULL ); + + // Delete old post filter if any + + delete iPostFilter; + iPostFilter = NULL; + + iCollectionModel->RefreshL( ECLFRefreshPostFilter ); + + // Set the default postfilter + iPostFilter = CUpnpPostFilter::NewL( ECLFFieldIdCollectionName, + KNullDesC, ETrue ); + iCollectionModel->SetPostFilter( iPostFilter ); + + iCollectionModel->RefreshL( ECLFRefreshPostFilter ); + __LOG8_1( "%s end.", __PRETTY_FUNCTION__ ); + } + +// -------------------------------------------------------------------------- +// CUpnpContentMetadataUtility::SetCallback +// ( other items are commented in header ) +// -------------------------------------------------------------------------- +void CUpnpContentMetadataUtility::SetCallback( + MUpnpMetadataObserver* aObserver ) + { + iHandler = aObserver; + + } + +// End of File