www.pudn.com > Full-Duplex_Audio_Example.rar > inputstreamthread.cpp


/* 
* ============================================================================= 
*  Name        : InputStreamThread.cpp 
*  Part of     : FullDuplexEx 
*  Description : Implementation for thread that is responsible for handling 
                 audio input stream 
                  
*  Version     :  
* 
*  Copyright © 2007 Nokia. All rights reserved. 
*  This material, including documentation and any related  
*  computer programs, is protected by copyright controlled by  
*  Nokia. All rights are reserved. Copying, including  
*  reproducing, storing, adapting or translating, any  
*  or all of this material requires the prior written consent of  
*  Nokia. This material also contains confidential  
*  information which may not be disclosed to others without the  
*  prior written consent of Nokia. 
* ============================================================================= 
*/ 
 
#include "InputStreamThread.h" 
#include "ao.h" 
 
#include "filelogger.h" 
 
/****************************************************************************** 
* Method Name:  CInputStreamThread::CInputStreamThread 
* Description:  Standard Constructor 
******************************************************************************/ 
CInputStreamThread::CInputStreamThread(TSharedData& aData) 
: CFullDuplexEngineBase(), 
  iShared(aData) 
    { 
    } 
 
 
/****************************************************************************** 
* Method Name:  CInputStreamThread::NewL 
* Description:  Symbian two-phase constructor 
******************************************************************************/ 
CInputStreamThread* CInputStreamThread::NewL(TSharedData& aData) 
    {    
    CInputStreamThread* self = new (ELeave) CInputStreamThread(aData); 
    CleanupStack::PushL(self); 
    self->ConstructL(); 
    CleanupStack::Pop(); // self 
    return self; 
    } 
 
 
/****************************************************************************** 
* Method Name:  CInputStreamThread::ConstructL 
* Description:  Part two of Symbian two phase construction 
******************************************************************************/ 
void CInputStreamThread::ConstructL()  
    { 
    // create and install active scheduler for this thread 
    iActiveScheduler = new (ELeave) CActiveScheduler;    
    CActiveScheduler::Install(iActiveScheduler);     
 
    iMMFDevSound = CMMFDevSound::NewL(); 
     
    iAO = new (ELeave) CAO(this); 
    iAO->Request(); 
    } 
 
 
/****************************************************************************** 
* Method Name:  CInputStreamThread::~CInputStreamThread 
* Description:  Destructor 
******************************************************************************/ 
CInputStreamThread::~CInputStreamThread() 
    { 
    iAO->Cancel(); 
    delete iAO;  
    delete iMMFDevSound; 
    delete iActiveScheduler; 
    } 
 
 
/****************************************************************************** 
* Method Name:  CInputStreamThread::ThreadFunction( TAny* aData ) 
* Description:  Thread Startup function 
******************************************************************************/ 
TInt CInputStreamThread::ThreadFunction(TAny* aData) 
    { 
    // get a pointer to the shared data object 
    TSharedData& shared = *((TSharedData*)aData); 
     
    // create a cleanup stack 
    CTrapCleanup* cleanupStack = CTrapCleanup::New(); 
    if(cleanupStack == NULL) 
        { 
        return KErrNoMemory; 
        } 
         
    CInputStreamThread* devSoundThread = 0; 
    TRAPD(createErr, devSoundThread = CInputStreamThread::NewL(shared)); 
    __LOGSTR_TOFILE1("input_stream: ThreadFunc/create: %d", createErr); 
     
    if( createErr != KErrNone ) 
        { 
        shared.iThreadSync.Signal(); 
        return createErr; 
        } 
         
     
    shared.iStatusPtr = &(devSoundThread->iAO->iStatus); 
     
    // signal main thread that we're alive 
    shared.iThreadSync.Signal(); 
     
    // if we're still here, active scheduler has been constructed 
    // start wait loop which runs until it's time to end the thread     
    CActiveScheduler::Start(); 
         
    delete devSoundThread;     
    delete cleanupStack; 
     
    return KErrNone; 
    } 
 
 
/****************************************************************************** 
* Method Name:  CInputStreamThread::DoHandleException 
* Description:  Exception handler - main thread uses an active object (not  
*               actual exceptions) to pass commands to this thread 
******************************************************************************/ 
void CInputStreamThread::DoHandleException(TExcType aExc) 
    { 
    // handle "exceptions"     
    switch( aExc ) 
        { 
        case EExcUserInterrupt: 
            { 
            switch( iShared.iCmd ) 
                {                 
                case ECmdInitialize: 
                    {                     
                    __LOGSTR_TOFILE1("input_stream: Initialize: %d", Initialize()); 
                    break; 
                    } 
                case ECmdStartInputStream: 
                    { 
                    TRAPD(recErr, RecordL()); 
                    __LOGSTR_TOFILE1("input_stream: RecordL: %d", recErr); 
                    break; 
                    } 
                case ECmdStopInputStream: 
                    { 
                    Stop(); 
                    break; 
                    }                    
                case ECmdTerminateThread: 
                    { 
                    Stop();                     // signals ThreadSync mutex 
                    CActiveScheduler::Stop();   // will end wait loop  
                    break; 
                    } 
 
                } 
            break; 
            } 
        default: 
            { 
            // if unknown exception is raised, just exit this thread 
            CActiveScheduler::Stop(); 
            break; 
            } 
        } 
 
    } 
 
 
