multimediacommscontroller/mmccsubcontroller/src/mcculdatapath.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccsubcontroller/src/mcculdatapath.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,508 @@
+/*
+* Copyright (c) 2004-2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:    Uplink (record) datapath
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include <mmf/common/mmfcontroller.h>
+#include "mcculdatapath.h"
+#include "mccsubcontrollerlogs.h"
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::CMccUlDataPath
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+CMccUlDataPath::CMccUlDataPath( 
+    MAsyncEventHandler* aEventHandler, 
+    MMccResources* aMccResources,
+    TMediaId aMediaId  ) : 
+    CMccDataPathBase( aEventHandler, aMccResources, aMediaId )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+void CMccUlDataPath::ConstructL()
+    {
+	__SUBCONTROLLER( "CMccUlDataPath::ConstructL" )
+    __ASSERT_ALWAYS( iEventHandler, User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS( iMccResources, User::Leave( KErrArgument ) );
+	__SUBCONTROLLER( "CMccUlDataPath::ConstructL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::NewL
+// Static constructor.
+// -----------------------------------------------------------------------------
+CMccUlDataPath* CMccUlDataPath::NewL( 
+    MAsyncEventHandler* aEventHandler, 
+    MMccResources* aMccResources,
+    TMediaId aMediaId )
+    {
+    __ASSERT_ALWAYS ( aEventHandler, User::Leave(KErrArgument) );
+    CMccUlDataPath* self = 
+        new ( ELeave ) CMccUlDataPath( aEventHandler, aMccResources, aMediaId );
+    
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::~CMccUlDataPath
+// Destructor
+// ----------------------------------------------------------------------------- 
+CMccUlDataPath::~CMccUlDataPath()
+    {
+	__SUBCONTROLLER( "CMccUlDataPath::~CMccUlDataPath" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::PrimeL
+// Primes the datapath
+// -----------------------------------------------------------------------------
+void CMccUlDataPath::PrimeL( TUint32 aEndpointId )
+    {
+	__SUBCONTROLLER( "CMccUlDataPath::PrimeL" )
+	
+	__ASSERT_ALWAYS( iDataPathCreated, User::Leave( KErrNotReady ) );
+    __ASSERT_ALWAYS( iDataSource, User::Leave( KErrGeneral ) );
+    __ASSERT_ALWAYS( iDataSink, User::Leave( KErrGeneral ) );
+    
+    if ( !iSinkBuffer )
+        {
+        TBool bufferReference;
+        iSinkBuffer = iDataSink->CreateSinkBufferL( iMediaId, bufferReference );
+        __ASSERT_ALWAYS ( iSinkBuffer, User::Leave( KErrGeneral ) );
+        __ASSERT_ALWAYS ( bufferReference, User::Leave( KErrGeneral ) );
+        }
+        
+    if ( ControlSink( aEndpointId ) )
+        {
+        __SUBCONTROLLER( "CMccUlDataPath::PrimeL, control sink" )
+
+        iDataSink->SinkPrimeL();
+        }
+        
+    if ( ControlSource( aEndpointId ) )
+        {
+        __SUBCONTROLLER( "CMccUlDataPath::PrimeL, control source" )
+        
+        SetStateL( EPrimed );
+        
+        iDataSource->SourcePrimeL();
+        }
+
+    CreateCompleteCallBackL();
+
+	__SUBCONTROLLER( "CMccUlDataPath::PrimeL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccDlDataPath::PauseL
+// Pauses the uplink streaming
+// -----------------------------------------------------------------------------
+void CMccUlDataPath::PauseL( TUint32 aEndpointId )
+    {
+	__SUBCONTROLLER( "CMccUlDataPath::PauseL" )
+	
+	__ASSERT_ALWAYS( iDataPathCreated, User::Leave( KErrNotReady ) );
+    __ASSERT_ALWAYS( iDataSource, User::Leave( KErrGeneral ) );
+    __ASSERT_ALWAYS( iDataSink, User::Leave( KErrGeneral ) );
+        
+    if ( ControlSink( aEndpointId ) )
+        {
+        __SUBCONTROLLER( "CMccUlDataPath::PauseL, control sink" )
+
+        iDataSink->SinkPauseL();
+        }
+    
+    if ( ControlSource( aEndpointId ) )
+        {   
+        __SUBCONTROLLER( "CMccUlDataPath::PauseL, control source" )
+        
+        SetStateL( EPaused );
+        
+        if ( IsMmfEndpoint( iAssociatedSource ) )
+            {
+            __SUBCONTROLLER( "CMccUlDataPath::PauseL, stop mmf source" )
+            
+            // Resource has to be freed
+            iDataSource->SourceStopL(); 
+            }
+        else
+            {
+            iDataSource->SourcePauseL();
+            }        
+        } 
+        
+    if ( State() == EPaused )
+        {                
+        iSinkBuffer = NULL;
+            
+        // Pause the whole path       
+        Cancel();
+        
+        ChangeDataPathTransferState( ECanceled );
+        }
+
+	__SUBCONTROLLER( "CMccUlDataPath::PauseL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::PlayL
+// Starts the uplink playing
+// -----------------------------------------------------------------------------
+void CMccUlDataPath::PlayL( TUint32 aEndpointId )
+    {
+	__SUBCONTROLLER( "CMccUlDataPath::PlayL" )
+	
+	__ASSERT_ALWAYS( iDataPathCreated, User::Leave( KErrNotReady ) );
+    __ASSERT_ALWAYS( iDataSource, User::Leave( KErrGeneral ) );
+    __ASSERT_ALWAYS( iDataSink, User::Leave( KErrGeneral ) );
+    __ASSERT_ALWAYS( iSinkBuffer, User::Leave( KErrGeneral ) );
+           
+    iDataPathCompletedErrorCode = KErrNone; 
+         
+    if ( ControlSink( aEndpointId ) )
+        {
+        __SUBCONTROLLER( "CMccUlDataPath::PlayL, control sink" )
+
+        iDataSink->SinkPlayL();
+        }
+    
+    if ( ControlSource( aEndpointId ) )
+        {
+        __SUBCONTROLLER( "CMccUlDataPath::PlayL, control source" )
+        
+        SetStateL( EStreaming );
+        
+        iDataSource->SourcePlayL();
+        }
+        
+    if ( State() == EStreaming && ChangeDataPathTransferState( ENeedSourceData ) )
+        {                
+        ActivateSinkBuffer();
+        }
+
+	__SUBCONTROLLER( "CMccUlDataPath::PlayL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::BufferEmptiedL
+// Buffer has been emptied callback
+// -----------------------------------------------------------------------------
+void CMccUlDataPath::BufferEmptiedL( CMMFBuffer* aBuffer )
+    {
+	__ASSERT_ALWAYS ( aBuffer, User::Leave(KErrArgument) );
+	
+    // This is the buffer emptied by payload format encoder
+    // If it returns NULL buffer then something serious has happened
+    // The NULL buffer is cheked in the IsBufferSupportedL() function
+    IsBufferSupportedL( aBuffer );
+
+    //Has the datapath stopped running, if so were not interested in any callbacks.
+    if( EStreaming == State() )
+        {
+        if ( iSinkBuffer != aBuffer ) //buffer has been updated
+            {
+            iSinkBuffer = aBuffer;
+            }     
+
+        iSinkBuffer->SetStatus( EAvailable );
+        ChangeDataPathTransferState( ENeedSourceData );
+        }
+    else
+        {
+        User::Leave( KErrNotReady );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::BufferFilledL
+// Databuffer filled callback
+// -----------------------------------------------------------------------------
+void CMccUlDataPath::BufferFilledL( CMMFBuffer* aBuffer )
+    {
+    // Has the datapath stopped running, if so were not interested in any
+    // callbacks.
+    if( EStreaming == State() )
+        {
+        if ( !aBuffer )
+            {
+            ChangeDataPathTransferState( EEndOfData );
+            }
+        else
+            {
+            // Sink buffer is with datapath, see if there is anything to send
+            // to sink
+	        IsBufferSupportedL( aBuffer );
+	        aBuffer->SetStatus( EFull );
+	        
+	        if ( iSinkBuffer != aBuffer )
+		        {
+	            CMMFDataBuffer* desBuffer = static_cast<CMMFDataBuffer*>(iSinkBuffer);
+		        if ( (TInt) aBuffer->BufferSize() > desBuffer->Data().MaxLength() )	
+			        {
+			        // if the buffer from source is too big, ignore it
+			        // ask next one
+                    __SUBCONTROLLER( "CMccUlDataPath::BufferFilledL, DATA IGNORED" )
+                    __SUBCONTROLLER_INT1( "CMccUlDataPath::BufferFilledL, source", aBuffer->BufferSize() )
+                    __SUBCONTROLLER_INT1( "CMccUlDataPath::BufferFilledL, dest", desBuffer->Data().MaxLength() )
+			        iSinkBuffer->SetStatus( EAvailable );
+			        aBuffer->SetStatus( EAvailable );
+		            ChangeDataPathTransferState( ENeedSourceData );	
+		            return;
+			        }
+			    else
+				    {
+				   	CopyBuffer( iSinkBuffer, aBuffer );
+				    }
+		        }
+		    
+		    if( !aBuffer->BufferSize() || aBuffer->LastBuffer() )
+			    {
+			    //ignore zero length buffer request for next buffer from AudioInput
+		        iSinkBuffer->SetStatus( EAvailable );
+
+		        ChangeDataPathTransferState( ENeedSourceData, ETrue );	
+			    }
+			else
+				{
+				ChangeDataPathTransferState( ESendDataToSink );	
+				}
+            }
+        }
+    else
+        {
+        User::Leave( KErrNotReady );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::FillSourceBufferL
+// Fill the source buffer
+// -----------------------------------------------------------------------------
+void CMccUlDataPath::FillSourceBufferL()
+    {
+    __ASSERT_ALWAYS( iSinkBuffer, User::Leave( KErrNotReady ) );
+    
+    iSinkBuffer->SetStatus( EBeingFilled );
+    iSinkBuffer->SetLastBuffer( EFalse );
+
+    // wait for BufferFilled callback from source. Do this here as some sources cause
+    // re-entrancy into data path via BufferFilledL
+    ChangeDataPathTransferState( EWaitSource );
+    
+	iDataSource->FillBufferL( iSinkBuffer, this, iMediaId );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::EmptySinkBufferL
+// Empty the sink buffer
+// -----------------------------------------------------------------------------
+void CMccUlDataPath::EmptySinkBufferL()
+    {
+    __ASSERT_ALWAYS( iSinkBuffer, User::Leave( KErrNotReady ) );
+    
+    ChangeDataPathTransferState( EWaitSink );  
+
+    iSinkBuffer->SetStatus( EFull );
+    TRAPD( error, iDataSink->EmptyBufferL( iSinkBuffer, this, iMediaId ) );
+
+    if ( KErrEof == error || KErrOverflow == error || KErrUnderflow == error )
+        {
+        iDataPathCompletedErrorCode = error;
+        ChangeDataPathTransferState( EEndOfData );
+        }
+    else
+	    {
+	   	User::LeaveIfError( error );
+	    }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::DoEndOfData
+// Worker function for data ending
+// -----------------------------------------------------------------------------
+void CMccUlDataPath::DoEndOfDataL()
+    {
+    if ( KErrNone == iDataPathCompletedErrorCode )
+        {
+        iDataPathCompletedErrorCode = KErrCompletion;
+        }
+
+    SignalDataPathCompleteL( iDataPathCompletedErrorCode );
+
+    SetStateL( EStopped );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::Stop
+// Stop the datapath
+// -----------------------------------------------------------------------------
+void CMccUlDataPath::StopL( TUint32 aEndpointId )
+    {   
+	__SUBCONTROLLER( "CMccUlDataPath::StopL" )
+    
+    __ASSERT_ALWAYS( iDataPathCreated, User::Leave( KErrNotReady ) );
+	__ASSERT_ALWAYS( iDataSource, User::Leave( KErrGeneral ) );
+    __ASSERT_ALWAYS( iDataSink, User::Leave( KErrGeneral ) );
+
+    iDataPathCompletedErrorCode = KErrNone;
+            
+    if ( ControlSink( aEndpointId ) )
+        {
+        __SUBCONTROLLER( "CMccUlDataPath::StopL, control sink" )
+
+        iDataSink->SinkStopL();                  
+        }
+    
+    if ( ControlSource( aEndpointId ) )
+        {
+        __SUBCONTROLLER( "CMccUlDataPath::StopL, control source" )
+        
+        SetStateL( EStopped ); 
+        
+        iDataSource->SourceStopL();  
+        }
+        
+    if ( State() == EStopped )
+        {
+        iSinkBuffer = NULL;   
+    
+        // Stop the whole path    
+        Cancel();
+        
+        ChangeDataPathTransferState( ECanceled );
+        }
+    
+	__SUBCONTROLLER( "CMccUlDataPath::StopL, exit" )
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::NegotiateL
+// Negotiate the source and sink
+// -----------------------------------------------------------------------------
+void CMccUlDataPath::NegotiateL( MDataSink& aDataSink )
+    {
+    __SUBCONTROLLER( "CMccUlDataPath::NegotiateL" )
+    __ASSERT_ALWAYS( iDataSource, User::Leave( KErrNotReady ) );
+    __ASSERT_ALWAYS( &aDataSink, User::Leave( KErrArgument ) );
+    	
+    // NegotiateL call will lead to a re-entry so we need to have iDataSink set
+    // for it to succeed.
+    iDataSink = &aDataSink;
+	iDataSink->NegotiateL( *iDataSource );
+    iDataSink = NULL;
+    this->AddDataSinkL( &aDataSink );
+    
+    __SUBCONTROLLER( "CMccUlDataPath::NegotiateL exit" )
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::LoadL
+// -----------------------------------------------------------------------------
+void CMccUlDataPath::LoadL( MDataSink& aDataSink )
+    {
+	__SUBCONTROLLER( "CMccUlDataPath::LoadL" )
+	
+    __ASSERT_ALWAYS( iDataSource, User::Leave( KErrNotReady ) );
+    iDataSource->NegotiateSourceL( aDataSink );
+    
+	__SUBCONTROLLER( "CMccUlDataPath::LoadL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::ResumeL
+// Resumes pause audio streaming
+// -----------------------------------------------------------------------------
+void CMccUlDataPath::ResumeL( TUint32 aEndpointId )
+    {
+	__SUBCONTROLLER( "CMccUlDataPath::ResumeL" )
+	
+    __ASSERT_ALWAYS( iDataPathCreated, User::Leave( KErrNotReady ) );
+	__ASSERT_ALWAYS( iDataSource, User::Leave( KErrGeneral ) );
+    __ASSERT_ALWAYS( iDataSink, User::Leave( KErrGeneral ) );
+    
+    iDataPathCompletedErrorCode = KErrNone;
+                
+    if ( ControlSink( aEndpointId ) )
+        {       
+        __SUBCONTROLLER( "CMccUlDataPath::ResumeL, control sink" )
+
+        iDataSink->SinkPlayL();
+        }
+        
+    if ( ControlSource( aEndpointId ) )
+        {
+        __SUBCONTROLLER( "CMccUlDataPath::ResumeL, control source" )
+        
+        SetStateL( EStreaming );
+        
+        if ( IsMmfEndpoint( iAssociatedSource ) )
+            {
+            __SUBCONTROLLER( "CMccUlDataPath::ResumeL, prime mmf source" )
+            
+            // Resource was freed at pause, initialize it again
+            iDataSource->SourcePrimeL(); 
+            }
+
+        iDataSource->SourcePlayL();  
+        }
+        
+    if ( State() == EStreaming && ChangeDataPathTransferState( ENeedSourceData ) )
+        {
+        iSinkBuffer = NULL;
+        TBool bufferReference;
+        iSinkBuffer = iDataSink->CreateSinkBufferL( iMediaId, bufferReference );
+        __ASSERT_ALWAYS( iSinkBuffer, User::Leave( KErrGeneral ) );
+        __ASSERT_ALWAYS( bufferReference, User::Leave( KErrGeneral ) );
+        
+        ActivateSinkBuffer();
+        }
+    
+	__SUBCONTROLLER( "CMccUlDataPath::ResumeL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccUlDataPath::ActivateSinkBuffer
+// Sets sink buffer available
+// -----------------------------------------------------------------------------    
+void CMccUlDataPath::ActivateSinkBuffer()
+    {
+    if ( iSinkBuffer )
+        {
+        iSinkBuffer->SetStatus( EAvailable );
+        }
+    }
+
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+//  End of File