1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/mmlibs/mmfw/src/Client/Audio/mmfclientaudioinputstream.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,995 @@
1.4 +// Copyright (c) 2002-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 +//
1.18 +
1.19 +#include "mmfclientaudioinputstream.h"
1.20 +#include "mmfclientaudiostreamutils.h"
1.21 +#include <mmf/server/devsoundstandardcustominterfaces.h>
1.22 +#include <mmf/common/mmfpaniccodes.h>
1.23 +#include "MmfFifo.h"
1.24 +#include <mdaaudioinputstream.h>
1.25 +
1.26 +const TInt KMicroSecsInOneSec = 1000000;
1.27 +
1.28 +
1.29 +enum TMmfAudioInputPanic
1.30 + {
1.31 + EAudioInputPanicNotSupported
1.32 + };
1.33 +
1.34 +_LIT(KAudioInputStreamCategory, "CMMFMdaAudioInputStream");
1.35 +LOCAL_C void Panic(const TMmfAudioInputPanic aPanic)
1.36 + {
1.37 + User::Panic(KAudioInputStreamCategory, aPanic);
1.38 + }
1.39 +
1.40 +/**
1.41 + *
1.42 + * Static NewL
1.43 + *
1.44 + * @return CMdaAudioInputStream*
1.45 + *
1.46 + */
1.47 +EXPORT_C CMdaAudioInputStream* CMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback)
1.48 + {
1.49 + return NewL(aCallback, EMdaPriorityNormal, EMdaPriorityPreferenceTimeAndQuality);
1.50 + }
1.51 +
1.52 +/**
1.53 + *
1.54 + * Static NewL
1.55 + *
1.56 + * @return CMdaAudioInputStream*
1.57 + *
1.58 + */
1.59 +EXPORT_C CMdaAudioInputStream* CMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback, TInt aPriority, TInt aPref)
1.60 + {
1.61 + CMdaAudioInputStream* self = new(ELeave) CMdaAudioInputStream();
1.62 + CleanupStack::PushL(self);
1.63 + self->iProperties = CMMFMdaAudioInputStream::NewL(aCallback, aPriority, aPref);
1.64 + CleanupStack::Pop(self);
1.65 + return self;
1.66 + }
1.67 +
1.68 +CMdaAudioInputStream::CMdaAudioInputStream()
1.69 + {
1.70 + }
1.71 +
1.72 +CMdaAudioInputStream::~CMdaAudioInputStream()
1.73 + {
1.74 + if(iProperties)
1.75 + {
1.76 + iProperties->ShutDown();
1.77 + }
1.78 +
1.79 + delete iProperties;
1.80 + }
1.81 +
1.82 +EXPORT_C void CMdaAudioInputStream::SetAudioPropertiesL(TInt aSampleRate, TInt aChannels)
1.83 + {
1.84 + ASSERT(iProperties);
1.85 + iProperties->SetAudioPropertiesL(aSampleRate, aChannels);
1.86 + }
1.87 +
1.88 +EXPORT_C void CMdaAudioInputStream::Open(TMdaPackage* aSettings)
1.89 + {
1.90 + ASSERT(iProperties);
1.91 + iProperties->Open(aSettings);
1.92 + }
1.93 +
1.94 +EXPORT_C void CMdaAudioInputStream::SetGain(TInt aNewGain)
1.95 + {
1.96 + ASSERT(iProperties);
1.97 + iProperties->SetGain(aNewGain);
1.98 + }
1.99 +
1.100 +EXPORT_C TInt CMdaAudioInputStream::Gain() const
1.101 + {
1.102 + ASSERT(iProperties);
1.103 + return iProperties->Gain();
1.104 + }
1.105 +
1.106 +EXPORT_C TInt CMdaAudioInputStream::MaxGain() const
1.107 + {
1.108 + ASSERT(iProperties);
1.109 + return iProperties->MaxGain();
1.110 + }
1.111 +
1.112 +EXPORT_C void CMdaAudioInputStream::SetBalanceL(TInt aBalance)
1.113 + {
1.114 + ASSERT(iProperties);
1.115 + iProperties->SetBalanceL(aBalance);
1.116 + }
1.117 +
1.118 +EXPORT_C TInt CMdaAudioInputStream::GetBalanceL() const
1.119 + {
1.120 + ASSERT(iProperties);
1.121 + return iProperties->GetBalanceL();
1.122 + }
1.123 +
1.124 +EXPORT_C void CMdaAudioInputStream::SetPriority(TInt aPriority, TInt aPref)
1.125 + {
1.126 + ASSERT(iProperties);
1.127 + iProperties->SetPriority(aPriority, aPref);
1.128 + }
1.129 +
1.130 +EXPORT_C void CMdaAudioInputStream::ReadL(TDes8& aData)
1.131 + {
1.132 + ASSERT(iProperties);
1.133 + iProperties->ReadL(aData);
1.134 + }
1.135 +
1.136 +EXPORT_C void CMdaAudioInputStream::Stop()
1.137 + {
1.138 + ASSERT(iProperties);
1.139 + iProperties->Stop();
1.140 + }
1.141 +
1.142 +EXPORT_C void CMdaAudioInputStream::RequestStop()
1.143 + {
1.144 + ASSERT(iProperties);
1.145 + iProperties->RequestStop();
1.146 + }
1.147 +
1.148 +EXPORT_C const TTimeIntervalMicroSeconds& CMdaAudioInputStream::Position()
1.149 + {
1.150 + ASSERT(iProperties);
1.151 + return iProperties->Position();
1.152 + }
1.153 +
1.154 +EXPORT_C TInt CMdaAudioInputStream::GetBytes()
1.155 + {
1.156 + ASSERT(iProperties);
1.157 + return iProperties->GetBytes();
1.158 + }
1.159 +
1.160 +EXPORT_C void CMdaAudioInputStream::SetSingleBufferMode(TBool aSingleMode)
1.161 + {
1.162 + ASSERT(iProperties);
1.163 + iProperties->SetSingleBufferMode(aSingleMode);
1.164 + }
1.165 +
1.166 +/**
1.167 +
1.168 +*/
1.169 +EXPORT_C void CMdaAudioInputStream::SetDataTypeL(TFourCC aAudioType)
1.170 + {
1.171 + ASSERT(iProperties);
1.172 + iProperties->SetDataTypeL(aAudioType);
1.173 + }
1.174 +
1.175 +/**
1.176 +
1.177 +*/
1.178 +EXPORT_C TFourCC CMdaAudioInputStream::DataType() const
1.179 + {
1.180 + ASSERT(iProperties);
1.181 + return iProperties->DataType();
1.182 + }
1.183 +
1.184 +
1.185 +EXPORT_C TInt CMdaAudioInputStream::BitRateL() const
1.186 + {
1.187 + ASSERT(iProperties);
1.188 + return iProperties->BitRateL();
1.189 + }
1.190 +
1.191 +EXPORT_C void CMdaAudioInputStream::SetBitRateL(TInt aBitRate)
1.192 + {
1.193 + ASSERT(iProperties);
1.194 + iProperties->SetBitRateL(aBitRate);
1.195 + }
1.196 +
1.197 +
1.198 +EXPORT_C void CMdaAudioInputStream::GetSupportedBitRatesL(RArray<TInt>& aSupportedBitRates)
1.199 + {
1.200 + ASSERT(iProperties);
1.201 + iProperties->GetSupportedBitRatesL(aSupportedBitRates);
1.202 + }
1.203 +
1.204 +EXPORT_C TAny* CMdaAudioInputStream::CustomInterface(TUid aInterfaceId)
1.205 + {
1.206 + ASSERT(iProperties);
1.207 + return iProperties->CustomInterface(aInterfaceId);
1.208 + }
1.209 +
1.210 +//
1.211 +
1.212 +CMMFMdaAudioInputStream* CMMFMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback)
1.213 + {
1.214 + return CMMFMdaAudioInputStream::NewL(aCallback, EMdaPriorityNormal, EMdaPriorityPreferenceTimeAndQuality);
1.215 + }
1.216 +
1.217 +CMMFMdaAudioInputStream* CMMFMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback, TInt aPriority, TInt aPref)
1.218 + {
1.219 + CMMFMdaAudioInputStream* self = new(ELeave) CMMFMdaAudioInputStream(aCallback);
1.220 + CleanupStack::PushL(self);
1.221 + self->ConstructL(aPriority, aPref);
1.222 + CleanupStack::Pop(self);
1.223 + return self;
1.224 + }
1.225 +/**
1.226 + *
1.227 + * Construct
1.228 + *
1.229 + * @param "MMdaAudioInputStreamCallback&"
1.230 + * a reference to MMdaAudioInputStreamCallback
1.231 + * a perference value
1.232 + *
1.233 + */
1.234 +CMMFMdaAudioInputStream::CMMFMdaAudioInputStream(MMdaAudioInputStreamCallback& aCallback)
1.235 + : iCallback(aCallback), iStorageItem (NULL, 0), iBufferPtr(NULL, 0)
1.236 + // Depending on zero for construction (i.e. attribute of CBase)
1.237 + // iSingleBuffer (EFalse)
1.238 + // iState(EStopped)
1.239 + // iIsOpened(EFalse)
1.240 + // iCallbackMade(EFalse)
1.241 + // iAudioDataStored(EFalse)
1.242 + {
1.243 + iDataTypeCode.Set(TFourCC(' ','P','1','6'));
1.244 + }
1.245 +
1.246 +/**
1.247 + *
1.248 + * Second phase constructor
1.249 + *
1.250 + */
1.251 +void CMMFMdaAudioInputStream::ConstructL(TInt aPriority, TInt aPref)
1.252 + {
1.253 + iDevSound = CMMFDevSound::NewL();
1.254 + SetPriority(aPriority, aPref);
1.255 + iFifo = new(ELeave) CMMFFifo<TDes8>();
1.256 + iActiveCallback = new(ELeave) CActiveCallback(iCallback);
1.257 + iActiveSchedulerWait = new(ELeave) CActiveSchedulerWait;
1.258 + }
1.259 +
1.260 +/**
1.261 + *
1.262 + * Destructor
1.263 + *
1.264 + */
1.265 +CMMFMdaAudioInputStream::~CMMFMdaAudioInputStream()
1.266 + {
1.267 + delete iFifo;
1.268 + delete iDevSound;
1.269 + delete iActiveCallback;
1.270 + delete iActiveSchedulerWait;
1.271 + }
1.272 +
1.273 +/**
1.274 + *
1.275 + * Set audio input stream properties
1.276 + *
1.277 + * @param "TInt aSampleRate"
1.278 + * a specified priority value
1.279 + * @param "TInt aChannels"
1.280 + * a specified preference value
1.281 + *
1.282 + */
1.283 +void CMMFMdaAudioInputStream::SetAudioPropertiesL(TInt aSampleRate, TInt aChannels)
1.284 + {
1.285 + if (iIsOpenState == EIsOpen)
1.286 + {
1.287 + RealSetAudioPropertiesL(aSampleRate, aChannels);
1.288 + }
1.289 + else
1.290 + {
1.291 + // cache for application later
1.292 + iSettings.iSampleRate = aSampleRate;
1.293 + iSettings.iChannels = aChannels;
1.294 + iAudioDataStored = ETrue;
1.295 + }
1.296 + }
1.297 +
1.298 +void CMMFMdaAudioInputStream::RealSetAudioPropertiesL(TInt aSampleRate, TInt aChannels)
1.299 + {
1.300 + TMMFCapabilities capabilities = iDevSound->Config();
1.301 + capabilities.iChannels = StreamUtils::MapChannelsMdaToMMFL(aChannels);
1.302 + capabilities.iRate = StreamUtils::MapSampleRateMdaToMMFL(aSampleRate);
1.303 + iDevSound->SetConfigL(capabilities);
1.304 + }
1.305 +
1.306 +/**
1.307 + *
1.308 + * Open a audio ouptut stream
1.309 + *
1.310 + * @param "TMdaPackage* Settings"
1.311 + * a pointer point to TMdaPackage
1.312 + *
1.313 + */
1.314 +void CMMFMdaAudioInputStream::Open(TMdaPackage* aSettings)
1.315 + {
1.316 + iIsOpenState = EIsOpening;
1.317 + //store aSettings
1.318 + if (aSettings && (aSettings->Type().iUid == KUidMdaDataTypeSettingsDefine))
1.319 + {
1.320 + TMdaAudioDataSettings* tmpSettings = STATIC_CAST(TMdaAudioDataSettings*, aSettings);
1.321 + iSettings = *tmpSettings;
1.322 + iAudioDataStored = ETrue;
1.323 + }
1.324 + TRAPD(err, iDevSound->InitializeL(*this, iDataTypeCode, EMMFStateRecording));
1.325 + if (err != KErrNone)
1.326 + {
1.327 + // Signal for the MaiscOpenComplete callback to be called asynchronously
1.328 + iActiveCallback->Signal(err);
1.329 + iIsOpenState = EIsNotOpen;
1.330 + iAudioDataStored = EFalse; // reset - if was set we throw away due to failure
1.331 + }
1.332 + }
1.333 +
1.334 +/**
1.335 + *
1.336 + * To get the maximum gain level
1.337 + *
1.338 + * @return "TInt"
1.339 + * the maximum gain value in integer
1.340 + *
1.341 + */
1.342 +TInt CMMFMdaAudioInputStream::MaxGain() const
1.343 + {
1.344 + return iDevSound->MaxGain();
1.345 + }
1.346 +
1.347 +/**
1.348 + *
1.349 + * To get the current gain level
1.350 + *
1.351 + * @return "TInt"
1.352 + * the current gain value in integer
1.353 + *
1.354 + */
1.355 +TInt CMMFMdaAudioInputStream::Gain() const
1.356 + {
1.357 + return iDevSound->Gain();
1.358 + }
1.359 +
1.360 +/**
1.361 + *
1.362 + * Set audio input stream gain to the specified value
1.363 + *
1.364 + * @param "TInt aGain"
1.365 + * a specified gain value
1.366 + *
1.367 + */
1.368 +void CMMFMdaAudioInputStream::SetGain(TInt aGain)
1.369 + {
1.370 + iDevSound->SetGain(aGain);
1.371 + }
1.372 +
1.373 +/**
1.374 + *
1.375 + * Set audio input stream balance
1.376 + *
1.377 + * @param "TInt aBalance"
1.378 + * a specified balance value
1.379 + *
1.380 + */
1.381 +void CMMFMdaAudioInputStream::SetBalanceL(TInt aBalance)
1.382 + {
1.383 + // test and clip balance to min / max range [-100 <-> 100]
1.384 + // clip rather than leave as this isn't a leaving function
1.385 + if (aBalance < KMMFBalanceMaxLeft) aBalance = KMMFBalanceMaxLeft;
1.386 + if (aBalance > KMMFBalanceMaxRight) aBalance = KMMFBalanceMaxRight;
1.387 +
1.388 + // separate out left and right balance
1.389 + TInt left = 0;
1.390 + TInt right = 0;
1.391 + StreamUtils::CalculateLeftRightBalance( left, right, aBalance );
1.392 +
1.393 + // send the balance to SoundDevice
1.394 + iDevSound->SetRecordBalanceL(left, right);
1.395 + }
1.396 +
1.397 +/**
1.398 + *
1.399 + * To get the current balance value.This function may not return the same value
1.400 + * as passed to SetBalanceL depending on the internal implementation in
1.401 + * the underlying components.
1.402 + *
1.403 + * @return "TInt"
1.404 + * the current balance value in integer
1.405 + *
1.406 + */
1.407 +TInt CMMFMdaAudioInputStream::GetBalanceL() const
1.408 + {
1.409 + TInt rightBalance = 0;
1.410 + TInt leftBalance = 0;
1.411 + iDevSound->GetRecordBalanceL(leftBalance, rightBalance);
1.412 + TInt balance = 0;
1.413 + StreamUtils::CalculateBalance( balance, leftBalance, rightBalance );
1.414 + return balance;
1.415 + }
1.416 +
1.417 +/**
1.418 + *
1.419 + * Set audio input stream priority
1.420 + *
1.421 + * @param "TInt aPriority"
1.422 + * a specified priority value
1.423 + * @param "TInt aPref"
1.424 + * a specified preference value
1.425 + *
1.426 + */
1.427 +void CMMFMdaAudioInputStream::SetPriority(TInt aPriority, TInt aPref)
1.428 + {
1.429 + TMMFPrioritySettings settings;
1.430 + settings.iPriority = aPriority;
1.431 + settings.iPref = aPref;
1.432 + iDevSound->SetPrioritySettings(settings);
1.433 + }
1.434 +
1.435 +
1.436 +/**
1.437 + *
1.438 + * To read data from input stream
1.439 + *
1.440 + * @param "TDesC8& aData"
1.441 + * a stream data
1.442 + *
1.443 + * @capability UserEnvironment
1.444 + * For recording - the requesting client process must have the
1.445 + * UserEnvironment capability.
1.446 + */
1.447 +void CMMFMdaAudioInputStream::ReadL(TDes8& aData)
1.448 + {
1.449 + User::LeaveIfError(Read(aData));
1.450 +
1.451 + if (iState == EStopped)
1.452 + {
1.453 + iDevSound->RecordInitL();
1.454 + iState = ERecording;
1.455 + }
1.456 + }
1.457 +
1.458 +/**
1.459 + *
1.460 + * To read data from input stream
1.461 + *
1.462 + * @param "TDesC8& aData"
1.463 + * a stream data
1.464 + *
1.465 + * @capability UserEnvironment
1.466 + * For recording - the requesting client process must have the
1.467 + * UserEnvironment capability.
1.468 + */
1.469 +TInt CMMFMdaAudioInputStream::Read(TDes8& aData)
1.470 + {
1.471 + TMMFFifoItem<TDes8>* item = new TMMFFifoItem<TDes8>(aData);
1.472 + if (!item)
1.473 + {
1.474 + return KErrNoMemory;
1.475 + }
1.476 +
1.477 + iFifo->AddToFifo(*item); // no issue with memory alloc
1.478 + // each element contains storage space for link to the next
1.479 + return KErrNone;
1.480 + }
1.481 +
1.482 +/**
1.483 + *
1.484 + * To stop write data to stream
1.485 + *
1.486 + */
1.487 +void CMMFMdaAudioInputStream::Stop()
1.488 + {
1.489 + // Need to take for the case where Stop is invoked directly after a call to RequestStop.
1.490 + // We have chosen to allow the Stop to go through as this could be more important.
1.491 + // This is non-reentrant code but will suffice for our needs.
1.492 + if (iState != EStopped)
1.493 + {
1.494 + // Amend the state so RequestStop or Stop initiated by it (indirectly) won't function
1.495 + iState = EStopped;
1.496 +
1.497 + if (iSingleBuffer && iStorageItem.Ptr() != NULL)
1.498 + {
1.499 + iCallback.MaiscBufferCopied(KErrAbort, iStorageItem);
1.500 + iStorageItem.Set (NULL,0,0);
1.501 + }
1.502 +
1.503 + // Delete all buffers in the fifo and notify the observer
1.504 + TMMFFifoItem<TDes8>* firstItem;
1.505 + while((firstItem = iFifo->Get()) != NULL)
1.506 + {
1.507 + iFifo->RemoveFirstItem();
1.508 + if (!iSingleBuffer)
1.509 + {
1.510 + iCallback.MaiscBufferCopied(KErrAbort,firstItem->GetData());
1.511 + }
1.512 + delete firstItem;
1.513 + }
1.514 +
1.515 + iDevSound->Stop();
1.516 + }
1.517 + }
1.518 +
1.519 +
1.520 +/**
1.521 + *
1.522 + * To pause write data to stream
1.523 + * Allow yet unprocessed buffers to be processed and passed back via BufferToBeEmptied.
1.524 + * When the last (empty) buffer arrives, Stop is called.
1.525 + */
1.526 +void CMMFMdaAudioInputStream::RequestStop()
1.527 + {
1.528 + // [ precondition that we are not already stopped
1.529 + // && if we are stopped do nothing.
1.530 + // If we are stopping a recording, we need to give the server a chance to
1.531 + // process that data which has already been captured. We therefore stay in the EPause
1.532 + // state.
1.533 + if (iState != EStopped)
1.534 + {
1.535 + if (iState != EStopping)
1.536 + {
1.537 + // We can only be Recording, if we have other states later they can be tested here.
1.538 + iDevSound->Pause();
1.539 + iState = EStopping;
1.540 + }
1.541 + }
1.542 + }
1.543 +
1.544 +
1.545 +/**
1.546 + *
1.547 + * To get the current position in the data stream
1.548 + *
1.549 + * @return "TTimeIntervalMicroSeconds&"
1.550 + * the current position in integer
1.551 + *
1.552 + */
1.553 +const TTimeIntervalMicroSeconds& CMMFMdaAudioInputStream::Position()
1.554 + {
1.555 + TInt64 position = iDevSound->SamplesRecorded();
1.556 + position = position * KMicroSecsInOneSec / StreamUtils::SampleRateAsValue(iDevSound->Config());
1.557 + iPosition = (iState == ERecording) ? position : 0; // Shouldn't need to check for playing but CMMFDevSound doesn't reset bytes played after a stop
1.558 + return iPosition;
1.559 + }
1.560 +
1.561 +
1.562 +
1.563 +/**
1.564 + *
1.565 + * To return the current number of bytes recorded by audio hardware
1.566 + * @return "the current current number of bytes rendered by audio hardware in integer"
1.567 + *
1.568 + */
1.569 +TInt CMMFMdaAudioInputStream::GetBytes()
1.570 + {
1.571 + return iBytesRecorded;
1.572 + }
1.573 +
1.574 +void CMMFMdaAudioInputStream::SetDataTypeL(TFourCC aAudioType)
1.575 + {
1.576 + if(iState != EStopped)
1.577 + User::Leave(KErrServerBusy);
1.578 +
1.579 + if(aAudioType == iDataTypeCode)
1.580 + return;
1.581 +
1.582 + TMMFPrioritySettings prioritySettings ;
1.583 + prioritySettings.iState = EMMFStateRecording;
1.584 +
1.585 + RArray<TFourCC> supportedDataTypes;
1.586 +
1.587 + CleanupClosePushL(supportedDataTypes);
1.588 +
1.589 + TRAPD(err, iDevSound->GetSupportedOutputDataTypesL(supportedDataTypes, prioritySettings));
1.590 +
1.591 + if (err == KErrNone)
1.592 + {
1.593 + if (supportedDataTypes.Find(aAudioType) == KErrNotFound)
1.594 + {
1.595 + User::Leave(KErrNotSupported);
1.596 + }
1.597 + //if match, set the 4CC of AudioType to match
1.598 + iDataTypeCode.Set(aAudioType);
1.599 + }
1.600 + else //we had a real leave error from GetSupportedInputDataTypesL
1.601 + {
1.602 + User::Leave(err);
1.603 + }
1.604 + CleanupStack::PopAndDestroy(&supportedDataTypes);
1.605 +
1.606 + if(iIsOpenState!=EIsNotOpen)
1.607 + {
1.608 + // need to recall or restart InitializeL() process
1.609 + iDevSound->CancelInitialize(); // call just in case mid-InitializeL. No harm if not.
1.610 + // if not supported then assume old DevSound behaviour anyway
1.611 + // where InitializeL() implicitly cancels, so no harm either way
1.612 + iIsOpenState = EIsOpening;
1.613 + iInitCallFrmSetDataType = ETrue;
1.614 + TRAPD(err, iDevSound->InitializeL(*this, iDataTypeCode, EMMFStateRecording));
1.615 + if (err != KErrNone)
1.616 + {
1.617 + // Leave if error.
1.618 + iIsOpenState = EIsNotOpen;
1.619 + iInitCallFrmSetDataType = EFalse;
1.620 + User::Leave(err);
1.621 + }
1.622 + // In some implementations InitializeComplete is sent
1.623 + // in context, so check before starting activeSchedulerWait.
1.624 + else if(iIsOpenState == EIsOpening)
1.625 + {
1.626 + iInitializeState = KRequestPending;
1.627 + iActiveSchedulerWait->Start();
1.628 + }
1.629 + iInitCallFrmSetDataType = EFalse;
1.630 + User::LeaveIfError(iInitializeState);
1.631 + }
1.632 + }
1.633 +
1.634 +/**
1.635 +
1.636 +*/
1.637 +TFourCC CMMFMdaAudioInputStream::DataType() const
1.638 + {
1.639 + return iDataTypeCode;
1.640 + }
1.641 +
1.642 +TInt CMMFMdaAudioInputStream::BitRateL() const
1.643 + {
1.644 + TAny* ptr = iDevSound->CustomInterface(KUidCustomInterfaceDevSoundBitRate);
1.645 + if (ptr == NULL)
1.646 + User::Leave(KErrNotSupported);
1.647 +
1.648 + MMMFDevSoundCustomInterfaceBitRate* bitrate = static_cast<MMMFDevSoundCustomInterfaceBitRate*>(ptr);
1.649 + return bitrate->BitRateL();
1.650 + }
1.651 +
1.652 +
1.653 +void CMMFMdaAudioInputStream::SetBitRateL(TInt aBitRate)
1.654 + {
1.655 + TAny* ptr = iDevSound->CustomInterface(KUidCustomInterfaceDevSoundBitRate);
1.656 + if (ptr == NULL)
1.657 + User::Leave(KErrNotSupported);
1.658 +
1.659 + MMMFDevSoundCustomInterfaceBitRate* bitrate = static_cast<MMMFDevSoundCustomInterfaceBitRate*>(ptr);
1.660 + bitrate->SetBitRateL(aBitRate);
1.661 + }
1.662 +
1.663 +void CMMFMdaAudioInputStream::GetSupportedBitRatesL(RArray<TInt>& aSupportedBitRates)
1.664 + {
1.665 + // ensure that the array is empty before passing it in
1.666 + aSupportedBitRates.Reset();
1.667 + TAny* ptr = iDevSound->CustomInterface(KUidCustomInterfaceDevSoundBitRate);
1.668 + if (ptr == NULL)
1.669 + User::Leave(KErrNotSupported);
1.670 + MMMFDevSoundCustomInterfaceBitRate* bitrate = static_cast<MMMFDevSoundCustomInterfaceBitRate*>(ptr);
1.671 + bitrate->GetSupportedBitRatesL(aSupportedBitRates);
1.672 + }
1.673 +
1.674 +
1.675 +//
1.676 +
1.677 +CMMFMdaAudioInputStream::CActiveCallback::CActiveCallback(MMdaAudioInputStreamCallback& aCallback)
1.678 + : CActive(EPriorityStandard), iCallback(aCallback)
1.679 + {
1.680 + CActiveScheduler::Add(this);
1.681 + }
1.682 +
1.683 +CMMFMdaAudioInputStream::CActiveCallback::~CActiveCallback()
1.684 + {
1.685 + Cancel();
1.686 + }
1.687 +
1.688 +void CMMFMdaAudioInputStream::CActiveCallback::RunL()
1.689 + {
1.690 + iCallback.MaiscOpenComplete(iStatus.Int());
1.691 + }
1.692 +
1.693 +void CMMFMdaAudioInputStream::CActiveCallback::DoCancel()
1.694 + {
1.695 + }
1.696 +
1.697 +void CMMFMdaAudioInputStream::CActiveCallback::Signal(const TInt aReason)
1.698 + {
1.699 + ASSERT(!IsActive());
1.700 +
1.701 + // Signal ourselves to run with the given completion code
1.702 + TRequestStatus* status = &iStatus;
1.703 + User::RequestComplete(status, aReason);
1.704 + SetActive();
1.705 + }
1.706 +
1.707 +//
1.708 +
1.709 +/**
1.710 + *
1.711 + * To be called when intialize stream complete
1.712 + *
1.713 + * @param "TInt aError"
1.714 + * error code, initialize stream succeed when aError = 0
1.715 + *
1.716 + */
1.717 +void CMMFMdaAudioInputStream::InitializeComplete(TInt aError)
1.718 + {
1.719 + TInt err = aError;
1.720 + if(iIsOpenState == EIsOpening)
1.721 + {
1.722 + if (err == KErrNone)
1.723 + {
1.724 + // Use settings to set audio properties after the dev sound has been
1.725 + // successfully initialised
1.726 + if(iAudioDataStored)
1.727 + {
1.728 + TRAP(err, RealSetAudioPropertiesL(iSettings.iSampleRate, iSettings.iChannels));
1.729 + }
1.730 +
1.731 + }
1.732 +
1.733 + // Signal for the MaiscOpenComplete callback to be called asynchronously.Ignore if InitializeL is called from SetDataTypeL
1.734 + if(!iInitCallFrmSetDataType)
1.735 + {
1.736 + iActiveCallback->Signal(err);
1.737 + }
1.738 + iIsOpenState = err ? EIsNotOpen : EIsOpen;
1.739 + //reset iAudioDataStored flag if set - whatever don't want to use next time
1.740 + iAudioDataStored = EFalse;
1.741 + if(iInitializeState == KRequestPending)
1.742 + {
1.743 + iInitializeState = err;
1.744 + iActiveSchedulerWait->AsyncStop();
1.745 + }
1.746 + else
1.747 + {
1.748 + iInitializeState = err;//Set the error.
1.749 + }
1.750 + }
1.751 + }
1.752 +
1.753 +/**
1.754 + *
1.755 + * Do not support
1.756 + *
1.757 + */
1.758 +void CMMFMdaAudioInputStream::ToneFinished(TInt /*aError*/)
1.759 + {
1.760 + Panic(EAudioInputPanicNotSupported);
1.761 + }
1.762 +
1.763 +/**
1.764 + *
1.765 + * Called when sound device has filled data buffer
1.766 + *
1.767 + * @param "CMMFBuffer* aBuffer"
1.768 + * a pointer point to CMMFBuffer, which is used for recieved data
1.769 + *
1.770 + */
1.771 +void CMMFMdaAudioInputStream::BufferToBeEmptied(CMMFBuffer* aBuffer)
1.772 + {
1.773 + // Simply put, tries to copy the data from aBuffer into the clients storage buffers.
1.774 + //
1.775 + // The input stream iFifo data member is used to store the clients storage buffers
1.776 + // that are passed to it via a call to ReadL.
1.777 + //
1.778 + // If iSingleBuffer is False, the first buffer on the fifo is copied to.
1.779 + // This buffer is then removed off the fifo.
1.780 + // The callback MaiscBufferCopied is invoked after each copy, passing that buffer.
1.781 + // If the data is greater than the buffer then this process repeats with the next buffer.
1.782 + //
1.783 + // If iSingleBuffer is True, it is assumed only one buffer is on the fifo.
1.784 + // The behaviour is the same as above except that a descriptor representing the
1.785 + // buffers empty part is placed at the end of the fifo, and the callback
1.786 + // MaiscBufferCopied is invoked only when the buffer is full.
1.787 + //
1.788 + // If the client sets iSingleBuffer to True and places more than one buffer on the fifo
1.789 + // the behaviour is undefined and unsupported.
1.790 + //
1.791 + // If there are no more storage buffers on the fifo, the callback
1.792 + // MaiscRecordComplete(KErrOverflow) is invoked.
1.793 +
1.794 + const TDesC8& buffer = STATIC_CAST(CMMFDataBuffer*, aBuffer)->Data();
1.795 +
1.796 + TInt lengthCopied = 0;
1.797 + iBytesRecorded += buffer.Length();
1.798 +
1.799 + // A stop was requested after all the data has been received
1.800 + if (iState == EStopping && buffer.Length() == 0)
1.801 + {
1.802 + Stop();
1.803 + iCallback.MaiscRecordComplete(KErrNone);
1.804 + return;
1.805 + }
1.806 + else
1.807 + {
1.808 + // The fifo may have multiple storage buffers, i.e. one in each of its entries.
1.809 + // Fill what we can in each. If we get an empty buffer then we have finished recording.
1.810 + while (lengthCopied < buffer.Length())
1.811 + {
1.812 + // Chop up aBuffer into slices the buffers in iFifo can handle
1.813 + TMMFFifoItem<TDes8>* firstItem = iFifo->Get();
1.814 +
1.815 + if(firstItem != NULL)
1.816 + {
1.817 + TDes8& writeBuf = firstItem->GetData();
1.818 +
1.819 + // We have a spare buffer slot
1.820 + TInt slotLength = Min(buffer.Length()-lengthCopied, writeBuf.MaxLength());
1.821 + writeBuf = buffer.Mid(lengthCopied, slotLength);
1.822 + lengthCopied += slotLength;
1.823 +
1.824 + // Determine whether to callback the client or not.
1.825 + // I.e. if we have multiple small buffers that we want to process quickly or
1.826 + // when a singular buffer is FULL.
1.827 + // Note: That if the client asks to Stop, the buffer may not be filled!
1.828 + if (iSingleBuffer)
1.829 + {
1.830 + // Remember this item for later.
1.831 + // We really only want the first item as this covers the entire
1.832 + // client storage buffer. We will adjust the actual length later.
1.833 + if (iStorageItem.Ptr() == NULL)
1.834 + {
1.835 + iStorageItem.Set (const_cast<TUint8*>(writeBuf.Ptr()), 0, writeBuf.MaxLength());
1.836 + }
1.837 +
1.838 + // In this iteration we may just be looking at a right-part of the original
1.839 + // buffer. Update the actual length of data.
1.840 + TInt actualLength = (writeBuf.Ptr()-iStorageItem.Ptr()) + writeBuf.Length();
1.841 + iStorageItem.SetLength(actualLength);
1.842 +
1.843 + // Is the buffer full?
1.844 + if (writeBuf.Length() == writeBuf.MaxLength())
1.845 + {
1.846 + // The singular buffer has been filled so pass it back to the client
1.847 + iCallback.MaiscBufferCopied(KErrNone, iStorageItem);
1.848 + iStorageItem.Set (NULL,0,0);
1.849 + }
1.850 + else
1.851 + {
1.852 + // Create a window to the 'remaining' free section of the storage buffer
1.853 + iBufferPtr.Set (const_cast<TUint8*>(writeBuf.Ptr())+lengthCopied, 0, writeBuf.MaxLength()-lengthCopied);
1.854 +
1.855 + // Add the window to the fifo
1.856 + TInt err = Read(iBufferPtr);
1.857 + if (err)
1.858 + {
1.859 + Stop();
1.860 + iCallback.MaiscRecordComplete(err);
1.861 + return;
1.862 + }
1.863 + ASSERT(iState == ERecording);
1.864 + }
1.865 + }
1.866 + else
1.867 + {
1.868 + // Notify client
1.869 + iCallback.MaiscBufferCopied(KErrNone, writeBuf);
1.870 + }
1.871 + //Check if client called Stop from the MaiscBufferCopied.
1.872 + //If so, we should neither continue this loop nor delete the first item. Stop cleans up all the buffers
1.873 + if(iState == EStopped)
1.874 + {
1.875 + break;
1.876 + }
1.877 + else
1.878 + {
1.879 + // Remove this storage buffer from the fifo as we want to have access to any others behind it.
1.880 + iFifo->RemoveFirstItem();
1.881 + delete firstItem;
1.882 + }
1.883 + }
1.884 + else
1.885 + {
1.886 + // run out of buffers - report an overflow error
1.887 + Stop();
1.888 + iCallback.MaiscRecordComplete(KErrOverflow);
1.889 + return;
1.890 + }
1.891 + }// while
1.892 + } // else
1.893 +
1.894 + // Keep recording if there are free buffers
1.895 + if (!iFifo->IsEmpty())
1.896 + iDevSound->RecordData();
1.897 + }
1.898 +
1.899 +/**
1.900 + *
1.901 + * Called when record operation complete, successfully or otherwise
1.902 + *
1.903 + * @param "TInt aError"
1.904 + * an error value which will indicate playing successfully complete
1.905 + * if error value is 0
1.906 + *
1.907 + */
1.908 +void CMMFMdaAudioInputStream::PlayError(TInt /*aError*/)
1.909 + {
1.910 + Panic(EAudioInputPanicNotSupported);
1.911 + }
1.912 +
1.913 +
1.914 +/**
1.915 + *
1.916 + * Do not support
1.917 + *
1.918 + */
1.919 +void CMMFMdaAudioInputStream::BufferToBeFilled(CMMFBuffer* /*aBuffer*/)
1.920 + {
1.921 + Panic(EAudioInputPanicNotSupported);
1.922 + }
1.923 +
1.924 +/**
1.925 + *
1.926 + * Do not support
1.927 + *
1.928 + */
1.929 +void CMMFMdaAudioInputStream::RecordError(TInt aError)
1.930 + {
1.931 + if (iState == ERecording)
1.932 + {
1.933 + if (aError != KErrCancel)
1.934 + {
1.935 + iCallback.MaiscRecordComplete(aError);
1.936 + }
1.937 + // else must have been cancelled by client. Doesn't need to be notified
1.938 +
1.939 + iState = EStopped;
1.940 + }
1.941 + }
1.942 +
1.943 +/**
1.944 + *
1.945 + * Do not support
1.946 + *
1.947 + */
1.948 +void CMMFMdaAudioInputStream::ConvertError(TInt /*aError*/)
1.949 + {
1.950 + Panic(EAudioInputPanicNotSupported);
1.951 + }
1.952 +
1.953 +/**
1.954 + *
1.955 + * Do not support
1.956 + *
1.957 + */
1.958 +void CMMFMdaAudioInputStream::DeviceMessage(TUid /*aMessageType*/, const TDesC8& /*aMsg*/)
1.959 + {
1.960 + Panic(EAudioInputPanicNotSupported);
1.961 + }
1.962 +
1.963 +// CustomInferface - just pass on to DevSound.
1.964 +TAny* CMMFMdaAudioInputStream::CustomInterface(TUid aInterfaceId)
1.965 + {
1.966 + return iDevSound->CustomInterface(aInterfaceId);
1.967 + }
1.968 +
1.969 +
1.970 +void CMMFMdaAudioInputStream::SetSingleBufferMode(TBool aSingleMode)
1.971 + {
1.972 + iSingleBuffer = aSingleMode;
1.973 + }
1.974 +
1.975 +void CMMFMdaAudioInputStream::ShutDown()
1.976 + {
1.977 + // Need to take for the case where Stop is invoked from the destructor of CMdaAudioInputStream
1.978 + // Need to ensure that there are no callbacks to the client at this stage
1.979 + if (iState != EStopped)
1.980 + {
1.981 + iState = EStopped;
1.982 +
1.983 + if (iSingleBuffer && iStorageItem.Ptr() != NULL)
1.984 + {
1.985 + iStorageItem.Set (NULL,0,0);
1.986 + }
1.987 +
1.988 + // Delete all buffers in the fifo
1.989 + TMMFFifoItem<TDes8>* firstItem;
1.990 + while((firstItem = iFifo->Get()) != NULL)
1.991 + {
1.992 + iFifo->RemoveFirstItem();
1.993 + delete firstItem;
1.994 + }
1.995 +
1.996 + iDevSound->Stop();
1.997 + }
1.998 + }