devsound/devsoundrefplugin/src/swcodecwrapper/mmfswaudioinput.cpp
changeset 0 79dd3e2336a0
equal deleted inserted replaced
-1:000000000000 0:79dd3e2336a0
       
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // mmfswaudioinput.cpp
       
    15 // 
       
    16 //
       
    17 #include "mmfswaudioinput.h"
       
    18 #include "mmfswaudioinputpriv.h"
       
    19 #include <d32soundsc.h>
       
    20 #include <e32debug.h>
       
    21 #include "mmf/utils/rateconvert.h" // if we need to resample
       
    22 _LIT(KPddFileName,"SOUNDSC.PDD");
       
    23 _LIT(KLddFileName,"ESOUNDSC.LDD");
       
    24 
       
    25 #ifdef SYMBIAN_SWCODEC_LOGGING
       
    26 
       
    27 const TText* const KStateNames[] = // must agree with TState
       
    28             {
       
    29             _S("EStateCreated2"), 
       
    30             _S("EStateInitialized2"), 
       
    31             _S("EStateRecordWait2"), 
       
    32             _S("EStateRecordWaitAck2"), 
       
    33             };
       
    34 
       
    35 static const TText* StateName(TInt aState)
       
    36     {
       
    37     return KStateNames[aState];
       
    38     }
       
    39 
       
    40 const TText* const KRStateNames[] = // must agree with TRunningState
       
    41             {
       
    42             _S("ERStateRunning"), 
       
    43             _S("ERStatePaused"), 
       
    44             _S("ERStateFinishing"), 
       
    45             _S("ERStateFinished"), 
       
    46             _S("ERStateFailed"), 
       
    47             };
       
    48 
       
    49 static const TText* RStateName(TInt aState)
       
    50     {
       
    51     return KRStateNames[aState];
       
    52     }
       
    53 
       
    54 #endif // SYMBIAN_SWCODEC_LOGGING
       
    55 
       
    56 #ifdef _DEBUG
       
    57 
       
    58 static void Panic(TInt aPanic)
       
    59     {
       
    60     _LIT(KPanicString, "SwAudioInput");
       
    61     User::Panic(KPanicString, aPanic);
       
    62     }
       
    63 
       
    64 void CAudioInput::CheckFullInvariant()
       
    65     {
       
    66     CheckInvariant();
       
    67     CheckActiveRecorders();
       
    68     }
       
    69 
       
    70 void CAudioInput::CheckInvariant(TBool aKnownConstructed)
       
    71     {
       
    72     // full check would be that each recorder is in one, and only one, queue.
       
    73     // However, since the queues share the same infrastructure, checking the overall length of queues
       
    74     // is correct should suffice. During construction or deletion this may obviously vary
       
    75     TInt totalLength = QLength(iIdleQueue) + QLength(iRecordingQueue) + 
       
    76            QLength(iPendingQueue) + QLength(iBusyQueue);
       
    77     if (aKnownConstructed)
       
    78         {
       
    79         __ASSERT_DEBUG(totalLength==KNumRecorders, Panic(KPanicBadTotalQueueLength));
       
    80         }
       
    81     else
       
    82         {
       
    83         __ASSERT_DEBUG(totalLength<=KNumRecorders, Panic(KPanicBadTotalQueueLength2));        
       
    84         }
       
    85     __ASSERT_DEBUG(QLength(iBusyQueue)<=1, Panic(KPanicBadTotalQueueLength));
       
    86     }
       
    87 
       
    88 #else // _DEBUG
       
    89 
       
    90 // inline versions that do nothing...
       
    91 
       
    92 inline void CAudioInput::CheckFullInvariant()
       
    93 	{
       
    94 	}
       
    95 	
       
    96 inline void CAudioInput::CheckInvariant(TBool /*aKnownConstructed*/)
       
    97 	{
       
    98 	}
       
    99 
       
   100 #endif // _DEBUG
       
   101 
       
   102 const TInt KMinBufferSize = 4; // assume a good default?
       
   103 //Shared chunk driver does not support max. buffer size. 16K is given in order to simulate the old driver behavior.
       
   104 const TInt KMaxBufferSize = 0x4000;
       
   105 
       
   106 //Table that maps given linear value of volume to the corresponding decibel value.
       
   107 const TUint8 KLinearToDbConstantLookup[] =
       
   108                         {
       
   109                             0,            // 0
       
   110                             158,
       
   111                             170,
       
   112                             177,
       
   113                             182,
       
   114                             186,
       
   115                             189,
       
   116                             192,
       
   117                             194,
       
   118                             196,
       
   119                             198,          // 10
       
   120                             200,
       
   121                             201,
       
   122                             203,
       
   123                             204,
       
   124                             205,
       
   125                             206,
       
   126                             207,
       
   127                             208,
       
   128                             209,
       
   129                             210,          // 20
       
   130                             211,
       
   131                             212,
       
   132                             213,
       
   133                             213,
       
   134                             214,
       
   135                             215,
       
   136                             215,
       
   137                             216,
       
   138                             217,
       
   139                             217,          // 30
       
   140                             218,
       
   141                             218,
       
   142                             219,
       
   143                             219,
       
   144                             220,
       
   145                             220,
       
   146                             221,
       
   147                             221,
       
   148                             222,
       
   149                             222,          // 40
       
   150                             223,
       
   151                             223,
       
   152                             224,
       
   153                             224,
       
   154                             224,
       
   155                             225,
       
   156                             225,
       
   157                             225,
       
   158                             226,
       
   159                             226,          // 50
       
   160                             226,
       
   161                             227,
       
   162                             227,
       
   163                             227,
       
   164                             228,
       
   165                             228,
       
   166                             228,
       
   167                             229,
       
   168                             229,
       
   169                             229,          // 60
       
   170                             230,
       
   171                             230,
       
   172                             230,
       
   173                             230,
       
   174                             231,
       
   175                             231,
       
   176                             231,
       
   177                             231,
       
   178                             232,
       
   179                             232,          // 70
       
   180                             232,
       
   181                             232,
       
   182                             233,
       
   183                             233,
       
   184                             233,
       
   185                             233,
       
   186                             234,
       
   187                             234,
       
   188                             234,
       
   189                             234,          // 80
       
   190                             235,
       
   191                             235,
       
   192                             235,
       
   193                             235,
       
   194                             235,
       
   195                             236,
       
   196                             236,
       
   197                             236,
       
   198                             236,
       
   199                             236,          // 90
       
   200                             237,
       
   201                             237,
       
   202                             237,
       
   203                             237,
       
   204                             237,
       
   205                             237,
       
   206                             238,
       
   207                             238,
       
   208                             238,
       
   209                             238,          // 100
       
   210                             238,
       
   211                             239,
       
   212                             239,
       
   213                             239,
       
   214                             239,
       
   215                             239,
       
   216                             239,
       
   217                             240,
       
   218                             240,
       
   219                             240,          // 110
       
   220                             240,
       
   221                             240,
       
   222                             240,
       
   223                             240,
       
   224                             241,
       
   225                             241,
       
   226                             241,
       
   227                             241,
       
   228                             241,
       
   229                             241,          // 120
       
   230                             241,
       
   231                             242,
       
   232                             242,
       
   233                             242,
       
   234                             242,
       
   235                             242,
       
   236                             242,
       
   237                             242,
       
   238                             243,
       
   239                             243,          // 130
       
   240                             243,
       
   241                             243,
       
   242                             243,
       
   243                             243,
       
   244                             243,
       
   245                             244,
       
   246                             244,
       
   247                             244,
       
   248                             244,
       
   249                             244,          // 140
       
   250                             244,
       
   251                             244,
       
   252                             244,
       
   253                             245,
       
   254                             245,
       
   255                             245,
       
   256                             245,
       
   257                             245,
       
   258                             245,
       
   259                             245,          // 150
       
   260                             245,
       
   261                             245,
       
   262                             246,
       
   263                             246,
       
   264                             246,
       
   265                             246,
       
   266                             246,
       
   267                             246,
       
   268                             246,
       
   269                             246,          // 160
       
   270                             246,
       
   271                             247,
       
   272                             247,
       
   273                             247,
       
   274                             247,
       
   275                             247,
       
   276                             247,
       
   277                             247,
       
   278                             247,
       
   279                             247,          // 170
       
   280                             247,
       
   281                             248,
       
   282                             248,
       
   283                             248,
       
   284                             248,
       
   285                             248,
       
   286                             248,
       
   287                             248,
       
   288                             248,
       
   289                             248,          // 180
       
   290                             248,
       
   291                             249,
       
   292                             249,
       
   293                             249,
       
   294                             249,
       
   295                             249,
       
   296                             249,
       
   297                             249,
       
   298                             249,
       
   299                             249,          // 190
       
   300                             249,
       
   301                             250,
       
   302                             250,
       
   303                             250,
       
   304                             250,
       
   305                             250,
       
   306                             250,
       
   307                             250,
       
   308                             250,
       
   309                             250,          // 200
       
   310                             250,
       
   311                             250,
       
   312                             250,
       
   313                             251,
       
   314                             251,
       
   315                             251,
       
   316                             251,
       
   317                             251,
       
   318                             251,
       
   319                             251,          // 210
       
   320                             251,
       
   321                             251,
       
   322                             251,
       
   323                             251,
       
   324                             251,
       
   325                             252,
       
   326                             252,
       
   327                             252,
       
   328                             252,
       
   329                             252,          // 220
       
   330                             252,
       
   331                             252,
       
   332                             252,
       
   333                             252,
       
   334                             252,
       
   335                             252,
       
   336                             252,
       
   337                             252,
       
   338                             253,
       
   339                             253,          // 230
       
   340                             253,
       
   341                             253,
       
   342                             253,
       
   343                             253,
       
   344                             253,
       
   345                             253,
       
   346                             253,
       
   347                             253,
       
   348                             253,
       
   349                             253,          // 240
       
   350                             253,
       
   351                             254,
       
   352                             254,
       
   353                             254,
       
   354                             254,
       
   355                             254,
       
   356                             254,
       
   357                             254,
       
   358                             254,
       
   359                             254,          // 250
       
   360                             254,
       
   361                             254,
       
   362                             254,
       
   363                             254,
       
   364                             254
       
   365                         };
       
   366 
       
   367 // rate lookup table
       
   368 
       
   369 const TInt KNumSampleRates = 9;
       
   370 
       
   371 struct TSampleRateEnumTable
       
   372     {
       
   373     TInt iRate;
       
   374     TSoundRate iRateEnum;
       
   375     TUint iRateConstant;
       
   376     };
       
   377 //Table that maps given samples per second to the corresponding enums in RSoundSc
       
   378 const TSampleRateEnumTable KRateEnumLookup[] =
       
   379     {
       
   380         {48000,ESoundRate48000Hz,KSoundRate48000Hz},
       
   381         {44100,ESoundRate44100Hz,KSoundRate44100Hz},
       
   382         {32000,ESoundRate32000Hz,KSoundRate32000Hz},
       
   383         {24000,ESoundRate24000Hz,KSoundRate24000Hz},
       
   384         {22050,ESoundRate22050Hz,KSoundRate22050Hz},
       
   385         {16000,ESoundRate16000Hz,KSoundRate16000Hz},
       
   386         {12000,ESoundRate12000Hz,KSoundRate12000Hz},
       
   387         {11025,ESoundRate11025Hz,KSoundRate11025Hz},
       
   388         {8000, ESoundRate8000Hz, KSoundRate8000Hz}
       
   389     };
       
   390 
       
   391 // TAudioInputParams
       
   392 
       
   393 EXPORT_C TAudioInputParams::TAudioInputParams() :
       
   394     iSampleRate(0), iNominalBufferSize(0)
       
   395     {
       
   396     // none	
       
   397     }
       
   398 
       
   399 // CAudioInput
       
   400 
       
   401 EXPORT_C MAudioInput* MAudioInput::CreateL(MAudioInputObserver& aObserver)
       
   402     {
       
   403     MAudioInput* result = CAudioInput::NewL(aObserver);
       
   404     return result;
       
   405     }
       
   406 
       
   407 CAudioInput* CAudioInput::NewL(MAudioInputObserver& aObserver)
       
   408     {
       
   409     CAudioInput* result = new CAudioInput(aObserver);
       
   410     CleanupStack::PushL(result);
       
   411     result->ConstructL();
       
   412     CleanupStack::Pop(result);
       
   413     return result;
       
   414     }
       
   415 
       
   416 CAudioInput::CAudioInput(MAudioInputObserver& aObserver) :
       
   417     iObserver(aObserver),
       
   418     iIdleQueue(_FOFF(CRecorder,iLink)),
       
   419     iRecordingQueue(_FOFF(CRecorder,iLink)),
       
   420     iPendingQueue(_FOFF(CRecorder,iLink)),
       
   421     iBusyQueue(_FOFF(CRecorder,iLink))
       
   422     {
       
   423     ASSERT(iState == EStateCreated2); // assume zero'ing initialises correctly
       
   424     }
       
   425 
       
   426 void CAudioInput::Release()
       
   427 // effective destructor call
       
   428     {
       
   429     delete this;
       
   430     }
       
   431 
       
   432 TAny* CAudioInput::Interface(TUid aInterfaceUid)
       
   433     {
       
   434     if (aInterfaceUid == KUidAIParamInterface)
       
   435         {
       
   436         MAIParamInterface* self = this;
       
   437         return self;
       
   438         }
       
   439     return NULL;
       
   440     }
       
   441 
       
   442 RSoundSc& CAudioInput::RecordSoundDevice()
       
   443     {
       
   444     ASSERT(iRecordSoundDevice.Handle()!=0); // should be open
       
   445     return iRecordSoundDevice;
       
   446     }
       
   447 
       
   448 CAudioInput::~CAudioInput()
       
   449     {
       
   450     CheckInvariant(EFalse); // may not be constructed
       
   451     Cancel();
       
   452     for (TInt i = 0; i < KNumRecorders; i++)
       
   453         {
       
   454         // just in case, call cancel directly from this point too
       
   455         // Cancel depends on the active queue, and might not be quite the same.
       
   456         CRecorder* recorder = iRecorders[i];
       
   457         if (recorder)
       
   458             {
       
   459             recorder->Cancel();
       
   460             }
       
   461         delete recorder;
       
   462         }
       
   463     delete iAsyncCallBack;
       
   464     iConvBuff.Close();
       
   465     iRecordSoundDevice.Close();
       
   466     iChunk.Close();
       
   467     }
       
   468 
       
   469 void CAudioInput::Cancel()
       
   470     {
       
   471 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   472     RDebug::Print(_L("--->CAudioInput::Cancel()"));
       
   473 #endif
       
   474     CancelRecorders();
       
   475     if (iAsyncCallBack)
       
   476         {
       
   477         iAsyncCallBack->Cancel();
       
   478         }
       
   479 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   480     RDebug::Print(_L("<---CAudioInput::Cancel()"));
       
   481 #endif
       
   482     }
       
   483 
       
   484 void CAudioInput::CancelRecorders()
       
   485 // if a recorder is active, then cancel it. Also move the list if required.
       
   486     {
       
   487     CheckInvariant(); // semi-invariant check - this is called from destructor
       
   488     
       
   489     CRecorder* recorder;
       
   490     while (QPop(recorder, iRecordingQueue))
       
   491         {
       
   492         recorder->Cancel();
       
   493         iIdleQueue.AddLast(*recorder);
       
   494         }
       
   495     CheckFullInvariant();
       
   496     }
       
   497 
       
   498 void CAudioInput::CancelPendingRecorders()
       
   499 // take any recorder in the pending queue. ack the buffer and send to idle
       
   500     {
       
   501     CheckFullInvariant();
       
   502     
       
   503     CRecorder* recorder;
       
   504     while (QPop(recorder, iPendingQueue))
       
   505         {
       
   506         recorder->ReleaseBuffer();
       
   507         iIdleQueue.AddLast(*recorder);
       
   508         }
       
   509     CheckFullInvariant();
       
   510     }
       
   511 
       
   512 void CAudioInput::CancelBusyRecorder()
       
   513 // take busy recorder. ack the buffer and send to idle
       
   514     {
       
   515     CheckFullInvariant();
       
   516     
       
   517     CRecorder* recorder;
       
   518     if (QPop(recorder, iBusyQueue))
       
   519         {
       
   520         recorder->ReleaseBuffer();
       
   521         iIdleQueue.AddLast(*recorder);
       
   522         }
       
   523     CheckFullInvariant();
       
   524     }
       
   525 
       
   526 void CAudioInput::RecordAllIdle()
       
   527 // take any recorder in idle queue and set recording
       
   528     {
       
   529     CheckFullInvariant();
       
   530     
       
   531     CRecorder* recorder;
       
   532     while (QPop(recorder, iIdleQueue))
       
   533         {
       
   534         recorder->RecordData();
       
   535         iRecordingQueue.AddLast(*recorder);
       
   536         }
       
   537     CheckFullInvariant();    
       
   538     }
       
   539 
       
   540 void CAudioInput::ConstructL()
       
   541     {
       
   542     for (TInt i = 0; i < KNumRecorders; i++)
       
   543         {
       
   544         iRecorders[i] = new (ELeave) CRecorder(*this, i);
       
   545         iIdleQueue.AddLast(*(iRecorders[i]));
       
   546         }
       
   547     iAsyncCallBack = new (ELeave) CAsyncCallBack(CActive::EPriorityStandard);
       
   548     TCallBack callback(Callback, this);
       
   549     iAsyncCallBack->Set(callback);
       
   550     User::LoadPhysicalDevice(KPddFileName);
       
   551     User::LoadLogicalDevice(KLddFileName);
       
   552     CheckFullInvariant();
       
   553     }
       
   554 
       
   555 TInt CAudioInput::Initialize(const TAudioInputParams& aParams)
       
   556     {
       
   557 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   558     RDebug::Print(_L("--->CAudioInput::Initialize() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
       
   559 #endif
       
   560     CheckFullInvariant();
       
   561     TInt error = KErrNone;
       
   562     if (iState == EStateCreated2)
       
   563         {
       
   564         if (!iRecordSoundDevice.Handle())
       
   565             {
       
   566             error = iRecordSoundDevice.Open(KSoundScRxUnit0);
       
   567             if (error)
       
   568                 {
       
   569                 Close(); // TODO Close() required?
       
   570                 }
       
   571             }
       
   572         if (!error)
       
   573             {
       
   574             iBufferLength = aParams.iNominalBufferSize; // will be updated by SetFormat() if required
       
   575             error = SetFormat(aParams);
       
   576             if (!error)
       
   577                 {
       
   578                 iRecordBufferConfig.iNumBuffers = KNumRecorders*2; // for each AO we create two buffers
       
   579                 iRecordBufferConfig.iFlags = 0;
       
   580                 iRecordBufferConfig.iBufferSizeInBytes = iBufferLength;
       
   581                 ASSERT(iChunk.Handle()==0); // should not be already open
       
   582                 TPckg<TRecordSharedChunkBufConfig> bufferConfigBuf(
       
   583                         iRecordBufferConfig);
       
   584                 error = iRecordSoundDevice.SetBufferChunkCreate(
       
   585                         bufferConfigBuf, iChunk);
       
   586 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   587                 RDebug::Print(
       
   588                         _L("iRecordBufferConfig.iNumBuffers =  [%d]"),iRecordBufferConfig.iNumBuffers);
       
   589                 RDebug::Print(
       
   590                         _L("iRecordBufferConfig.iFlags =  [%d]"),iRecordBufferConfig.iFlags);
       
   591                 RDebug::Print(
       
   592                         _L("iRecordBufferConfig.iBufferSizeInBytes =  [%d]"),iRecordBufferConfig.iBufferSizeInBytes);
       
   593 #endif			
       
   594                 if (error == KErrNone)
       
   595                     {
       
   596 					ASSERT(iChunk.Handle()); // should now be open
       
   597                     iRecordSoundDevice.GetBufferConfig(bufferConfigBuf); // overwrite iRecordBufferConfig
       
   598 					SetGain(aParams.iInitialGain);
       
   599                     iState = EStateInitialized2;
       
   600                     }
       
   601                 }
       
   602             }
       
   603         }
       
   604     else
       
   605         {
       
   606         error = KErrNotReady;
       
   607         }
       
   608 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   609     RDebug::Print(_L("<---CAudioInput::Initialize(%d) state=%s rstate=%s"), error, StateName(
       
   610             iState), RStateName(iRState));
       
   611 #endif
       
   612     CheckFullInvariant();
       
   613     return error;
       
   614     }
       
   615 
       
   616 void CAudioInput::Close()
       
   617     {
       
   618 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   619     RDebug::Print(_L("--->CAudioInput::Close() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
       
   620 #endif
       
   621     CheckFullInvariant();
       
   622     InternalStop(); // Technically this should not be required, as client should Stop() first, but just in case
       
   623     if (iState == EStateInitialized2)
       
   624         {
       
   625         iRecordSoundDevice.Close();
       
   626         iChunk.Close();
       
   627         iConvBuff.Close();
       
   628         iState = EStateCreated2;
       
   629         }
       
   630     ASSERT(iState==EStateCreated2);
       
   631     ASSERT(QLength(iIdleQueue)==KNumRecorders);
       
   632 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   633     RDebug::Print(_L("<---CAudioInput::Close() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
       
   634 #endif
       
   635     CheckFullInvariant();
       
   636     }
       
   637 
       
   638 TInt CAudioInput::Start()
       
   639     {
       
   640 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   641     RDebug::Print(_L("--->CAudioInput::Start() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
       
   642 #endif
       
   643     CheckFullInvariant();
       
   644     TInt error = KErrNone;
       
   645     if (iState == EStateInitialized2)
       
   646         {
       
   647         RecordAllIdle();
       
   648         iState = EStateRecordWait2;
       
   649         iRState = ERStateRunning;
       
   650         }
       
   651     else
       
   652         {
       
   653         error = KErrNotReady;
       
   654         }
       
   655 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   656     RDebug::Print(_L("<---CAudioInput::Start(%d) state=%s rstate=%s"), 
       
   657             error, StateName(iState), RStateName(iRState));
       
   658 #endif
       
   659     CheckFullInvariant();
       
   660     return error;
       
   661     }
       
   662 
       
   663 void CAudioInput::BufferAck()
       
   664     {
       
   665 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   666     RDebug::Print(_L("--->CAudioInput::BufferAck() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
       
   667 #endif
       
   668     CheckFullInvariant();
       
   669     ASSERT(iState==EStateRecordWaitAck2);
       
   670     HandleBufferAck();
       
   671     iState = EStateRecordWait2;
       
   672     RequestCallback();
       
   673 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   674     RDebug::Print(_L("<---CAudioInput::BufferAck() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
       
   675 #endif
       
   676     CheckFullInvariant();
       
   677     }
       
   678 
       
   679 void CAudioInput::HandleBufferAck()
       
   680     {
       
   681     CRecorder* recorder = QPop(iBusyQueue);
       
   682     recorder->ReleaseBuffer();
       
   683     if (iRState == ERStateRunning)
       
   684         {
       
   685         recorder->RecordData();
       
   686         iRecordingQueue.AddLast(*recorder);
       
   687         }
       
   688     else
       
   689         {
       
   690         iIdleQueue.AddLast(*recorder);
       
   691         if (iRState == ERStatePaused && (QLength(iRecordingQueue)+QLength(iPendingQueue) == 0))
       
   692             {
       
   693             iRState = ERStateFinishing;
       
   694             }
       
   695         }
       
   696     }
       
   697 
       
   698 TInt CAudioInput::Pause()
       
   699     {
       
   700 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   701     RDebug::Print(_L("--->CAudioInput::Pause() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
       
   702 #endif
       
   703     CheckFullInvariant();
       
   704     TInt err = KErrNone; // note we are silent if called in wrong state
       
   705     
       
   706 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   707     RDebug::Print(
       
   708                 _L("***!pause irecordingquelength %d pendingquelength %d ibusyquelength=%d"), QLength(iRecordingQueue),
       
   709                 QLength(iPendingQueue), QLength(iBusyQueue));
       
   710 #endif
       
   711     if ((iState == EStateRecordWait2 || iState == EStateRecordWaitAck2) && iRState==ERStateRunning)
       
   712         {
       
   713         iRecordSoundDevice.Pause();
       
   714 
       
   715         iRState = ERStatePaused;
       
   716         }
       
   717 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   718     RDebug::Print(_L("<---CAudioInput::Pause(%d) state=%s err=%d"), err, StateName(iState), RStateName(iRState));
       
   719 #endif
       
   720     CheckFullInvariant();
       
   721     return err; 
       
   722     }
       
   723 
       
   724 TInt CAudioInput::Resume()
       
   725     {
       
   726 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   727     RDebug::Print(_L("--->CAudioInput::Resume() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
       
   728 #endif
       
   729     CheckFullInvariant();
       
   730     TInt err = KErrNone; // note we are silent if called in the wrong state
       
   731     if ((iState == EStateRecordWait2 || iState == EStateRecordWaitAck2) && 
       
   732             ((iRState==ERStatePaused || iRState==ERStateFinishing || iRState==ERStateFinished)))
       
   733         {
       
   734         err = RecordSoundDevice().Resume();
       
   735         
       
   736         RecordAllIdle();
       
   737         
       
   738         iRState = ERStateRunning;
       
   739         }
       
   740 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   741     RDebug::Print(_L("<---CAudioInput::Resume(%d) state=%s rstate=%s"), err, StateName(iState), RStateName(iRState));
       
   742 #endif
       
   743     CheckFullInvariant();
       
   744     return err; 
       
   745     }
       
   746 
       
   747 TInt CAudioInput::Flush()
       
   748     {
       
   749 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   750     RDebug::Print(_L("--->CAudioInput::Flush() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
       
   751 #endif
       
   752     CheckFullInvariant();
       
   753     TInt error = KErrNotReady;
       
   754     if (iRState==ERStatePaused)
       
   755         {
       
   756         if (iState == EStateRecordWait2)
       
   757             {
       
   758             InternalFlush();
       
   759             ASSERT(iState == EStateRecordWait2); // stay put
       
   760             error = KErrNone;
       
   761             }
       
   762         else if (iState == EStateRecordWaitAck2)
       
   763             {
       
   764             InternalFlush();
       
   765             iState = EStateRecordWait2;
       
   766             error = KErrNone;
       
   767             }       
       
   768         }
       
   769  #ifdef SYMBIAN_SWCODEC_LOGGING
       
   770     RDebug::Print(_L("--->CAudioInput::Flush(%d) state=%s rstate=%s"), error, StateName(iState), RStateName(iRState));
       
   771 #endif
       
   772     CheckFullInvariant();
       
   773     return error;
       
   774     }
       
   775 
       
   776 void CAudioInput::Stop()
       
   777     {
       
   778 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   779     RDebug::Print(_L("--->CAudioInput::Stop() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
       
   780 #endif
       
   781     CheckFullInvariant();
       
   782     InternalStop();
       
   783 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   784     RDebug::Print(_L("<---CAudioInput::Stop() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
       
   785 #endif
       
   786     }
       
   787 
       
   788 void CAudioInput::InternalStop()
       
   789 // This stops all recording and returns pending and busy buffers to idle. Must be called when
       
   790 // client knows the buffer has been grabbed (e.g. _not_ before error callback)
       
   791     {
       
   792     CheckInvariant(); // Can be called from buffer error, so can't check full invariant.
       
   793     if (iState != EStateInitialized2 && iState != EStateCreated2)
       
   794         {
       
   795         InternalFlush();
       
   796         iState = EStateInitialized2;
       
   797         }
       
   798     CheckFullInvariant();
       
   799     ASSERT((QLength(iRecordingQueue) + QLength(iPendingQueue) + 
       
   800 					QLength(iBusyQueue))==0); // everything is stopped 
       
   801     }
       
   802 
       
   803 void CAudioInput::InternalFlush()
       
   804     {
       
   805     CancelRecorders();
       
   806     CancelPendingRecorders();
       
   807     CancelBusyRecorder();
       
   808     }
       
   809 
       
   810 void CAudioInput::BufferArrives(CRecorder* aRecorder)
       
   811     {
       
   812 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   813     RDebug::Print(
       
   814             _L("--->CAudioInput::BufferArrives(%d,%d) state=%s rstate=%s"), aRecorder->Index(),
       
   815             aRecorder->StatusOrOffset(), StateName(iState), RStateName(iRState));
       
   816 #endif
       
   817     CheckInvariant(); // Can't use CheckFullInvariant() from RunL
       
   818     ASSERT(iState==EStateRecordWait2 || iState==EStateRecordWaitAck2);
       
   819     ASSERT(aRecorder->Offset()>=0); // assert we're not here due to an error
       
   820     iRecordingQueue.Remove(*aRecorder);
       
   821     iPendingQueue.AddLast(*aRecorder);
       
   822     if (iState==EStateRecordWait2)
       
   823         {
       
   824         RequestCallback();
       
   825         }
       
   826 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   827     RDebug::Print(_L("<---CAudioInput::BufferArrives() state=%s rstate=%s"), 
       
   828             StateName(iState), RStateName(iRState));
       
   829 #endif
       
   830     CheckFullInvariant();
       
   831     }
       
   832 
       
   833 void CAudioInput::UseBuffer(CRecorder* aRecorder)
       
   834 // incomming buffer is pointed to by iBufPtr. Either directly or via convert, use for callback
       
   835     {
       
   836     iBufPtr.Set(iChunk.Base() + aRecorder->Offset(), aRecorder->Length());
       
   837     if (iConverter)
       
   838         {
       
   839 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   840         RDebug::Print(_L("iBufPtr length [%d] iconvbuff length [%d,%d]"),
       
   841                 iBufPtr.Length(), iConvBuff.Length(), iConvBuff.MaxLength());
       
   842 #endif
       
   843         __DEBUG_ONLY(TInt converted =) iConverter->Convert(iBufPtr, iConvBuff);
       
   844         // the following assert should check we convert the log. 
       
   845         // Actually we sometimes fail at the end of the operation with what is effectively
       
   846         // the last buffer. Arguably a driver fault, but there we are
       
   847         // ASSERT(converted==iBufPtr.Length());  
       
   848 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   849         RDebug::Print(_L("iBufPtr length [%d] iconvbuff length after [%d,%d]"),
       
   850         iBufPtr.Length(), iConvBuff.Length(), iConvBuff.MaxLength());
       
   851 #endif
       
   852         iObserver.InputBufferAvailable(iConvBuff);
       
   853         }
       
   854     else
       
   855         {
       
   856         iObserver.InputBufferAvailable(iBufPtr);
       
   857         }
       
   858 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   859     RDebug::Print(_L("12345 ibufptr =  [0x%x]"),iBufPtr.Ptr());
       
   860 #endif
       
   861     }
       
   862 
       
   863 void CAudioInput::BufferError(CRecorder* aRecorder, TInt aError)
       
   864     {
       
   865 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   866     RDebug::Print(
       
   867             _L("--->CAudioInput::BufferError(%d,%d) state=%s rstate=%s"), aRecorder->Index(),
       
   868             aError, StateName(iState), RStateName(iRState));
       
   869 #endif
       
   870     CheckInvariant(); // Can't use CheckFullInvariant() from RunL
       
   871     if (aError==KErrCancel || aError==KErrOverflow)
       
   872         {
       
   873         // Cancel: sign of a Pause operation. If paused etc, then merely add to idle list. potentially generate finished signal
       
   874         //         if not paused, then not clear but just in case request record again
       
   875         // Overflow: basically try again, but if paused merely add to idle. Check for last buffer just in case
       
   876         if (iRState!=ERStateRunning)
       
   877             {
       
   878             iRecordingQueue.Remove(*aRecorder);
       
   879             iIdleQueue.AddLast(*aRecorder);
       
   880 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   881             RDebug::Print(
       
   882                         _L("***! irecordingquelength %d pendingquelength %d ibusyquelength=%d"), QLength(iRecordingQueue),
       
   883                         QLength(iPendingQueue), QLength(iBusyQueue));
       
   884 #endif
       
   885             if (iRState == ERStatePaused && (QLength(iRecordingQueue)+QLength(iPendingQueue)+QLength(iBusyQueue) == 0))
       
   886                 {
       
   887                 iRState = ERStateFinishing;
       
   888                 RequestCallback();
       
   889                 }
       
   890             }
       
   891         else
       
   892             {
       
   893             aRecorder->RecordData();
       
   894             }
       
   895         }
       
   896     else
       
   897         {
       
   898         iRecordingQueue.Remove(*aRecorder);
       
   899         iIdleQueue.AddLast(*aRecorder);
       
   900         iRState = ERStateFailed;
       
   901         iObserver.InputError(aError);        
       
   902         }
       
   903 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   904     RDebug::Print(_L("<---CAudioInput::BufferError() state=%s rstate=%s"), 
       
   905             StateName(iState), RStateName(iRState));
       
   906 #endif
       
   907     CheckFullInvariant();
       
   908     }
       
   909 
       
   910 TInt CAudioInput::Callback(TAny* aPtr)
       
   911     {
       
   912     CAudioInput* self = static_cast<CAudioInput*> (aPtr);
       
   913     TRAPD(error,self->AsyncCallbackL());
       
   914     return error; // TODO really have to handle error
       
   915     }
       
   916 
       
   917 void CAudioInput::RequestCallback()
       
   918     {
       
   919     // ensure iAsyncCallBack is active
       
   920     if (!iAsyncCallBack->IsActive())
       
   921         {
       
   922         iAsyncCallBack->Call();
       
   923         }
       
   924     }
       
   925 
       
   926 void CAudioInput::AsyncCallbackL()
       
   927     {
       
   928 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   929     RDebug::Print(_L("--->CAudioInput::AsyncCallbackL() state=%s rstate=%s"), 
       
   930             StateName(iState), RStateName(iRState));
       
   931 #endif
       
   932     CheckFullInvariant();
       
   933     ASSERT(iState==EStateRecordWait2 || iState==EStateRecordWaitAck2); // should not occur in other states. Actually ignore in 2nd
       
   934     if (iState==EStateRecordWait2)
       
   935         {
       
   936         if (QLength(iPendingQueue)>0)
       
   937             {
       
   938             ASSERT(QLength(iBusyQueue)==0);
       
   939             iState = EStateRecordWaitAck2; // change state prior to callback, in case sync call from callback
       
   940             CRecorder* recorder = QPop(iPendingQueue);
       
   941             iBusyQueue.AddLast(*recorder);
       
   942             UseBuffer(recorder);
       
   943             }
       
   944         else 
       
   945             {
       
   946             if (iRState == ERStateFinishing)
       
   947                 {
       
   948                 ASSERT(QLength(iRecordingQueue)+QLength(iPendingQueue)+QLength(iBusyQueue) == 0); // should be true
       
   949                 iRState = ERStateFinished;
       
   950                 iObserver.InputFinished();
       
   951                 }
       
   952             }
       
   953         }
       
   954 #ifdef SYMBIAN_SWCODEC_LOGGING
       
   955     RDebug::Print(_L("<---CAudioInput::AsyncCallbackL() state=%s rstate=%s"), 
       
   956             StateName(iState), RStateName(iRState));
       
   957 #endif
       
   958     CheckFullInvariant();
       
   959     }
       
   960 
       
   961 TInt CAudioInput::GetBufferSizes(TInt& aMinSize, TInt& aMaxSize)
       
   962     {
       
   963     aMinSize = KMinBufferSize;
       
   964     aMaxSize = KMaxBufferSize;
       
   965     return KErrNone;
       
   966     }
       
   967 
       
   968 TInt CAudioInput::SetGain(TInt aGain)
       
   969     {
       
   970     TInt error = KErrNone; // note: silent if in wrong state
       
   971     if (iRecordSoundDevice.Handle())
       
   972         {
       
   973         // we have to switch from level to dB value
       
   974         if(aGain >=0 && aGain<=KSoundMaxVolume)
       
   975             {
       
   976             error = iRecordSoundDevice.SetVolume(KLinearToDbConstantLookup[aGain]);
       
   977             }
       
   978         else
       
   979             {
       
   980             error = KErrArgument;
       
   981             }
       
   982         }
       
   983     return error;
       
   984     }
       
   985 
       
   986 TInt CAudioInput::SetFormat(const TAudioInputParams& aFormat)
       
   987     {
       
   988     TInt err = KErrNotFound;
       
   989     TCurrentSoundFormatV02Buf formatBuf;
       
   990     TFormatData formatData;
       
   991 
       
   992     delete iConverter;
       
   993     iConverter = NULL; // setting this to NULL indicates we are not using converter. No other flag
       
   994 
       
   995     TInt wantedRate = aFormat.iSampleRate;
       
   996     for (TInt index = 0; index < KNumSampleRates; index++)
       
   997         {
       
   998         if (wantedRate == KRateEnumLookup[index].iRate)
       
   999             {
       
  1000             formatBuf().iRate = KRateEnumLookup[index].iRateEnum;
       
  1001             formatData.iSampleRate = wantedRate;
       
  1002             err = KErrNone;
       
  1003             break;
       
  1004             }
       
  1005         }
       
  1006 
       
  1007     if (err == KErrNone)
       
  1008         {
       
  1009         formatBuf().iChannels = aFormat.iNumChannels;
       
  1010         formatBuf().iEncoding = ESoundEncoding16BitPCM;
       
  1011         formatBuf().iDataFormat = ESoundDataFormatInterleaved;
       
  1012         err = iRecordSoundDevice.SetAudioFormat(formatBuf);
       
  1013 #if defined(SYMBIAN_SOUNDADAPTER_FORCECDRATES) || defined (SYMBIAN_SOUNDADAPTER_FORCESTEREO)
       
  1014         err = KErrNotSupported; // force Negotiate - for debugging
       
  1015 #endif
       
  1016         if (err == KErrNotSupported)
       
  1017             {
       
  1018             // don't support directly. Perhaps can rate convert?
       
  1019             err = NegotiateFormat(aFormat, formatData);
       
  1020             }
       
  1021         }
       
  1022     return err;
       
  1023     }
       
  1024 
       
  1025 TInt CAudioInput::NegotiateFormat(const TAudioInputParams& aFormat, TFormatData &aFormatData)
       
  1026     {
       
  1027     TInt err = KErrNotFound;
       
  1028     TCurrentSoundFormatV02Buf formatBuf;
       
  1029     
       
  1030     TInt origBufferLength = iBufferLength; // cache in case we change
       
  1031 
       
  1032     // find out first what the driver supports
       
  1033     TSoundFormatsSupportedV02Buf supportedFormat;
       
  1034     iRecordSoundDevice.Caps(supportedFormat);
       
  1035     TUint32 supportedRates = supportedFormat().iRates;
       
  1036 #ifdef SYMBIAN_SOUNDADAPTER_FORCECDRATES
       
  1037     supportedRates &= KSoundRate11025Hz | KSoundRate22050Hz
       
  1038             | KSoundRate44100Hz; // only use CD rates - for debugging
       
  1039 #endif
       
  1040 
       
  1041     // For RecordCase:
       
  1042     //		We want the next rate above consistently - we go down from this to the requested rate.
       
  1043     //		If there is one, we don't support - we _never_ upsample.
       
  1044     // note that the table is given in descending order, so we start with the highest
       
  1045     TInt wantedRate = aFormat.iSampleRate;
       
  1046     TInt takeTheFirst = EFalse;
       
  1047     TInt nextUpValidIndex = -1;
       
  1048     for (TInt index = 0; index < KNumSampleRates; index++)
       
  1049         {
       
  1050         TBool lookingAtRequestedRate = wantedRate
       
  1051                 == KRateEnumLookup[index].iRate;
       
  1052         TSoundRate wantedEnum = KRateEnumLookup[index].iRateEnum;
       
  1053         TUint32 equivBitmap = KRateEnumLookup[index].iRateConstant;
       
  1054         TBool isSupported = (equivBitmap & supportedRates) != EFalse;
       
  1055         if (lookingAtRequestedRate || takeTheFirst)
       
  1056             {
       
  1057             if (isSupported)
       
  1058                 {
       
  1059                 // this rate is supported
       
  1060                 formatBuf().iRate = wantedEnum;
       
  1061                 aFormatData.iActualRate = KRateEnumLookup[index].iRate;
       
  1062                 err = KErrNone;
       
  1063                 break;
       
  1064                 }
       
  1065             }
       
  1066         else if (!takeTheFirst)
       
  1067             {
       
  1068             // while we are still looking for the rate, want to cache any supported index
       
  1069             // at end of loop, this will be the first rate above ours that is supported
       
  1070             // use for fallback if required
       
  1071             if (isSupported)
       
  1072                 {
       
  1073                 nextUpValidIndex = index;
       
  1074                 }
       
  1075             }
       
  1076         if (lookingAtRequestedRate)
       
  1077             {
       
  1078             // For record we just abort.
       
  1079             break;
       
  1080             }
       
  1081         }
       
  1082 
       
  1083     if (err)
       
  1084         {
       
  1085         // if there is one above the requested rate, use that
       
  1086         if (nextUpValidIndex >= 0)
       
  1087             {
       
  1088             TSoundRate wantedEnum =
       
  1089                     KRateEnumLookup[nextUpValidIndex].iRateEnum;
       
  1090             formatBuf().iRate = wantedEnum;
       
  1091             aFormatData.iActualRate = KRateEnumLookup[nextUpValidIndex].iRate;
       
  1092             err = KErrNone;
       
  1093             }
       
  1094         }
       
  1095 
       
  1096     if (err)
       
  1097         {
       
  1098         // should have something!
       
  1099         return err;
       
  1100         }
       
  1101 
       
  1102     aFormatData.iSampleRate = wantedRate; // iSampleRate is our requested/apparent rate, not the device rate.
       
  1103 
       
  1104     TUint32 channelsSupported = supportedFormat().iChannels;
       
  1105 #ifdef SYMBIAN_SOUNDADAPTER_FORCESTEREO
       
  1106     channelsSupported &= KSoundStereoChannel; // don't use mono - for debugging
       
  1107 #endif
       
  1108 
       
  1109     if (aFormat.iNumChannels == 1)
       
  1110         {
       
  1111         aFormatData.iRequestedChannels = 1;
       
  1112         // want mono
       
  1113         if (channelsSupported & KSoundMonoChannel)
       
  1114             {
       
  1115             // mono is supported, as usual
       
  1116             aFormatData.iActualChannels = 1;
       
  1117             }
       
  1118         else if (channelsSupported & KSoundStereoChannel)
       
  1119             {
       
  1120             aFormatData.iActualChannels = 2;
       
  1121             iBufferLength *= 2; // double size, will do stereo->mono
       
  1122             }
       
  1123         else
       
  1124             {
       
  1125             return KErrNotSupported; // should not get this far for real
       
  1126             }
       
  1127         }
       
  1128     else if (aFormat.iNumChannels == 2)
       
  1129         {
       
  1130         aFormatData.iRequestedChannels = 2;
       
  1131         // want stereo
       
  1132         if (channelsSupported & KSoundStereoChannel)
       
  1133             {
       
  1134             // stereo is supported, as usual
       
  1135             aFormatData.iActualChannels = 2;
       
  1136             }
       
  1137         else if (channelsSupported & KSoundMonoChannel)
       
  1138             {
       
  1139             aFormatData.iActualChannels = 1;
       
  1140             iBufferLength /= 2; // halve size, will do mono->stereo
       
  1141             }
       
  1142         else
       
  1143             {
       
  1144             return KErrNotSupported; // should not get this far for real
       
  1145             }
       
  1146         }
       
  1147     else
       
  1148         {
       
  1149         return KErrNotSupported; // unknown number of channels requested!
       
  1150         }
       
  1151 
       
  1152     formatBuf().iChannels = aFormatData.iActualChannels;
       
  1153 
       
  1154     formatBuf().iEncoding = ESoundEncoding16BitPCM;
       
  1155     formatBuf().iDataFormat = ESoundDataFormatInterleaved;
       
  1156     err = iRecordSoundDevice.SetAudioFormat(formatBuf);
       
  1157 
       
  1158     if (!err)
       
  1159         {
       
  1160         ASSERT(!iConverter); // pre-condition at top of function anyway
       
  1161         // when recording we convert from actual to requested
       
  1162         TInt outputRateToUse = aFormatData.iSampleRate;
       
  1163 #ifdef SYMBIAN_SKIP_RESAMPLE_ON_RECORD
       
  1164 		// with this macro just channel convert at most
       
  1165         outputRateToUse = aFormatData.iActualRate;
       
  1166 #endif
       
  1167 #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
       
  1168 		RDebug::Print(_L("RMdaDevSound::CBody::NegotiateFormat: Convert:CreateL from %d/%d to %d/%d"),
       
  1169                         aFormatData.iActualRate, aFormatData.iActualChannels,
       
  1170                         aFormatData.iSampleRate, aFormatData.iRequestedChannels);
       
  1171 #endif																	       
       
  1172         TRAP(err, iConverter = CChannelAndSampleRateConverter::CreateL(aFormatData.iActualRate,
       
  1173                                 aFormatData.iActualChannels,
       
  1174                                 outputRateToUse,
       
  1175                                 aFormatData.iRequestedChannels));
       
  1176         }
       
  1177     if (!err && iConverter)
       
  1178         {
       
  1179         err = iConvBuff.Create(origBufferLength);
       
  1180 #ifdef SYMBIAN_SWCODEC_LOGGING
       
  1181         RDebug::Print(_L("iBufferLength length [%d] iconvbuff length [%d,%d]"),
       
  1182         iBufferLength, iConvBuff.Length(), iConvBuff.MaxLength());
       
  1183 #endif
       
  1184         }
       
  1185 
       
  1186     return err;
       
  1187     }
       
  1188 
       
  1189 TInt CAudioInput::GetSupportedSampleRates(RArray<TInt>& aSupportedSampleRates)
       
  1190     {
       
  1191     TInt err = KErrNone;
       
  1192 
       
  1193     if (iRecordSoundDevice.Handle())
       
  1194         {
       
  1195         GetSupportedSampleRates(aSupportedSampleRates, iRecordSoundDevice);
       
  1196         }
       
  1197     else
       
  1198         {//temporarily open the device if we can
       
  1199         RSoundSc tempsound;
       
  1200         err = tempsound.Open(KSoundScRxUnit0);
       
  1201         if (!err)
       
  1202             {
       
  1203             err = GetSupportedSampleRates(aSupportedSampleRates, tempsound);
       
  1204             tempsound.Close();
       
  1205             }
       
  1206         }
       
  1207     return err;
       
  1208     }
       
  1209 
       
  1210 TInt CAudioInput::GetSupportedSampleRates(
       
  1211         RArray<TInt>& aSupportedSampleRates, RSoundSc& aSoundDevice)
       
  1212     {
       
  1213     ASSERT(aSoundDevice.Handle()); // parent to ensure this is open
       
  1214 
       
  1215     TInt err = KErrNone;
       
  1216 
       
  1217     TSoundFormatsSupportedV02Buf supportedFormat;
       
  1218     aSoundDevice.Caps(supportedFormat);
       
  1219     TUint32 rates = supportedFormat().iRates;
       
  1220 
       
  1221     for (TInt i = KNumSampleRates - 1; i > 0; i--)//min to max
       
  1222         {
       
  1223         if (rates & KRateEnumLookup[i].iRateConstant)
       
  1224             {
       
  1225             err = aSupportedSampleRates.Append(KRateEnumLookup[i].iRate);
       
  1226             if (err)
       
  1227                 {
       
  1228                 break;
       
  1229                 }
       
  1230             }
       
  1231         }
       
  1232     return err;
       
  1233     }
       
  1234 
       
  1235 TInt CAudioInput::QLength(TSglQue<CRecorder>& aQueue)
       
  1236 // count elements in List/Q. Have to use iterator to do this - it seems.
       
  1237     {
       
  1238     TSglQueIter<CRecorder> iter(aQueue);
       
  1239     TInt count=0;
       
  1240     while (iter++)
       
  1241         {
       
  1242         // like old-fashioned C string manipulations. iterate through all members
       
  1243         count++;
       
  1244         }
       
  1245     return count;
       
  1246     }
       
  1247 
       
  1248 CAudioInput::CRecorder* CAudioInput::QPop(TSglQue<CRecorder>& aQueue)
       
  1249     {
       
  1250     CRecorder* recorder = NULL;
       
  1251     if (! aQueue.IsEmpty())
       
  1252         {
       
  1253         recorder = aQueue.First();
       
  1254         aQueue.Remove(*recorder);
       
  1255         }
       
  1256     return recorder;
       
  1257     }
       
  1258 	
       
  1259 #ifdef _DEBUG
       
  1260 
       
  1261 // these functions are used in invariant checking only
       
  1262 
       
  1263 void CAudioInput::CheckActiveRecorders(TSglQue<CRecorder>& aQueue, TBool aExpected, TInt aPanicCode)
       
  1264 // check that all the elements in the given Q are IsActive() or vice-versa
       
  1265     {
       
  1266     TSglQueIter<CRecorder> iter(aQueue);
       
  1267     
       
  1268     CRecorder* recorder;
       
  1269     while ((recorder=iter++)!=NULL)
       
  1270         {
       
  1271         TBool expected = aExpected != EFalse; // ensure these are either true or false
       
  1272         TBool active = recorder->IsActive() != EFalse;
       
  1273         __ASSERT_DEBUG(expected == active, Panic(aPanicCode));
       
  1274         }
       
  1275     }
       
  1276 
       
  1277 void CAudioInput::CheckActiveRecorders()
       
  1278 // check that all the elements in the recordingQueue are IsActive() etc
       
  1279 // can't be used as CRecorder::RunL() pre-condition
       
  1280     {
       
  1281     CheckActiveRecorders(iRecordingQueue, ETrue, EPanicBusyRecorderNotActive);
       
  1282     CheckActiveRecorders(iIdleQueue, EFalse, EPanicNonBusyRecorderActive);
       
  1283     CheckActiveRecorders(iPendingQueue, EFalse, EPanicNonBusyRecorderActive);
       
  1284     CheckActiveRecorders(iBusyQueue, EFalse, EPanicNonBusyRecorderActive);
       
  1285     }
       
  1286 
       
  1287 #endif // _DEBUG
       
  1288 
       
  1289 //
       
  1290 // CRecorder
       
  1291 //	
       
  1292 
       
  1293 
       
  1294 CAudioInput::CRecorder::CRecorder(CAudioInput& aParent, TInt aIndex) :
       
  1295     CActive(EPriorityStandard), iParent(aParent), iIndex(aIndex)
       
  1296     {
       
  1297     CActiveScheduler::Add(this);
       
  1298     }
       
  1299 
       
  1300 CAudioInput::CRecorder::~CRecorder()
       
  1301     {
       
  1302     Cancel();
       
  1303     }
       
  1304 
       
  1305 void CAudioInput::CRecorder::Cancel()
       
  1306     {
       
  1307     // this override takes into account that ReleaseBuffer must be called - this is not the
       
  1308     // normal pattern where following Cancel() we're not concerned with the results
       
  1309     if (IsActive())
       
  1310         {
       
  1311         ASSERT(!BufferHeld()); // if active then buffer held should be clear. don't reset then
       
  1312         CActive::Cancel();
       
  1313         ReleaseBuffer(ETrue); // release - might have been a successful run!
       
  1314         }
       
  1315     else
       
  1316         {
       
  1317         ReleaseBuffer(); // this will release buffer if still outstanding	
       
  1318         }
       
  1319     }
       
  1320 
       
  1321 void CAudioInput::CRecorder::RunL()
       
  1322     {
       
  1323 #ifdef SYMBIAN_SWCODEC_LOGGING
       
  1324     RDebug::Print(_L("--->CAudioInput::CRecorder::RunL(%d, %d)"), Index(),
       
  1325             iStatus.Int());
       
  1326 #endif
       
  1327     TInt errorOrOffset = iStatus.Int(); // negative -> error. non-negative is offset in chunk
       
  1328 
       
  1329     if (errorOrOffset < 0)
       
  1330         {
       
  1331 #ifdef SYMBIAN_SWCODEC_LOGGING
       
  1332         RDebug::Print(_L("errorOrOffset =  [%d]"),errorOrOffset);
       
  1333 #endif
       
  1334         // ReleaseBuffer(ETrue); // calls ReleaseBuffer() on error code. Driver requires this, even though seems wrong
       
  1335         iParent.BufferError(this, errorOrOffset);
       
  1336         }
       
  1337     else
       
  1338         {
       
  1339         ASSERT(!iBufferHeld);
       
  1340         iBufferHeld = ETrue;
       
  1341 
       
  1342 #ifdef SYMBIAN_SWCODEC_LOGGING
       
  1343         RDebug::Print(_L("errorOrOffset =  [%d]"),errorOrOffset);
       
  1344 #endif
       
  1345         // If a buffer larger than expected arrives truncate it.
       
  1346         iLength = Min(iLength,iParent.iBufferLength);
       
  1347         iParent.BufferArrives(this);
       
  1348         }
       
  1349 #ifdef SYMBIAN_SWCODEC_LOGGING
       
  1350     RDebug::Print(_L("<---CAudioInput::CRecorder::RunL(%d)"), Index());
       
  1351 #endif
       
  1352     }
       
  1353 
       
  1354 void CAudioInput::CRecorder::RecordData()
       
  1355     {
       
  1356 #ifdef SYMBIAN_SWCODEC_LOGGING
       
  1357     RDebug::Print(_L("--->CAudioInput::CRecorder::RecordData(%d)"), Index());
       
  1358 #endif
       
  1359     ASSERT(!iBufferHeld);
       
  1360     Deque(); // ensure we append to the AO queue, so if it comes to it we process oldest request first
       
  1361     CActiveScheduler::Add(this);
       
  1362     iLength = iParent.BufferLength(); // TODO do we have to set this first or is it an OUT param purely
       
  1363     iParent.RecordSoundDevice().RecordData(iStatus, iLength);
       
  1364     SetActive();
       
  1365 
       
  1366 #ifdef SYMBIAN_SWCODEC_LOGGING
       
  1367     RDebug::Print(_L("###****#####!!!! Buffer length [%d], status [%d] "), iLength,
       
  1368             iStatus.Int());
       
  1369 #endif
       
  1370 #ifdef SYMBIAN_SWCODEC_LOGGING
       
  1371     RDebug::Print(_L("<---CAudioInput::CRecorder::RecordData(%d)"), Index());
       
  1372 #endif
       
  1373     }
       
  1374 
       
  1375 void CAudioInput::CRecorder::DoCancel()
       
  1376     {
       
  1377 #ifdef SYMBIAN_SWCODEC_LOGGING
       
  1378     RDebug::Print(_L("--->CAudioInput::CRecorder::DoCancel(%d)"), Index());
       
  1379 #endif
       
  1380     iParent.RecordSoundDevice().Cancel(iStatus);
       
  1381 #ifdef SYMBIAN_SWCODEC_LOGGING
       
  1382     RDebug::Print(_L("<---CAudioInput::CRecorder::DoCancel(%d)"), Index());
       
  1383 #endif
       
  1384     }
       
  1385 
       
  1386 void CAudioInput::CRecorder::ReleaseBuffer(TBool aDoAnyway)
       
  1387     {
       
  1388     if (iBufferHeld || aDoAnyway)
       
  1389         {
       
  1390         iParent.RecordSoundDevice().ReleaseBuffer(iStatus.Int());
       
  1391         iBufferHeld = EFalse;
       
  1392         }
       
  1393     }
       
  1394 
       
  1395 TInt CAudioInput::CRecorder::Index() const
       
  1396     {
       
  1397     return iIndex;
       
  1398     }
       
  1399 
       
  1400 TInt CAudioInput::CRecorder::Length() const
       
  1401     {
       
  1402     return iLength;
       
  1403     }
       
  1404 
       
  1405 TBool CAudioInput::CRecorder::IsBusy() const
       
  1406     {
       
  1407     return IsActive() || BufferHeld();
       
  1408     }
       
  1409 
       
  1410 TBool CAudioInput::CRecorder::BufferHeld() const
       
  1411 // BufferHeld() means we're in control of a passed buffer
       
  1412     {
       
  1413     return iBufferHeld;
       
  1414     }
       
  1415 
       
  1416 TInt CAudioInput::CRecorder::Offset() const
       
  1417 // If we call this, we've discounted errors so can assert non-negative
       
  1418     {
       
  1419     TInt result = StatusOrOffset();
       
  1420     ASSERT(result>=0); 
       
  1421     return result;
       
  1422     }
       
  1423 
       
  1424 TInt CAudioInput::CRecorder::StatusOrOffset() const
       
  1425 // The iStatus assuming is valid
       
  1426     {
       
  1427     ASSERT(!IsActive()); // or would not be valid
       
  1428     TInt result = iStatus.Int();
       
  1429     return result;    
       
  1430     }