diff -r 6369bfd1b60d -r 08b5eae9f9ff upnpsharing/upnpgstwrapper/src/upnpgstwrapper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/upnpsharing/upnpgstwrapper/src/upnpgstwrapper.cpp Wed Nov 03 11:45:09 2010 +0200 @@ -0,0 +1,955 @@ +/* +* Copyright (c) 2010 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: Implementation of UPnP GStreamer wrapper +* +*/ + +// INCLUDES +#include + +#include + +#include +#include + +#include +#include + +#include "upnpgstwrapper.h" + +_LIT( KComponentLogfile, "upnpgstwrapper.txt"); +#include "upnplog.h" + +#define __FUNC_LOG __LOG8_1( "%s", __PRETTY_FUNCTION__ ); + +_LIT( KAlreadyInUseErrorMsg, "GST already in use (call Stop first)" ); +_LIT( KUnknownErrorErrorMsg, "Unknown error" ); +_LIT( KOutOfMemoryErrorMsg, "Out of memory" ); + +const char* const KMimeTypeVideo = "video/"; +const char* const KMimeTypeAudio = "audio/"; +const char* const KDemuxerName = "demux"; + +class CUpnpGstWrapperPimpl : CBase + { + +public: // construction / destruction + + /** + * Static NewL + * + * @param none + * @return instance to CUpnpGstWrapperPimpl + */ + static CUpnpGstWrapperPimpl* NewL(); + + /** + * Destructor + */ + ~CUpnpGstWrapperPimpl(); + +private: + + /** + * Constructor + */ + CUpnpGstWrapperPimpl(); + + /** + * 2nd phrase Constructor + */ + void ConstructL(); + +public: + + inline void SetPipeline( GstElement* aPipeline ); + + inline GstElement* Pipeline(); + + inline void SetDemuxer( GstElement* aDemuxer ); + + inline GstElement* Demuxer(); + + inline void InitAppSinkL(); + + inline TBool PullBufferL( TPtr8& aPointer,TInt aMaxBytesLength, RBuf8* aBuf ); + + inline TInt TranscodedBytes(); + +public: //callbacks + + /** + * A function to receive any message occured within the pipeline + * Note that the function will be called in the same thread context as + * the posting object. + * + * @param GstBus* a bus to create the watch for + * @param GstMessage* a message created within the pipeline + * @param gponter the user data that has been given, + * when registering the handler + * @return GstBusSyncReply indicates whether the message is also added + * into async queue (after this callback) or dropped + */ + static GstBusSyncReply SyncBusCallback( GstBus* aBus, GstMessage* aMsg, + gpointer aData ); + + /** + * A function to receive callback from demuxer whenever source pad is + * added into it + * + * @param GstElement* an element (demuxer) where the source pad was added + * @param GstPad* a souce pad that was added + * @param gponter the user data that has been given, + * when registering the handler + */ + static void DemuxPadAddedCallback( GstElement* aElement, GstPad* aPad, + gpointer aData ); + + /** + * Internal log handler. + * Implements GStreamer's log handler callback. + * Ouputs GStreamer debug traces if DEBUG_ENABLE flag is enabled in + * GStreamer. + */ + static void LogCallback( GstDebugCategory *category, GstDebugLevel level, + const gchar *file, const gchar *function, gint line, + GObject *object, GstDebugMessage *message, gpointer data ); + +private: + + GstElement* iPipeline; + GstElement* iDemuxer; + + TInt iBytesOffSet; + + GstElement* iAppsink; + + GstElement* iElement; + + GstBuffer* iGstBuffer; + + }; + +// -------------------------------------------------------------------------- +// CUpnpGstWrapperPimpl::NewL +//--------------------------------------------------------------------------- +CUpnpGstWrapperPimpl* CUpnpGstWrapperPimpl::NewL() + { + __FUNC_LOG; + + CUpnpGstWrapperPimpl* self = new( ELeave ) CUpnpGstWrapperPimpl(); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapperPimpl::~CUpnpGstWrapperPimpl +//--------------------------------------------------------------------------- +CUpnpGstWrapperPimpl::~CUpnpGstWrapperPimpl() + { + __FUNC_LOG; + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapperPimpl::CUpnpGstWrapperPimpl +//--------------------------------------------------------------------------- +CUpnpGstWrapperPimpl::CUpnpGstWrapperPimpl() + { + __FUNC_LOG; + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapperPimpl::ConstructL +//--------------------------------------------------------------------------- +void CUpnpGstWrapperPimpl::ConstructL() + { + __FUNC_LOG; + } + +void CUpnpGstWrapperPimpl::SetPipeline( GstElement* aPipeline ) + { + __FUNC_LOG; + + iPipeline = aPipeline; + } + +GstElement* CUpnpGstWrapperPimpl::Pipeline() + { + __FUNC_LOG; + return iPipeline; + } + +void CUpnpGstWrapperPimpl::SetDemuxer( GstElement* aDemuxer ) + { + __FUNC_LOG; + + iDemuxer = aDemuxer; + } + +GstElement* CUpnpGstWrapperPimpl::Demuxer() + { + __FUNC_LOG; + + return iDemuxer; + } + +void CUpnpGstWrapperPimpl::InitAppSinkL() + { + iAppsink = gst_bin_get_by_name ( + GST_BIN ( iPipeline ), "sinkbuffer"); + + if( !iAppsink ) + User::Leave( KErrNotFound); + + g_object_set ( + G_OBJECT (iAppsink), "emit-signals", TRUE, "sync", FALSE, NULL); + gst_object_unref (iAppsink); + } + +TBool CUpnpGstWrapperPimpl::PullBufferL( TPtr8& aPointer,TInt aMaxBytesLength, RBuf8* aBuf ) + { + guint size; + + if( iGstBuffer ) + { + delete [] GST_BUFFER_DATA(iGstBuffer); + GST_BUFFER_DATA(iGstBuffer) = NULL; + } + + iGstBuffer = gst_app_sink_pull_buffer( GST_APP_SINK ( iAppsink )); + + if( iGstBuffer ) + { + size = GST_BUFFER_SIZE( iGstBuffer ); + + iBytesOffSet += size; + + if( aBuf && ( size + aBuf->Length() ) > aBuf->MaxLength() ) + { + HBufC8* tmp(NULL); + TInt len(aBuf->Length()); + if( len > 0 ) + { + tmp = aBuf->AllocLC(); + } + aBuf->Close(); + aBuf->CreateL(size+len); + if( tmp ) + { + aBuf->Append(*tmp); + CleanupStack::PopAndDestroy(tmp); + } + + aBuf->Append( (TUint8*)GST_BUFFER_DATA(iGstBuffer),size ); + } + else + { + __ASSERT( (aMaxBytesLength >= size), __FILE__, __LINE__ ); + aPointer.Set((TUint8*)GST_BUFFER_DATA(iGstBuffer),size,aMaxBytesLength); + } + } + return ( iGstBuffer ) ? EFalse : ETrue; + } + +TInt CUpnpGstWrapperPimpl::TranscodedBytes() + { + return iBytesOffSet; + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapperPimpl::SyncBusCallback +//--------------------------------------------------------------------------- +GstBusSyncReply CUpnpGstWrapperPimpl::SyncBusCallback( GstBus* /*aBus*/, + GstMessage* aMsg, gpointer aData ) + { + __FUNC_LOG; + + GstMessageType messageType = GST_MESSAGE_TYPE( aMsg ); + + if( messageType == GST_MESSAGE_EOS || + messageType == GST_MESSAGE_ERROR ) + { + __ASSERT( aData, __FILE__, __LINE__ ); + + CUpnpGstWrapper* parent = static_cast( aData ); + Gst::TEvent event = Gst::EUnknown; + + parent->iMutex.Wait(); + + switch( messageType ) + { + case GST_MESSAGE_EOS: + { + event = Gst::EEOS; + break; + } + case GST_MESSAGE_ERROR: + { + GError* err = NULL; + + char* debug; + gst_message_parse_error( aMsg, &err, &debug ); + g_free( debug ); + + if( err ) + { + TRAP_IGNORE( parent->SetErrorMsg( + parent->ConvertCharToDescL( + err->message ) ) ); + g_error_free( err ); + err = NULL; + } + event = Gst::EError; + break; + } + default: + { + __ASSERT( EFalse, __FILE__, __LINE__ ); + } + } + + parent->iEventQueue.Append( event ); + + __ASSERT( parent->IsActive(), __FILE__, __LINE__ ); + if( parent->iStatus == KRequestPending ) + { + TRequestStatus* status = &parent->iStatus; + RThread thread; + TInt err = thread.Open( parent->iClientThreadId ); + __ASSERT( !err, __FILE__, __LINE__ ); + + thread.RequestComplete( status, KErrNone ); + thread.Close(); + } + + parent->iMutex.Signal(); + + gst_message_unref( aMsg ); + } + + return GST_BUS_DROP; //do not add anything into async queue + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapperPimpl::DemuxPadAddedCallback +//--------------------------------------------------------------------------- +void CUpnpGstWrapperPimpl::DemuxPadAddedCallback( GstElement* /*aElement*/, + GstPad* aPad, gpointer aData ) + { + __FUNC_LOG; + __ASSERT( aData, __FILE__, __LINE__ ); + + CUpnpGstWrapper* parent = static_cast( aData ); + + GstCaps* caps = gst_pad_get_caps( aPad ); + char* str = gst_caps_to_string( caps ); + Gst::TEvent event = Gst::EUnknown; + + parent->iMutex.Wait(); + + if( g_str_has_prefix( str, KMimeTypeVideo ) ) + { + delete parent->iVideoInfo; parent->iVideoInfo = NULL; + TRAPD( err, parent->iVideoInfo = parent->ConvertCharToDescL( str ) ); + if( !err ) + { + event = Gst::EVideoStreamInfoAvailable; + } + else + { + event = Gst::EError; + TRAP_IGNORE( parent->SetErrorMsgL( KOutOfMemoryErrorMsg ) ); + } + } + else if( g_str_has_prefix( str, KMimeTypeAudio ) ) + { + delete parent->iAudioInfo; parent->iAudioInfo = NULL; + TRAPD( err, parent->iAudioInfo = parent->ConvertCharToDescL( str ) ); + if( !err ) + { + event = Gst::EAudioStreamInfoAvailable; + } + else + { + event = Gst::EError; + TRAP_IGNORE( parent->SetErrorMsgL( KOutOfMemoryErrorMsg ) ); + } + } + else + { + __ASSERT( EFalse, __FILE__, __LINE__ ); + } + + parent->iEventQueue.Append( event ); + + __ASSERT( parent->IsActive(), __FILE__, __LINE__ ); + if( parent->iStatus == KRequestPending ) + { + TRequestStatus* status = &parent->iStatus; + RThread thread; + TInt err = thread.Open( parent->iClientThreadId ); + __ASSERT( !err, __FILE__, __LINE__ ); + + thread.RequestComplete( status, KErrNone ); + thread.Close(); + } + + parent->iMutex.Signal(); + + g_free(str); + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapperPimpl::LogCallback +//--------------------------------------------------------------------------- +void CUpnpGstWrapperPimpl::LogCallback( GstDebugCategory* category, + GstDebugLevel level, const char* file, const char* function, + gint line, GObject* /*object*/, GstDebugMessage* message, + gpointer /*data*/ ) + { + if (level > gst_debug_category_get_threshold (category)) + { + return; + } + +#ifndef __UPNP_LOG_FILE + const char* const KGstLogFmt = "%s %20s %s:%d:%s %s\n"; + RDebug::Printf( KGstLogFmt, + gst_debug_level_get_name (level), + gst_debug_category_get_name (category), file, line, function, + gst_debug_message_get (message) ); +#else + _LIT8( KGstLogFmtDesc, "%s %20s %s:%d:%s %s\n" ); + RFileLogger::WriteFormat( KLogDir, KComponentLogfile, + EFileLoggingModeAppend, KGstLogFmtDesc, + gst_debug_level_get_name (level), + gst_debug_category_get_name (category), file, line, function, + gst_debug_message_get (message) ); +#endif + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::GetInstanceL +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +EXPORT_C CUpnpGstWrapper* CUpnpGstWrapper::GetInstanceL() + { + CUpnpGstWrapper* singleton = static_cast( Dll::Tls() ); + if ( singleton == 0 ) + { + // singleton must be created first + singleton = new ( ELeave ) CUpnpGstWrapper(); + CleanupStack::PushL( singleton ); + singleton->ConstructL(); + User::LeaveIfError( Dll::SetTls( singleton ) ); + CleanupStack::Pop( singleton ); + } + singleton->iSingletonRefCount++; + + return singleton; + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::Close +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +EXPORT_C void CUpnpGstWrapper::Close() + { + if(--iSingletonRefCount == 0) + { + Dll::FreeTls(); + delete this; + } + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::~CUpnpGstWrapper +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +EXPORT_C CUpnpGstWrapper::~CUpnpGstWrapper() + { + __FUNC_LOG; + + Stop(); + + Cancel(); + + gst_deinit(); + + delete iErrorMsg; + delete iVideoInfo; + delete iAudioInfo; + + iEventQueue.Close(); + iMutex.Close(); + iObservers.Close(); + + delete iPimpl; + delete iPipeline; + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::CUpnpGstWrapper +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +CUpnpGstWrapper::CUpnpGstWrapper() + : CActive( EPriorityStandard ) + , iDuration( KErrNotFound ) + { + __FUNC_LOG; + + CActiveScheduler::Add( this ); + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::ConstructL +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +void CUpnpGstWrapper::ConstructL() + { + __FUNC_LOG; + + iPimpl = CUpnpGstWrapperPimpl::NewL(); + + iMutex.CreateLocal(); + + RThread thread; + iClientThreadId = thread.Id(); + + /* + * Install our own log handler + * FIXME: After this there is two log handlers: + * + * Default: Uses glib's g_printerr() that prints + * RDebug::RawPrints ONLY in full udeb mode + * Our own: See behaviour in LogCallback function below + * + * We should somehow get rid of the default one... + */ + gst_debug_add_log_function( CUpnpGstWrapperPimpl::LogCallback, this ); + + __LOG( "Initializing GStreamer..." ); + gst_init( NULL, NULL ); + __LOG( "GStreamer initialization done!" ); + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::SetObserverL +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +EXPORT_C void CUpnpGstWrapper::SetObserverL( + MUpnpGstWrapperObserver& aObserver ) + { + if( iObservers.Find( &aObserver ) < 0 ) + { + iObservers.AppendL( &aObserver ); + } + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::RemoveObserverL +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +EXPORT_C void CUpnpGstWrapper::RemoveObserver( + MUpnpGstWrapperObserver& aObserver ) + { + TInt index = iObservers.Find( &aObserver ); + if( index >= 0 ) + { + iObservers.Remove( index ); + } + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::StartL +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +EXPORT_C void CUpnpGstWrapper::StartL() + { + __FUNC_LOG; + + if( !iPipeline ) + { + SetErrorMsgL( KAlreadyInUseErrorMsg ); + User::Leave( KErrNotReady ); + } + + //Create pipeline according to the input description + char* pipelineStr = ConvertDescToCharL( *iPipeline ); + + GError* err = NULL; + /** + * Create a new pipeline based on command line syntax. + * Please note that you might get a return value that is not NULL even + * though the error is set. In this case there was a recoverable + * parsing error and you can try to play the pipeline + */ + __LOG( "Parsing GStreamer pipeline..." ); + GstElement* pipeline = gst_parse_launch( pipelineStr, &err ); + __LOG( "GStreamer pipeline parsing done!" ); + User::Free( pipelineStr ); + + if( err ) + { + SetErrorMsg( ConvertCharToDescL( err->message ) ); + g_error_free( err ); + err = NULL; + User::Leave( KErrGeneral ); + } + + iPimpl->SetPipeline( pipeline ); + + //TODO: Hardcoded demuxer name 'KDemuxerName -> should be fetched somehow + //dynamically ?? + GstElement* demuxer = gst_bin_get_by_name( GST_BIN( pipeline ), + KDemuxerName ); + + //If a demuxer is found, create 'pad-added' callback; else do nothing + if( demuxer ) + { + g_signal_connect( demuxer, "pad-added", + G_CALLBACK( CUpnpGstWrapperPimpl::DemuxPadAddedCallback ), + this ); + iPimpl->SetDemuxer( demuxer ); + } + + GstBus* bus = NULL; + bus = gst_pipeline_get_bus( GST_PIPELINE( pipeline ) ); + if( !bus ) + { + //unknown error + User::Leave(KErrGeneral); + } + + if( !IsActive() ) + { + iStatus = KRequestPending; + SetActive(); + } + + gst_bus_set_sync_handler( bus, CUpnpGstWrapperPimpl::SyncBusCallback, this ); + + gst_object_unref( bus ); + + gst_element_set_state( pipeline, GST_STATE_PLAYING ); + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::Stop +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +EXPORT_C void CUpnpGstWrapper::Stop() + { + __FUNC_LOG; + GstElement* demuxer = iPimpl->Demuxer(); + if( demuxer ) + { + gst_object_unref( GST_OBJECT( demuxer ) ); + iPimpl->SetDemuxer( NULL ); + } + + GstElement* pipeline = iPimpl->Pipeline(); + if( pipeline ) + { + gst_element_set_state( pipeline, GST_STATE_NULL ); + gst_object_unref( GST_OBJECT( pipeline ) ); + iPimpl->SetPipeline( NULL ); + } + //Cancel(); + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::ErrorMsg +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +EXPORT_C const TDesC& CUpnpGstWrapper::ErrorMsg() + { + __FUNC_LOG; + + if( iErrorMsg ) + { + return *iErrorMsg; + } + else + { + return KUnknownErrorErrorMsg(); + } + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::FeatureListL +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +EXPORT_C CDesCArray* CUpnpGstWrapper::FeatureListL() + { + __FUNC_LOG; + + CDesCArray* array = new (ELeave) CDesCArrayFlat( 5 ); + CleanupStack::PushL( array ); + + GList* features = gst_registry_get_feature_list( + gst_registry_get_default(), GST_TYPE_ELEMENT_FACTORY ); + while( features ) + { + GstPluginFeature* feature = (GstPluginFeature*)features->data; + HBufC* tempBuf = ConvertCharToDescL( gst_plugin_feature_get_name( + feature ) ); + CleanupStack::PushL( tempBuf ); + array->AppendL( *tempBuf ); + CleanupStack::PopAndDestroy( tempBuf ); + features = features->next; + } + + CleanupStack::Pop( array ); + return array; + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::VideoInfo +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +EXPORT_C const TDesC& CUpnpGstWrapper::VideoInfo() + { + __FUNC_LOG; + + if( iVideoInfo ) + { + return *iVideoInfo; + } + else + { + return KNullDesC; + } + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::AudioInfo +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +EXPORT_C const TDesC& CUpnpGstWrapper::AudioInfo() + { + __FUNC_LOG; + + if( iAudioInfo ) + { + return *iAudioInfo; + } + else + { + return KNullDesC; + } + } +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::Position +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +EXPORT_C TInt64 CUpnpGstWrapper::Position() + { + __FUNC_LOG; + + GstFormat fmt = GST_FORMAT_TIME; + TInt64 position = KErrNotFound; + + //fetch position from pipeline (not from the demuxer) + GstElement* pipeline = iPimpl->Pipeline(); + + if( pipeline ) + { + gst_element_query_position( pipeline, &fmt, &position ); + } + + return position; + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::Duration +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +EXPORT_C TInt64 CUpnpGstWrapper::Duration() + { + __FUNC_LOG; + + if( iDuration < 0 ) + { + GstFormat fmt = GST_FORMAT_TIME; + if( iPimpl->Demuxer() ) + { + //fetch duration from demuxer + gst_element_query_duration( iPimpl->Demuxer(), &fmt, &iDuration ); + } + else if( iPimpl->Pipeline() ) + { + //backup plan: not so good choice as demuxer + gst_element_query_position( iPimpl->Pipeline(), &fmt, &iDuration ); + } + } + + return iDuration; + } + +EXPORT_C TAny* CUpnpGstWrapper::PipelinePtr() + { + return iPimpl->Pipeline(); + } + +EXPORT_C void CUpnpGstWrapper::InitAppsinkL() + { + iPimpl->InitAppSinkL(); + } + +EXPORT_C TBool CUpnpGstWrapper::PullBufferL( TPtr8& aPointer,TInt aMaxBytesLength, RBuf8* aBuf ) + { + return iPimpl->PullBufferL(aPointer,aMaxBytesLength,aBuf); + } + +EXPORT_C TInt CUpnpGstWrapper::TranscodedBytes() + { + return iPimpl->TranscodedBytes(); + } + +EXPORT_C void CUpnpGstWrapper::SetTranscodedFileSize( TInt aSize ) + { + iFileSize = aSize; + } + +EXPORT_C TInt CUpnpGstWrapper::TranscodedFileSize() + { + return iFileSize; + } + +EXPORT_C void CUpnpGstWrapper::SetPipelineL( const TDesC8& aPipeline ) + { + delete iPipeline; + iPipeline = NULL; + iPipeline = aPipeline.AllocL(); + } + + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::SetErrorMsgL +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +void CUpnpGstWrapper::SetErrorMsgL( const TDesC& aErrorMsg ) + { + __FUNC_LOG; + + delete iErrorMsg; iErrorMsg = NULL; + iErrorMsg = aErrorMsg.AllocL(); + + __LOG1( "CUpnpGstWrapper::SetErrorMsgL Error desc: %S", iErrorMsg ); + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::SetErrorMsg +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +void CUpnpGstWrapper::SetErrorMsg( HBufC* const aErrorMsg ) + { + delete iErrorMsg; iErrorMsg = NULL; + iErrorMsg = aErrorMsg; + + __LOG1( "CUpnpGstWrapper::SetErrorMsg Error desc: %S", iErrorMsg ); + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::ConvertCharToDescL +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +HBufC* CUpnpGstWrapper::ConvertCharToDescL( const char* aString ) + { + __FUNC_LOG; + + HBufC* desc = NULL; + TPtrC8 tempPtr8( (TUint8*)(aString) ); + desc = HBufC::NewL( tempPtr8.Length() ); + desc->Des().Copy( tempPtr8 ); + + return desc; + } + + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::ConvertDescToCharL +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +char* CUpnpGstWrapper::ConvertDescToCharL( const TDesC8& aDescriptor ) + { + __FUNC_LOG; + + TUint length = aDescriptor.Length(); + char* string = (char*)User::AllocL( length + 1 ); + Mem::Copy((char*)string, aDescriptor.Ptr(), length ); + string[length] = 0; //null terminated + return string; + } + +void CUpnpGstWrapper::SendEventToObsevers( Gst::TEvent aEvent ) + { + __FUNC_LOG; + + TInt observerCount = iObservers.Count(); + for( TInt i = 0; i < observerCount; i++ ) + { + iObservers[i]->HandleGstEvent( aEvent ); + } + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::RunL +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +void CUpnpGstWrapper::RunL() + { + __FUNC_LOG; + if( iStatus.Int() >= KErrNone ) + { + TBool completed = EFalse; + + iMutex.Wait(); + + TInt eventQueueCount = iEventQueue.Count(); + for( TInt i = 0; i < eventQueueCount; i++ ) + { + Gst::TEvent event = iEventQueue[i]; + SendEventToObsevers( event ); + if( event == Gst::EEOS || event == Gst::EError ) + { + __LOG1( "CUpnpGstWrapper::RunL Completed: %d (2=Error, 3=EOS)", + event); + completed = ETrue; + } + } + iEventQueue.Reset(); + + if( !completed ) + { + iStatus = KRequestPending; + SetActive(); + } + iMutex.Signal(); + } + } + +// -------------------------------------------------------------------------- +// CUpnpGstWrapper::DoCancel +// See upnpgstwrapper.h +//--------------------------------------------------------------------------- +void CUpnpGstWrapper::DoCancel() + { + __FUNC_LOG; + } + +// end of file