/****************************************************************************** 
* Method Name:  CInputStreamThread::InitializeL() 
* Description:  Initialises the DevSound with a hardware UID 
******************************************************************************/ 
TInt CInputStreamThread::Initialize() 
    { 
    TInt initError; 
    // delete and reconstruct devSound object 
    if(iStreamStatus == ERestartNeeded) 
        { 
        delete iMMFDevSound; 
        TRAP(initError, iMMFDevSound = CMMFDevSound::NewL()); 
        __LOGSTR_TOFILE1("input_stream: reinit: %d", initError); 
        if(initError) 
            return initError; 
        } 
     
    TRAP(initError, iMMFDevSound->InitializeL( *this,  
                                               iShared.iFourCC, 
                                               EMMFStateRecording)); 
                                                
    return initError; 
    } 
 
 
/****************************************************************************** 
* Method Name:  CInputStreamThread::RecordL() 
******************************************************************************/ 
void CInputStreamThread::RecordL() 
    { 
    if(iStreamStatus != EReady) 
        return; 
 
    iMMFDevSound->SetGain(iMMFDevSound->MaxGain()); 
    iMMFDevSound->RecordInitL(); 
    iStreamStatus = ERecording; 
    } 
 
 
/****************************************************************************** 
* Method Name:  CInputStreamThread::Stop() 
******************************************************************************/ 
void CInputStreamThread::Stop() 
    { 
    if(iStreamStatus == ERecording) 
        {   
        // stop the stream and signal the main thread 
        iMMFDevSound->Stop(); 
        iStreamStatus = EReady; 
        } 
     
    // main thread is waiting on this semaphore - signal to notify that 
    // the input stream has been stopped.            
    iShared.iThreadSync.Signal();     
    } 
     
 
/****************************************************************************** 
******************************** CALLBACKS ************************************ 
*******************************************************************************/ 
 
/****************************************************************************** 
* Method Name:  CInputStreamThread::InitializeComplete 
* Description:  CMMFDevSound callback when Initialization is complete 
******************************************************************************/ 
void CInputStreamThread::InitializeComplete(TInt aError)  
    { 
     
    if(aError == KErrNone) 
        { 
        iPrioritySettings.iPref = (TMdaPriorityPreference)KAudioPrefInput; 
        iPrioritySettings.iPriority = KAudioPriority; 
        iMMFDevSound->SetPrioritySettings(iPrioritySettings); 
 
        // set sample rate and channels 
        TMMFCapabilities conf; 
        conf = iMMFDevSound->Config(); 
         
        conf.iRate = EMMFSampleRate8000Hz; 
        conf.iChannels = EMMFMono; 
        TRAPD(configErr, iMMFDevSound->SetConfigL(conf)); 
        if(!configErr) 
            { 
            iStreamStatus = EReady;          
            } 
        __LOGSTR_TOFILE1("input_stream: init complete/config: %d", configErr); 
        } 
    else 
        { 
        __LOGSTR_TOFILE1("input_stream: init failed: %d", aError); 
        }     
    } 
 
 
/****************************************************************************** 
* Method Name:  CInputStreamThread::BufferToBeEmptied 
* Description:  CMMFDevSound callback when a buffer of data is ready to be 
*               consumed 
******************************************************************************/ 
void CInputStreamThread::BufferToBeEmptied(CMMFBuffer* aBuffer) 
    { 
    CMMFDataBuffer* buffer = static_cast(aBuffer); 
 
    // wait for access to the shared buffer 
    iShared.iMutex.Wait(); 
     
    // append data from MMF-side buffer to shared buffer 
    iShared.iBuffer->SetStatus(EBeingFilled); 
    if( iShared.iBuffer->BufferSize()+buffer->Data().Length() < KBufferLength ) 
        { 
        iShared.iBuffer->Data().Append(buffer->Data()); 
        } 
         
    iShared.iBuffer->SetStatus(EFull);             
    iShared.iMutex.Signal(); 
     
    // signal the other thread that the buffer has been filled 
    iShared.iBufferFilled.Signal(); 
     
    // continue recording 
    iMMFDevSound->RecordData(); 
    } 
 
 
/****************************************************************************** 
* Method Name:  CInputStreamThread::RecordError 
* Description:  CMMFDevSound callback when recording error occurs 
******************************************************************************/ 
void CInputStreamThread::RecordError(TInt aError)  
    { 
    // signal the output stream so it doesn't hang, in case it's waiting on the 
    // bufferFilled semaphore 
    __LOGSTR_TOFILE1("input_stream: RecordError: %d", aError); 
    iShared.iBufferFilled.Signal(); 
 
    switch(aError) 
        { 
        case KErrNone: 
        case KErrAbort: 
        case KErrCancel: 
        case KErrOverflow:          // never seem to get these...        
            { 
            iStreamStatus = EReady; 
            break; 
            } 
        case KErrDied:              // incoming call has reserved the devSound 
            {                       // -> need to reinit 
            iStreamStatus = ERestartNeeded; 
            break; 
            } 
        default: 
            iStreamStatus = ENotReady; 
            break; 
        } 
    } 
 
// End of File