sl@0: // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: // mmfswaudioinput.cpp
sl@0: // 
sl@0: //
sl@0: #include "mmfswaudioinput.h"
sl@0: #include "mmfswaudioinputpriv.h"
sl@0: #include <d32soundsc.h>
sl@0: #include <e32debug.h>
sl@0: #include "mmf/utils/rateconvert.h" // if we need to resample
sl@0: _LIT(KPddFileName,"SOUNDSC.PDD");
sl@0: _LIT(KLddFileName,"ESOUNDSC.LDD");
sl@0: 
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0: 
sl@0: const TText* const KStateNames[] = // must agree with TState
sl@0:             {
sl@0:             _S("EStateCreated2"), 
sl@0:             _S("EStateInitialized2"), 
sl@0:             _S("EStateRecordWait2"), 
sl@0:             _S("EStateRecordWaitAck2"), 
sl@0:             };
sl@0: 
sl@0: static const TText* StateName(TInt aState)
sl@0:     {
sl@0:     return KStateNames[aState];
sl@0:     }
sl@0: 
sl@0: const TText* const KRStateNames[] = // must agree with TRunningState
sl@0:             {
sl@0:             _S("ERStateRunning"), 
sl@0:             _S("ERStatePaused"), 
sl@0:             _S("ERStateFinishing"), 
sl@0:             _S("ERStateFinished"), 
sl@0:             _S("ERStateFailed"), 
sl@0:             };
sl@0: 
sl@0: static const TText* RStateName(TInt aState)
sl@0:     {
sl@0:     return KRStateNames[aState];
sl@0:     }
sl@0: 
sl@0: #endif // SYMBIAN_SWCODEC_LOGGING
sl@0: 
sl@0: #ifdef _DEBUG
sl@0: 
sl@0: static void Panic(TInt aPanic)
sl@0:     {
sl@0:     _LIT(KPanicString, "SwAudioInput");
sl@0:     User::Panic(KPanicString, aPanic);
sl@0:     }
sl@0: 
sl@0: void CAudioInput::CheckFullInvariant()
sl@0:     {
sl@0:     CheckInvariant();
sl@0:     CheckActiveRecorders();
sl@0:     }
sl@0: 
sl@0: void CAudioInput::CheckInvariant(TBool aKnownConstructed)
sl@0:     {
sl@0:     // full check would be that each recorder is in one, and only one, queue.
sl@0:     // However, since the queues share the same infrastructure, checking the overall length of queues
sl@0:     // is correct should suffice. During construction or deletion this may obviously vary
sl@0:     TInt totalLength = QLength(iIdleQueue) + QLength(iRecordingQueue) + 
sl@0:            QLength(iPendingQueue) + QLength(iBusyQueue);
sl@0:     if (aKnownConstructed)
sl@0:         {
sl@0:         __ASSERT_DEBUG(totalLength==KNumRecorders, Panic(KPanicBadTotalQueueLength));
sl@0:         }
sl@0:     else
sl@0:         {
sl@0:         __ASSERT_DEBUG(totalLength<=KNumRecorders, Panic(KPanicBadTotalQueueLength2));        
sl@0:         }
sl@0:     __ASSERT_DEBUG(QLength(iBusyQueue)<=1, Panic(KPanicBadTotalQueueLength));
sl@0:     }
sl@0: 
sl@0: #else // _DEBUG
sl@0: 
sl@0: // inline versions that do nothing...
sl@0: 
sl@0: inline void CAudioInput::CheckFullInvariant()
sl@0: 	{
sl@0: 	}
sl@0: 	
sl@0: inline void CAudioInput::CheckInvariant(TBool /*aKnownConstructed*/)
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: #endif // _DEBUG
sl@0: 
sl@0: const TInt KMinBufferSize = 4; // assume a good default?
sl@0: //Shared chunk driver does not support max. buffer size. 16K is given in order to simulate the old driver behavior.
sl@0: const TInt KMaxBufferSize = 0x4000;
sl@0: 
sl@0: //Table that maps given linear value of volume to the corresponding decibel value.
sl@0: const TUint8 KLinearToDbConstantLookup[] =
sl@0:                         {
sl@0:                             0,            // 0
sl@0:                             158,
sl@0:                             170,
sl@0:                             177,
sl@0:                             182,
sl@0:                             186,
sl@0:                             189,
sl@0:                             192,
sl@0:                             194,
sl@0:                             196,
sl@0:                             198,          // 10
sl@0:                             200,
sl@0:                             201,
sl@0:                             203,
sl@0:                             204,
sl@0:                             205,
sl@0:                             206,
sl@0:                             207,
sl@0:                             208,
sl@0:                             209,
sl@0:                             210,          // 20
sl@0:                             211,
sl@0:                             212,
sl@0:                             213,
sl@0:                             213,
sl@0:                             214,
sl@0:                             215,
sl@0:                             215,
sl@0:                             216,
sl@0:                             217,
sl@0:                             217,          // 30
sl@0:                             218,
sl@0:                             218,
sl@0:                             219,
sl@0:                             219,
sl@0:                             220,
sl@0:                             220,
sl@0:                             221,
sl@0:                             221,
sl@0:                             222,
sl@0:                             222,          // 40
sl@0:                             223,
sl@0:                             223,
sl@0:                             224,
sl@0:                             224,
sl@0:                             224,
sl@0:                             225,
sl@0:                             225,
sl@0:                             225,
sl@0:                             226,
sl@0:                             226,          // 50
sl@0:                             226,
sl@0:                             227,
sl@0:                             227,
sl@0:                             227,
sl@0:                             228,
sl@0:                             228,
sl@0:                             228,
sl@0:                             229,
sl@0:                             229,
sl@0:                             229,          // 60
sl@0:                             230,
sl@0:                             230,
sl@0:                             230,
sl@0:                             230,
sl@0:                             231,
sl@0:                             231,
sl@0:                             231,
sl@0:                             231,
sl@0:                             232,
sl@0:                             232,          // 70
sl@0:                             232,
sl@0:                             232,
sl@0:                             233,
sl@0:                             233,
sl@0:                             233,
sl@0:                             233,
sl@0:                             234,
sl@0:                             234,
sl@0:                             234,
sl@0:                             234,          // 80
sl@0:                             235,
sl@0:                             235,
sl@0:                             235,
sl@0:                             235,
sl@0:                             235,
sl@0:                             236,
sl@0:                             236,
sl@0:                             236,
sl@0:                             236,
sl@0:                             236,          // 90
sl@0:                             237,
sl@0:                             237,
sl@0:                             237,
sl@0:                             237,
sl@0:                             237,
sl@0:                             237,
sl@0:                             238,
sl@0:                             238,
sl@0:                             238,
sl@0:                             238,          // 100
sl@0:                             238,
sl@0:                             239,
sl@0:                             239,
sl@0:                             239,
sl@0:                             239,
sl@0:                             239,
sl@0:                             239,
sl@0:                             240,
sl@0:                             240,
sl@0:                             240,          // 110
sl@0:                             240,
sl@0:                             240,
sl@0:                             240,
sl@0:                             240,
sl@0:                             241,
sl@0:                             241,
sl@0:                             241,
sl@0:                             241,
sl@0:                             241,
sl@0:                             241,          // 120
sl@0:                             241,
sl@0:                             242,
sl@0:                             242,
sl@0:                             242,
sl@0:                             242,
sl@0:                             242,
sl@0:                             242,
sl@0:                             242,
sl@0:                             243,
sl@0:                             243,          // 130
sl@0:                             243,
sl@0:                             243,
sl@0:                             243,
sl@0:                             243,
sl@0:                             243,
sl@0:                             244,
sl@0:                             244,
sl@0:                             244,
sl@0:                             244,
sl@0:                             244,          // 140
sl@0:                             244,
sl@0:                             244,
sl@0:                             244,
sl@0:                             245,
sl@0:                             245,
sl@0:                             245,
sl@0:                             245,
sl@0:                             245,
sl@0:                             245,
sl@0:                             245,          // 150
sl@0:                             245,
sl@0:                             245,
sl@0:                             246,
sl@0:                             246,
sl@0:                             246,
sl@0:                             246,
sl@0:                             246,
sl@0:                             246,
sl@0:                             246,
sl@0:                             246,          // 160
sl@0:                             246,
sl@0:                             247,
sl@0:                             247,
sl@0:                             247,
sl@0:                             247,
sl@0:                             247,
sl@0:                             247,
sl@0:                             247,
sl@0:                             247,
sl@0:                             247,          // 170
sl@0:                             247,
sl@0:                             248,
sl@0:                             248,
sl@0:                             248,
sl@0:                             248,
sl@0:                             248,
sl@0:                             248,
sl@0:                             248,
sl@0:                             248,
sl@0:                             248,          // 180
sl@0:                             248,
sl@0:                             249,
sl@0:                             249,
sl@0:                             249,
sl@0:                             249,
sl@0:                             249,
sl@0:                             249,
sl@0:                             249,
sl@0:                             249,
sl@0:                             249,          // 190
sl@0:                             249,
sl@0:                             250,
sl@0:                             250,
sl@0:                             250,
sl@0:                             250,
sl@0:                             250,
sl@0:                             250,
sl@0:                             250,
sl@0:                             250,
sl@0:                             250,          // 200
sl@0:                             250,
sl@0:                             250,
sl@0:                             250,
sl@0:                             251,
sl@0:                             251,
sl@0:                             251,
sl@0:                             251,
sl@0:                             251,
sl@0:                             251,
sl@0:                             251,          // 210
sl@0:                             251,
sl@0:                             251,
sl@0:                             251,
sl@0:                             251,
sl@0:                             251,
sl@0:                             252,
sl@0:                             252,
sl@0:                             252,
sl@0:                             252,
sl@0:                             252,          // 220
sl@0:                             252,
sl@0:                             252,
sl@0:                             252,
sl@0:                             252,
sl@0:                             252,
sl@0:                             252,
sl@0:                             252,
sl@0:                             252,
sl@0:                             253,
sl@0:                             253,          // 230
sl@0:                             253,
sl@0:                             253,
sl@0:                             253,
sl@0:                             253,
sl@0:                             253,
sl@0:                             253,
sl@0:                             253,
sl@0:                             253,
sl@0:                             253,
sl@0:                             253,          // 240
sl@0:                             253,
sl@0:                             254,
sl@0:                             254,
sl@0:                             254,
sl@0:                             254,
sl@0:                             254,
sl@0:                             254,
sl@0:                             254,
sl@0:                             254,
sl@0:                             254,          // 250
sl@0:                             254,
sl@0:                             254,
sl@0:                             254,
sl@0:                             254,
sl@0:                             254
sl@0:                         };
sl@0: 
sl@0: // rate lookup table
sl@0: 
sl@0: const TInt KNumSampleRates = 9;
sl@0: 
sl@0: struct TSampleRateEnumTable
sl@0:     {
sl@0:     TInt iRate;
sl@0:     TSoundRate iRateEnum;
sl@0:     TUint iRateConstant;
sl@0:     };
sl@0: //Table that maps given samples per second to the corresponding enums in RSoundSc
sl@0: const TSampleRateEnumTable KRateEnumLookup[] =
sl@0:     {
sl@0:         {48000,ESoundRate48000Hz,KSoundRate48000Hz},
sl@0:         {44100,ESoundRate44100Hz,KSoundRate44100Hz},
sl@0:         {32000,ESoundRate32000Hz,KSoundRate32000Hz},
sl@0:         {24000,ESoundRate24000Hz,KSoundRate24000Hz},
sl@0:         {22050,ESoundRate22050Hz,KSoundRate22050Hz},
sl@0:         {16000,ESoundRate16000Hz,KSoundRate16000Hz},
sl@0:         {12000,ESoundRate12000Hz,KSoundRate12000Hz},
sl@0:         {11025,ESoundRate11025Hz,KSoundRate11025Hz},
sl@0:         {8000, ESoundRate8000Hz, KSoundRate8000Hz}
sl@0:     };
sl@0: 
sl@0: // TAudioInputParams
sl@0: 
sl@0: EXPORT_C TAudioInputParams::TAudioInputParams() :
sl@0:     iSampleRate(0), iNominalBufferSize(0)
sl@0:     {
sl@0:     // none	
sl@0:     }
sl@0: 
sl@0: // CAudioInput
sl@0: 
sl@0: EXPORT_C MAudioInput* MAudioInput::CreateL(MAudioInputObserver& aObserver)
sl@0:     {
sl@0:     MAudioInput* result = CAudioInput::NewL(aObserver);
sl@0:     return result;
sl@0:     }
sl@0: 
sl@0: CAudioInput* CAudioInput::NewL(MAudioInputObserver& aObserver)
sl@0:     {
sl@0:     CAudioInput* result = new CAudioInput(aObserver);
sl@0:     CleanupStack::PushL(result);
sl@0:     result->ConstructL();
sl@0:     CleanupStack::Pop(result);
sl@0:     return result;
sl@0:     }
sl@0: 
sl@0: CAudioInput::CAudioInput(MAudioInputObserver& aObserver) :
sl@0:     iObserver(aObserver),
sl@0:     iIdleQueue(_FOFF(CRecorder,iLink)),
sl@0:     iRecordingQueue(_FOFF(CRecorder,iLink)),
sl@0:     iPendingQueue(_FOFF(CRecorder,iLink)),
sl@0:     iBusyQueue(_FOFF(CRecorder,iLink))
sl@0:     {
sl@0:     ASSERT(iState == EStateCreated2); // assume zero'ing initialises correctly
sl@0:     }
sl@0: 
sl@0: void CAudioInput::Release()
sl@0: // effective destructor call
sl@0:     {
sl@0:     delete this;
sl@0:     }
sl@0: 
sl@0: TAny* CAudioInput::Interface(TUid aInterfaceUid)
sl@0:     {
sl@0:     if (aInterfaceUid == KUidAIParamInterface)
sl@0:         {
sl@0:         MAIParamInterface* self = this;
sl@0:         return self;
sl@0:         }
sl@0:     return NULL;
sl@0:     }
sl@0: 
sl@0: RSoundSc& CAudioInput::RecordSoundDevice()
sl@0:     {
sl@0:     ASSERT(iRecordSoundDevice.Handle()!=0); // should be open
sl@0:     return iRecordSoundDevice;
sl@0:     }
sl@0: 
sl@0: CAudioInput::~CAudioInput()
sl@0:     {
sl@0:     CheckInvariant(EFalse); // may not be constructed
sl@0:     Cancel();
sl@0:     for (TInt i = 0; i < KNumRecorders; i++)
sl@0:         {
sl@0:         // just in case, call cancel directly from this point too
sl@0:         // Cancel depends on the active queue, and might not be quite the same.
sl@0:         CRecorder* recorder = iRecorders[i];
sl@0:         if (recorder)
sl@0:             {
sl@0:             recorder->Cancel();
sl@0:             }
sl@0:         delete recorder;
sl@0:         }
sl@0:     delete iAsyncCallBack;
sl@0:     iConvBuff.Close();
sl@0:     iRecordSoundDevice.Close();
sl@0:     iChunk.Close();
sl@0:     }
sl@0: 
sl@0: void CAudioInput::Cancel()
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::Cancel()"));
sl@0: #endif
sl@0:     CancelRecorders();
sl@0:     if (iAsyncCallBack)
sl@0:         {
sl@0:         iAsyncCallBack->Cancel();
sl@0:         }
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::Cancel()"));
sl@0: #endif
sl@0:     }
sl@0: 
sl@0: void CAudioInput::CancelRecorders()
sl@0: // if a recorder is active, then cancel it. Also move the list if required.
sl@0:     {
sl@0:     CheckInvariant(); // semi-invariant check - this is called from destructor
sl@0:     
sl@0:     CRecorder* recorder;
sl@0:     while (QPop(recorder, iRecordingQueue))
sl@0:         {
sl@0:         recorder->Cancel();
sl@0:         iIdleQueue.AddLast(*recorder);
sl@0:         }
sl@0:     CheckFullInvariant();
sl@0:     }
sl@0: 
sl@0: void CAudioInput::CancelPendingRecorders()
sl@0: // take any recorder in the pending queue. ack the buffer and send to idle
sl@0:     {
sl@0:     CheckFullInvariant();
sl@0:     
sl@0:     CRecorder* recorder;
sl@0:     while (QPop(recorder, iPendingQueue))
sl@0:         {
sl@0:         recorder->ReleaseBuffer();
sl@0:         iIdleQueue.AddLast(*recorder);
sl@0:         }
sl@0:     CheckFullInvariant();
sl@0:     }
sl@0: 
sl@0: void CAudioInput::CancelBusyRecorder()
sl@0: // take busy recorder. ack the buffer and send to idle
sl@0:     {
sl@0:     CheckFullInvariant();
sl@0:     
sl@0:     CRecorder* recorder;
sl@0:     if (QPop(recorder, iBusyQueue))
sl@0:         {
sl@0:         recorder->ReleaseBuffer();
sl@0:         iIdleQueue.AddLast(*recorder);
sl@0:         }
sl@0:     CheckFullInvariant();
sl@0:     }
sl@0: 
sl@0: void CAudioInput::RecordAllIdle()
sl@0: // take any recorder in idle queue and set recording
sl@0:     {
sl@0:     CheckFullInvariant();
sl@0:     
sl@0:     CRecorder* recorder;
sl@0:     while (QPop(recorder, iIdleQueue))
sl@0:         {
sl@0:         recorder->RecordData();
sl@0:         iRecordingQueue.AddLast(*recorder);
sl@0:         }
sl@0:     CheckFullInvariant();    
sl@0:     }
sl@0: 
sl@0: void CAudioInput::ConstructL()
sl@0:     {
sl@0:     for (TInt i = 0; i < KNumRecorders; i++)
sl@0:         {
sl@0:         iRecorders[i] = new (ELeave) CRecorder(*this, i);
sl@0:         iIdleQueue.AddLast(*(iRecorders[i]));
sl@0:         }
sl@0:     iAsyncCallBack = new (ELeave) CAsyncCallBack(CActive::EPriorityStandard);
sl@0:     TCallBack callback(Callback, this);
sl@0:     iAsyncCallBack->Set(callback);
sl@0:     User::LoadPhysicalDevice(KPddFileName);
sl@0:     User::LoadLogicalDevice(KLddFileName);
sl@0:     CheckFullInvariant();
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::Initialize(const TAudioInputParams& aParams)
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::Initialize() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     TInt error = KErrNone;
sl@0:     if (iState == EStateCreated2)
sl@0:         {
sl@0:         if (!iRecordSoundDevice.Handle())
sl@0:             {
sl@0:             error = iRecordSoundDevice.Open(KSoundScRxUnit0);
sl@0:             if (error)
sl@0:                 {
sl@0:                 Close(); // TODO Close() required?
sl@0:                 }
sl@0:             }
sl@0:         if (!error)
sl@0:             {
sl@0:             iBufferLength = aParams.iNominalBufferSize; // will be updated by SetFormat() if required
sl@0:             error = SetFormat(aParams);
sl@0:             if (!error)
sl@0:                 {
sl@0:                 iRecordBufferConfig.iNumBuffers = KNumRecorders*2; // for each AO we create two buffers
sl@0:                 iRecordBufferConfig.iFlags = 0;
sl@0:                 iRecordBufferConfig.iBufferSizeInBytes = iBufferLength;
sl@0:                 ASSERT(iChunk.Handle()==0); // should not be already open
sl@0:                 TPckg<TRecordSharedChunkBufConfig> bufferConfigBuf(
sl@0:                         iRecordBufferConfig);
sl@0:                 error = iRecordSoundDevice.SetBufferChunkCreate(
sl@0:                         bufferConfigBuf, iChunk);
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:                 RDebug::Print(
sl@0:                         _L("iRecordBufferConfig.iNumBuffers =  [%d]"),iRecordBufferConfig.iNumBuffers);
sl@0:                 RDebug::Print(
sl@0:                         _L("iRecordBufferConfig.iFlags =  [%d]"),iRecordBufferConfig.iFlags);
sl@0:                 RDebug::Print(
sl@0:                         _L("iRecordBufferConfig.iBufferSizeInBytes =  [%d]"),iRecordBufferConfig.iBufferSizeInBytes);
sl@0: #endif			
sl@0:                 if (error == KErrNone)
sl@0:                     {
sl@0: 					ASSERT(iChunk.Handle()); // should now be open
sl@0:                     iRecordSoundDevice.GetBufferConfig(bufferConfigBuf); // overwrite iRecordBufferConfig
sl@0: 					SetGain(aParams.iInitialGain);
sl@0:                     iState = EStateInitialized2;
sl@0:                     }
sl@0:                 }
sl@0:             }
sl@0:         }
sl@0:     else
sl@0:         {
sl@0:         error = KErrNotReady;
sl@0:         }
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::Initialize(%d) state=%s rstate=%s"), error, StateName(
sl@0:             iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     return error;
sl@0:     }
sl@0: 
sl@0: void CAudioInput::Close()
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::Close() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     InternalStop(); // Technically this should not be required, as client should Stop() first, but just in case
sl@0:     if (iState == EStateInitialized2)
sl@0:         {
sl@0:         iRecordSoundDevice.Close();
sl@0:         iChunk.Close();
sl@0:         iConvBuff.Close();
sl@0:         iState = EStateCreated2;
sl@0:         }
sl@0:     ASSERT(iState==EStateCreated2);
sl@0:     ASSERT(QLength(iIdleQueue)==KNumRecorders);
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::Close() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::Start()
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::Start() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     TInt error = KErrNone;
sl@0:     if (iState == EStateInitialized2)
sl@0:         {
sl@0:         RecordAllIdle();
sl@0:         iState = EStateRecordWait2;
sl@0:         iRState = ERStateRunning;
sl@0:         }
sl@0:     else
sl@0:         {
sl@0:         error = KErrNotReady;
sl@0:         }
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::Start(%d) state=%s rstate=%s"), 
sl@0:             error, StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     return error;
sl@0:     }
sl@0: 
sl@0: void CAudioInput::BufferAck()
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::BufferAck() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     ASSERT(iState==EStateRecordWaitAck2);
sl@0:     HandleBufferAck();
sl@0:     iState = EStateRecordWait2;
sl@0:     RequestCallback();
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::BufferAck() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     }
sl@0: 
sl@0: void CAudioInput::HandleBufferAck()
sl@0:     {
sl@0:     CRecorder* recorder = QPop(iBusyQueue);
sl@0:     recorder->ReleaseBuffer();
sl@0:     if (iRState == ERStateRunning)
sl@0:         {
sl@0:         recorder->RecordData();
sl@0:         iRecordingQueue.AddLast(*recorder);
sl@0:         }
sl@0:     else
sl@0:         {
sl@0:         iIdleQueue.AddLast(*recorder);
sl@0:         if (iRState == ERStatePaused && (QLength(iRecordingQueue)+QLength(iPendingQueue) == 0))
sl@0:             {
sl@0:             iRState = ERStateFinishing;
sl@0:             }
sl@0:         }
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::Pause()
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::Pause() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     TInt err = KErrNone; // note we are silent if called in wrong state
sl@0:     
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(
sl@0:                 _L("***!pause irecordingquelength %d pendingquelength %d ibusyquelength=%d"), QLength(iRecordingQueue),
sl@0:                 QLength(iPendingQueue), QLength(iBusyQueue));
sl@0: #endif
sl@0:     if ((iState == EStateRecordWait2 || iState == EStateRecordWaitAck2) && iRState==ERStateRunning)
sl@0:         {
sl@0:         iRecordSoundDevice.Pause();
sl@0: 
sl@0:         iRState = ERStatePaused;
sl@0:         }
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::Pause(%d) state=%s err=%d"), err, StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     return err; 
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::Resume()
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::Resume() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     TInt err = KErrNone; // note we are silent if called in the wrong state
sl@0:     if ((iState == EStateRecordWait2 || iState == EStateRecordWaitAck2) && 
sl@0:             ((iRState==ERStatePaused || iRState==ERStateFinishing || iRState==ERStateFinished)))
sl@0:         {
sl@0:         err = RecordSoundDevice().Resume();
sl@0:         
sl@0:         RecordAllIdle();
sl@0:         
sl@0:         iRState = ERStateRunning;
sl@0:         }
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::Resume(%d) state=%s rstate=%s"), err, StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     return err; 
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::Flush()
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::Flush() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     TInt error = KErrNotReady;
sl@0:     if (iRState==ERStatePaused)
sl@0:         {
sl@0:         if (iState == EStateRecordWait2)
sl@0:             {
sl@0:             InternalFlush();
sl@0:             ASSERT(iState == EStateRecordWait2); // stay put
sl@0:             error = KErrNone;
sl@0:             }
sl@0:         else if (iState == EStateRecordWaitAck2)
sl@0:             {
sl@0:             InternalFlush();
sl@0:             iState = EStateRecordWait2;
sl@0:             error = KErrNone;
sl@0:             }       
sl@0:         }
sl@0:  #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::Flush(%d) state=%s rstate=%s"), error, StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     return error;
sl@0:     }
sl@0: 
sl@0: void CAudioInput::Stop()
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::Stop() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     InternalStop();
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::Stop() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     }
sl@0: 
sl@0: void CAudioInput::InternalStop()
sl@0: // This stops all recording and returns pending and busy buffers to idle. Must be called when
sl@0: // client knows the buffer has been grabbed (e.g. _not_ before error callback)
sl@0:     {
sl@0:     CheckInvariant(); // Can be called from buffer error, so can't check full invariant.
sl@0:     if (iState != EStateInitialized2 && iState != EStateCreated2)
sl@0:         {
sl@0:         InternalFlush();
sl@0:         iState = EStateInitialized2;
sl@0:         }
sl@0:     CheckFullInvariant();
sl@0:     ASSERT((QLength(iRecordingQueue) + QLength(iPendingQueue) + 
sl@0: 					QLength(iBusyQueue))==0); // everything is stopped 
sl@0:     }
sl@0: 
sl@0: void CAudioInput::InternalFlush()
sl@0:     {
sl@0:     CancelRecorders();
sl@0:     CancelPendingRecorders();
sl@0:     CancelBusyRecorder();
sl@0:     }
sl@0: 
sl@0: void CAudioInput::BufferArrives(CRecorder* aRecorder)
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(
sl@0:             _L("--->CAudioInput::BufferArrives(%d,%d) state=%s rstate=%s"), aRecorder->Index(),
sl@0:             aRecorder->StatusOrOffset(), StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckInvariant(); // Can't use CheckFullInvariant() from RunL
sl@0:     ASSERT(iState==EStateRecordWait2 || iState==EStateRecordWaitAck2);
sl@0:     ASSERT(aRecorder->Offset()>=0); // assert we're not here due to an error
sl@0:     iRecordingQueue.Remove(*aRecorder);
sl@0:     iPendingQueue.AddLast(*aRecorder);
sl@0:     if (iState==EStateRecordWait2)
sl@0:         {
sl@0:         RequestCallback();
sl@0:         }
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::BufferArrives() state=%s rstate=%s"), 
sl@0:             StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     }
sl@0: 
sl@0: void CAudioInput::UseBuffer(CRecorder* aRecorder)
sl@0: // incomming buffer is pointed to by iBufPtr. Either directly or via convert, use for callback
sl@0:     {
sl@0:     iBufPtr.Set(iChunk.Base() + aRecorder->Offset(), aRecorder->Length());
sl@0:     if (iConverter)
sl@0:         {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:         RDebug::Print(_L("iBufPtr length [%d] iconvbuff length [%d,%d]"),
sl@0:                 iBufPtr.Length(), iConvBuff.Length(), iConvBuff.MaxLength());
sl@0: #endif
sl@0:         __DEBUG_ONLY(TInt converted =) iConverter->Convert(iBufPtr, iConvBuff);
sl@0:         // the following assert should check we convert the log. 
sl@0:         // Actually we sometimes fail at the end of the operation with what is effectively
sl@0:         // the last buffer. Arguably a driver fault, but there we are
sl@0:         // ASSERT(converted==iBufPtr.Length());  
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:         RDebug::Print(_L("iBufPtr length [%d] iconvbuff length after [%d,%d]"),
sl@0:         iBufPtr.Length(), iConvBuff.Length(), iConvBuff.MaxLength());
sl@0: #endif
sl@0:         iObserver.InputBufferAvailable(iConvBuff);
sl@0:         }
sl@0:     else
sl@0:         {
sl@0:         iObserver.InputBufferAvailable(iBufPtr);
sl@0:         }
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("12345 ibufptr =  [0x%x]"),iBufPtr.Ptr());
sl@0: #endif
sl@0:     }
sl@0: 
sl@0: void CAudioInput::BufferError(CRecorder* aRecorder, TInt aError)
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(
sl@0:             _L("--->CAudioInput::BufferError(%d,%d) state=%s rstate=%s"), aRecorder->Index(),
sl@0:             aError, StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckInvariant(); // Can't use CheckFullInvariant() from RunL
sl@0:     if (aError==KErrCancel || aError==KErrOverflow)
sl@0:         {
sl@0:         // Cancel: sign of a Pause operation. If paused etc, then merely add to idle list. potentially generate finished signal
sl@0:         //         if not paused, then not clear but just in case request record again
sl@0:         // Overflow: basically try again, but if paused merely add to idle. Check for last buffer just in case
sl@0:         if (iRState!=ERStateRunning)
sl@0:             {
sl@0:             iRecordingQueue.Remove(*aRecorder);
sl@0:             iIdleQueue.AddLast(*aRecorder);
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:             RDebug::Print(
sl@0:                         _L("***! irecordingquelength %d pendingquelength %d ibusyquelength=%d"), QLength(iRecordingQueue),
sl@0:                         QLength(iPendingQueue), QLength(iBusyQueue));
sl@0: #endif
sl@0:             if (iRState == ERStatePaused && (QLength(iRecordingQueue)+QLength(iPendingQueue)+QLength(iBusyQueue) == 0))
sl@0:                 {
sl@0:                 iRState = ERStateFinishing;
sl@0:                 RequestCallback();
sl@0:                 }
sl@0:             }
sl@0:         else
sl@0:             {
sl@0:             aRecorder->RecordData();
sl@0:             }
sl@0:         }
sl@0:     else
sl@0:         {
sl@0:         iRecordingQueue.Remove(*aRecorder);
sl@0:         iIdleQueue.AddLast(*aRecorder);
sl@0:         iRState = ERStateFailed;
sl@0:         iObserver.InputError(aError);        
sl@0:         }
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::BufferError() state=%s rstate=%s"), 
sl@0:             StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::Callback(TAny* aPtr)
sl@0:     {
sl@0:     CAudioInput* self = static_cast<CAudioInput*> (aPtr);
sl@0:     TRAPD(error,self->AsyncCallbackL());
sl@0:     return error; // TODO really have to handle error
sl@0:     }
sl@0: 
sl@0: void CAudioInput::RequestCallback()
sl@0:     {
sl@0:     // ensure iAsyncCallBack is active
sl@0:     if (!iAsyncCallBack->IsActive())
sl@0:         {
sl@0:         iAsyncCallBack->Call();
sl@0:         }
sl@0:     }
sl@0: 
sl@0: void CAudioInput::AsyncCallbackL()
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::AsyncCallbackL() state=%s rstate=%s"), 
sl@0:             StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     ASSERT(iState==EStateRecordWait2 || iState==EStateRecordWaitAck2); // should not occur in other states. Actually ignore in 2nd
sl@0:     if (iState==EStateRecordWait2)
sl@0:         {
sl@0:         if (QLength(iPendingQueue)>0)
sl@0:             {
sl@0:             ASSERT(QLength(iBusyQueue)==0);
sl@0:             iState = EStateRecordWaitAck2; // change state prior to callback, in case sync call from callback
sl@0:             CRecorder* recorder = QPop(iPendingQueue);
sl@0:             iBusyQueue.AddLast(*recorder);
sl@0:             UseBuffer(recorder);
sl@0:             }
sl@0:         else 
sl@0:             {
sl@0:             if (iRState == ERStateFinishing)
sl@0:                 {
sl@0:                 ASSERT(QLength(iRecordingQueue)+QLength(iPendingQueue)+QLength(iBusyQueue) == 0); // should be true
sl@0:                 iRState = ERStateFinished;
sl@0:                 iObserver.InputFinished();
sl@0:                 }
sl@0:             }
sl@0:         }
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::AsyncCallbackL() state=%s rstate=%s"), 
sl@0:             StateName(iState), RStateName(iRState));
sl@0: #endif
sl@0:     CheckFullInvariant();
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::GetBufferSizes(TInt& aMinSize, TInt& aMaxSize)
sl@0:     {
sl@0:     aMinSize = KMinBufferSize;
sl@0:     aMaxSize = KMaxBufferSize;
sl@0:     return KErrNone;
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::SetGain(TInt aGain)
sl@0:     {
sl@0:     TInt error = KErrNone; // note: silent if in wrong state
sl@0:     if (iRecordSoundDevice.Handle())
sl@0:         {
sl@0:         // we have to switch from level to dB value
sl@0:         if(aGain >=0 && aGain<=KSoundMaxVolume)
sl@0:             {
sl@0:             error = iRecordSoundDevice.SetVolume(KLinearToDbConstantLookup[aGain]);
sl@0:             }
sl@0:         else
sl@0:             {
sl@0:             error = KErrArgument;
sl@0:             }
sl@0:         }
sl@0:     return error;
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::SetFormat(const TAudioInputParams& aFormat)
sl@0:     {
sl@0:     TInt err = KErrNotFound;
sl@0:     TCurrentSoundFormatV02Buf formatBuf;
sl@0:     TFormatData formatData;
sl@0: 
sl@0:     delete iConverter;
sl@0:     iConverter = NULL; // setting this to NULL indicates we are not using converter. No other flag
sl@0: 
sl@0:     TInt wantedRate = aFormat.iSampleRate;
sl@0:     for (TInt index = 0; index < KNumSampleRates; index++)
sl@0:         {
sl@0:         if (wantedRate == KRateEnumLookup[index].iRate)
sl@0:             {
sl@0:             formatBuf().iRate = KRateEnumLookup[index].iRateEnum;
sl@0:             formatData.iSampleRate = wantedRate;
sl@0:             err = KErrNone;
sl@0:             break;
sl@0:             }
sl@0:         }
sl@0: 
sl@0:     if (err == KErrNone)
sl@0:         {
sl@0:         formatBuf().iChannels = aFormat.iNumChannels;
sl@0:         formatBuf().iEncoding = ESoundEncoding16BitPCM;
sl@0:         formatBuf().iDataFormat = ESoundDataFormatInterleaved;
sl@0:         err = iRecordSoundDevice.SetAudioFormat(formatBuf);
sl@0: #if defined(SYMBIAN_SOUNDADAPTER_FORCECDRATES) || defined (SYMBIAN_SOUNDADAPTER_FORCESTEREO)
sl@0:         err = KErrNotSupported; // force Negotiate - for debugging
sl@0: #endif
sl@0:         if (err == KErrNotSupported)
sl@0:             {
sl@0:             // don't support directly. Perhaps can rate convert?
sl@0:             err = NegotiateFormat(aFormat, formatData);
sl@0:             }
sl@0:         }
sl@0:     return err;
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::NegotiateFormat(const TAudioInputParams& aFormat, TFormatData &aFormatData)
sl@0:     {
sl@0:     TInt err = KErrNotFound;
sl@0:     TCurrentSoundFormatV02Buf formatBuf;
sl@0:     
sl@0:     TInt origBufferLength = iBufferLength; // cache in case we change
sl@0: 
sl@0:     // find out first what the driver supports
sl@0:     TSoundFormatsSupportedV02Buf supportedFormat;
sl@0:     iRecordSoundDevice.Caps(supportedFormat);
sl@0:     TUint32 supportedRates = supportedFormat().iRates;
sl@0: #ifdef SYMBIAN_SOUNDADAPTER_FORCECDRATES
sl@0:     supportedRates &= KSoundRate11025Hz | KSoundRate22050Hz
sl@0:             | KSoundRate44100Hz; // only use CD rates - for debugging
sl@0: #endif
sl@0: 
sl@0:     // For RecordCase:
sl@0:     //		We want the next rate above consistently - we go down from this to the requested rate.
sl@0:     //		If there is one, we don't support - we _never_ upsample.
sl@0:     // note that the table is given in descending order, so we start with the highest
sl@0:     TInt wantedRate = aFormat.iSampleRate;
sl@0:     TInt takeTheFirst = EFalse;
sl@0:     TInt nextUpValidIndex = -1;
sl@0:     for (TInt index = 0; index < KNumSampleRates; index++)
sl@0:         {
sl@0:         TBool lookingAtRequestedRate = wantedRate
sl@0:                 == KRateEnumLookup[index].iRate;
sl@0:         TSoundRate wantedEnum = KRateEnumLookup[index].iRateEnum;
sl@0:         TUint32 equivBitmap = KRateEnumLookup[index].iRateConstant;
sl@0:         TBool isSupported = (equivBitmap & supportedRates) != EFalse;
sl@0:         if (lookingAtRequestedRate || takeTheFirst)
sl@0:             {
sl@0:             if (isSupported)
sl@0:                 {
sl@0:                 // this rate is supported
sl@0:                 formatBuf().iRate = wantedEnum;
sl@0:                 aFormatData.iActualRate = KRateEnumLookup[index].iRate;
sl@0:                 err = KErrNone;
sl@0:                 break;
sl@0:                 }
sl@0:             }
sl@0:         else if (!takeTheFirst)
sl@0:             {
sl@0:             // while we are still looking for the rate, want to cache any supported index
sl@0:             // at end of loop, this will be the first rate above ours that is supported
sl@0:             // use for fallback if required
sl@0:             if (isSupported)
sl@0:                 {
sl@0:                 nextUpValidIndex = index;
sl@0:                 }
sl@0:             }
sl@0:         if (lookingAtRequestedRate)
sl@0:             {
sl@0:             // For record we just abort.
sl@0:             break;
sl@0:             }
sl@0:         }
sl@0: 
sl@0:     if (err)
sl@0:         {
sl@0:         // if there is one above the requested rate, use that
sl@0:         if (nextUpValidIndex >= 0)
sl@0:             {
sl@0:             TSoundRate wantedEnum =
sl@0:                     KRateEnumLookup[nextUpValidIndex].iRateEnum;
sl@0:             formatBuf().iRate = wantedEnum;
sl@0:             aFormatData.iActualRate = KRateEnumLookup[nextUpValidIndex].iRate;
sl@0:             err = KErrNone;
sl@0:             }
sl@0:         }
sl@0: 
sl@0:     if (err)
sl@0:         {
sl@0:         // should have something!
sl@0:         return err;
sl@0:         }
sl@0: 
sl@0:     aFormatData.iSampleRate = wantedRate; // iSampleRate is our requested/apparent rate, not the device rate.
sl@0: 
sl@0:     TUint32 channelsSupported = supportedFormat().iChannels;
sl@0: #ifdef SYMBIAN_SOUNDADAPTER_FORCESTEREO
sl@0:     channelsSupported &= KSoundStereoChannel; // don't use mono - for debugging
sl@0: #endif
sl@0: 
sl@0:     if (aFormat.iNumChannels == 1)
sl@0:         {
sl@0:         aFormatData.iRequestedChannels = 1;
sl@0:         // want mono
sl@0:         if (channelsSupported & KSoundMonoChannel)
sl@0:             {
sl@0:             // mono is supported, as usual
sl@0:             aFormatData.iActualChannels = 1;
sl@0:             }
sl@0:         else if (channelsSupported & KSoundStereoChannel)
sl@0:             {
sl@0:             aFormatData.iActualChannels = 2;
sl@0:             iBufferLength *= 2; // double size, will do stereo->mono
sl@0:             }
sl@0:         else
sl@0:             {
sl@0:             return KErrNotSupported; // should not get this far for real
sl@0:             }
sl@0:         }
sl@0:     else if (aFormat.iNumChannels == 2)
sl@0:         {
sl@0:         aFormatData.iRequestedChannels = 2;
sl@0:         // want stereo
sl@0:         if (channelsSupported & KSoundStereoChannel)
sl@0:             {
sl@0:             // stereo is supported, as usual
sl@0:             aFormatData.iActualChannels = 2;
sl@0:             }
sl@0:         else if (channelsSupported & KSoundMonoChannel)
sl@0:             {
sl@0:             aFormatData.iActualChannels = 1;
sl@0:             iBufferLength /= 2; // halve size, will do mono->stereo
sl@0:             }
sl@0:         else
sl@0:             {
sl@0:             return KErrNotSupported; // should not get this far for real
sl@0:             }
sl@0:         }
sl@0:     else
sl@0:         {
sl@0:         return KErrNotSupported; // unknown number of channels requested!
sl@0:         }
sl@0: 
sl@0:     formatBuf().iChannels = aFormatData.iActualChannels;
sl@0: 
sl@0:     formatBuf().iEncoding = ESoundEncoding16BitPCM;
sl@0:     formatBuf().iDataFormat = ESoundDataFormatInterleaved;
sl@0:     err = iRecordSoundDevice.SetAudioFormat(formatBuf);
sl@0: 
sl@0:     if (!err)
sl@0:         {
sl@0:         ASSERT(!iConverter); // pre-condition at top of function anyway
sl@0:         // when recording we convert from actual to requested
sl@0:         TInt outputRateToUse = aFormatData.iSampleRate;
sl@0: #ifdef SYMBIAN_SKIP_RESAMPLE_ON_RECORD
sl@0: 		// with this macro just channel convert at most
sl@0:         outputRateToUse = aFormatData.iActualRate;
sl@0: #endif
sl@0: #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0: 		RDebug::Print(_L("RMdaDevSound::CBody::NegotiateFormat: Convert:CreateL from %d/%d to %d/%d"),
sl@0:                         aFormatData.iActualRate, aFormatData.iActualChannels,
sl@0:                         aFormatData.iSampleRate, aFormatData.iRequestedChannels);
sl@0: #endif																	       
sl@0:         TRAP(err, iConverter = CChannelAndSampleRateConverter::CreateL(aFormatData.iActualRate,
sl@0:                                 aFormatData.iActualChannels,
sl@0:                                 outputRateToUse,
sl@0:                                 aFormatData.iRequestedChannels));
sl@0:         }
sl@0:     if (!err && iConverter)
sl@0:         {
sl@0:         err = iConvBuff.Create(origBufferLength);
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:         RDebug::Print(_L("iBufferLength length [%d] iconvbuff length [%d,%d]"),
sl@0:         iBufferLength, iConvBuff.Length(), iConvBuff.MaxLength());
sl@0: #endif
sl@0:         }
sl@0: 
sl@0:     return err;
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::GetSupportedSampleRates(RArray<TInt>& aSupportedSampleRates)
sl@0:     {
sl@0:     TInt err = KErrNone;
sl@0: 
sl@0:     if (iRecordSoundDevice.Handle())
sl@0:         {
sl@0:         GetSupportedSampleRates(aSupportedSampleRates, iRecordSoundDevice);
sl@0:         }
sl@0:     else
sl@0:         {//temporarily open the device if we can
sl@0:         RSoundSc tempsound;
sl@0:         err = tempsound.Open(KSoundScRxUnit0);
sl@0:         if (!err)
sl@0:             {
sl@0:             err = GetSupportedSampleRates(aSupportedSampleRates, tempsound);
sl@0:             tempsound.Close();
sl@0:             }
sl@0:         }
sl@0:     return err;
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::GetSupportedSampleRates(
sl@0:         RArray<TInt>& aSupportedSampleRates, RSoundSc& aSoundDevice)
sl@0:     {
sl@0:     ASSERT(aSoundDevice.Handle()); // parent to ensure this is open
sl@0: 
sl@0:     TInt err = KErrNone;
sl@0: 
sl@0:     TSoundFormatsSupportedV02Buf supportedFormat;
sl@0:     aSoundDevice.Caps(supportedFormat);
sl@0:     TUint32 rates = supportedFormat().iRates;
sl@0: 
sl@0:     for (TInt i = KNumSampleRates - 1; i > 0; i--)//min to max
sl@0:         {
sl@0:         if (rates & KRateEnumLookup[i].iRateConstant)
sl@0:             {
sl@0:             err = aSupportedSampleRates.Append(KRateEnumLookup[i].iRate);
sl@0:             if (err)
sl@0:                 {
sl@0:                 break;
sl@0:                 }
sl@0:             }
sl@0:         }
sl@0:     return err;
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::QLength(TSglQue<CRecorder>& aQueue)
sl@0: // count elements in List/Q. Have to use iterator to do this - it seems.
sl@0:     {
sl@0:     TSglQueIter<CRecorder> iter(aQueue);
sl@0:     TInt count=0;
sl@0:     while (iter++)
sl@0:         {
sl@0:         // like old-fashioned C string manipulations. iterate through all members
sl@0:         count++;
sl@0:         }
sl@0:     return count;
sl@0:     }
sl@0: 
sl@0: CAudioInput::CRecorder* CAudioInput::QPop(TSglQue<CRecorder>& aQueue)
sl@0:     {
sl@0:     CRecorder* recorder = NULL;
sl@0:     if (! aQueue.IsEmpty())
sl@0:         {
sl@0:         recorder = aQueue.First();
sl@0:         aQueue.Remove(*recorder);
sl@0:         }
sl@0:     return recorder;
sl@0:     }
sl@0: 	
sl@0: #ifdef _DEBUG
sl@0: 
sl@0: // these functions are used in invariant checking only
sl@0: 
sl@0: void CAudioInput::CheckActiveRecorders(TSglQue<CRecorder>& aQueue, TBool aExpected, TInt aPanicCode)
sl@0: // check that all the elements in the given Q are IsActive() or vice-versa
sl@0:     {
sl@0:     TSglQueIter<CRecorder> iter(aQueue);
sl@0:     
sl@0:     CRecorder* recorder;
sl@0:     while ((recorder=iter++)!=NULL)
sl@0:         {
sl@0:         TBool expected = aExpected != EFalse; // ensure these are either true or false
sl@0:         TBool active = recorder->IsActive() != EFalse;
sl@0:         __ASSERT_DEBUG(expected == active, Panic(aPanicCode));
sl@0:         }
sl@0:     }
sl@0: 
sl@0: void CAudioInput::CheckActiveRecorders()
sl@0: // check that all the elements in the recordingQueue are IsActive() etc
sl@0: // can't be used as CRecorder::RunL() pre-condition
sl@0:     {
sl@0:     CheckActiveRecorders(iRecordingQueue, ETrue, EPanicBusyRecorderNotActive);
sl@0:     CheckActiveRecorders(iIdleQueue, EFalse, EPanicNonBusyRecorderActive);
sl@0:     CheckActiveRecorders(iPendingQueue, EFalse, EPanicNonBusyRecorderActive);
sl@0:     CheckActiveRecorders(iBusyQueue, EFalse, EPanicNonBusyRecorderActive);
sl@0:     }
sl@0: 
sl@0: #endif // _DEBUG
sl@0: 
sl@0: //
sl@0: // CRecorder
sl@0: //	
sl@0: 
sl@0: 
sl@0: CAudioInput::CRecorder::CRecorder(CAudioInput& aParent, TInt aIndex) :
sl@0:     CActive(EPriorityStandard), iParent(aParent), iIndex(aIndex)
sl@0:     {
sl@0:     CActiveScheduler::Add(this);
sl@0:     }
sl@0: 
sl@0: CAudioInput::CRecorder::~CRecorder()
sl@0:     {
sl@0:     Cancel();
sl@0:     }
sl@0: 
sl@0: void CAudioInput::CRecorder::Cancel()
sl@0:     {
sl@0:     // this override takes into account that ReleaseBuffer must be called - this is not the
sl@0:     // normal pattern where following Cancel() we're not concerned with the results
sl@0:     if (IsActive())
sl@0:         {
sl@0:         ASSERT(!BufferHeld()); // if active then buffer held should be clear. don't reset then
sl@0:         CActive::Cancel();
sl@0:         ReleaseBuffer(ETrue); // release - might have been a successful run!
sl@0:         }
sl@0:     else
sl@0:         {
sl@0:         ReleaseBuffer(); // this will release buffer if still outstanding	
sl@0:         }
sl@0:     }
sl@0: 
sl@0: void CAudioInput::CRecorder::RunL()
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::CRecorder::RunL(%d, %d)"), Index(),
sl@0:             iStatus.Int());
sl@0: #endif
sl@0:     TInt errorOrOffset = iStatus.Int(); // negative -> error. non-negative is offset in chunk
sl@0: 
sl@0:     if (errorOrOffset < 0)
sl@0:         {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:         RDebug::Print(_L("errorOrOffset =  [%d]"),errorOrOffset);
sl@0: #endif
sl@0:         // ReleaseBuffer(ETrue); // calls ReleaseBuffer() on error code. Driver requires this, even though seems wrong
sl@0:         iParent.BufferError(this, errorOrOffset);
sl@0:         }
sl@0:     else
sl@0:         {
sl@0:         ASSERT(!iBufferHeld);
sl@0:         iBufferHeld = ETrue;
sl@0: 
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:         RDebug::Print(_L("errorOrOffset =  [%d]"),errorOrOffset);
sl@0: #endif
sl@0:         // If a buffer larger than expected arrives truncate it.
sl@0:         iLength = Min(iLength,iParent.iBufferLength);
sl@0:         iParent.BufferArrives(this);
sl@0:         }
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::CRecorder::RunL(%d)"), Index());
sl@0: #endif
sl@0:     }
sl@0: 
sl@0: void CAudioInput::CRecorder::RecordData()
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::CRecorder::RecordData(%d)"), Index());
sl@0: #endif
sl@0:     ASSERT(!iBufferHeld);
sl@0:     Deque(); // ensure we append to the AO queue, so if it comes to it we process oldest request first
sl@0:     CActiveScheduler::Add(this);
sl@0:     iLength = iParent.BufferLength(); // TODO do we have to set this first or is it an OUT param purely
sl@0:     iParent.RecordSoundDevice().RecordData(iStatus, iLength);
sl@0:     SetActive();
sl@0: 
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("###****#####!!!! Buffer length [%d], status [%d] "), iLength,
sl@0:             iStatus.Int());
sl@0: #endif
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::CRecorder::RecordData(%d)"), Index());
sl@0: #endif
sl@0:     }
sl@0: 
sl@0: void CAudioInput::CRecorder::DoCancel()
sl@0:     {
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("--->CAudioInput::CRecorder::DoCancel(%d)"), Index());
sl@0: #endif
sl@0:     iParent.RecordSoundDevice().Cancel(iStatus);
sl@0: #ifdef SYMBIAN_SWCODEC_LOGGING
sl@0:     RDebug::Print(_L("<---CAudioInput::CRecorder::DoCancel(%d)"), Index());
sl@0: #endif
sl@0:     }
sl@0: 
sl@0: void CAudioInput::CRecorder::ReleaseBuffer(TBool aDoAnyway)
sl@0:     {
sl@0:     if (iBufferHeld || aDoAnyway)
sl@0:         {
sl@0:         iParent.RecordSoundDevice().ReleaseBuffer(iStatus.Int());
sl@0:         iBufferHeld = EFalse;
sl@0:         }
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::CRecorder::Index() const
sl@0:     {
sl@0:     return iIndex;
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::CRecorder::Length() const
sl@0:     {
sl@0:     return iLength;
sl@0:     }
sl@0: 
sl@0: TBool CAudioInput::CRecorder::IsBusy() const
sl@0:     {
sl@0:     return IsActive() || BufferHeld();
sl@0:     }
sl@0: 
sl@0: TBool CAudioInput::CRecorder::BufferHeld() const
sl@0: // BufferHeld() means we're in control of a passed buffer
sl@0:     {
sl@0:     return iBufferHeld;
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::CRecorder::Offset() const
sl@0: // If we call this, we've discounted errors so can assert non-negative
sl@0:     {
sl@0:     TInt result = StatusOrOffset();
sl@0:     ASSERT(result>=0); 
sl@0:     return result;
sl@0:     }
sl@0: 
sl@0: TInt CAudioInput::CRecorder::StatusOrOffset() const
sl@0: // The iStatus assuming is valid
sl@0:     {
sl@0:     ASSERT(!IsActive()); // or would not be valid
sl@0:     TInt result = iStatus.Int();
sl@0:     return result;    
sl@0:     }