mmappcomponents/harvester/metadataextractor/src/mpxmetadataextractor.cpp
branchRCL_3
changeset 23 4740b34b83ce
parent 19 51035f0751c2
child 28 f56ec6ce2732
--- a/mmappcomponents/harvester/metadataextractor/src/mpxmetadataextractor.cpp	Wed Apr 14 16:28:17 2010 +0300
+++ b/mmappcomponents/harvester/metadataextractor/src/mpxmetadataextractor.cpp	Tue Apr 27 17:09:22 2010 +0300
@@ -12,7 +12,7 @@
 * Contributors:
 *
 * Description:  Extracts metadata from a file
-*  Version     : %version: da1mmcf#38.1.4.2.6.1.9 % << Don't touch! Updated by Synergy at check-out.
+*  Version     : %version: da1mmcf#38.1.4.2.6.1.10 % << Don't touch! Updated by Synergy at check-out.
 *
 */
 
@@ -41,6 +41,7 @@
 #include <mpxmediaaudiodefs.h>
 #include <mpxmediadrmdefs.h>
 #include <mpxmediamtpdefs.h>
+#include <mpxmetadataextractorobserver.h>
 
 #include "mpxmetadataextractor.h"
 #include "mpxfileinfoutility.h"
@@ -82,8 +83,11 @@
                                   : iFs( aFs ),
                                     iAppArc( aAppArc ),
                                     iSupportedTypes( aTypes ),
-                                    iOutstandingThumbnailRequest(0),
-                                    iTNMBlockCount(0)
+                                    iCancelled( EFalse ),
+                                    iObs( NULL ),
+                                    iMedia( NULL ),
+                                    iMetadataOnly( EFalse ),
+                                    iFileOpenError( KErrNone )
     {
 
     }
@@ -98,6 +102,7 @@
     iMetadataUtility = CMetaDataUtility::NewL();
     iDrmMediaUtility = CMPXDrmMediaUtility::NewL();
     iFileInfoUtil    = CMPXFileInfoUtility::NewL();
+    iTaskTimer = CPeriodic::NewL( CActive::EPriorityIdle );
 
 #ifdef RD_MPX_TNM_INTEGRATION
     // Create Thumbnail Manager instance. This object is the observer.
@@ -107,6 +112,8 @@
     // create wait loop
     iTNSyncWait = new (ELeave) CActiveSchedulerWait;
     iTimer = CPeriodic::NewL( CActive::EPriorityIdle );
+    iArrayTNRequestId.Reset();
+    iArrayTasks.Reset();
 #endif //RD_MPX_TNM_INTEGRATION
     }
 
@@ -138,6 +145,8 @@
     delete iMetadataUtility;
     delete iFileInfoUtil;
     delete iDrmMediaUtility;
+    delete iTaskTimer;
+    iFile.Close();
 #ifdef RD_MPX_TNM_INTEGRATION
     delete iTNManager;
     if (iTNSyncWait && iTNSyncWait->IsStarted() )
@@ -146,137 +155,64 @@
         }
     delete iTNSyncWait;
     delete iTimer;
+    iArrayTNRequestId.Close();
+    iArrayTasks.Close();
 #endif //RD_MPX_TNM_INTEGRATION
-    
-    MPX_DEBUG2("CMPXMetadataExtractor: TNM Block Count: %d ", iTNMBlockCount );
     }
 
 // ---------------------------------------------------------------------------
