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