1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/devsound/devsoundrefplugin/src/swcodecwrapper/mmfswaudioinput.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1430 @@
1.4 +// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// mmfswaudioinput.cpp
1.18 +//
1.19 +//
1.20 +#include "mmfswaudioinput.h"
1.21 +#include "mmfswaudioinputpriv.h"
1.22 +#include <d32soundsc.h>
1.23 +#include <e32debug.h>
1.24 +#include "mmf/utils/rateconvert.h" // if we need to resample
1.25 +_LIT(KPddFileName,"SOUNDSC.PDD");
1.26 +_LIT(KLddFileName,"ESOUNDSC.LDD");
1.27 +
1.28 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.29 +
1.30 +const TText* const KStateNames[] = // must agree with TState
1.31 + {
1.32 + _S("EStateCreated2"),
1.33 + _S("EStateInitialized2"),
1.34 + _S("EStateRecordWait2"),
1.35 + _S("EStateRecordWaitAck2"),
1.36 + };
1.37 +
1.38 +static const TText* StateName(TInt aState)
1.39 + {
1.40 + return KStateNames[aState];
1.41 + }
1.42 +
1.43 +const TText* const KRStateNames[] = // must agree with TRunningState
1.44 + {
1.45 + _S("ERStateRunning"),
1.46 + _S("ERStatePaused"),
1.47 + _S("ERStateFinishing"),
1.48 + _S("ERStateFinished"),
1.49 + _S("ERStateFailed"),
1.50 + };
1.51 +
1.52 +static const TText* RStateName(TInt aState)
1.53 + {
1.54 + return KRStateNames[aState];
1.55 + }
1.56 +
1.57 +#endif // SYMBIAN_SWCODEC_LOGGING
1.58 +
1.59 +#ifdef _DEBUG
1.60 +
1.61 +static void Panic(TInt aPanic)
1.62 + {
1.63 + _LIT(KPanicString, "SwAudioInput");
1.64 + User::Panic(KPanicString, aPanic);
1.65 + }
1.66 +
1.67 +void CAudioInput::CheckFullInvariant()
1.68 + {
1.69 + CheckInvariant();
1.70 + CheckActiveRecorders();
1.71 + }
1.72 +
1.73 +void CAudioInput::CheckInvariant(TBool aKnownConstructed)
1.74 + {
1.75 + // full check would be that each recorder is in one, and only one, queue.
1.76 + // However, since the queues share the same infrastructure, checking the overall length of queues
1.77 + // is correct should suffice. During construction or deletion this may obviously vary
1.78 + TInt totalLength = QLength(iIdleQueue) + QLength(iRecordingQueue) +
1.79 + QLength(iPendingQueue) + QLength(iBusyQueue);
1.80 + if (aKnownConstructed)
1.81 + {
1.82 + __ASSERT_DEBUG(totalLength==KNumRecorders, Panic(KPanicBadTotalQueueLength));
1.83 + }
1.84 + else
1.85 + {
1.86 + __ASSERT_DEBUG(totalLength<=KNumRecorders, Panic(KPanicBadTotalQueueLength2));
1.87 + }
1.88 + __ASSERT_DEBUG(QLength(iBusyQueue)<=1, Panic(KPanicBadTotalQueueLength));
1.89 + }
1.90 +
1.91 +#else // _DEBUG
1.92 +
1.93 +// inline versions that do nothing...
1.94 +
1.95 +inline void CAudioInput::CheckFullInvariant()
1.96 + {
1.97 + }
1.98 +
1.99 +inline void CAudioInput::CheckInvariant(TBool /*aKnownConstructed*/)
1.100 + {
1.101 + }
1.102 +
1.103 +#endif // _DEBUG
1.104 +
1.105 +const TInt KMinBufferSize = 4; // assume a good default?
1.106 +//Shared chunk driver does not support max. buffer size. 16K is given in order to simulate the old driver behavior.
1.107 +const TInt KMaxBufferSize = 0x4000;
1.108 +
1.109 +//Table that maps given linear value of volume to the corresponding decibel value.
1.110 +const TUint8 KLinearToDbConstantLookup[] =
1.111 + {
1.112 + 0, // 0
1.113 + 158,
1.114 + 170,
1.115 + 177,
1.116 + 182,
1.117 + 186,
1.118 + 189,
1.119 + 192,
1.120 + 194,
1.121 + 196,
1.122 + 198, // 10
1.123 + 200,
1.124 + 201,
1.125 + 203,
1.126 + 204,
1.127 + 205,
1.128 + 206,
1.129 + 207,
1.130 + 208,
1.131 + 209,
1.132 + 210, // 20
1.133 + 211,
1.134 + 212,
1.135 + 213,
1.136 + 213,
1.137 + 214,
1.138 + 215,
1.139 + 215,
1.140 + 216,
1.141 + 217,
1.142 + 217, // 30
1.143 + 218,
1.144 + 218,
1.145 + 219,
1.146 + 219,
1.147 + 220,
1.148 + 220,
1.149 + 221,
1.150 + 221,
1.151 + 222,
1.152 + 222, // 40
1.153 + 223,
1.154 + 223,
1.155 + 224,
1.156 + 224,
1.157 + 224,
1.158 + 225,
1.159 + 225,
1.160 + 225,
1.161 + 226,
1.162 + 226, // 50
1.163 + 226,
1.164 + 227,
1.165 + 227,
1.166 + 227,
1.167 + 228,
1.168 + 228,
1.169 + 228,
1.170 + 229,
1.171 + 229,
1.172 + 229, // 60
1.173 + 230,
1.174 + 230,
1.175 + 230,
1.176 + 230,
1.177 + 231,
1.178 + 231,
1.179 + 231,
1.180 + 231,
1.181 + 232,
1.182 + 232, // 70
1.183 + 232,
1.184 + 232,
1.185 + 233,
1.186 + 233,
1.187 + 233,
1.188 + 233,
1.189 + 234,
1.190 + 234,
1.191 + 234,
1.192 + 234, // 80
1.193 + 235,
1.194 + 235,
1.195 + 235,
1.196 + 235,
1.197 + 235,
1.198 + 236,
1.199 + 236,
1.200 + 236,
1.201 + 236,
1.202 + 236, // 90
1.203 + 237,
1.204 + 237,
1.205 + 237,
1.206 + 237,
1.207 + 237,
1.208 + 237,
1.209 + 238,
1.210 + 238,
1.211 + 238,
1.212 + 238, // 100
1.213 + 238,
1.214 + 239,
1.215 + 239,
1.216 + 239,
1.217 + 239,
1.218 + 239,
1.219 + 239,
1.220 + 240,
1.221 + 240,
1.222 + 240, // 110
1.223 + 240,
1.224 + 240,
1.225 + 240,
1.226 + 240,
1.227 + 241,
1.228 + 241,
1.229 + 241,
1.230 + 241,
1.231 + 241,
1.232 + 241, // 120
1.233 + 241,
1.234 + 242,
1.235 + 242,
1.236 + 242,
1.237 + 242,
1.238 + 242,
1.239 + 242,
1.240 + 242,
1.241 + 243,
1.242 + 243, // 130
1.243 + 243,
1.244 + 243,
1.245 + 243,
1.246 + 243,
1.247 + 243,
1.248 + 244,
1.249 + 244,
1.250 + 244,
1.251 + 244,
1.252 + 244, // 140
1.253 + 244,
1.254 + 244,
1.255 + 244,
1.256 + 245,
1.257 + 245,
1.258 + 245,
1.259 + 245,
1.260 + 245,
1.261 + 245,
1.262 + 245, // 150
1.263 + 245,
1.264 + 245,
1.265 + 246,
1.266 + 246,
1.267 + 246,
1.268 + 246,
1.269 + 246,
1.270 + 246,
1.271 + 246,
1.272 + 246, // 160
1.273 + 246,
1.274 + 247,
1.275 + 247,
1.276 + 247,
1.277 + 247,
1.278 + 247,
1.279 + 247,
1.280 + 247,
1.281 + 247,
1.282 + 247, // 170
1.283 + 247,
1.284 + 248,
1.285 + 248,
1.286 + 248,
1.287 + 248,
1.288 + 248,
1.289 + 248,
1.290 + 248,
1.291 + 248,
1.292 + 248, // 180
1.293 + 248,
1.294 + 249,
1.295 + 249,
1.296 + 249,
1.297 + 249,
1.298 + 249,
1.299 + 249,
1.300 + 249,
1.301 + 249,
1.302 + 249, // 190
1.303 + 249,
1.304 + 250,
1.305 + 250,
1.306 + 250,
1.307 + 250,
1.308 + 250,
1.309 + 250,
1.310 + 250,
1.311 + 250,
1.312 + 250, // 200
1.313 + 250,
1.314 + 250,
1.315 + 250,
1.316 + 251,
1.317 + 251,
1.318 + 251,
1.319 + 251,
1.320 + 251,
1.321 + 251,
1.322 + 251, // 210
1.323 + 251,
1.324 + 251,
1.325 + 251,
1.326 + 251,
1.327 + 251,
1.328 + 252,
1.329 + 252,
1.330 + 252,
1.331 + 252,
1.332 + 252, // 220
1.333 + 252,
1.334 + 252,
1.335 + 252,
1.336 + 252,
1.337 + 252,
1.338 + 252,
1.339 + 252,
1.340 + 252,
1.341 + 253,
1.342 + 253, // 230
1.343 + 253,
1.344 + 253,
1.345 + 253,
1.346 + 253,
1.347 + 253,
1.348 + 253,
1.349 + 253,
1.350 + 253,
1.351 + 253,
1.352 + 253, // 240
1.353 + 253,
1.354 + 254,
1.355 + 254,
1.356 + 254,
1.357 + 254,
1.358 + 254,
1.359 + 254,
1.360 + 254,
1.361 + 254,
1.362 + 254, // 250
1.363 + 254,
1.364 + 254,
1.365 + 254,
1.366 + 254,
1.367 + 254
1.368 + };
1.369 +
1.370 +// rate lookup table
1.371 +
1.372 +const TInt KNumSampleRates = 9;
1.373 +
1.374 +struct TSampleRateEnumTable
1.375 + {
1.376 + TInt iRate;
1.377 + TSoundRate iRateEnum;
1.378 + TUint iRateConstant;
1.379 + };
1.380 +//Table that maps given samples per second to the corresponding enums in RSoundSc
1.381 +const TSampleRateEnumTable KRateEnumLookup[] =
1.382 + {
1.383 + {48000,ESoundRate48000Hz,KSoundRate48000Hz},
1.384 + {44100,ESoundRate44100Hz,KSoundRate44100Hz},
1.385 + {32000,ESoundRate32000Hz,KSoundRate32000Hz},
1.386 + {24000,ESoundRate24000Hz,KSoundRate24000Hz},
1.387 + {22050,ESoundRate22050Hz,KSoundRate22050Hz},
1.388 + {16000,ESoundRate16000Hz,KSoundRate16000Hz},
1.389 + {12000,ESoundRate12000Hz,KSoundRate12000Hz},
1.390 + {11025,ESoundRate11025Hz,KSoundRate11025Hz},
1.391 + {8000, ESoundRate8000Hz, KSoundRate8000Hz}
1.392 + };
1.393 +
1.394 +// TAudioInputParams
1.395 +
1.396 +EXPORT_C TAudioInputParams::TAudioInputParams() :
1.397 + iSampleRate(0), iNominalBufferSize(0)
1.398 + {
1.399 + // none
1.400 + }
1.401 +
1.402 +// CAudioInput
1.403 +
1.404 +EXPORT_C MAudioInput* MAudioInput::CreateL(MAudioInputObserver& aObserver)
1.405 + {
1.406 + MAudioInput* result = CAudioInput::NewL(aObserver);
1.407 + return result;
1.408 + }
1.409 +
1.410 +CAudioInput* CAudioInput::NewL(MAudioInputObserver& aObserver)
1.411 + {
1.412 + CAudioInput* result = new CAudioInput(aObserver);
1.413 + CleanupStack::PushL(result);
1.414 + result->ConstructL();
1.415 + CleanupStack::Pop(result);
1.416 + return result;
1.417 + }
1.418 +
1.419 +CAudioInput::CAudioInput(MAudioInputObserver& aObserver) :
1.420 + iObserver(aObserver),
1.421 + iIdleQueue(_FOFF(CRecorder,iLink)),
1.422 + iRecordingQueue(_FOFF(CRecorder,iLink)),
1.423 + iPendingQueue(_FOFF(CRecorder,iLink)),
1.424 + iBusyQueue(_FOFF(CRecorder,iLink))
1.425 + {
1.426 + ASSERT(iState == EStateCreated2); // assume zero'ing initialises correctly
1.427 + }
1.428 +
1.429 +void CAudioInput::Release()
1.430 +// effective destructor call
1.431 + {
1.432 + delete this;
1.433 + }
1.434 +
1.435 +TAny* CAudioInput::Interface(TUid aInterfaceUid)
1.436 + {
1.437 + if (aInterfaceUid == KUidAIParamInterface)
1.438 + {
1.439 + MAIParamInterface* self = this;
1.440 + return self;
1.441 + }
1.442 + return NULL;
1.443 + }
1.444 +
1.445 +RSoundSc& CAudioInput::RecordSoundDevice()
1.446 + {
1.447 + ASSERT(iRecordSoundDevice.Handle()!=0); // should be open
1.448 + return iRecordSoundDevice;
1.449 + }
1.450 +
1.451 +CAudioInput::~CAudioInput()
1.452 + {
1.453 + CheckInvariant(EFalse); // may not be constructed
1.454 + Cancel();
1.455 + for (TInt i = 0; i < KNumRecorders; i++)
1.456 + {
1.457 + // just in case, call cancel directly from this point too
1.458 + // Cancel depends on the active queue, and might not be quite the same.
1.459 + CRecorder* recorder = iRecorders[i];
1.460 + if (recorder)
1.461 + {
1.462 + recorder->Cancel();
1.463 + }
1.464 + delete recorder;
1.465 + }
1.466 + delete iAsyncCallBack;
1.467 + iConvBuff.Close();
1.468 + iRecordSoundDevice.Close();
1.469 + iChunk.Close();
1.470 + }
1.471 +
1.472 +void CAudioInput::Cancel()
1.473 + {
1.474 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.475 + RDebug::Print(_L("--->CAudioInput::Cancel()"));
1.476 +#endif
1.477 + CancelRecorders();
1.478 + if (iAsyncCallBack)
1.479 + {
1.480 + iAsyncCallBack->Cancel();
1.481 + }
1.482 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.483 + RDebug::Print(_L("<---CAudioInput::Cancel()"));
1.484 +#endif
1.485 + }
1.486 +
1.487 +void CAudioInput::CancelRecorders()
1.488 +// if a recorder is active, then cancel it. Also move the list if required.
1.489 + {
1.490 + CheckInvariant(); // semi-invariant check - this is called from destructor
1.491 +
1.492 + CRecorder* recorder;
1.493 + while (QPop(recorder, iRecordingQueue))
1.494 + {
1.495 + recorder->Cancel();
1.496 + iIdleQueue.AddLast(*recorder);
1.497 + }
1.498 + CheckFullInvariant();
1.499 + }
1.500 +
1.501 +void CAudioInput::CancelPendingRecorders()
1.502 +// take any recorder in the pending queue. ack the buffer and send to idle
1.503 + {
1.504 + CheckFullInvariant();
1.505 +
1.506 + CRecorder* recorder;
1.507 + while (QPop(recorder, iPendingQueue))
1.508 + {
1.509 + recorder->ReleaseBuffer();
1.510 + iIdleQueue.AddLast(*recorder);
1.511 + }
1.512 + CheckFullInvariant();
1.513 + }
1.514 +
1.515 +void CAudioInput::CancelBusyRecorder()
1.516 +// take busy recorder. ack the buffer and send to idle
1.517 + {
1.518 + CheckFullInvariant();
1.519 +
1.520 + CRecorder* recorder;
1.521 + if (QPop(recorder, iBusyQueue))
1.522 + {
1.523 + recorder->ReleaseBuffer();
1.524 + iIdleQueue.AddLast(*recorder);
1.525 + }
1.526 + CheckFullInvariant();
1.527 + }
1.528 +
1.529 +void CAudioInput::RecordAllIdle()
1.530 +// take any recorder in idle queue and set recording
1.531 + {
1.532 + CheckFullInvariant();
1.533 +
1.534 + CRecorder* recorder;
1.535 + while (QPop(recorder, iIdleQueue))
1.536 + {
1.537 + recorder->RecordData();
1.538 + iRecordingQueue.AddLast(*recorder);
1.539 + }
1.540 + CheckFullInvariant();
1.541 + }
1.542 +
1.543 +void CAudioInput::ConstructL()
1.544 + {
1.545 + for (TInt i = 0; i < KNumRecorders; i++)
1.546 + {
1.547 + iRecorders[i] = new (ELeave) CRecorder(*this, i);
1.548 + iIdleQueue.AddLast(*(iRecorders[i]));
1.549 + }
1.550 + iAsyncCallBack = new (ELeave) CAsyncCallBack(CActive::EPriorityStandard);
1.551 + TCallBack callback(Callback, this);
1.552 + iAsyncCallBack->Set(callback);
1.553 + User::LoadPhysicalDevice(KPddFileName);
1.554 + User::LoadLogicalDevice(KLddFileName);
1.555 + CheckFullInvariant();
1.556 + }
1.557 +
1.558 +TInt CAudioInput::Initialize(const TAudioInputParams& aParams)
1.559 + {
1.560 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.561 + RDebug::Print(_L("--->CAudioInput::Initialize() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
1.562 +#endif
1.563 + CheckFullInvariant();
1.564 + TInt error = KErrNone;
1.565 + if (iState == EStateCreated2)
1.566 + {
1.567 + if (!iRecordSoundDevice.Handle())
1.568 + {
1.569 + error = iRecordSoundDevice.Open(KSoundScRxUnit0);
1.570 + if (error)
1.571 + {
1.572 + Close(); // TODO Close() required?
1.573 + }
1.574 + }
1.575 + if (!error)
1.576 + {
1.577 + iBufferLength = aParams.iNominalBufferSize; // will be updated by SetFormat() if required
1.578 + error = SetFormat(aParams);
1.579 + if (!error)
1.580 + {
1.581 + iRecordBufferConfig.iNumBuffers = KNumRecorders*2; // for each AO we create two buffers
1.582 + iRecordBufferConfig.iFlags = 0;
1.583 + iRecordBufferConfig.iBufferSizeInBytes = iBufferLength;
1.584 + ASSERT(iChunk.Handle()==0); // should not be already open
1.585 + TPckg<TRecordSharedChunkBufConfig> bufferConfigBuf(
1.586 + iRecordBufferConfig);
1.587 + error = iRecordSoundDevice.SetBufferChunkCreate(
1.588 + bufferConfigBuf, iChunk);
1.589 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.590 + RDebug::Print(
1.591 + _L("iRecordBufferConfig.iNumBuffers = [%d]"),iRecordBufferConfig.iNumBuffers);
1.592 + RDebug::Print(
1.593 + _L("iRecordBufferConfig.iFlags = [%d]"),iRecordBufferConfig.iFlags);
1.594 + RDebug::Print(
1.595 + _L("iRecordBufferConfig.iBufferSizeInBytes = [%d]"),iRecordBufferConfig.iBufferSizeInBytes);
1.596 +#endif
1.597 + if (error == KErrNone)
1.598 + {
1.599 + ASSERT(iChunk.Handle()); // should now be open
1.600 + iRecordSoundDevice.GetBufferConfig(bufferConfigBuf); // overwrite iRecordBufferConfig
1.601 + SetGain(aParams.iInitialGain);
1.602 + iState = EStateInitialized2;
1.603 + }
1.604 + }
1.605 + }
1.606 + }
1.607 + else
1.608 + {
1.609 + error = KErrNotReady;
1.610 + }
1.611 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.612 + RDebug::Print(_L("<---CAudioInput::Initialize(%d) state=%s rstate=%s"), error, StateName(
1.613 + iState), RStateName(iRState));
1.614 +#endif
1.615 + CheckFullInvariant();
1.616 + return error;
1.617 + }
1.618 +
1.619 +void CAudioInput::Close()
1.620 + {
1.621 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.622 + RDebug::Print(_L("--->CAudioInput::Close() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
1.623 +#endif
1.624 + CheckFullInvariant();
1.625 + InternalStop(); // Technically this should not be required, as client should Stop() first, but just in case
1.626 + if (iState == EStateInitialized2)
1.627 + {
1.628 + iRecordSoundDevice.Close();
1.629 + iChunk.Close();
1.630 + iConvBuff.Close();
1.631 + iState = EStateCreated2;
1.632 + }
1.633 + ASSERT(iState==EStateCreated2);
1.634 + ASSERT(QLength(iIdleQueue)==KNumRecorders);
1.635 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.636 + RDebug::Print(_L("<---CAudioInput::Close() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
1.637 +#endif
1.638 + CheckFullInvariant();
1.639 + }
1.640 +
1.641 +TInt CAudioInput::Start()
1.642 + {
1.643 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.644 + RDebug::Print(_L("--->CAudioInput::Start() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
1.645 +#endif
1.646 + CheckFullInvariant();
1.647 + TInt error = KErrNone;
1.648 + if (iState == EStateInitialized2)
1.649 + {
1.650 + RecordAllIdle();
1.651 + iState = EStateRecordWait2;
1.652 + iRState = ERStateRunning;
1.653 + }
1.654 + else
1.655 + {
1.656 + error = KErrNotReady;
1.657 + }
1.658 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.659 + RDebug::Print(_L("<---CAudioInput::Start(%d) state=%s rstate=%s"),
1.660 + error, StateName(iState), RStateName(iRState));
1.661 +#endif
1.662 + CheckFullInvariant();
1.663 + return error;
1.664 + }
1.665 +
1.666 +void CAudioInput::BufferAck()
1.667 + {
1.668 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.669 + RDebug::Print(_L("--->CAudioInput::BufferAck() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
1.670 +#endif
1.671 + CheckFullInvariant();
1.672 + ASSERT(iState==EStateRecordWaitAck2);
1.673 + HandleBufferAck();
1.674 + iState = EStateRecordWait2;
1.675 + RequestCallback();
1.676 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.677 + RDebug::Print(_L("<---CAudioInput::BufferAck() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
1.678 +#endif
1.679 + CheckFullInvariant();
1.680 + }
1.681 +
1.682 +void CAudioInput::HandleBufferAck()
1.683 + {
1.684 + CRecorder* recorder = QPop(iBusyQueue);
1.685 + recorder->ReleaseBuffer();
1.686 + if (iRState == ERStateRunning)
1.687 + {
1.688 + recorder->RecordData();
1.689 + iRecordingQueue.AddLast(*recorder);
1.690 + }
1.691 + else
1.692 + {
1.693 + iIdleQueue.AddLast(*recorder);
1.694 + if (iRState == ERStatePaused && (QLength(iRecordingQueue)+QLength(iPendingQueue) == 0))
1.695 + {
1.696 + iRState = ERStateFinishing;
1.697 + }
1.698 + }
1.699 + }
1.700 +
1.701 +TInt CAudioInput::Pause()
1.702 + {
1.703 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.704 + RDebug::Print(_L("--->CAudioInput::Pause() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
1.705 +#endif
1.706 + CheckFullInvariant();
1.707 + TInt err = KErrNone; // note we are silent if called in wrong state
1.708 +
1.709 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.710 + RDebug::Print(
1.711 + _L("***!pause irecordingquelength %d pendingquelength %d ibusyquelength=%d"), QLength(iRecordingQueue),
1.712 + QLength(iPendingQueue), QLength(iBusyQueue));
1.713 +#endif
1.714 + if ((iState == EStateRecordWait2 || iState == EStateRecordWaitAck2) && iRState==ERStateRunning)
1.715 + {
1.716 + iRecordSoundDevice.Pause();
1.717 +
1.718 + iRState = ERStatePaused;
1.719 + }
1.720 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.721 + RDebug::Print(_L("<---CAudioInput::Pause(%d) state=%s err=%d"), err, StateName(iState), RStateName(iRState));
1.722 +#endif
1.723 + CheckFullInvariant();
1.724 + return err;
1.725 + }
1.726 +
1.727 +TInt CAudioInput::Resume()
1.728 + {
1.729 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.730 + RDebug::Print(_L("--->CAudioInput::Resume() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
1.731 +#endif
1.732 + CheckFullInvariant();
1.733 + TInt err = KErrNone; // note we are silent if called in the wrong state
1.734 + if ((iState == EStateRecordWait2 || iState == EStateRecordWaitAck2) &&
1.735 + ((iRState==ERStatePaused || iRState==ERStateFinishing || iRState==ERStateFinished)))
1.736 + {
1.737 + err = RecordSoundDevice().Resume();
1.738 +
1.739 + RecordAllIdle();
1.740 +
1.741 + iRState = ERStateRunning;
1.742 + }
1.743 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.744 + RDebug::Print(_L("<---CAudioInput::Resume(%d) state=%s rstate=%s"), err, StateName(iState), RStateName(iRState));
1.745 +#endif
1.746 + CheckFullInvariant();
1.747 + return err;
1.748 + }
1.749 +
1.750 +TInt CAudioInput::Flush()
1.751 + {
1.752 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.753 + RDebug::Print(_L("--->CAudioInput::Flush() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
1.754 +#endif
1.755 + CheckFullInvariant();
1.756 + TInt error = KErrNotReady;
1.757 + if (iRState==ERStatePaused)
1.758 + {
1.759 + if (iState == EStateRecordWait2)
1.760 + {
1.761 + InternalFlush();
1.762 + ASSERT(iState == EStateRecordWait2); // stay put
1.763 + error = KErrNone;
1.764 + }
1.765 + else if (iState == EStateRecordWaitAck2)
1.766 + {
1.767 + InternalFlush();
1.768 + iState = EStateRecordWait2;
1.769 + error = KErrNone;
1.770 + }
1.771 + }
1.772 + #ifdef SYMBIAN_SWCODEC_LOGGING
1.773 + RDebug::Print(_L("--->CAudioInput::Flush(%d) state=%s rstate=%s"), error, StateName(iState), RStateName(iRState));
1.774 +#endif
1.775 + CheckFullInvariant();
1.776 + return error;
1.777 + }
1.778 +
1.779 +void CAudioInput::Stop()
1.780 + {
1.781 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.782 + RDebug::Print(_L("--->CAudioInput::Stop() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
1.783 +#endif
1.784 + CheckFullInvariant();
1.785 + InternalStop();
1.786 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.787 + RDebug::Print(_L("<---CAudioInput::Stop() state=%s rstate=%s"), StateName(iState), RStateName(iRState));
1.788 +#endif
1.789 + }
1.790 +
1.791 +void CAudioInput::InternalStop()
1.792 +// This stops all recording and returns pending and busy buffers to idle. Must be called when
1.793 +// client knows the buffer has been grabbed (e.g. _not_ before error callback)
1.794 + {
1.795 + CheckInvariant(); // Can be called from buffer error, so can't check full invariant.
1.796 + if (iState != EStateInitialized2 && iState != EStateCreated2)
1.797 + {
1.798 + InternalFlush();
1.799 + iState = EStateInitialized2;
1.800 + }
1.801 + CheckFullInvariant();
1.802 + ASSERT((QLength(iRecordingQueue) + QLength(iPendingQueue) +
1.803 + QLength(iBusyQueue))==0); // everything is stopped
1.804 + }
1.805 +
1.806 +void CAudioInput::InternalFlush()
1.807 + {
1.808 + CancelRecorders();
1.809 + CancelPendingRecorders();
1.810 + CancelBusyRecorder();
1.811 + }
1.812 +
1.813 +void CAudioInput::BufferArrives(CRecorder* aRecorder)
1.814 + {
1.815 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.816 + RDebug::Print(
1.817 + _L("--->CAudioInput::BufferArrives(%d,%d) state=%s rstate=%s"), aRecorder->Index(),
1.818 + aRecorder->StatusOrOffset(), StateName(iState), RStateName(iRState));
1.819 +#endif
1.820 + CheckInvariant(); // Can't use CheckFullInvariant() from RunL
1.821 + ASSERT(iState==EStateRecordWait2 || iState==EStateRecordWaitAck2);
1.822 + ASSERT(aRecorder->Offset()>=0); // assert we're not here due to an error
1.823 + iRecordingQueue.Remove(*aRecorder);
1.824 + iPendingQueue.AddLast(*aRecorder);
1.825 + if (iState==EStateRecordWait2)
1.826 + {
1.827 + RequestCallback();
1.828 + }
1.829 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.830 + RDebug::Print(_L("<---CAudioInput::BufferArrives() state=%s rstate=%s"),
1.831 + StateName(iState), RStateName(iRState));
1.832 +#endif
1.833 + CheckFullInvariant();
1.834 + }
1.835 +
1.836 +void CAudioInput::UseBuffer(CRecorder* aRecorder)
1.837 +// incomming buffer is pointed to by iBufPtr. Either directly or via convert, use for callback
1.838 + {
1.839 + iBufPtr.Set(iChunk.Base() + aRecorder->Offset(), aRecorder->Length());
1.840 + if (iConverter)
1.841 + {
1.842 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.843 + RDebug::Print(_L("iBufPtr length [%d] iconvbuff length [%d,%d]"),
1.844 + iBufPtr.Length(), iConvBuff.Length(), iConvBuff.MaxLength());
1.845 +#endif
1.846 + __DEBUG_ONLY(TInt converted =) iConverter->Convert(iBufPtr, iConvBuff);
1.847 + // the following assert should check we convert the log.
1.848 + // Actually we sometimes fail at the end of the operation with what is effectively
1.849 + // the last buffer. Arguably a driver fault, but there we are
1.850 + // ASSERT(converted==iBufPtr.Length());
1.851 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.852 + RDebug::Print(_L("iBufPtr length [%d] iconvbuff length after [%d,%d]"),
1.853 + iBufPtr.Length(), iConvBuff.Length(), iConvBuff.MaxLength());
1.854 +#endif
1.855 + iObserver.InputBufferAvailable(iConvBuff);
1.856 + }
1.857 + else
1.858 + {
1.859 + iObserver.InputBufferAvailable(iBufPtr);
1.860 + }
1.861 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.862 + RDebug::Print(_L("12345 ibufptr = [0x%x]"),iBufPtr.Ptr());
1.863 +#endif
1.864 + }
1.865 +
1.866 +void CAudioInput::BufferError(CRecorder* aRecorder, TInt aError)
1.867 + {
1.868 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.869 + RDebug::Print(
1.870 + _L("--->CAudioInput::BufferError(%d,%d) state=%s rstate=%s"), aRecorder->Index(),
1.871 + aError, StateName(iState), RStateName(iRState));
1.872 +#endif
1.873 + CheckInvariant(); // Can't use CheckFullInvariant() from RunL
1.874 + if (aError==KErrCancel || aError==KErrOverflow)
1.875 + {
1.876 + // Cancel: sign of a Pause operation. If paused etc, then merely add to idle list. potentially generate finished signal
1.877 + // if not paused, then not clear but just in case request record again
1.878 + // Overflow: basically try again, but if paused merely add to idle. Check for last buffer just in case
1.879 + if (iRState!=ERStateRunning)
1.880 + {
1.881 + iRecordingQueue.Remove(*aRecorder);
1.882 + iIdleQueue.AddLast(*aRecorder);
1.883 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.884 + RDebug::Print(
1.885 + _L("***! irecordingquelength %d pendingquelength %d ibusyquelength=%d"), QLength(iRecordingQueue),
1.886 + QLength(iPendingQueue), QLength(iBusyQueue));
1.887 +#endif
1.888 + if (iRState == ERStatePaused && (QLength(iRecordingQueue)+QLength(iPendingQueue)+QLength(iBusyQueue) == 0))
1.889 + {
1.890 + iRState = ERStateFinishing;
1.891 + RequestCallback();
1.892 + }
1.893 + }
1.894 + else
1.895 + {
1.896 + aRecorder->RecordData();
1.897 + }
1.898 + }
1.899 + else
1.900 + {
1.901 + iRecordingQueue.Remove(*aRecorder);
1.902 + iIdleQueue.AddLast(*aRecorder);
1.903 + iRState = ERStateFailed;
1.904 + iObserver.InputError(aError);
1.905 + }
1.906 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.907 + RDebug::Print(_L("<---CAudioInput::BufferError() state=%s rstate=%s"),
1.908 + StateName(iState), RStateName(iRState));
1.909 +#endif
1.910 + CheckFullInvariant();
1.911 + }
1.912 +
1.913 +TInt CAudioInput::Callback(TAny* aPtr)
1.914 + {
1.915 + CAudioInput* self = static_cast<CAudioInput*> (aPtr);
1.916 + TRAPD(error,self->AsyncCallbackL());
1.917 + return error; // TODO really have to handle error
1.918 + }
1.919 +
1.920 +void CAudioInput::RequestCallback()
1.921 + {
1.922 + // ensure iAsyncCallBack is active
1.923 + if (!iAsyncCallBack->IsActive())
1.924 + {
1.925 + iAsyncCallBack->Call();
1.926 + }
1.927 + }
1.928 +
1.929 +void CAudioInput::AsyncCallbackL()
1.930 + {
1.931 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.932 + RDebug::Print(_L("--->CAudioInput::AsyncCallbackL() state=%s rstate=%s"),
1.933 + StateName(iState), RStateName(iRState));
1.934 +#endif
1.935 + CheckFullInvariant();
1.936 + ASSERT(iState==EStateRecordWait2 || iState==EStateRecordWaitAck2); // should not occur in other states. Actually ignore in 2nd
1.937 + if (iState==EStateRecordWait2)
1.938 + {
1.939 + if (QLength(iPendingQueue)>0)
1.940 + {
1.941 + ASSERT(QLength(iBusyQueue)==0);
1.942 + iState = EStateRecordWaitAck2; // change state prior to callback, in case sync call from callback
1.943 + CRecorder* recorder = QPop(iPendingQueue);
1.944 + iBusyQueue.AddLast(*recorder);
1.945 + UseBuffer(recorder);
1.946 + }
1.947 + else
1.948 + {
1.949 + if (iRState == ERStateFinishing)
1.950 + {
1.951 + ASSERT(QLength(iRecordingQueue)+QLength(iPendingQueue)+QLength(iBusyQueue) == 0); // should be true
1.952 + iRState = ERStateFinished;
1.953 + iObserver.InputFinished();
1.954 + }
1.955 + }
1.956 + }
1.957 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.958 + RDebug::Print(_L("<---CAudioInput::AsyncCallbackL() state=%s rstate=%s"),
1.959 + StateName(iState), RStateName(iRState));
1.960 +#endif
1.961 + CheckFullInvariant();
1.962 + }
1.963 +
1.964 +TInt CAudioInput::GetBufferSizes(TInt& aMinSize, TInt& aMaxSize)
1.965 + {
1.966 + aMinSize = KMinBufferSize;
1.967 + aMaxSize = KMaxBufferSize;
1.968 + return KErrNone;
1.969 + }
1.970 +
1.971 +TInt CAudioInput::SetGain(TInt aGain)
1.972 + {
1.973 + TInt error = KErrNone; // note: silent if in wrong state
1.974 + if (iRecordSoundDevice.Handle())
1.975 + {
1.976 + // we have to switch from level to dB value
1.977 + if(aGain >=0 && aGain<=KSoundMaxVolume)
1.978 + {
1.979 + error = iRecordSoundDevice.SetVolume(KLinearToDbConstantLookup[aGain]);
1.980 + }
1.981 + else
1.982 + {
1.983 + error = KErrArgument;
1.984 + }
1.985 + }
1.986 + return error;
1.987 + }
1.988 +
1.989 +TInt CAudioInput::SetFormat(const TAudioInputParams& aFormat)
1.990 + {
1.991 + TInt err = KErrNotFound;
1.992 + TCurrentSoundFormatV02Buf formatBuf;
1.993 + TFormatData formatData;
1.994 +
1.995 + delete iConverter;
1.996 + iConverter = NULL; // setting this to NULL indicates we are not using converter. No other flag
1.997 +
1.998 + TInt wantedRate = aFormat.iSampleRate;
1.999 + for (TInt index = 0; index < KNumSampleRates; index++)
1.1000 + {
1.1001 + if (wantedRate == KRateEnumLookup[index].iRate)
1.1002 + {
1.1003 + formatBuf().iRate = KRateEnumLookup[index].iRateEnum;
1.1004 + formatData.iSampleRate = wantedRate;
1.1005 + err = KErrNone;
1.1006 + break;
1.1007 + }
1.1008 + }
1.1009 +
1.1010 + if (err == KErrNone)
1.1011 + {
1.1012 + formatBuf().iChannels = aFormat.iNumChannels;
1.1013 + formatBuf().iEncoding = ESoundEncoding16BitPCM;
1.1014 + formatBuf().iDataFormat = ESoundDataFormatInterleaved;
1.1015 + err = iRecordSoundDevice.SetAudioFormat(formatBuf);
1.1016 +#if defined(SYMBIAN_SOUNDADAPTER_FORCECDRATES) || defined (SYMBIAN_SOUNDADAPTER_FORCESTEREO)
1.1017 + err = KErrNotSupported; // force Negotiate - for debugging
1.1018 +#endif
1.1019 + if (err == KErrNotSupported)
1.1020 + {
1.1021 + // don't support directly. Perhaps can rate convert?
1.1022 + err = NegotiateFormat(aFormat, formatData);
1.1023 + }
1.1024 + }
1.1025 + return err;
1.1026 + }
1.1027 +
1.1028 +TInt CAudioInput::NegotiateFormat(const TAudioInputParams& aFormat, TFormatData &aFormatData)
1.1029 + {
1.1030 + TInt err = KErrNotFound;
1.1031 + TCurrentSoundFormatV02Buf formatBuf;
1.1032 +
1.1033 + TInt origBufferLength = iBufferLength; // cache in case we change
1.1034 +
1.1035 + // find out first what the driver supports
1.1036 + TSoundFormatsSupportedV02Buf supportedFormat;
1.1037 + iRecordSoundDevice.Caps(supportedFormat);
1.1038 + TUint32 supportedRates = supportedFormat().iRates;
1.1039 +#ifdef SYMBIAN_SOUNDADAPTER_FORCECDRATES
1.1040 + supportedRates &= KSoundRate11025Hz | KSoundRate22050Hz
1.1041 + | KSoundRate44100Hz; // only use CD rates - for debugging
1.1042 +#endif
1.1043 +
1.1044 + // For RecordCase:
1.1045 + // We want the next rate above consistently - we go down from this to the requested rate.
1.1046 + // If there is one, we don't support - we _never_ upsample.
1.1047 + // note that the table is given in descending order, so we start with the highest
1.1048 + TInt wantedRate = aFormat.iSampleRate;
1.1049 + TInt takeTheFirst = EFalse;
1.1050 + TInt nextUpValidIndex = -1;
1.1051 + for (TInt index = 0; index < KNumSampleRates; index++)
1.1052 + {
1.1053 + TBool lookingAtRequestedRate = wantedRate
1.1054 + == KRateEnumLookup[index].iRate;
1.1055 + TSoundRate wantedEnum = KRateEnumLookup[index].iRateEnum;
1.1056 + TUint32 equivBitmap = KRateEnumLookup[index].iRateConstant;
1.1057 + TBool isSupported = (equivBitmap & supportedRates) != EFalse;
1.1058 + if (lookingAtRequestedRate || takeTheFirst)
1.1059 + {
1.1060 + if (isSupported)
1.1061 + {
1.1062 + // this rate is supported
1.1063 + formatBuf().iRate = wantedEnum;
1.1064 + aFormatData.iActualRate = KRateEnumLookup[index].iRate;
1.1065 + err = KErrNone;
1.1066 + break;
1.1067 + }
1.1068 + }
1.1069 + else if (!takeTheFirst)
1.1070 + {
1.1071 + // while we are still looking for the rate, want to cache any supported index
1.1072 + // at end of loop, this will be the first rate above ours that is supported
1.1073 + // use for fallback if required
1.1074 + if (isSupported)
1.1075 + {
1.1076 + nextUpValidIndex = index;
1.1077 + }
1.1078 + }
1.1079 + if (lookingAtRequestedRate)
1.1080 + {
1.1081 + // For record we just abort.
1.1082 + break;
1.1083 + }
1.1084 + }
1.1085 +
1.1086 + if (err)
1.1087 + {
1.1088 + // if there is one above the requested rate, use that
1.1089 + if (nextUpValidIndex >= 0)
1.1090 + {
1.1091 + TSoundRate wantedEnum =
1.1092 + KRateEnumLookup[nextUpValidIndex].iRateEnum;
1.1093 + formatBuf().iRate = wantedEnum;
1.1094 + aFormatData.iActualRate = KRateEnumLookup[nextUpValidIndex].iRate;
1.1095 + err = KErrNone;
1.1096 + }
1.1097 + }
1.1098 +
1.1099 + if (err)
1.1100 + {
1.1101 + // should have something!
1.1102 + return err;
1.1103 + }
1.1104 +
1.1105 + aFormatData.iSampleRate = wantedRate; // iSampleRate is our requested/apparent rate, not the device rate.
1.1106 +
1.1107 + TUint32 channelsSupported = supportedFormat().iChannels;
1.1108 +#ifdef SYMBIAN_SOUNDADAPTER_FORCESTEREO
1.1109 + channelsSupported &= KSoundStereoChannel; // don't use mono - for debugging
1.1110 +#endif
1.1111 +
1.1112 + if (aFormat.iNumChannels == 1)
1.1113 + {
1.1114 + aFormatData.iRequestedChannels = 1;
1.1115 + // want mono
1.1116 + if (channelsSupported & KSoundMonoChannel)
1.1117 + {
1.1118 + // mono is supported, as usual
1.1119 + aFormatData.iActualChannels = 1;
1.1120 + }
1.1121 + else if (channelsSupported & KSoundStereoChannel)
1.1122 + {
1.1123 + aFormatData.iActualChannels = 2;
1.1124 + iBufferLength *= 2; // double size, will do stereo->mono
1.1125 + }
1.1126 + else
1.1127 + {
1.1128 + return KErrNotSupported; // should not get this far for real
1.1129 + }
1.1130 + }
1.1131 + else if (aFormat.iNumChannels == 2)
1.1132 + {
1.1133 + aFormatData.iRequestedChannels = 2;
1.1134 + // want stereo
1.1135 + if (channelsSupported & KSoundStereoChannel)
1.1136 + {
1.1137 + // stereo is supported, as usual
1.1138 + aFormatData.iActualChannels = 2;
1.1139 + }
1.1140 + else if (channelsSupported & KSoundMonoChannel)
1.1141 + {
1.1142 + aFormatData.iActualChannels = 1;
1.1143 + iBufferLength /= 2; // halve size, will do mono->stereo
1.1144 + }
1.1145 + else
1.1146 + {
1.1147 + return KErrNotSupported; // should not get this far for real
1.1148 + }
1.1149 + }
1.1150 + else
1.1151 + {
1.1152 + return KErrNotSupported; // unknown number of channels requested!
1.1153 + }
1.1154 +
1.1155 + formatBuf().iChannels = aFormatData.iActualChannels;
1.1156 +
1.1157 + formatBuf().iEncoding = ESoundEncoding16BitPCM;
1.1158 + formatBuf().iDataFormat = ESoundDataFormatInterleaved;
1.1159 + err = iRecordSoundDevice.SetAudioFormat(formatBuf);
1.1160 +
1.1161 + if (!err)
1.1162 + {
1.1163 + ASSERT(!iConverter); // pre-condition at top of function anyway
1.1164 + // when recording we convert from actual to requested
1.1165 + TInt outputRateToUse = aFormatData.iSampleRate;
1.1166 +#ifdef SYMBIAN_SKIP_RESAMPLE_ON_RECORD
1.1167 + // with this macro just channel convert at most
1.1168 + outputRateToUse = aFormatData.iActualRate;
1.1169 +#endif
1.1170 +#ifdef SYMBIAN_SOUNDADAPTER_DEBUG
1.1171 + RDebug::Print(_L("RMdaDevSound::CBody::NegotiateFormat: Convert:CreateL from %d/%d to %d/%d"),
1.1172 + aFormatData.iActualRate, aFormatData.iActualChannels,
1.1173 + aFormatData.iSampleRate, aFormatData.iRequestedChannels);
1.1174 +#endif
1.1175 + TRAP(err, iConverter = CChannelAndSampleRateConverter::CreateL(aFormatData.iActualRate,
1.1176 + aFormatData.iActualChannels,
1.1177 + outputRateToUse,
1.1178 + aFormatData.iRequestedChannels));
1.1179 + }
1.1180 + if (!err && iConverter)
1.1181 + {
1.1182 + err = iConvBuff.Create(origBufferLength);
1.1183 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.1184 + RDebug::Print(_L("iBufferLength length [%d] iconvbuff length [%d,%d]"),
1.1185 + iBufferLength, iConvBuff.Length(), iConvBuff.MaxLength());
1.1186 +#endif
1.1187 + }
1.1188 +
1.1189 + return err;
1.1190 + }
1.1191 +
1.1192 +TInt CAudioInput::GetSupportedSampleRates(RArray<TInt>& aSupportedSampleRates)
1.1193 + {
1.1194 + TInt err = KErrNone;
1.1195 +
1.1196 + if (iRecordSoundDevice.Handle())
1.1197 + {
1.1198 + GetSupportedSampleRates(aSupportedSampleRates, iRecordSoundDevice);
1.1199 + }
1.1200 + else
1.1201 + {//temporarily open the device if we can
1.1202 + RSoundSc tempsound;
1.1203 + err = tempsound.Open(KSoundScRxUnit0);
1.1204 + if (!err)
1.1205 + {
1.1206 + err = GetSupportedSampleRates(aSupportedSampleRates, tempsound);
1.1207 + tempsound.Close();
1.1208 + }
1.1209 + }
1.1210 + return err;
1.1211 + }
1.1212 +
1.1213 +TInt CAudioInput::GetSupportedSampleRates(
1.1214 + RArray<TInt>& aSupportedSampleRates, RSoundSc& aSoundDevice)
1.1215 + {
1.1216 + ASSERT(aSoundDevice.Handle()); // parent to ensure this is open
1.1217 +
1.1218 + TInt err = KErrNone;
1.1219 +
1.1220 + TSoundFormatsSupportedV02Buf supportedFormat;
1.1221 + aSoundDevice.Caps(supportedFormat);
1.1222 + TUint32 rates = supportedFormat().iRates;
1.1223 +
1.1224 + for (TInt i = KNumSampleRates - 1; i > 0; i--)//min to max
1.1225 + {
1.1226 + if (rates & KRateEnumLookup[i].iRateConstant)
1.1227 + {
1.1228 + err = aSupportedSampleRates.Append(KRateEnumLookup[i].iRate);
1.1229 + if (err)
1.1230 + {
1.1231 + break;
1.1232 + }
1.1233 + }
1.1234 + }
1.1235 + return err;
1.1236 + }
1.1237 +
1.1238 +TInt CAudioInput::QLength(TSglQue<CRecorder>& aQueue)
1.1239 +// count elements in List/Q. Have to use iterator to do this - it seems.
1.1240 + {
1.1241 + TSglQueIter<CRecorder> iter(aQueue);
1.1242 + TInt count=0;
1.1243 + while (iter++)
1.1244 + {
1.1245 + // like old-fashioned C string manipulations. iterate through all members
1.1246 + count++;
1.1247 + }
1.1248 + return count;
1.1249 + }
1.1250 +
1.1251 +CAudioInput::CRecorder* CAudioInput::QPop(TSglQue<CRecorder>& aQueue)
1.1252 + {
1.1253 + CRecorder* recorder = NULL;
1.1254 + if (! aQueue.IsEmpty())
1.1255 + {
1.1256 + recorder = aQueue.First();
1.1257 + aQueue.Remove(*recorder);
1.1258 + }
1.1259 + return recorder;
1.1260 + }
1.1261 +
1.1262 +#ifdef _DEBUG
1.1263 +
1.1264 +// these functions are used in invariant checking only
1.1265 +
1.1266 +void CAudioInput::CheckActiveRecorders(TSglQue<CRecorder>& aQueue, TBool aExpected, TInt aPanicCode)
1.1267 +// check that all the elements in the given Q are IsActive() or vice-versa
1.1268 + {
1.1269 + TSglQueIter<CRecorder> iter(aQueue);
1.1270 +
1.1271 + CRecorder* recorder;
1.1272 + while ((recorder=iter++)!=NULL)
1.1273 + {
1.1274 + TBool expected = aExpected != EFalse; // ensure these are either true or false
1.1275 + TBool active = recorder->IsActive() != EFalse;
1.1276 + __ASSERT_DEBUG(expected == active, Panic(aPanicCode));
1.1277 + }
1.1278 + }
1.1279 +
1.1280 +void CAudioInput::CheckActiveRecorders()
1.1281 +// check that all the elements in the recordingQueue are IsActive() etc
1.1282 +// can't be used as CRecorder::RunL() pre-condition
1.1283 + {
1.1284 + CheckActiveRecorders(iRecordingQueue, ETrue, EPanicBusyRecorderNotActive);
1.1285 + CheckActiveRecorders(iIdleQueue, EFalse, EPanicNonBusyRecorderActive);
1.1286 + CheckActiveRecorders(iPendingQueue, EFalse, EPanicNonBusyRecorderActive);
1.1287 + CheckActiveRecorders(iBusyQueue, EFalse, EPanicNonBusyRecorderActive);
1.1288 + }
1.1289 +
1.1290 +#endif // _DEBUG
1.1291 +
1.1292 +//
1.1293 +// CRecorder
1.1294 +//
1.1295 +
1.1296 +
1.1297 +CAudioInput::CRecorder::CRecorder(CAudioInput& aParent, TInt aIndex) :
1.1298 + CActive(EPriorityStandard), iParent(aParent), iIndex(aIndex)
1.1299 + {
1.1300 + CActiveScheduler::Add(this);
1.1301 + }
1.1302 +
1.1303 +CAudioInput::CRecorder::~CRecorder()
1.1304 + {
1.1305 + Cancel();
1.1306 + }
1.1307 +
1.1308 +void CAudioInput::CRecorder::Cancel()
1.1309 + {
1.1310 + // this override takes into account that ReleaseBuffer must be called - this is not the
1.1311 + // normal pattern where following Cancel() we're not concerned with the results
1.1312 + if (IsActive())
1.1313 + {
1.1314 + ASSERT(!BufferHeld()); // if active then buffer held should be clear. don't reset then
1.1315 + CActive::Cancel();
1.1316 + ReleaseBuffer(ETrue); // release - might have been a successful run!
1.1317 + }
1.1318 + else
1.1319 + {
1.1320 + ReleaseBuffer(); // this will release buffer if still outstanding
1.1321 + }
1.1322 + }
1.1323 +
1.1324 +void CAudioInput::CRecorder::RunL()
1.1325 + {
1.1326 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.1327 + RDebug::Print(_L("--->CAudioInput::CRecorder::RunL(%d, %d)"), Index(),
1.1328 + iStatus.Int());
1.1329 +#endif
1.1330 + TInt errorOrOffset = iStatus.Int(); // negative -> error. non-negative is offset in chunk
1.1331 +
1.1332 + if (errorOrOffset < 0)
1.1333 + {
1.1334 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.1335 + RDebug::Print(_L("errorOrOffset = [%d]"),errorOrOffset);
1.1336 +#endif
1.1337 + // ReleaseBuffer(ETrue); // calls ReleaseBuffer() on error code. Driver requires this, even though seems wrong
1.1338 + iParent.BufferError(this, errorOrOffset);
1.1339 + }
1.1340 + else
1.1341 + {
1.1342 + ASSERT(!iBufferHeld);
1.1343 + iBufferHeld = ETrue;
1.1344 +
1.1345 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.1346 + RDebug::Print(_L("errorOrOffset = [%d]"),errorOrOffset);
1.1347 +#endif
1.1348 + // If a buffer larger than expected arrives truncate it.
1.1349 + iLength = Min(iLength,iParent.iBufferLength);
1.1350 + iParent.BufferArrives(this);
1.1351 + }
1.1352 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.1353 + RDebug::Print(_L("<---CAudioInput::CRecorder::RunL(%d)"), Index());
1.1354 +#endif
1.1355 + }
1.1356 +
1.1357 +void CAudioInput::CRecorder::RecordData()
1.1358 + {
1.1359 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.1360 + RDebug::Print(_L("--->CAudioInput::CRecorder::RecordData(%d)"), Index());
1.1361 +#endif
1.1362 + ASSERT(!iBufferHeld);
1.1363 + Deque(); // ensure we append to the AO queue, so if it comes to it we process oldest request first
1.1364 + CActiveScheduler::Add(this);
1.1365 + iLength = iParent.BufferLength(); // TODO do we have to set this first or is it an OUT param purely
1.1366 + iParent.RecordSoundDevice().RecordData(iStatus, iLength);
1.1367 + SetActive();
1.1368 +
1.1369 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.1370 + RDebug::Print(_L("###****#####!!!! Buffer length [%d], status [%d] "), iLength,
1.1371 + iStatus.Int());
1.1372 +#endif
1.1373 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.1374 + RDebug::Print(_L("<---CAudioInput::CRecorder::RecordData(%d)"), Index());
1.1375 +#endif
1.1376 + }
1.1377 +
1.1378 +void CAudioInput::CRecorder::DoCancel()
1.1379 + {
1.1380 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.1381 + RDebug::Print(_L("--->CAudioInput::CRecorder::DoCancel(%d)"), Index());
1.1382 +#endif
1.1383 + iParent.RecordSoundDevice().Cancel(iStatus);
1.1384 +#ifdef SYMBIAN_SWCODEC_LOGGING
1.1385 + RDebug::Print(_L("<---CAudioInput::CRecorder::DoCancel(%d)"), Index());
1.1386 +#endif
1.1387 + }
1.1388 +
1.1389 +void CAudioInput::CRecorder::ReleaseBuffer(TBool aDoAnyway)
1.1390 + {
1.1391 + if (iBufferHeld || aDoAnyway)
1.1392 + {
1.1393 + iParent.RecordSoundDevice().ReleaseBuffer(iStatus.Int());
1.1394 + iBufferHeld = EFalse;
1.1395 + }
1.1396 + }
1.1397 +
1.1398 +TInt CAudioInput::CRecorder::Index() const
1.1399 + {
1.1400 + return iIndex;
1.1401 + }
1.1402 +
1.1403 +TInt CAudioInput::CRecorder::Length() const
1.1404 + {
1.1405 + return iLength;
1.1406 + }
1.1407 +
1.1408 +TBool CAudioInput::CRecorder::IsBusy() const
1.1409 + {
1.1410 + return IsActive() || BufferHeld();
1.1411 + }
1.1412 +
1.1413 +TBool CAudioInput::CRecorder::BufferHeld() const
1.1414 +// BufferHeld() means we're in control of a passed buffer
1.1415 + {
1.1416 + return iBufferHeld;
1.1417 + }
1.1418 +
1.1419 +TInt CAudioInput::CRecorder::Offset() const
1.1420 +// If we call this, we've discounted errors so can assert non-negative
1.1421 + {
1.1422 + TInt result = StatusOrOffset();
1.1423 + ASSERT(result>=0);
1.1424 + return result;
1.1425 + }
1.1426 +
1.1427 +TInt CAudioInput::CRecorder::StatusOrOffset() const
1.1428 +// The iStatus assuming is valid
1.1429 + {
1.1430 + ASSERT(!IsActive()); // or would not be valid
1.1431 + TInt result = iStatus.Int();
1.1432 + return result;
1.1433 + }