upnpsharing/upnpgstwrapper/src/upnpgstwrapper.cpp
branchIOP_Improvements
changeset 40 08b5eae9f9ff
equal deleted inserted replaced
39:6369bfd1b60d 40:08b5eae9f9ff
       
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Implementation of UPnP GStreamer wrapper
       
    15 *
       
    16 */
       
    17 
       
    18 // INCLUDES
       
    19 #include <bautils.h>
       
    20 
       
    21 #include <gst/app/gstappsink.h>
       
    22 
       
    23 #include <gst/app/gstappsink.h>
       
    24 #include <gst/app/gstappbuffer.h>
       
    25 
       
    26 #include <gst/gst.h>
       
    27 #include <gst/gstinfo.h>
       
    28 
       
    29 #include "upnpgstwrapper.h"
       
    30 
       
    31 _LIT( KComponentLogfile, "upnpgstwrapper.txt");
       
    32 #include "upnplog.h"
       
    33 
       
    34 #define __FUNC_LOG __LOG8_1( "%s", __PRETTY_FUNCTION__ );
       
    35 
       
    36 _LIT( KAlreadyInUseErrorMsg, "GST already in use (call Stop first)" );
       
    37 _LIT( KUnknownErrorErrorMsg, "Unknown error" );
       
    38 _LIT( KOutOfMemoryErrorMsg, "Out of memory" );
       
    39 
       
    40 const char* const KMimeTypeVideo = "video/";
       
    41 const char* const KMimeTypeAudio = "audio/";
       
    42 const char* const KDemuxerName = "demux";
       
    43 
       
    44 class CUpnpGstWrapperPimpl : CBase
       
    45     {
       
    46     
       
    47 public: // construction / destruction
       
    48        
       
    49     /**
       
    50      * Static NewL
       
    51      *
       
    52      * @param none
       
    53      * @return instance to CUpnpGstWrapperPimpl
       
    54      */
       
    55     static CUpnpGstWrapperPimpl* NewL();    
       
    56     
       
    57     /**
       
    58      * Destructor
       
    59      */
       
    60     ~CUpnpGstWrapperPimpl();
       
    61     
       
    62 private:
       
    63     
       
    64     /**
       
    65      * Constructor
       
    66      */
       
    67     CUpnpGstWrapperPimpl();
       
    68     
       
    69     /**
       
    70      * 2nd phrase Constructor
       
    71      */
       
    72     void ConstructL();
       
    73 
       
    74 public:
       
    75     
       
    76     inline void SetPipeline( GstElement* aPipeline );
       
    77     
       
    78     inline GstElement* Pipeline(); 
       
    79     
       
    80     inline void SetDemuxer( GstElement* aDemuxer );
       
    81     
       
    82     inline GstElement* Demuxer();
       
    83     
       
    84     inline void InitAppSinkL();
       
    85     
       
    86     inline TBool PullBufferL( TPtr8& aPointer,TInt aMaxBytesLength, RBuf8* aBuf );
       
    87     
       
    88     inline TInt TranscodedBytes();
       
    89     
       
    90 public: //callbacks
       
    91     
       
    92     /**
       
    93      * A function to receive any message occured within the pipeline
       
    94      * Note that the function will be called in the same thread context as
       
    95      * the posting object.
       
    96      * 
       
    97      * @param GstBus* a bus to create the watch for
       
    98      * @param GstMessage* a message created within the pipeline
       
    99      * @param gponter the user data that has been given, 
       
   100      *        when registering the handler
       
   101      * @return GstBusSyncReply indicates whether the message is also added
       
   102      *         into async queue (after this callback) or dropped
       
   103      */
       
   104     static GstBusSyncReply SyncBusCallback( GstBus* aBus, GstMessage* aMsg, 
       
   105             gpointer aData );
       
   106     
       
   107     /**
       
   108      * A function to receive callback from demuxer whenever source pad is
       
   109      * added into it
       
   110      * 
       
   111      * @param GstElement* an element (demuxer) where the source pad was added 
       
   112      * @param GstPad* a souce pad that was added
       
   113      * @param gponter the user data that has been given, 
       
   114      *        when registering the handler
       
   115      */
       
   116     static void DemuxPadAddedCallback( GstElement* aElement, GstPad* aPad,
       
   117             gpointer aData );
       
   118     
       
   119     /**
       
   120      * Internal log handler.
       
   121      * Implements GStreamer's log handler callback.
       
   122      * Ouputs GStreamer debug traces if DEBUG_ENABLE flag is enabled in
       
   123      * GStreamer.
       
   124      */    
       
   125     static void LogCallback( GstDebugCategory *category, GstDebugLevel level,
       
   126             const gchar *file, const gchar *function, gint line, 
       
   127             GObject *object, GstDebugMessage *message, gpointer data );
       
   128 
       
   129 private:
       
   130     
       
   131     GstElement*                            iPipeline;
       
   132     GstElement*                            iDemuxer;        
       
   133     
       
   134     TInt                                   iBytesOffSet;
       
   135     
       
   136     GstElement*                            iAppsink;
       
   137 
       
   138     GstElement*                            iElement;
       
   139     
       
   140     GstBuffer*                             iGstBuffer;
       
   141     
       
   142     };
       
   143 
       
   144 // --------------------------------------------------------------------------
       
   145 // CUpnpGstWrapperPimpl::NewL
       
   146 //---------------------------------------------------------------------------
       
   147 CUpnpGstWrapperPimpl* CUpnpGstWrapperPimpl::NewL()
       
   148     {    
       
   149     __FUNC_LOG;
       
   150     
       
   151     CUpnpGstWrapperPimpl* self = new( ELeave ) CUpnpGstWrapperPimpl();
       
   152     CleanupStack::PushL( self );
       
   153     self->ConstructL();
       
   154     CleanupStack::Pop( self );  
       
   155     return self;
       
   156     }
       
   157 
       
   158 // --------------------------------------------------------------------------
       
   159 // CUpnpGstWrapperPimpl::~CUpnpGstWrapperPimpl
       
   160 //---------------------------------------------------------------------------
       
   161 CUpnpGstWrapperPimpl::~CUpnpGstWrapperPimpl()
       
   162     {  
       
   163     __FUNC_LOG;
       
   164     }
       
   165 
       
   166 // --------------------------------------------------------------------------
       
   167 // CUpnpGstWrapperPimpl::CUpnpGstWrapperPimpl
       
   168 //---------------------------------------------------------------------------
       
   169 CUpnpGstWrapperPimpl::CUpnpGstWrapperPimpl()
       
   170     {    
       
   171     __FUNC_LOG;
       
   172     }
       
   173 
       
   174 // --------------------------------------------------------------------------
       
   175 // CUpnpGstWrapperPimpl::ConstructL
       
   176 //---------------------------------------------------------------------------
       
   177 void CUpnpGstWrapperPimpl::ConstructL()
       
   178     {    
       
   179     __FUNC_LOG;
       
   180     }
       
   181 
       
   182 void CUpnpGstWrapperPimpl::SetPipeline( GstElement* aPipeline )
       
   183     {
       
   184     __FUNC_LOG;
       
   185     
       
   186     iPipeline = aPipeline;
       
   187     }
       
   188 
       
   189 GstElement* CUpnpGstWrapperPimpl::Pipeline()
       
   190     {
       
   191     __FUNC_LOG;
       
   192     return iPipeline;
       
   193     }
       
   194 
       
   195 void CUpnpGstWrapperPimpl::SetDemuxer( GstElement* aDemuxer )
       
   196     {    
       
   197     __FUNC_LOG;
       
   198     
       
   199     iDemuxer = aDemuxer;
       
   200     }
       
   201 
       
   202 GstElement* CUpnpGstWrapperPimpl::Demuxer()
       
   203     {
       
   204     __FUNC_LOG;
       
   205     
       
   206     return iDemuxer;
       
   207     }
       
   208 
       
   209 void CUpnpGstWrapperPimpl::InitAppSinkL()
       
   210     {
       
   211     iAppsink = gst_bin_get_by_name (
       
   212             GST_BIN ( iPipeline ), "sinkbuffer");
       
   213   
       
   214     if( !iAppsink )
       
   215         User::Leave( KErrNotFound);
       
   216     
       
   217     g_object_set (
       
   218              G_OBJECT (iAppsink), "emit-signals", TRUE, "sync", FALSE, NULL);       
       
   219     gst_object_unref (iAppsink); 
       
   220     }
       
   221     
       
   222 TBool CUpnpGstWrapperPimpl::PullBufferL( TPtr8& aPointer,TInt aMaxBytesLength, RBuf8* aBuf )
       
   223     {
       
   224     guint size;     
       
   225      
       
   226     if( iGstBuffer )
       
   227         {
       
   228         delete [] GST_BUFFER_DATA(iGstBuffer);
       
   229         GST_BUFFER_DATA(iGstBuffer) = NULL;
       
   230         }
       
   231     
       
   232     iGstBuffer = gst_app_sink_pull_buffer( GST_APP_SINK ( iAppsink  ));
       
   233     
       
   234     if( iGstBuffer )
       
   235         {
       
   236         size = GST_BUFFER_SIZE( iGstBuffer );
       
   237 
       
   238         iBytesOffSet += size;
       
   239         
       
   240         if( aBuf && ( size + aBuf->Length() ) > aBuf->MaxLength() )
       
   241             {
       
   242             HBufC8* tmp(NULL);
       
   243             TInt len(aBuf->Length());
       
   244             if( len > 0 )
       
   245                 {
       
   246                 tmp = aBuf->AllocLC();
       
   247                 }
       
   248             aBuf->Close();
       
   249             aBuf->CreateL(size+len);
       
   250             if( tmp )
       
   251                 {
       
   252                 aBuf->Append(*tmp);
       
   253                 CleanupStack::PopAndDestroy(tmp);
       
   254                 }
       
   255             
       
   256             aBuf->Append( (TUint8*)GST_BUFFER_DATA(iGstBuffer),size );
       
   257             }
       
   258         else
       
   259             {                       
       
   260             __ASSERT( (aMaxBytesLength >= size), __FILE__, __LINE__ );
       
   261             aPointer.Set((TUint8*)GST_BUFFER_DATA(iGstBuffer),size,aMaxBytesLength);
       
   262             }
       
   263         }
       
   264     return ( iGstBuffer ) ? EFalse : ETrue;
       
   265     }
       
   266 
       
   267 TInt CUpnpGstWrapperPimpl::TranscodedBytes()
       
   268     {
       
   269     return iBytesOffSet;
       
   270     }
       
   271     
       
   272 // --------------------------------------------------------------------------
       
   273 // CUpnpGstWrapperPimpl::SyncBusCallback
       
   274 //---------------------------------------------------------------------------
       
   275 GstBusSyncReply CUpnpGstWrapperPimpl::SyncBusCallback( GstBus* /*aBus*/, 
       
   276         GstMessage* aMsg, gpointer aData )
       
   277     {
       
   278     __FUNC_LOG;
       
   279     
       
   280     GstMessageType messageType = GST_MESSAGE_TYPE( aMsg );    
       
   281     
       
   282     if( messageType == GST_MESSAGE_EOS ||
       
   283         messageType == GST_MESSAGE_ERROR )
       
   284         {
       
   285         __ASSERT( aData, __FILE__, __LINE__ );      
       
   286         
       
   287         CUpnpGstWrapper* parent = static_cast<CUpnpGstWrapper*>( aData );
       
   288         Gst::TEvent event = Gst::EUnknown;
       
   289     
       
   290         parent->iMutex.Wait();
       
   291         
       
   292         switch( messageType ) 
       
   293             {
       
   294             case GST_MESSAGE_EOS:
       
   295                 {        
       
   296                 event = Gst::EEOS;  
       
   297                 break;
       
   298                 }
       
   299             case GST_MESSAGE_ERROR: 
       
   300                 {
       
   301                 GError* err = NULL;
       
   302                 
       
   303                 char* debug;
       
   304                 gst_message_parse_error( aMsg, &err, &debug );
       
   305                 g_free( debug );   
       
   306                 
       
   307                 if( err )
       
   308                     {
       
   309                     TRAP_IGNORE( parent->SetErrorMsg( 
       
   310                             parent->ConvertCharToDescL(
       
   311                             err->message ) ) );
       
   312                     g_error_free( err );
       
   313                     err = NULL;
       
   314                     }
       
   315                 event = Gst::EError;        
       
   316                 break;
       
   317                 }
       
   318             default:
       
   319                 {
       
   320                 __ASSERT( EFalse, __FILE__, __LINE__ );
       
   321                 }
       
   322             }
       
   323 
       
   324         parent->iEventQueue.Append( event );        
       
   325         
       
   326         __ASSERT( parent->IsActive(), __FILE__, __LINE__ );
       
   327         if( parent->iStatus == KRequestPending )
       
   328             {
       
   329             TRequestStatus* status = &parent->iStatus;
       
   330             RThread thread;
       
   331             TInt err = thread.Open( parent->iClientThreadId );
       
   332             __ASSERT( !err, __FILE__, __LINE__ );                        
       
   333                 
       
   334             thread.RequestComplete( status, KErrNone );            
       
   335             thread.Close();
       
   336             }
       
   337         
       
   338         parent->iMutex.Signal();
       
   339 
       
   340         gst_message_unref( aMsg );
       
   341         }
       
   342 
       
   343     return GST_BUS_DROP; //do not add anything into async queue
       
   344     }
       
   345 
       
   346 // --------------------------------------------------------------------------
       
   347 // CUpnpGstWrapperPimpl::DemuxPadAddedCallback
       
   348 //---------------------------------------------------------------------------
       
   349 void CUpnpGstWrapperPimpl::DemuxPadAddedCallback( GstElement* /*aElement*/, 
       
   350         GstPad* aPad, gpointer aData )
       
   351     {
       
   352     __FUNC_LOG;    
       
   353     __ASSERT( aData, __FILE__, __LINE__ );       
       
   354     
       
   355     CUpnpGstWrapper* parent = static_cast<CUpnpGstWrapper*>( aData );
       
   356     
       
   357     GstCaps* caps = gst_pad_get_caps( aPad );
       
   358     char* str = gst_caps_to_string( caps );  
       
   359     Gst::TEvent event = Gst::EUnknown;
       
   360     
       
   361     parent->iMutex.Wait();
       
   362     
       
   363     if( g_str_has_prefix( str, KMimeTypeVideo ) )
       
   364         {
       
   365         delete parent->iVideoInfo; parent->iVideoInfo = NULL;
       
   366         TRAPD( err, parent->iVideoInfo = parent->ConvertCharToDescL( str ) );
       
   367         if( !err )
       
   368             {
       
   369             event = Gst::EVideoStreamInfoAvailable;
       
   370             }
       
   371         else
       
   372             {            
       
   373             event = Gst::EError;
       
   374             TRAP_IGNORE( parent->SetErrorMsgL( KOutOfMemoryErrorMsg ) );
       
   375             }
       
   376         }
       
   377     else if( g_str_has_prefix( str, KMimeTypeAudio ) )
       
   378         {
       
   379         delete parent->iAudioInfo; parent->iAudioInfo = NULL;
       
   380         TRAPD( err, parent->iAudioInfo = parent->ConvertCharToDescL( str ) );
       
   381         if( !err )
       
   382             {
       
   383             event = Gst::EAudioStreamInfoAvailable;
       
   384             }
       
   385         else
       
   386             {            
       
   387             event = Gst::EError;
       
   388             TRAP_IGNORE( parent->SetErrorMsgL( KOutOfMemoryErrorMsg ) );
       
   389             }        
       
   390         }
       
   391     else
       
   392         {
       
   393         __ASSERT( EFalse, __FILE__, __LINE__ );
       
   394         }
       
   395     
       
   396     parent->iEventQueue.Append( event );        
       
   397     
       
   398     __ASSERT( parent->IsActive(), __FILE__, __LINE__ );
       
   399     if( parent->iStatus == KRequestPending )
       
   400         {
       
   401         TRequestStatus* status = &parent->iStatus;
       
   402         RThread thread;
       
   403         TInt err = thread.Open( parent->iClientThreadId );
       
   404         __ASSERT( !err, __FILE__, __LINE__ );                        
       
   405             
       
   406         thread.RequestComplete( status, KErrNone );            
       
   407         thread.Close();
       
   408         }
       
   409     
       
   410     parent->iMutex.Signal();
       
   411     
       
   412     g_free(str);
       
   413     }
       
   414 
       
   415 // --------------------------------------------------------------------------
       
   416 // CUpnpGstWrapperPimpl::LogCallback
       
   417 //---------------------------------------------------------------------------
       
   418 void CUpnpGstWrapperPimpl::LogCallback( GstDebugCategory* category, 
       
   419         GstDebugLevel level, const char* file, const char* function, 
       
   420         gint line, GObject* /*object*/, GstDebugMessage* message, 
       
   421         gpointer /*data*/ )
       
   422     {  
       
   423     if (level > gst_debug_category_get_threshold (category))
       
   424         {
       
   425         return;    
       
   426         }    
       
   427     
       
   428 #ifndef __UPNP_LOG_FILE    
       
   429     const char* const KGstLogFmt = "%s %20s %s:%d:%s %s\n";
       
   430     RDebug::Printf( KGstLogFmt,
       
   431             gst_debug_level_get_name (level),
       
   432             gst_debug_category_get_name (category), file, line, function,
       
   433             gst_debug_message_get (message) );
       
   434 #else
       
   435     _LIT8( KGstLogFmtDesc, "%s %20s %s:%d:%s %s\n" );
       
   436     RFileLogger::WriteFormat( KLogDir, KComponentLogfile,
       
   437             EFileLoggingModeAppend, KGstLogFmtDesc, 
       
   438             gst_debug_level_get_name (level),
       
   439             gst_debug_category_get_name (category), file, line, function,
       
   440             gst_debug_message_get (message) );
       
   441 #endif    
       
   442     }
       
   443 
       
   444 // --------------------------------------------------------------------------
       
   445 // CUpnpGstWrapper::GetInstanceL
       
   446 // See upnpgstwrapper.h
       
   447 //---------------------------------------------------------------------------
       
   448 EXPORT_C CUpnpGstWrapper* CUpnpGstWrapper::GetInstanceL()
       
   449     {
       
   450     CUpnpGstWrapper* singleton = static_cast<CUpnpGstWrapper*>( Dll::Tls() );
       
   451     if ( singleton == 0 )
       
   452         {
       
   453         // singleton must be created first
       
   454         singleton = new ( ELeave ) CUpnpGstWrapper();
       
   455         CleanupStack::PushL( singleton );
       
   456         singleton->ConstructL();
       
   457         User::LeaveIfError( Dll::SetTls( singleton ) );
       
   458         CleanupStack::Pop( singleton );
       
   459         }    
       
   460     singleton->iSingletonRefCount++;
       
   461 
       
   462     return singleton;
       
   463     }
       
   464 	
       
   465 // --------------------------------------------------------------------------
       
   466 // CUpnpGstWrapper::Close
       
   467 // See upnpgstwrapper.h
       
   468 //---------------------------------------------------------------------------
       
   469 EXPORT_C void CUpnpGstWrapper::Close()
       
   470     {
       
   471     if(--iSingletonRefCount == 0)
       
   472         {
       
   473         Dll::FreeTls();
       
   474         delete this;
       
   475         }
       
   476     }
       
   477 
       
   478 // --------------------------------------------------------------------------
       
   479 // CUpnpGstWrapper::~CUpnpGstWrapper
       
   480 // See upnpgstwrapper.h
       
   481 //---------------------------------------------------------------------------
       
   482 EXPORT_C CUpnpGstWrapper::~CUpnpGstWrapper()
       
   483     {    
       
   484     __FUNC_LOG;
       
   485 
       
   486     Stop();
       
   487 
       
   488     Cancel();
       
   489     
       
   490     gst_deinit();
       
   491     
       
   492     delete iErrorMsg;
       
   493     delete iVideoInfo;
       
   494     delete iAudioInfo;
       
   495     
       
   496     iEventQueue.Close();    
       
   497     iMutex.Close();
       
   498     iObservers.Close();
       
   499     
       
   500     delete iPimpl;
       
   501     delete iPipeline;
       
   502     }
       
   503 
       
   504 // --------------------------------------------------------------------------
       
   505 // CUpnpGstWrapper::CUpnpGstWrapper
       
   506 // See upnpgstwrapper.h
       
   507 //---------------------------------------------------------------------------
       
   508 CUpnpGstWrapper::CUpnpGstWrapper()
       
   509     : CActive( EPriorityStandard )
       
   510     , iDuration( KErrNotFound )
       
   511     {    
       
   512     __FUNC_LOG;    
       
   513     
       
   514     CActiveScheduler::Add( this );
       
   515     }
       
   516 
       
   517 // --------------------------------------------------------------------------
       
   518 // CUpnpGstWrapper::ConstructL
       
   519 // See upnpgstwrapper.h
       
   520 //---------------------------------------------------------------------------
       
   521 void CUpnpGstWrapper::ConstructL()
       
   522     {
       
   523     __FUNC_LOG;      
       
   524     
       
   525     iPimpl = CUpnpGstWrapperPimpl::NewL();
       
   526     
       
   527     iMutex.CreateLocal();
       
   528     
       
   529     RThread thread;
       
   530     iClientThreadId = thread.Id(); 
       
   531     
       
   532     /*
       
   533      * Install our own log handler
       
   534      * FIXME: After this there is two log handlers:
       
   535      *        
       
   536      *          Default: Uses glib's g_printerr() that prints 
       
   537      *                   RDebug::RawPrints ONLY in full udeb mode
       
   538      *          Our own: See behaviour in LogCallback function below
       
   539      *          
       
   540      *        We should somehow get rid of the default one...
       
   541      */                    
       
   542     gst_debug_add_log_function( CUpnpGstWrapperPimpl::LogCallback, this );
       
   543     
       
   544     __LOG( "Initializing GStreamer..." );
       
   545     gst_init( NULL, NULL );    
       
   546     __LOG( "GStreamer initialization done!" );     
       
   547     }
       
   548 
       
   549 // --------------------------------------------------------------------------
       
   550 // CUpnpGstWrapper::SetObserverL
       
   551 // See upnpgstwrapper.h
       
   552 //---------------------------------------------------------------------------
       
   553 EXPORT_C void CUpnpGstWrapper::SetObserverL( 
       
   554         MUpnpGstWrapperObserver& aObserver )
       
   555     {
       
   556     if( iObservers.Find( &aObserver ) < 0 )
       
   557         {
       
   558         iObservers.AppendL( &aObserver );
       
   559         }
       
   560     }
       
   561 
       
   562 // --------------------------------------------------------------------------
       
   563 // CUpnpGstWrapper::RemoveObserverL
       
   564 // See upnpgstwrapper.h
       
   565 //---------------------------------------------------------------------------
       
   566 EXPORT_C void CUpnpGstWrapper::RemoveObserver( 
       
   567         MUpnpGstWrapperObserver& aObserver )
       
   568     {
       
   569     TInt index = iObservers.Find( &aObserver );
       
   570     if( index >= 0 )
       
   571         {
       
   572         iObservers.Remove( index );
       
   573         }    
       
   574     }
       
   575 
       
   576 // --------------------------------------------------------------------------
       
   577 // CUpnpGstWrapper::StartL
       
   578 // See upnpgstwrapper.h
       
   579 //---------------------------------------------------------------------------
       
   580 EXPORT_C void CUpnpGstWrapper::StartL()
       
   581     {
       
   582     __FUNC_LOG;
       
   583     
       
   584     if( !iPipeline )
       
   585         {
       
   586         SetErrorMsgL( KAlreadyInUseErrorMsg );        
       
   587         User::Leave( KErrNotReady );  
       
   588         }
       
   589 
       
   590     //Create pipeline according to the input description
       
   591     char* pipelineStr = ConvertDescToCharL( *iPipeline );
       
   592 
       
   593     GError* err = NULL;
       
   594     /**
       
   595      * Create a new pipeline based on command line syntax. 
       
   596      * Please note that you might get a return value that is not NULL even 
       
   597      * though the error is set. In this case there was a recoverable 
       
   598      * parsing error and you can try to play the pipeline
       
   599      */
       
   600     __LOG( "Parsing GStreamer pipeline..." );
       
   601     GstElement* pipeline = gst_parse_launch( pipelineStr, &err );
       
   602     __LOG( "GStreamer pipeline parsing done!" );
       
   603     User::Free( pipelineStr );
       
   604     
       
   605     if( err )
       
   606         {    
       
   607         SetErrorMsg( ConvertCharToDescL( err->message ) );
       
   608         g_error_free( err );
       
   609         err = NULL;
       
   610         User::Leave( KErrGeneral );
       
   611         }
       
   612     
       
   613     iPimpl->SetPipeline( pipeline );
       
   614 	
       
   615     //TODO: Hardcoded demuxer name 'KDemuxerName -> should be fetched somehow 
       
   616     //dynamically ??
       
   617     GstElement* demuxer = gst_bin_get_by_name( GST_BIN( pipeline ), 
       
   618             KDemuxerName );
       
   619          
       
   620     //If a demuxer is found, create 'pad-added' callback; else do nothing 
       
   621     if( demuxer )
       
   622         {
       
   623         g_signal_connect( demuxer, "pad-added", 
       
   624                 G_CALLBACK( CUpnpGstWrapperPimpl::DemuxPadAddedCallback ), 
       
   625                 this );
       
   626         iPimpl->SetDemuxer( demuxer );
       
   627         }     
       
   628 
       
   629     GstBus* bus = NULL;
       
   630     bus = gst_pipeline_get_bus( GST_PIPELINE( pipeline ) );
       
   631     if( !bus )
       
   632         {
       
   633         //unknown error
       
   634         User::Leave(KErrGeneral);	
       
   635         }	
       
   636     
       
   637     if( !IsActive() )
       
   638         {
       
   639         iStatus = KRequestPending;
       
   640         SetActive();     
       
   641         }
       
   642     
       
   643     gst_bus_set_sync_handler( bus, CUpnpGstWrapperPimpl::SyncBusCallback, this );
       
   644     
       
   645     gst_object_unref( bus );
       
   646 
       
   647     gst_element_set_state( pipeline, GST_STATE_PLAYING );       
       
   648     }
       
   649 
       
   650 // --------------------------------------------------------------------------
       
   651 // CUpnpGstWrapper::Stop
       
   652 // See upnpgstwrapper.h
       
   653 //---------------------------------------------------------------------------
       
   654 EXPORT_C void CUpnpGstWrapper::Stop()
       
   655     {    
       
   656     __FUNC_LOG;
       
   657     GstElement* demuxer = iPimpl->Demuxer();
       
   658     if( demuxer )
       
   659         {
       
   660         gst_object_unref( GST_OBJECT( demuxer ) );
       
   661         iPimpl->SetDemuxer( NULL );
       
   662         }    
       
   663     
       
   664     GstElement* pipeline = iPimpl->Pipeline();
       
   665     if( pipeline )
       
   666         {
       
   667         gst_element_set_state( pipeline, GST_STATE_NULL );
       
   668         gst_object_unref( GST_OBJECT( pipeline ) );
       
   669         iPimpl->SetPipeline( NULL );
       
   670         }
       
   671     //Cancel();    
       
   672     }
       
   673 
       
   674 // --------------------------------------------------------------------------
       
   675 // CUpnpGstWrapper::ErrorMsg
       
   676 // See upnpgstwrapper.h
       
   677 //---------------------------------------------------------------------------
       
   678 EXPORT_C const TDesC& CUpnpGstWrapper::ErrorMsg()
       
   679     {
       
   680     __FUNC_LOG;
       
   681     
       
   682     if( iErrorMsg )
       
   683         {
       
   684         return *iErrorMsg;
       
   685         }
       
   686     else
       
   687         {
       
   688         return KUnknownErrorErrorMsg();
       
   689         }
       
   690     }
       
   691 
       
   692 // --------------------------------------------------------------------------
       
   693 // CUpnpGstWrapper::FeatureListL
       
   694 // See upnpgstwrapper.h
       
   695 //---------------------------------------------------------------------------
       
   696 EXPORT_C CDesCArray* CUpnpGstWrapper::FeatureListL()
       
   697     {
       
   698     __FUNC_LOG;
       
   699     
       
   700     CDesCArray* array = new (ELeave) CDesCArrayFlat( 5 );
       
   701     CleanupStack::PushL( array );
       
   702 
       
   703     GList* features = gst_registry_get_feature_list( 
       
   704             gst_registry_get_default(), GST_TYPE_ELEMENT_FACTORY );
       
   705     while( features )
       
   706         {
       
   707         GstPluginFeature* feature = (GstPluginFeature*)features->data;        
       
   708         HBufC* tempBuf = ConvertCharToDescL( gst_plugin_feature_get_name( 
       
   709                 feature ) );
       
   710         CleanupStack::PushL( tempBuf );
       
   711         array->AppendL( *tempBuf );
       
   712         CleanupStack::PopAndDestroy( tempBuf );
       
   713         features = features->next;
       
   714         }
       
   715 
       
   716     CleanupStack::Pop( array );
       
   717     return array;
       
   718     }
       
   719 
       
   720 // --------------------------------------------------------------------------
       
   721 // CUpnpGstWrapper::VideoInfo
       
   722 // See upnpgstwrapper.h
       
   723 //---------------------------------------------------------------------------
       
   724 EXPORT_C const TDesC& CUpnpGstWrapper::VideoInfo()
       
   725     {
       
   726     __FUNC_LOG;
       
   727     
       
   728     if( iVideoInfo )
       
   729         {
       
   730         return *iVideoInfo;
       
   731         }
       
   732     else
       
   733         {
       
   734         return KNullDesC;
       
   735         }
       
   736     }
       
   737 
       
   738 // --------------------------------------------------------------------------
       
   739 // CUpnpGstWrapper::AudioInfo
       
   740 // See upnpgstwrapper.h
       
   741 //---------------------------------------------------------------------------
       
   742 EXPORT_C const TDesC& CUpnpGstWrapper::AudioInfo()
       
   743     {
       
   744     __FUNC_LOG;
       
   745     
       
   746     if( iAudioInfo )
       
   747         {
       
   748         return *iAudioInfo;
       
   749         }
       
   750     else
       
   751         {
       
   752         return KNullDesC;
       
   753         }
       
   754     }
       
   755 // --------------------------------------------------------------------------
       
   756 // CUpnpGstWrapper::Position
       
   757 // See upnpgstwrapper.h
       
   758 //---------------------------------------------------------------------------
       
   759 EXPORT_C TInt64 CUpnpGstWrapper::Position()
       
   760     {
       
   761     __FUNC_LOG;
       
   762     
       
   763     GstFormat fmt = GST_FORMAT_TIME;
       
   764     TInt64 position = KErrNotFound;
       
   765     
       
   766     //fetch position from pipeline (not from the demuxer)
       
   767     GstElement* pipeline = iPimpl->Pipeline();
       
   768     
       
   769     if( pipeline )
       
   770         {
       
   771         gst_element_query_position( pipeline, &fmt, &position );
       
   772         }
       
   773     
       
   774     return position;
       
   775     }
       
   776 
       
   777 // --------------------------------------------------------------------------
       
   778 // CUpnpGstWrapper::Duration
       
   779 // See upnpgstwrapper.h
       
   780 //---------------------------------------------------------------------------
       
   781 EXPORT_C TInt64 CUpnpGstWrapper::Duration()
       
   782     {
       
   783     __FUNC_LOG;
       
   784      
       
   785      if( iDuration < 0 )
       
   786          {
       
   787          GstFormat fmt = GST_FORMAT_TIME;
       
   788          if( iPimpl->Demuxer() )
       
   789              {
       
   790              //fetch duration from demuxer
       
   791              gst_element_query_duration( iPimpl->Demuxer(), &fmt, &iDuration );
       
   792              } 
       
   793          else if( iPimpl->Pipeline() )
       
   794              {
       
   795              //backup plan: not so good choice as demuxer
       
   796              gst_element_query_position( iPimpl->Pipeline(), &fmt, &iDuration );
       
   797              }
       
   798          }
       
   799      
       
   800      return iDuration;
       
   801     }
       
   802 
       
   803 EXPORT_C TAny* CUpnpGstWrapper::PipelinePtr()
       
   804     {
       
   805     return iPimpl->Pipeline();
       
   806     }
       
   807 
       
   808 EXPORT_C void CUpnpGstWrapper::InitAppsinkL()
       
   809     {
       
   810     iPimpl->InitAppSinkL();
       
   811     }
       
   812    
       
   813 EXPORT_C TBool CUpnpGstWrapper::PullBufferL( TPtr8& aPointer,TInt aMaxBytesLength, RBuf8* aBuf )
       
   814     {
       
   815     return iPimpl->PullBufferL(aPointer,aMaxBytesLength,aBuf);
       
   816     }
       
   817    
       
   818 EXPORT_C TInt CUpnpGstWrapper::TranscodedBytes()
       
   819     {
       
   820     return iPimpl->TranscodedBytes();
       
   821     }
       
   822        
       
   823 EXPORT_C void CUpnpGstWrapper::SetTranscodedFileSize( TInt aSize )
       
   824     {
       
   825     iFileSize = aSize;
       
   826     }
       
   827 
       
   828 EXPORT_C TInt CUpnpGstWrapper::TranscodedFileSize()
       
   829     {
       
   830     return iFileSize;
       
   831     }
       
   832 
       
   833 EXPORT_C void CUpnpGstWrapper::SetPipelineL( const TDesC8& aPipeline )
       
   834     {
       
   835     delete iPipeline;
       
   836     iPipeline = NULL;
       
   837     iPipeline = aPipeline.AllocL();
       
   838     }
       
   839      
       
   840 
       
   841 // --------------------------------------------------------------------------
       
   842 // CUpnpGstWrapper::SetErrorMsgL
       
   843 // See upnpgstwrapper.h
       
   844 //---------------------------------------------------------------------------
       
   845 void CUpnpGstWrapper::SetErrorMsgL( const TDesC& aErrorMsg )
       
   846     {
       
   847     __FUNC_LOG;     
       
   848     
       
   849     delete iErrorMsg; iErrorMsg = NULL;
       
   850     iErrorMsg = aErrorMsg.AllocL();
       
   851     
       
   852     __LOG1( "CUpnpGstWrapper::SetErrorMsgL Error desc: %S", iErrorMsg );
       
   853     }
       
   854 
       
   855 // --------------------------------------------------------------------------
       
   856 // CUpnpGstWrapper::SetErrorMsg
       
   857 // See upnpgstwrapper.h
       
   858 //---------------------------------------------------------------------------
       
   859 void CUpnpGstWrapper::SetErrorMsg( HBufC* const aErrorMsg )
       
   860     {
       
   861     delete iErrorMsg; iErrorMsg = NULL;
       
   862     iErrorMsg = aErrorMsg;
       
   863     
       
   864     __LOG1( "CUpnpGstWrapper::SetErrorMsg Error desc: %S", iErrorMsg );
       
   865     }
       
   866 
       
   867 // --------------------------------------------------------------------------
       
   868 // CUpnpGstWrapper::ConvertCharToDescL
       
   869 // See upnpgstwrapper.h
       
   870 //---------------------------------------------------------------------------
       
   871 HBufC* CUpnpGstWrapper::ConvertCharToDescL( const char* aString )
       
   872     {
       
   873     __FUNC_LOG;
       
   874     
       
   875     HBufC* desc = NULL;
       
   876     TPtrC8 tempPtr8( (TUint8*)(aString) );
       
   877     desc = HBufC::NewL( tempPtr8.Length() );
       
   878     desc->Des().Copy( tempPtr8 );
       
   879     
       
   880     return desc; 
       
   881     }
       
   882 
       
   883 
       
   884 // --------------------------------------------------------------------------
       
   885 // CUpnpGstWrapper::ConvertDescToCharL
       
   886 // See upnpgstwrapper.h
       
   887 //---------------------------------------------------------------------------
       
   888 char* CUpnpGstWrapper::ConvertDescToCharL( const TDesC8& aDescriptor )
       
   889     {
       
   890     __FUNC_LOG;
       
   891     
       
   892     TUint length = aDescriptor.Length();
       
   893     char* string = (char*)User::AllocL( length + 1 );
       
   894     Mem::Copy((char*)string, aDescriptor.Ptr(), length );
       
   895     string[length] = 0; //null terminated
       
   896     return string;
       
   897     }
       
   898 
       
   899 void CUpnpGstWrapper::SendEventToObsevers( Gst::TEvent aEvent )
       
   900     {
       
   901     __FUNC_LOG;
       
   902     
       
   903     TInt observerCount = iObservers.Count();
       
   904     for( TInt i = 0; i < observerCount; i++ )
       
   905         {
       
   906         iObservers[i]->HandleGstEvent( aEvent );
       
   907         }
       
   908     }
       
   909 
       
   910 // --------------------------------------------------------------------------
       
   911 // CUpnpGstWrapper::RunL
       
   912 // See upnpgstwrapper.h
       
   913 //---------------------------------------------------------------------------
       
   914 void CUpnpGstWrapper::RunL()
       
   915     {    
       
   916     __FUNC_LOG;
       
   917     if( iStatus.Int() >= KErrNone )
       
   918         {
       
   919         TBool completed = EFalse;   
       
   920         
       
   921         iMutex.Wait();
       
   922         
       
   923         TInt eventQueueCount = iEventQueue.Count();
       
   924         for( TInt i = 0; i < eventQueueCount; i++ )
       
   925             {
       
   926             Gst::TEvent event = iEventQueue[i];
       
   927             SendEventToObsevers( event );
       
   928             if( event == Gst::EEOS || event == Gst::EError )
       
   929                 {
       
   930                 __LOG1( "CUpnpGstWrapper::RunL Completed: %d (2=Error, 3=EOS)",
       
   931                         event);
       
   932                 completed = ETrue;
       
   933                 }
       
   934             }
       
   935         iEventQueue.Reset();
       
   936         
       
   937         if( !completed )
       
   938             {        
       
   939             iStatus = KRequestPending;
       
   940             SetActive();
       
   941             }        
       
   942         iMutex.Signal();
       
   943         }
       
   944     }
       
   945 
       
   946 // --------------------------------------------------------------------------
       
   947 // CUpnpGstWrapper::DoCancel
       
   948 // See upnpgstwrapper.h
       
   949 //---------------------------------------------------------------------------
       
   950 void CUpnpGstWrapper::DoCancel()
       
   951     {  
       
   952     __FUNC_LOG;
       
   953     }
       
   954 
       
   955 // end of file