-// Constructs a media properties object
+// Constructs a media properties object : synchronous function
 // ---------------------------------------------------------------------------
 //
 EXPORT_C void CMPXMetadataExtractor::CreateMediaL( const TDesC& aFile,
                                                    CMPXMedia*& aNewProperty,
                                                    TBool aMetadataOnly )
     {
-    // make a copy of aFile
-    HBufC* fileName = HBufC::NewL(KMaxFileName);
-    CleanupStack::PushL( fileName );
-    fileName->Des().Append( aFile );
-    MPX_DEBUG2("CMPXMetadataExtractor::CreateMediaL %S <---", fileName );
-
-    RArray<TInt> contentIDs;
-    contentIDs.AppendL( KMPXMediaIdGeneral );
-    contentIDs.AppendL( KMPXMediaIdAudio );
-    contentIDs.AppendL( KMPXMediaIdMusic );
-    contentIDs.AppendL( KMPXMediaIdDrm );
-    contentIDs.AppendL( KMPXMediaIdMTP );
-    aNewProperty = NULL;
-    CMPXMedia* media = CMPXMedia::NewL( contentIDs.Array() );
-    CleanupStack::PushL( media );
-    contentIDs.Close();
-
-    // CMPXMedia default types
-
-    media->SetTObjectValueL<TMPXGeneralType>( KMPXMediaGeneralType,
-                                              EMPXItem );
-    media->SetTObjectValueL<TMPXGeneralCategory>( KMPXMediaGeneralCategory,
-                                                  EMPXSong );
+    MPX_FUNC("CMPXMetadataExtractor::CreateMediaL()");
+    // check if we are still processing a request.
+    if ( iArrayTasks.Count() )
+        {
+        MPX_DEBUG1("CMPXMetadataExtractor::CreateMediaL Request ongoing. Abort!" );
+        User::Leave( KErrAbort );
+        }
 
-    TParsePtrC parse( *fileName );
-
-    // Title, default is file name
-    media->SetTextValueL( KMPXMediaGeneralTitle,
-                          parse.Name() );
-
-    // Default album track
-    media->SetTextValueL( KMPXMediaMusicAlbumTrack,
-                          KNullDesC );
-
-    // Set the Mime Type and collection UID
-    //
-    if( !aMetadataOnly )
+    iCancelled = EFalse;
+    iFileOpenError = KErrNone;
+    iObs = NULL;
+    aNewProperty = NULL;
+    iFileName = aFile;
+    iMetadataOnly = aMetadataOnly;
+    
+    // populate the task array
+    AddTasksL();
+    
+    // execute all tasks in the array
+    while ( iArrayTasks.Count() )
         {
-        TInt index(KErrNotFound);
-        TInt count( iSupportedTypes.Count() );
-        for (TInt i=0; i <count; ++i)
+        // execute task at index 0
+        TRAPD( error, ExecuteTaskL() );
+        if ( error || iCancelled )
             {
-            TInt index2(KErrNotFound);
-            const CDesCArray& exts = iSupportedTypes[i]->Extensions();
-            const TDesC& ext = parse.Ext();
-            if (!exts.FindIsq(ext, index2))
-                { // found
-                index = i;
-                break;
+            // cleanup
+            if ( iMedia != NULL )
+                {
+                delete iMedia;
+                iMedia = NULL;
                 }
+            iArrayTasks.Reset();
+            if ( error )
+                {
+                CleanUp();
+                User::LeaveIfError( error );
+                }
+            break;
             }
-        if( KErrNotFound != index )
-            {
-            MPX_DEBUG1("CMPXMetadataExtractor::CreateMediaPropertiesL apparc <---" );
-            TInt mimeIndex = SupportedContainerTypeL( *fileName, index );
-            User::LeaveIfError( mimeIndex );
-            MPX_DEBUG1("CMPXMetadataExtractor::CreateMediaPropertiesL apparc --->" );
-
-            media->SetTextValueL( KMPXMediaGeneralMimeType,
-                                  iSupportedTypes[index]->Mimetypes()[mimeIndex] );
-
-            media->SetTObjectValueL( KMPXMediaGeneralCollectionId,
-                                     iSupportedTypes[index]->Uid() );
-            }
-        else
-            {
-            User::Leave(KErrNotSupported);
-            }
-        }
-    else // other case use apparc to fetch and set mimetype
-        {
-        TDataType dataType;
-        TUid dummyUid(KNullUid);
-        iAppArc.AppForDocument(*fileName, dummyUid, dataType);
-        media->SetTextValueL( KMPXMediaGeneralMimeType,dataType.Des() );
-        }
         
-    // Use file handle here
-    //
-    RFile file;
-    TInt err = file.Open( iFs, *fileName, EFileRead | EFileShareReadersOrWriters );
-    CleanupClosePushL(file);
-    
-    // Initially set default tags.
-    SetDefaultL( *media );
-    // Metadata related
-    //
-    if( err == KErrNone )
-        {
-        const TDesC& mimeType = media->ValueText( KMPXMediaGeneralMimeType );
-        HBufC8* mimeType8 = HBufC8::NewLC( mimeType.Length() );
-        mimeType8->Des().Append( mimeType );
-        TRAPD( metadataerror, iMetadataUtility->OpenFileL( file, *mimeType8 ) );
-        MPX_DEBUG2("CMPXMetadataExtractor::CreateMediaL, error %d parsing metadata", 
-            metadataerror );
-        CleanupStack::PopAndDestroy( mimeType8 );
-        
-        // Even if there is error extracting metadata, fill extracted tags.
-        TRAP( metadataerror, SetMediaPropertiesL( *media, *fileName ) ); 
-        MPX_DEBUG2("CMPXMetadataExtractor::CreateMediaL, error %d setting tags", 
-            metadataerror );
-
-        // Reset the utility
-        iMetadataUtility->ResetL();
+        iArrayTasks.Remove( 0 );
         }
     
-    // Common properties that we can extract
-    //
-    SetExtMediaPropertiesL( *media, *fileName, aMetadataOnly, file, err );
-    CleanupStack::PopAndDestroy(&file);
-
-    // Set the pointers now that the object is ready
-    //
-    CleanupStack::Pop( media );
-    aNewProperty = media;
-
-    CleanupStack::PopAndDestroy( fileName );
-    MPX_DEBUG1("CMPXMetadataExtractor::CreateMediaPropertiesL --->");
+    aNewProperty = iMedia;
+    CleanUp();
     }
 
 // ---------------------------------------------------------------------------
@@ -285,6 +221,7 @@
 //
 void CMPXMetadataExtractor::SetDefaultL( CMPXMedia& aMediaProp )
     {
+    MPX_FUNC("CMPXMetadataExtractor::SetDefaultL()");
     // Comment
     aMediaProp.SetTextValueL( KMPXMediaGeneralComment,
                               KNullDesC );
@@ -318,13 +255,21 @@
 // Sets media object attributes from metadata utilities
 // ---------------------------------------------------------------------------
 //
-void CMPXMetadataExtractor::SetMediaPropertiesL( CMPXMedia& aMedia,
-                                                 const TDesC& aFile )
+void CMPXMetadataExtractor::SetMediaPropertiesL()
     {
-    MPX_DEBUG1("CMPXMetadataExtractor::SetMediaPropertiesL <---" );
+    MPX_FUNC("CMPXMetadataExtractor::SetMediaPropertiesL()");
 
-    const CMetaDataFieldContainer& metaCont =
-                                          iMetadataUtility->MetaDataFieldsL();
+    const TDesC& mimeType = iMedia->ValueText( KMPXMediaGeneralMimeType );
+    HBufC8* mimeType8 = HBufC8::NewLC( mimeType.Length() );
+    mimeType8->Des().Append( mimeType );
+    
+    // Continue to extract metadata even if fail.
+    TRAPD( metadataerror, iMetadataUtility->OpenFileL( iFile, *mimeType8 ) );
+    MPX_DEBUG2("CMPXMetadataExtractor::CreateMediaL, error %d parsing metadata", 
+        metadataerror );
+    CleanupStack::PopAndDestroy( mimeType8 );
+    
+    const CMetaDataFieldContainer& metaCont = iMetadataUtility->MetaDataFieldsL();
     TInt count( metaCont.Count() );
     for( TInt i=0; i<count; ++i )
         {
@@ -337,13 +282,12 @@
         if ( fieldType != EMetaDataJpeg )
            {
            TRAPD( err, value = metaCont.At( i, fieldType ).AllocL() );
-           CleanupStack::PushL( value );
            if ( KErrNone != err )
                {
                MPX_DEBUG2("CMPXMetadataExtractor::SetMediaPropertiesL - error = %i", err);           
-               CleanupStack::PopAndDestroy( value );
                continue;
                }     
+           CleanupStack::PushL( value );
            }
         
         switch( fieldType )
@@ -356,7 +300,7 @@
                 if (vallen>0)
                     {
                     FindAndReplaceForbiddenChars(valptr, vallen);
-                    aMedia.SetTextValueL(KMPXMediaGeneralTitle, *value);
+                    iMedia->SetTextValueL(KMPXMediaGeneralTitle, *value);
                     }
                 break;
                 }
@@ -368,7 +312,7 @@
                 if (vallen>0)
                     {
                     FindAndReplaceForbiddenChars(valptr, vallen);
-                    aMedia.SetTextValueL(KMPXMediaMusicArtist, *value);
+                    iMedia->SetTextValueL(KMPXMediaMusicArtist, *value);
                     }
                 break;
                 }
@@ -380,7 +324,7 @@
                 if (vallen>0)
                     {
                     FindAndReplaceForbiddenChars(valptr, vallen);
-                    aMedia.SetTextValueL(KMPXMediaMusicAlbum, *value );
+                    iMedia->SetTextValueL(KMPXMediaMusicAlbum, *value );
                     }
                 break;
                 }
@@ -395,19 +339,19 @@
                 TDateTime dt;
                 dt.SetYear( year );
                 TTime time( dt );
-                aMedia.SetTObjectValueL<TInt64>( KMPXMediaMusicYear,
+                iMedia->SetTObjectValueL<TInt64>( KMPXMediaMusicYear,
                                                  time.Int64() );
                 break;
                 }
             case EMetaDataComment:
                 {
-                aMedia.SetTextValueL( KMPXMediaGeneralComment,
+                iMedia->SetTextValueL( KMPXMediaGeneralComment,
                                       *value );
                 break;
                 }
             case EMetaDataAlbumTrack:
                 {
-                aMedia.SetTextValueL( KMPXMediaMusicAlbumTrack,
+                iMedia->SetTextValueL( KMPXMediaMusicAlbumTrack,
                                       *value );
                 break;
                 }
@@ -419,7 +363,7 @@
                 if (vallen>0)
                     {
                     FindAndReplaceForbiddenChars(valptr, vallen);
-                    aMedia.SetTextValueL(KMPXMediaMusicGenre, *value);
+                    iMedia->SetTextValueL(KMPXMediaMusicGenre, *value);
                     }
                 break;
                 }
@@ -431,54 +375,31 @@
                 if (vallen>0)
                     {
                     FindAndReplaceForbiddenChars(valptr, vallen);
-                    aMedia.SetTextValueL(KMPXMediaMusicComposer, *value);
+                    iMedia->SetTextValueL(KMPXMediaMusicComposer, *value);
                     }
                 break;
                 }
             case EMetaDataUrl:
             case EMetaDataUserUrl:  // fall through
                 {
-                aMedia.SetTextValueL( KMPXMediaMusicURL,
+                iMedia->SetTextValueL( KMPXMediaMusicURL,
                                       *value );
                 break;
                 }
             case EMetaDataJpeg:
                 {
-#ifdef RD_MPX_TNM_INTEGRATION
-                MPX_PERF_START(CMPXMetadataExtractor_SetMediaPropertiesL_JPEG_TNM);
-                TPtrC8 ptr8 = metaCont.Field8( EMetaDataJpeg );
-                HBufC8* value8; 
-                TRAPD( err, value8 = ptr8.AllocL() );
-                if ( KErrNone != err )
-                    {
-                    MPX_DEBUG2("CMPXMetadataExtractor::SetMediaPropertiesL - error jpeg = %i", err);           
-                    }
-                else
-                    {
-                    CleanupStack::PushL( value8 );
-                    TRAPD( err, AddMediaAlbumArtL( aMedia, aFile, *value8 ) );
-                    if ( KErrNone != err )
-                        {
-                        MPX_DEBUG2("CMPXMetadataExtractor::SetMediaPropertiesL - error album art = %i", err);           
-                        }
-                    CleanupStack::Pop( value8 );
-                    }
-                MPX_PERF_END(CMPXMetadataExtractor_SetMediaPropertiesL_JPEG_TNM);
-#else //RD_MPX_TNM_INTEGRATION
-                aMedia.SetTextValueL( KMPXMediaMusicAlbumArtFileName,
-                                      aFile );
-#endif //RD_MPX_TNM_INTEGRATION
+                // Album art handled in AddMediaAlbumArtL()
                 break;
                 }
             case EMetaDataCopyright:
                 {
-                aMedia.SetTextValueL( KMPXMediaGeneralCopyright,
+                iMedia->SetTextValueL( KMPXMediaGeneralCopyright,
                                       *value );
                 break;
                 }
             case EMetaDataDuration:     
                 {                  
-                const TDesC& mimeType = aMedia.ValueText( KMPXMediaGeneralMimeType );
+                const TDesC& mimeType = iMedia->ValueText( KMPXMediaGeneralMimeType );
                 MPX_DEBUG2("CMPXMetadataExtractor::SetExtMediaPropertiesL, mimeType = %S", &mimeType);   
                 
                 // Verify if WMA, get the duration
@@ -492,7 +413,7 @@
                     lexer.Val( duration );   // [second]      
                     duration *= 1000;        // [msec]
                 
-                    aMedia.SetTObjectValueL<TInt32>( KMPXMediaGeneralDuration,
+                    iMedia->SetTObjectValueL<TInt32>( KMPXMediaGeneralDuration,
                                                 duration );      
                 
                     MPX_DEBUG2("CMPXMetadataExtractor::SetMediaPropertiesL- duration = %i", duration);  
@@ -519,21 +440,15 @@
             CleanupStack::PopAndDestroy( value );       
             }
         }
-
-    MPX_DEBUG1("CMPXMetadataExtractor::SetMediaPropertiesL --->" );
     }
 
 // ---------------------------------------------------------------------------
 // Sets extra media properties not returned by metadata utilities
 // ---------------------------------------------------------------------------
 //
-void CMPXMetadataExtractor::SetExtMediaPropertiesL( CMPXMedia& aProp, 
-                                                    const TDesC& aFile,
-                                                    TBool aMetadataOnly,
-                                                    RFile& aFileHandle,
-                                                    TInt aFileErr )
+void CMPXMetadataExtractor::SetExtMediaPropertiesL()
     {
-    MPX_DEBUG1("CMPXMetadataExtractor::SetExtMediaPropertiesL <---");
+    MPX_FUNC("CMPXMetadataExtractor::SetExtMediaPropertiesL()");
 
     // DB Flags to set
     //
@@ -541,18 +456,16 @@
 
     // File Path
     //
-    TParsePtrC parse( aFile );
-    aProp.SetTextValueL( KMPXMediaGeneralUri,
-                         aFile );
-    aProp.SetTextValueL( KMPXMediaGeneralDrive,
-                         parse.Drive() );
+    TParsePtrC parse( iFileName );
+    iMedia->SetTextValueL( KMPXMediaGeneralUri, iFileName );
+    iMedia->SetTextValueL( KMPXMediaGeneralDrive, parse.Drive() );
 
     // DRM Rights
     //
     CMPXMedia* drm = NULL;
-    TRAPD( drmError, iDrmMediaUtility->InitL( aFile );
-                     drm = CMPXMedia::NewL( *iDrmMediaUtility->GetMediaL( KMPXMediaDrmProtected.iAttributeId |
-                                                                          KMPXMediaDrmRightsStatus.iAttributeId ) );
+    TRAPD( drmError, iDrmMediaUtility->InitL( iFileName );
+           drm = CMPXMedia::NewL( *iDrmMediaUtility->GetMediaL( KMPXMediaDrmProtected.iAttributeId |
+                                                                KMPXMediaDrmRightsStatus.iAttributeId ) );
          );
 
     TBool prot(EFalse);
@@ -570,7 +483,7 @@
         if( drm->IsSupported( KMPXMediaDrmRightsStatus ) )
             {
             status = drm->ValueTObjectL<TMPXMediaDrmRightsStatus>(KMPXMediaDrmRightsStatus);
-            aProp.SetTObjectValueL<TInt>(KMPXMediaDrmRightsStatus, status );
+            iMedia->SetTObjectValueL<TInt>(KMPXMediaDrmRightsStatus, status );
             MPX_DEBUG2("CMPXMetadataExtractor::SetExtMediaPropertiesL -- status %i", status);
             }
 
@@ -594,8 +507,8 @@
         User::LeaveIfError( drmError );
         }
 
-    aProp.SetTObjectValueL<TBool>( KMPXMediaDrmProtected, prot );
-    aProp.SetTObjectValueL<TUint16>( KMPXMediaMTPDrmStatus, (TUint16)prot );
+    iMedia->SetTObjectValueL<TBool>( KMPXMediaDrmProtected, prot );
+    iMedia->SetTObjectValueL<TUint16>( KMPXMediaMTPDrmStatus, (TUint16)prot );
     
     iDrmMediaUtility->Close();
     
@@ -603,9 +516,9 @@
     // File Size --- The following needs MMF support
     //
     TInt size( 0 );
-    if( aFileErr == KErrNone )
+    if( iFileOpenError == KErrNone )
         {
-        const TDesC& mimeType = aProp.ValueText( KMPXMediaGeneralMimeType );
+        const TDesC& mimeType = iMedia->ValueText( KMPXMediaGeneralMimeType );
         MPX_DEBUG2("CMPXMetadataExtractor::SetExtMediaPropertiesL, mimeType = %S", &mimeType);   
         
         // Verify if WMA, skip getting info from MMF
@@ -617,25 +530,25 @@
         else
             {
             MPX_DEBUG1("CMPXMetadataExtractor::SetExtMediaPropertiesL, get MMF controller");   
-            aFileHandle.Size( size );
-            aProp.SetTObjectValueL<TInt>( KMPXMediaGeneralSize, size );
+            iFile.Size( size );
+            iMedia->SetTObjectValueL<TInt>( KMPXMediaGeneralSize, size );
 
             // Duration, bitrate, samplerate, etc
             //
-            if( !aMetadataOnly )
+            if( !iMetadataOnly )
             {
                 TRAPD(err2, iFileInfoUtil->OpenFileL(
-                          aFileHandle, 
-                          aProp.ValueText(KMPXMediaGeneralMimeType)));
+                          iFile, 
+                          iMedia->ValueText(KMPXMediaGeneralMimeType)));
                 MPX_DEBUG2("CMPXMetadataExtractor::SetExtMediaPropertiesL, file info util error %i", err2);
                 if( KErrNone == err2 )
                     {
-                    aProp.SetTObjectValueL<TUint>( KMPXMediaAudioBitrate,
+                    iMedia->SetTObjectValueL<TUint>( KMPXMediaAudioBitrate,
                                                    iFileInfoUtil->BitRate() );
-                    aProp.SetTObjectValueL<TUint>( KMPXMediaAudioSamplerate,
+                    iMedia->SetTObjectValueL<TUint>( KMPXMediaAudioSamplerate,
                                                    iFileInfoUtil->SampleRate() );
                     TInt64 duration = (TInt64) iFileInfoUtil->Duration().Int64() / 1000; // ms
-                    aProp.SetTObjectValueL<TInt32>( KMPXMediaGeneralDuration,
+                    iMedia->SetTObjectValueL<TInt32>( KMPXMediaGeneralDuration,
                                                     duration );
 
                     MPX_DEBUG2("CMPXMetadataExtractor::SetExtMediaPropertiesL -- duration %i", duration);
@@ -645,16 +558,14 @@
                 }
             }
         }
-    else if( aFileErr == KErrNotFound || aFileErr == KErrPathNotFound )
+    else if( iFileOpenError == KErrNotFound || iFileOpenError == KErrPathNotFound )
         {
         dbFlags |= KMPXMediaGeneralFlagsIsInvalid;
         }
     // Finally set the db flag
     //
-    aProp.SetTObjectValueL( KMPXMediaGeneralFlags,
+    iMedia->SetTObjectValueL( KMPXMediaGeneralFlags,
                             dbFlags );
-    
-    MPX_DEBUG1("CMPXMetadataExtractor::SetExtMediaPropertiesL --->");
     }
 
 // ---------------------------------------------------------------------------
@@ -664,6 +575,7 @@
 TInt CMPXMetadataExtractor::SupportedContainerTypeL( const TDesC& aFile,
                                                      TInt aIndex )
     {
+    MPX_FUNC("CMPXMetadataExtractor::SupportedContainerTypeL()");
     TInt index(KErrNotFound);
 
     TDataType dataType;
@@ -697,13 +609,20 @@
 // Callback but not used here
 // ---------------------------------------------------------------------------
 void CMPXMetadataExtractor::ThumbnailReady( TInt /*aError*/, 
-        MThumbnailData& /*aThumbnail*/, TThumbnailRequestId /*aId*/ )
+        MThumbnailData& /*aThumbnail*/, TThumbnailRequestId aId )
     {
     MPX_FUNC("CMPXMetadataExtractor::ThumbnailReady()");
-    MPX_DEBUG2("CMPXMetadataExtractor::ThumbnailReady(): iOutstandingThumbnailRequest %d",
-        iOutstandingThumbnailRequest);
-    iOutstandingThumbnailRequest--;
-    if ( iOutstandingThumbnailRequest < KMPXMaxThumbnailRequest )
+    
+    // Remove thumbnail id from array.
+    TInt index = iArrayTNRequestId.Find( aId );
+    if ( index >= 0 )
+        {
+        iArrayTNRequestId.Remove( index );
+        }
+    MPX_DEBUG2("CMPXMetadataExtractor::ThumbnailReady(): Outstanding Thumbnail Request = %d",
+            iArrayTNRequestId.Count());
+
+    if ( iArrayTNRequestId.Count() < KMPXMaxThumbnailRequest )
         {
         StopWaitLoop();
         }
@@ -762,7 +681,8 @@
 EXPORT_C TInt CMPXMetadataExtractor::ExtractAlbumArtL( CMPXMedia* aMedia )
     {
     MPX_FUNC("CMPXMetadataExtractor::ExtractAlbumArtL()");
-    TInt err = KErrNone; 
+    TInt err = KErrNone;
+    iCancelled = EFalse;
     
     if ( !aMedia->IsSupported(KMPXMediaGeneralUri) )
         {
@@ -778,25 +698,18 @@
     if (ext.CompareF(KNonEmbeddedArtExt)== 0)
         {
 		#ifdef RD_MPX_TNM_INTEGRATION
-
         //check if can send TN request, If thumbnail creation is ongoing, wait til it is done
         CheckBeforeSendRequest();
-
         CThumbnailObjectSource* source = CThumbnailObjectSource::NewLC(
            path, KImageFileType  );
-          
-       
-
-        iTNManager->CreateThumbnails( *source );
-        
-        iOutstandingThumbnailRequest++;
+        TThumbnailRequestId tnId = iTNManager->CreateThumbnails( *source );
+        iArrayTNRequestId.Append( tnId );
         CleanupStack::PopAndDestroy( source );
-
-        #endif
+        #endif // RD_MPX_TNM_INTEGRATION
         }
     else
         {
-#endif
+#endif // ABSTRACTAUDIOALBUM_INCLUDED
     // create wanted fields array
     RArray<TMetaDataFieldId> wantedFields;
     CleanupClosePushL( wantedFields );
@@ -820,54 +733,16 @@
     
     if ( !err )
         {
-        TRAP( err, GetMediaAlbumArtL( *aMedia, path ));
+        //check if can send TN request, If thumbnail creation is ongoing, wait til it is done
+        CheckBeforeSendRequest();
+        TRAP( err, AddMediaAlbumArtL( *aMedia, path ));
         }
 
     // Reset the utility
     iMetadataUtility->ResetL();
 #ifdef ABSTRACTAUDIOALBUM_INCLUDED
       }
-#endif
-    return err;
-    }
-
-// ----------------------------------------------------------------------------
-// Set album art.
-// ----------------------------------------------------------------------------
-TInt CMPXMetadataExtractor::GetMediaAlbumArtL( CMPXMedia& aMedia, 
-                                               const TDesC& aFile )
-    {
-    MPX_FUNC("CMPXMetadataExtractor::GetMediaAlbumArtL()");
-    TInt err = KErrNone;
-    // get metadata container.
-    const CMetaDataFieldContainer& metaCont = iMetadataUtility->MetaDataFieldsL();
-
-    TPtrC8 data8 = metaCont.Field8( EMetaDataJpeg );
-    
-    if ( data8.Length() )
-        {
-        MPX_DEBUG1("CMPXMetadataExtractor::GetMediaAlbumArtL(): Album art exist.");
-
-#ifdef RD_MPX_TNM_INTEGRATION
-        HBufC8* value8; 
-        TRAPD( err, value8 = data8.AllocL() );
-        if ( KErrNone != err )
-            {
-            MPX_DEBUG2("CMPXMetadataExtractor::GetMediaAlbumArtL - error jpeg = %i", err);           
-            User::Leave( err );  
-            }              
-        CleanupStack::PushL( value8 );
-        AddMediaAlbumArtL( aMedia, aFile, *value8 );
-        CleanupStack::Pop( value8 );
-#else // RD_MPX_TNM_INTEGRATION
-        aMedia.SetTextValueL( KMPXMediaMusicAlbumArtFileName, aFile );
-#endif // RD_MPX_TNM_INTEGRATION          
-        }
-    else
-        {
-        err = KErrNotFound;
-        }
-    
+#endif // ABSTRACTAUDIOALBUM_INCLUDED
     return err;
     }
 
@@ -875,40 +750,53 @@
 // Add album art to media object.
 // ----------------------------------------------------------------------------
 void CMPXMetadataExtractor::AddMediaAlbumArtL( CMPXMedia& aMedia, 
-                                               const TDesC& aFile,
-                                               TDesC8& aValue )
+                                               const TDesC& aFile )
     {
     MPX_FUNC("CMPXMetadataExtractor::AddMediaAlbumArtL()");
-#ifdef RD_MPX_TNM_INTEGRATION
-    
-    //check if can send TN request, If thumbnail creation is ongoing, wait til it is done
-    CheckBeforeSendRequest();
-
-    aMedia.SetTextValueL( KMPXMediaMusicAlbumArtFileName, aFile );
     
-    TBuf<256> mimeType;
-    mimeType.Copy( KImageFileType );
-    CThumbnailObjectSource* source = CThumbnailObjectSource::NewLC(
-        &aValue, mimeType, aFile );
-    iTNManager->CreateThumbnails( *source );
-    CleanupStack::PopAndDestroy( source );
-    aMedia.SetTextValueL( KMPXMediaMusicOriginalAlbumArtFileName, aFile );
-    iOutstandingThumbnailRequest++;
+    // get metadata container.
+    const CMetaDataFieldContainer& metaCont = iMetadataUtility->MetaDataFieldsL();
+    TPtrC8 data8 = metaCont.Field8( EMetaDataJpeg );
+   
+    if ( data8.Length() )
+        {
+        MPX_DEBUG1("CMPXMetadataExtractor::GetMediaAlbumArtL(): Album art exist.");
+#ifdef RD_MPX_TNM_INTEGRATION
+        HBufC8* value8 = NULL; 
+        TRAPD( err, value8 = data8.AllocL() );
+        if ( KErrNone != err )
+            {
+            MPX_DEBUG2("CMPXMetadataExtractor::GetMediaAlbumArtL - error jpeg = %i", err);
+            return;
+            }              
+        CleanupStack::PushL( value8 );
     
+        TBuf<256> mimeType;
+        mimeType.Copy( KImageFileType );
+        CThumbnailObjectSource* source = CThumbnailObjectSource::NewL(
+                value8, mimeType, aFile );
+        TThumbnailRequestId tnId = iTNManager->CreateThumbnails( *source );
+        iArrayTNRequestId.Append( tnId ); // add thumbnail id to array
+        CleanupStack::Pop( value8 );
+        aMedia.SetTextValueL( KMPXMediaMusicOriginalAlbumArtFileName, aFile );
 #endif // RD_MPX_TNM_INTEGRATION          
+        aMedia.SetTextValueL( KMPXMediaMusicAlbumArtFileName, aFile );
+        }
     }
 
+// ----------------------------------------------------------------------------
+// Check if can send request to TNM or not.
+// ----------------------------------------------------------------------------
 void CMPXMetadataExtractor::CheckBeforeSendRequest()
      {
      MPX_FUNC("CMPXMetadataExtractor::CheckBeforeSendRequest()");
 #ifdef RD_MPX_TNM_INTEGRATION
-    MPX_DEBUG2("CMPXMetadataExtractor::CheckBeforeSendRequest(): iOutstandingThumbnailRequest %d",
-        iOutstandingThumbnailRequest);
+    MPX_DEBUG2("CMPXMetadataExtractor::CheckBeforeSendRequest(): Outstanding Thumbnail Request = %d",
+            iArrayTNRequestId.Count());
 	// If thumbnail creation is ongoing, wait til it is done
-    if ( iOutstandingThumbnailRequest >= KMPXMaxThumbnailRequest )
+    if ( iArrayTNRequestId.Count() >= KMPXMaxThumbnailRequest )
         {
         MPX_DEBUG1("CMPXMetadataExtractor::CheckBeforeSendRequest(): Thumbnail creation ongoing!");
-        iTNMBlockCount++;
         // Cancel timer.
         CancelTimeoutTimer();
         // Start timer in case there is no callback from ThumbNail Manager.
@@ -925,3 +813,292 @@
         }
 #endif // RD_MPX_TNM_INTEGRATION
      }
+
+// ----------------------------------------------------------------------------
+// Cancel request. This will empty the task array and stop the wait loop. This
+//                 will cause the CreateMediaL() to finish more quickly.
+// ----------------------------------------------------------------------------
+EXPORT_C void CMPXMetadataExtractor::CancelRequest()
+    {
+    MPX_FUNC("CMPXMetadataExtractor::CancelRequest()");
+    iCancelled = ETrue;
+    // Cancel all tasks
+    iArrayTasks.Reset();
+    // Cancel all thumbnail request
+    CancelAllThumbnailRequests();
+    StopWaitLoop();
+    }
+
+// ----------------------------------------------------------------------------
+// Cancel all outstanding thumbnail requests.
+// ----------------------------------------------------------------------------
+void CMPXMetadataExtractor::CancelAllThumbnailRequests()
+    {
+    MPX_FUNC("CMPXMetadataExtractor::CancelAllThumbnailRequests()");
+#ifdef RD_MPX_TNM_INTEGRATION
+    // TODO: remove comments when TNM make CancelRequest asynchronous.
+    /*TInt count = iArrayTNRequestId.Count();
+    for ( TInt i=0; i<count; i++ )
+        {
+        iTNManager->CancelRequest( iArrayTNRequestId[i] );
+        }
+    */
+    iArrayTNRequestId.Reset();
+#endif // RD_MPX_TNM_INTEGRATION
+    }
+
+// ----------------------------------------------------------------------------
+// Create media and set default data and mimetype.
+// ----------------------------------------------------------------------------
+void CMPXMetadataExtractor::DoCreateMediaL()
+    {
+    MPX_FUNC("CMPXMetadataExtractor::DoCreateMediaL()");
+    RArray<TInt> contentIDs;
+    contentIDs.AppendL( KMPXMediaIdGeneral );
+    contentIDs.AppendL( KMPXMediaIdAudio );
+    contentIDs.AppendL( KMPXMediaIdMusic );
+    contentIDs.AppendL( KMPXMediaIdDrm );
+    contentIDs.AppendL( KMPXMediaIdMTP );
+    iMedia = CMPXMedia::NewL( contentIDs.Array() );
+    contentIDs.Close();
+
+    // CMPXMedia default types
+    iMedia->SetTObjectValueL<TMPXGeneralType>( KMPXMediaGeneralType,
+                                              EMPXItem );
+    iMedia->SetTObjectValueL<TMPXGeneralCategory>( KMPXMediaGeneralCategory,
+                                                  EMPXSong );
+
+    TParsePtrC parse( iFileName );
+    // Title, default is file name
+    iMedia->SetTextValueL( KMPXMediaGeneralTitle,
+                          parse.Name() );
+    // Default album track
+    iMedia->SetTextValueL( KMPXMediaMusicAlbumTrack,
+                          KNullDesC );
+
+    // Set the Mime Type and collection UID
+    //
+    if( !iMetadataOnly )
+        {
+        TInt index(KErrNotFound);
+        TInt count( iSupportedTypes.Count() );
+        for (TInt i=0; i <count; ++i)
+            {
+            TInt index2(KErrNotFound);
+            const CDesCArray& exts = iSupportedTypes[i]->Extensions();
+            const TDesC& ext = parse.Ext();
+            if (!exts.FindIsq(ext, index2))
+                { // found
+                index = i;
+                break;
+                }
+            }
+        if( KErrNotFound != index )
+            {
+            MPX_DEBUG1("CMPXMetadataExtractor::DoCreateMediaL apparc <---" );
+            TInt mimeIndex = SupportedContainerTypeL( iFileName, index );
+            User::LeaveIfError( mimeIndex );
+            MPX_DEBUG1("CMPXMetadataExtractor::DoCreateMediaL apparc --->" );
+
+            iMedia->SetTextValueL( KMPXMediaGeneralMimeType,
+                                  iSupportedTypes[index]->Mimetypes()[mimeIndex] );
+
+            iMedia->SetTObjectValueL( KMPXMediaGeneralCollectionId,
+                                     iSupportedTypes[index]->Uid() );
+            }
+        else
+            {
+            User::Leave(KErrNotSupported);
+            }
+        }
+    else // other case use apparc to fetch and set mimetype
+        {
+        TDataType dataType;
+        TUid dummyUid(KNullUid);
+        iAppArc.AppForDocument(iFileName, dummyUid, dataType);
+        iMedia->SetTextValueL( KMPXMediaGeneralMimeType,dataType.Des() );
+        }
+        
+    // Initially set default tags.
+    SetDefaultL( *iMedia );
+    }
+
+// ----------------------------------------------------------------------------
+// Execute task at index 0.
+// ----------------------------------------------------------------------------
+void CMPXMetadataExtractor::ExecuteTaskL()
+    {
+    MPX_FUNC("CMPXMetadataExtractor::ExecuteTasksL()");
+
+    if ( iArrayTasks.Count() )
+        {
+        switch ( iArrayTasks[0] )
+            {
+            case ETaskCreateMedia:
+                DoCreateMediaL();
+                break;
+            case ETaskAddMetadata:
+                SetMediaPropertiesL();
+                break;
+            case ETaskAddExtMetadata:
+                SetExtMediaPropertiesL();
+                break;
+            case ETaskAddAlbumArt:
+                AddMediaAlbumArtL( *iMedia, iFileName );
+                break;
+            case ETaskCheckBeforeSend:
+                CheckBeforeSendRequest();
+                break;
+            default:
+                MPX_ASSERT(0); // Should never get here
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Constructs a media properties object : asynchronous funcion
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CMPXMetadataExtractor::CreateMediaAsyncL( const TDesC& aFile,
+                                                        MMPXMetadataExtractorObserver* aObs,
+                                                        TBool aMetadataOnly )
+    {
+    MPX_FUNC("CMPXMetadataExtractor::CreateMediaAsyncL()");
+    // check if we are still processing a request.
+    if ( iArrayTasks.Count() )
+        {
+        MPX_DEBUG1("CMPXMetadataExtractor::CreateMediaAsyncL Request ongoing. Abort!" );
+        User::Leave( KErrAbort );
+        }
+    
+    iCancelled = EFalse;
+    iFileOpenError = KErrNone;
+    iFileName = aFile;
+    iObs = aObs;
+    iMetadataOnly = aMetadataOnly;
+    
+    // populate the task array
+    AddTasksL();
+    
+    // Start task timer to execute task
+    if ( iArrayTasks.Count() )
+        {
+        if ( iTaskTimer->IsActive() )
+            {
+            iTaskTimer->Cancel();
+            }   
+        iTaskTimer->Start( 0, 0, TCallBack(TaskTimerCallback, this ));
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Opens the file
+// ---------------------------------------------------------------------------
+//
+TInt CMPXMetadataExtractor::OpenFile()
+    {
+    MPX_FUNC("CMPXMetadataExtractor::OpenFile()");
+    
+    // Open the file
+    iFile.Close();
+    TInt error = iFile.Open( iFs, iFileName, EFileRead | EFileShareReadersOrWriters );
+    MPX_DEBUG2("CMPXMetadataExtractor::OpenFile open error = %d", error );
+    return error;
+    }
+
+// ---------------------------------------------------------------------------
+// Populat task array
+// ---------------------------------------------------------------------------
+//
+void CMPXMetadataExtractor::AddTasksL()
+    {
+    MPX_FUNC("CMPXMetadataExtractor::AddTasks()");
+    iFileOpenError = OpenFile();
+    
+    // Do not change the order of the task below.
+    iArrayTasks.Reset();
+    if ( iFileOpenError == KErrNone )
+        {
+        iArrayTasks.AppendL(ETaskCreateMedia);
+        iArrayTasks.AppendL(ETaskAddMetadata);
+        iArrayTasks.AppendL(ETaskCheckBeforeSend);
+        iArrayTasks.AppendL(ETaskAddAlbumArt);
+        iArrayTasks.AppendL(ETaskAddExtMetadata);
+        }
+    else
+        {
+        iArrayTasks.AppendL(ETaskCreateMedia);
+        iArrayTasks.AppendL(ETaskAddExtMetadata);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Callback for timer.
+// ----------------------------------------------------------------------------
+TInt CMPXMetadataExtractor::TaskTimerCallback(TAny* aPtr)
+    {
+    MPX_FUNC("CMPXMetadataExtractor::TaskTimerCallback()");
+
+    CMPXMetadataExtractor* ptr =
+        static_cast<CMPXMetadataExtractor*>(aPtr);
+
+    ptr->HandleTaskTimerExpired();
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------------------------
+// Handle task timer expired
+// ----------------------------------------------------------------------------
+void CMPXMetadataExtractor::HandleTaskTimerExpired()
+    {
+    MPX_FUNC("CMPXMetadataExtractor::HandleTaskTimerExpired()");
+    
+    iTaskTimer->Cancel();
+    // execute task at index 0
+    TRAPD( error, ExecuteTaskL() );
+    if ( error || iCancelled )
+        {
+        // cleanup
+        if ( iMedia != NULL )
+            {
+            delete iMedia;
+            iMedia = NULL;
+            }
+        iArrayTasks.Reset();
+        }
+    
+    // Remove task at index 0.
+    if ( iArrayTasks.Count() )
+        {
+        iArrayTasks.Remove( 0 );
+        }
+    
+    // check if we have any more task to run
+    if ( iArrayTasks.Count() )
+        {
+        // start task timer
+        iTaskTimer->Start( 0, 0, TCallBack(TaskTimerCallback, this ));
+        }
+    else
+        {
+        // done
+        if ( iObs && !iCancelled )
+            {
+            iObs->HandleCreateMediaComplete( iMedia, error );
+            }
+        
+        CleanUp();
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Callback for timer.
+// ----------------------------------------------------------------------------
+void CMPXMetadataExtractor::CleanUp()
+    {
+    MPX_FUNC("CMPXMetadataExtractor::CleanUp()");
+    // Reset the utility
+    TRAP_IGNORE( iMetadataUtility->ResetL() );
+    iFile.Close();
+    }
+