--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/camcordermmfplugin/mediarecorder/Src/CCMRAudioInput.cpp Thu Dec 17 08:51:24 2009 +0200
@@ -0,0 +1,1041 @@
+/*
+* Copyright (c) 2004 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Audio input class for handling audio data and giving it to CCMRActiveOutput
+*
+*/
+
+
+// INCLUDES
+#include "CCMRAudioInput.h"
+#include "CCMRAudioInputSW.h"
+#include "CCMRAudioInputHW.h"
+#include "CCMRActiveOutput.h"
+#include "CCMRAudioCodecData.h"
+#include "CCMRFifo.h"
+#include "CCMRVideoHWParams.h"
+#include "CCMRConfigManager.h"
+#include <mmf/server/mmfaudioinput.h>
+#include <AudioInput.h>
+#include <AudioPreference.h> // For MMF audio preference definitions.
+#include <mmf/common/mmfaudio.h> // For KMMFEventCategoryAudioLoadingComplete
+
+// CONSTANTS
+// Initial number of buffers allocated
+const TInt KCMRNumAudioBuffers = 10;
+
+// MACROS
+#define AIASSERT(x) __ASSERT_DEBUG(x, User::Panic(_L("CCMRAUDIOINPUT"), EInternalAssertionFailure))
+
+// Debug print macro
+#ifdef _DEBUG
+#include <e32svr.h>
+#define PRINT(x) RDebug::Print x
+#else
+#define PRINT(x)
+#endif
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::~CCMRAudioInput
+// -----------------------------------------------------------------------------
+//
+CCMRAudioInput::~CCMRAudioInput()
+ {
+
+ if ( iInputEmpty )
+ {
+ delete iInputEmpty;
+ iInputEmpty = NULL;
+ }
+ if ( iInputFilled )
+ {
+ delete iInputFilled;
+ iInputFilled = NULL;
+ }
+ if ( iOutputFilled )
+ {
+ delete iOutputFilled;
+ iOutputFilled = NULL;
+ }
+ if ( iOutputEmptied )
+ {
+ delete iOutputEmptied;
+ iOutputEmptied = NULL;
+ }
+
+ if ( (!iSrcBufRef) && iDevSoundBuffer )
+ {
+ delete iDevSoundBuffer;
+ iDevSoundBuffer = NULL;
+ }
+ if ( iProcessingBuffer )
+ {
+ // we happen to have the last buffer still in process, must delete it now
+ delete iProcessingBuffer;
+ iProcessingBuffer = NULL;
+ }
+
+ if ( iDecConfigInfo )
+ {
+ delete iDecConfigInfo;
+ iDecConfigInfo = NULL;
+ // iOutputVideoBuffer is not used with decspecinfo
+ }
+
+ if ( iMediaSinkBuffer )
+ {
+ delete iMediaSinkBuffer;
+ iMediaSinkBuffer = NULL;
+ }
+
+ iOutputThreadHandle.Close();
+
+ if ( iMutexCreated )
+ {
+ iMutexObj.Close();
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::ConstructL(CCMRActiveOutput* aOutput, TUint aThreadId, CCMRConfigManager* aConfig )
+ {
+ PRINT((_L("CCMRAudioInput::ConstructL() in") ));
+ iConfig = aConfig; // doesn't own
+ iPrioritySettings.iPriority = KAudioPriorityVideoRecording;
+ iPrioritySettings.iPref = TMdaPriorityPreference( KAudioPrefVideoRecording );
+
+ // Create input fifos
+ // this fifo is for buffers that are available for storing data from MMFAudioInput/DevSound
+ iInputEmpty = CCMRFifo::NewL(KCMRNumAudioBuffers);
+ // this fifo is for buffers that are storing data from MMFAudioInput/DevSound
+ iInputFilled = CCMRFifo::NewL(KCMRNumAudioBuffers);
+ // this fifo is for buffers that contain encoded data and are waiting for sink to retrieve
+ iOutputFilled = CCMRFifo::NewL(KCMRNumAudioBuffers);
+ // this fifo is for buffers that sink has read and are available for reuse in iOutputFilled
+ iOutputEmptied = CCMRFifo::NewL(KCMRNumAudioBuffers);
+
+ iFirstTime = ETrue;
+ iFirstBufferRequested = EFalse;
+ iTimeStampWhenPaused = TTimeIntervalMicroSeconds(0);
+ User::LeaveIfError(iOutputThreadHandle.Open(aThreadId));
+ User::LeaveIfError(iMutexObj.CreateLocal());
+ iMutexCreated = ETrue;
+
+ iMediaSinkBuffer = new (ELeave) CCMRMediaBuffer();
+ iConsumer = aOutput;
+ iConsumer->RegisterSourceL( this );
+
+ PRINT((_L("CCMRAudioInput::ConstructL() out") ));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::SetCodecL
+//
+// Set codec
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::SetCodecL( CCMRAudioCodecData* aCodecData )
+ {
+ PRINT((_L("CCMRAudioInput::SetCodecL() in")));
+ iCodecData = aCodecData;
+ PRINT((_L("CCMRAudioInput::SetCodecL() out")));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::SourcePrimeL
+// Primes the source
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::SourcePrimeL()
+ {
+ PRINT((_L("CCMRAudioInput::SourcePrimeL()")));
+ iDevSoundBuffer = NULL;
+ iSendBufCount = 0;
+ iFirstTime = ETrue;
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::SourceRecordL
+// Start recording
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::SourceRecordL()
+ {
+ PRINT((_L("CCMRAudioInput::SourceRecordL() in")));
+ ConfigDevSoundL();
+ iState = EStateRecording;
+ iSamplesUpdatedAfterStart = EFalse;
+ iFirstBufferRequested = EFalse;
+ PRINT((_L("CCMRAudioInput::SourceRecordL() out")));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::SourcePauseL
+// Pause recording
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::SourcePauseL()
+ {
+ PRINT((_L("CCMRAudioInput::SourcePauseL(), calling iDataSource->SourceStopL")));
+ iState = EStateStopping;
+
+ // store the latest timestamp - must do it already here, since sending event may reset it and we should not touch it after reset
+ MMMFAudioInput* audioInput = static_cast<MMMFAudioInput*>(iMMFDataSource);
+ CMMFDevSound* devSound = &audioInput->SoundDevice();
+ TInt sampleRate = iCodecData->GetSampleRate();
+
+ TBool firstPause = EFalse;
+ if (iTimeStampWhenPaused == 0)
+ {
+ firstPause = ETrue;
+ }
+
+ if ( sampleRate )
+ {
+ TTimeIntervalMicroSeconds currentTimeStamp;
+ currentTimeStamp = devSound->SamplesRecorded();
+ currentTimeStamp = currentTimeStamp.Int64() * 1000000;
+ currentTimeStamp = currentTimeStamp.Int64() / sampleRate;
+ iTimeStampWhenPaused = iTimeStampWhenPaused.Int64() + currentTimeStamp.Int64();
+ }
+ else
+ {
+ iTimeStampWhenPaused = 0;
+ }
+
+ TInt initialDelay = 0;
+ // Add A/V sync constant to paused timestamp
+ if ( iConfig && iConfig->IsICMConfigDataAvailable() )
+ {
+ PRINT((_L("CCMRAudioInput::SourcePauseL(), using ICM setting value for AVsync delay")));
+ iTimeStampWhenPaused = iTimeStampWhenPaused.Int64() + (iConfig->VideoQualitySettings().iAVSyncResumeDelay*1000);
+ initialDelay = iConfig->VideoQualitySettings().iAVSyncStartDelay;
+ }
+ else
+ {
+ initialDelay = KCMRInitialVideoAudioTimeSyncDC;
+ if ( sampleRate <= KCMRPauseVideoAudioTimeSyncDC_LowSampleRateValue )
+ {
+ PRINT((_L("CCMRAudioInput::SourcePauseL(), using LowSampleRateValue")));
+ iTimeStampWhenPaused = iTimeStampWhenPaused.Int64() + (KCMRPauseVideoAudioTimeSyncDC_LowSampleRate*1000);
+ }
+ else if ( sampleRate <= KCMRPauseVideoAudioTimeSyncDC_MidSampleRateValue )
+ {
+ PRINT((_L("CCMRAudioInput::SourcePauseL(), using MidSampleRateValue")));
+ iTimeStampWhenPaused = iTimeStampWhenPaused.Int64() + (KCMRPauseVideoAudioTimeSyncDC_MidSampleRate*1000);
+ }
+ else
+ {
+ iTimeStampWhenPaused = iTimeStampWhenPaused.Int64() + (KCMRPauseVideoAudioTimeSyncDC*1000);
+ }
+ }
+
+ // Add startdelay if first pause.
+ if ( firstPause )
+ {
+ // only add start delay if we haven't been paused. Only add delay after first audio available
+ if ( initialDelay < 0 )
+ {
+ if ( iTimeStampWhenPaused > -(initialDelay*1000) )
+ {
+ iTimeStampWhenPaused = iTimeStampWhenPaused.Int64() + (initialDelay*1000);
+ }
+ else
+ {
+ iTimeStampWhenPaused = 0;
+ }
+ }
+ else
+ {
+ iTimeStampWhenPaused = iTimeStampWhenPaused.Int64() + (initialDelay*1000);
+ }
+ }
+
+ // Stop audio.
+ PRINT((_L("CCMRAudioInput::SourceStopL() DevSound SourceStopL()")));
+ devSound->Stop();
+
+ if ( iOutputFilled->IsEmpty() )
+ {
+ PRINT((_L("CCMRAudioInput::SourcePauseL(), no data buffers queued so no chance to signal end of data; sending an event instead")));
+ TMMFEvent event (KMMFEventCategoryPlaybackComplete, KErrNone);
+ iEventHandler.SendEventToClient(event);
+ }
+
+ PRINT((_L("CCMRAudioInput::SourcePauseL() out")));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::SourceStopL
+// Stop playing (recording)
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::SourceStopL()
+ {
+ PRINT((_L("CCMRAudioInput::SourceStopL() in")));
+ if ( iState != EStateStopping )
+ {
+ // we came here without pause => there was an error, must stop source
+ PRINT((_L("CCMRAudioInput::SourceStopL() DevSound SourceStopL()")));
+ MMMFAudioInput* audioInput = static_cast<MMMFAudioInput*>(iMMFDataSource);
+ CMMFDevSound* devSound = &audioInput->SoundDevice();
+ devSound->Stop();
+ iFirstBufferRequested = EFalse;
+ }
+ // else data source was already stopped in pause
+ iState = EStateStopped;
+ PRINT((_L("CCMRAudioInput::SourceStopL() out")));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::SetSourcePrioritySettings
+// Set priority settings to source
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::SetSourcePrioritySettings(const TMMFPrioritySettings& aPrioritySettings)
+ {
+ iPrioritySettings = aPrioritySettings;
+ MMMFAudioInput* audioInput = static_cast<MMMFAudioInput*>(iMMFDataSource);
+ CMMFDevSound* devSound = &audioInput->SoundDevice();
+ devSound->SetPrioritySettings(aPrioritySettings);
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::SoundDevice
+// Get reference to DevSound from MMFAudioInput
+// -----------------------------------------------------------------------------
+//
+CMMFDevSound& CCMRAudioInput::SoundDevice()
+ {
+ MMMFAudioInput* audioInput = static_cast<MMMFAudioInput*>(iMMFDataSource);
+ return audioInput->SoundDevice();
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::ResetTimeStamp
+//
+// Resets audio timestamp before new recording; can't be reset automatically
+// in stop/play since they are used also in pause/resume when the stamp should
+// not reset
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::ResetTimeStamp()
+ {
+ iTimeStampWhenPaused = TTimeIntervalMicroSeconds(0);
+ iNumFramesReceived = 0;
+ iDecConfigInfoChecked = EFalse;
+ iSamplesUpdatedAfterStart = EFalse;
+ iLatestTimeStamp = 0;
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::SendEventToClient
+// Stop & send event (error) to client
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::SendEventToClient(const TMMFEvent& aEvent)
+ {
+ PRINT((_L("CCMRAudioInput::SendEventToClient() in, event & error, %x & %d"), aEvent.iEventType, aEvent.iErrorCode));
+ TRAPD(error,SourceStopL()); // errors can be ignored, we are already reporting an error here
+ if (error != KErrNone)
+ {
+ PRINT((_L("CCMRAudioInput::SendEventToClient() stop error: %d"), error));
+ }
+ iEventHandler.SendEventToClient(aEvent);
+ PRINT((_L("CCMRAudioInput::SendEventToClient() out")));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::NewBufferL
+// Inform sink about new coded buffer, and store it in iOutputCoded unless there
+// aren't any older buffer under processing
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::NewBufferL(CMMFBuffer* aBuffer)
+ {
+ // enter restricted area
+ iMutexObj.Wait();
+
+ CMMFBuffer* storeBuffer = NULL;
+ storeBuffer = aBuffer;
+
+ TInt bufLength = storeBuffer->BufferSize();
+ TInt frameLength = 1; // set to 1 since nonzero needed as the initial value in the while-loop below
+ TUint8* data = const_cast<TUint8*>((static_cast<CMMFDataBuffer*>(storeBuffer))->Data().Ptr());
+ while ( (bufLength > 0) && (frameLength > 0) )
+ {
+ frameLength = iCodecData->FrameLength( data, bufLength );
+ bufLength -= frameLength;
+ data += frameLength;
+ iNumFramesReceived++;
+ iNumFramesWaiting++;
+ }
+
+ TInt error = KErrNone;
+ if ( iProcessingBuffer )
+ {
+ // there is one under processing, store this one to fifo
+ TRAP(error, iOutputFilled->PutL( reinterpret_cast<TAny*>(storeBuffer) ));
+ PRINT((_L("CCMRAudioInput::NewBufferL() added %x to fifo. Fifo size %d"), storeBuffer, iOutputFilled->NumberOfItems() ));
+ }
+ else
+ {
+ // take it into use immediately
+ iProcessingBuffer = static_cast<CMMFDataBuffer*>(storeBuffer);
+ iProcessingIndex = 0;
+ iSrcNumUnreadBytes = storeBuffer->BufferSize();
+ PRINT((_L("CCMRAudioInput::NewBufferL() taken buffer into iProcessingBuffer %x, size %d"), storeBuffer, iSrcNumUnreadBytes ));
+ }
+
+ // signal to sink
+ if ( ( error == KErrNone ) && iSinkRequestStatus )
+ {
+ PRINT((_L("CCMRAudioInput::EmptyBufferL() RequestComplete")));
+ iOutputThreadHandle.RequestComplete( iSinkRequestStatus, KErrNone );
+ }
+ else
+ {
+ // else a new request has not been issued yet; this buffer will be handled jointly with previous ones
+ PRINT((_L("CCMRAudioInput::NewBufferL() skipping RequestComplete")));
+ }
+
+ // leave restricted area
+ iMutexObj.Signal();
+
+ if ( error != KErrNone )
+ {
+ // leave postponed here to get out of mutex
+ PRINT((_L("CCMRAudioInput::NewBufferL() leave with error code %d"), error));
+ User::Leave( error );
+ }
+
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::FillBufferL
+// Ask new buffers from devsound.
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::FillBufferL()
+ {
+ PRINT((_L("CCMRAudioInput::FillBufferL() in")));
+ //this is a one-shot "prime" funtion for MMFDevSound as first buffer is uninitialised
+ MMMFAudioInput* audioInput = static_cast<MMMFAudioInput*>(iMMFDataSource);
+ CMMFDevSound* devSound = &audioInput->SoundDevice();
+
+ if (!iFirstBufferRequested)
+ {
+ PRINT((_L("CCMRAudioInput::FillBufferL() DevSound RecordInitL")));
+ devSound->RecordInitL();
+ iFirstBufferRequested = ETrue;
+ PRINT((_L("CCMRAudioInput::FillBufferL() out")));
+ return;
+ }
+ PRINT((_L("CCMRAudioInput::FillBufferL() DevSound RecordData")));
+ devSound->RecordData();
+ PRINT((_L("CCMRAudioInput::FillBufferL() out")));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::RequestNewData
+// Output active object is ready to accept new data
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::RequestNewData(TRequestStatus& aStatus)
+ {
+ PRINT((_L("CCMRAudioInput::RequestNewData() - START - aStatus: 0x%08x, iSinkRequestStatus: 0x%08x"), &aStatus, iSinkRequestStatus ));
+ // enter restricted area
+ iMutexObj.Wait();
+
+ iSinkRequestStatus = &aStatus;
+ aStatus = KRequestPending;
+
+ // leave restricted area
+ iMutexObj.Signal();
+ PRINT((_L("CCMRAudioInput::RequestNewData() - END - aStatus: 0x%08x, iSinkRequestStatus: 0x%08x"), &aStatus, iSinkRequestStatus ));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::RequestNewDataCancel
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::RequestNewDataCancel(TRequestStatus& aStatus)
+ {
+ PRINT((_L("CCMRAudioInput::RequestNewDataCancel() - START - aStatus: 0x%08x, iSinkRequestStatus: 0x%08x"), &aStatus, iSinkRequestStatus ));
+
+ // enter restricted area
+ iMutexObj.Wait();
+
+ if ( &aStatus == iSinkRequestStatus )
+ {
+ iOutputThreadHandle.RequestComplete( iSinkRequestStatus, KErrCancel );
+ }
+
+ // leave restricted area
+ iMutexObj.Signal();
+
+ PRINT((_L("CCMRAudioInput::RequestNewDataCancel() - END - aStatus: 0x%08x, iSinkRequestStatus: 0x%08x"), &aStatus, iSinkRequestStatus ));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::GetNextBuffer
+// Output active object takes the next output buffer
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CCMRMediaBuffer* CCMRAudioInput::GetNextBuffer()
+ {
+ PRINT((_L("CCMRAudioInput::GetNextBuffer() in")));
+
+ if ( (!iDecConfigInfoChecked) && (iState == EStateRecording) )
+ {
+ // check if we have to provide decoder config info first
+
+ iDecConfigInfoChecked = ETrue;
+
+ TRAPD(err,
+ {
+ iDecConfigInfo = iCodecData->GetDecoderConfigInfoLC();
+ if ( iDecConfigInfo != NULL )
+ {
+ // must pop, otherwise TRAPD will panic
+ CleanupStack::Pop(iDecConfigInfo);
+ }
+ }
+ );
+ if ( err != KErrNone )
+ {
+ return NULL;
+ }
+ if ( iDecConfigInfo )
+ {
+ PRINT((_L("CCMRAudioInput::GetNextBuffer() providing decoder config info first")));
+ const TUint8* data = iDecConfigInfo->Ptr();
+ TInt length = iDecConfigInfo->Length();
+ PRINT((_L("CCMRAudioInput::GetNextBuffer() length of the info %d"), length));
+
+ iMediaSinkBuffer->Set( TPtrC8(data,length),
+ CCMRMediaBuffer::EAudioDecSpecInfo,
+ length,
+ EFalse,
+ TTimeIntervalMicroSeconds(0) );
+
+ // can handle only 1 output buffer at a time
+ iOutputBufferInUse = ETrue;
+
+ PRINT((_L("CCMRAudioInput::GetNextBuffer() with DecConfigInfo out")));
+ return iMediaSinkBuffer;
+ }
+ // else the codec doesn't provide it
+ }
+
+
+ // enter restricted area
+ iMutexObj.Wait();
+
+ // take it from fifo
+ if ( iProcessingBuffer && (!iOutputBufferInUse) )
+ {
+
+ // check frame length
+
+ TUint8* data = const_cast<TUint8*>(iProcessingBuffer->Data().Ptr());
+ data += iProcessingIndex;
+
+ AIASSERT( iCodecData );
+
+ TInt frameLength = iCodecData->FrameLength( data, iProcessingBuffer->BufferSize() );
+
+ // associate the next frame from the buffer to mediabuffer
+ iMediaSinkBuffer->Set( TPtrC8(data,frameLength),
+ iCodecData->BufferType(),
+ frameLength,
+ EFalse,
+ TTimeIntervalMicroSeconds((iNumFramesReceived - iNumFramesWaiting)*iCodecData->GetFrameDurationUs()) );
+
+ iNumFramesWaiting--;
+
+ PRINT((_L("CCMRAudioInput::GetNextBuffer() send buf of length %d"),frameLength));
+
+ iProcessingIndex += frameLength;
+ iSrcNumUnreadBytes -= frameLength;
+
+ // leave restricted area
+ iMutexObj.Signal();
+
+ // can handle only 1 output buffer at a time
+ iOutputBufferInUse = ETrue;
+
+ PRINT((_L("CCMRAudioInput::GetNextBuffer() out")));
+ return iMediaSinkBuffer;
+ }
+ else
+ {
+ // leave restricted area
+ iMutexObj.Signal();
+
+ PRINT((_L("CCMRAudioInput::GetNextBuffer() out (no data)")));
+ return NULL;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::NumBuffersWaiting
+// Return the number of buffers in the source
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CCMRAudioInput::NumBuffersWaiting()
+ {
+ return iNumFramesWaiting;
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::LatestTimeStampL
+// Return the latest time stamp from the input stream
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::LatestTimeStampL(TTimeIntervalMicroSeconds& aTimeStamp) const
+ {
+ // estimate the time since the previous call to devsound's samplesrecorded
+ if ( iSamplesUpdatedAfterStart )
+ {
+ TTime current;
+ current.UniversalTime();
+ aTimeStamp = iLatestTimeStamp.Int64() + current.MicroSecondsFrom(iTimeWhenSamplesUpdated).Int64();
+ }
+ else
+ {
+ aTimeStamp = iLatestTimeStamp.Int64();
+ }
+
+ PRINT((_L("CCMRAudioInput::LatestTimeStampL() timestamp %d"), I64INT(aTimeStamp.Int64()) ));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::DurationL
+// Return the duration of the recording
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::DurationL(TTimeIntervalMicroSeconds& aDuration) const
+ {
+ aDuration = TTimeIntervalMicroSeconds(iNumFramesReceived*iCodecData->GetFrameDurationUs());
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::ReturnBuffer
+// Output active object returns an emptied buffer
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::ReturnBuffer(CCMRMediaBuffer* aBuffer)
+ {
+ PRINT((_L("CCMRAudioInput::ReturnBuffer() in")));
+ // save it for reuse
+ iMediaSinkBuffer = aBuffer;
+ iOutputBufferInUse = EFalse;
+ if ( iDecConfigInfo )
+ {
+ delete iDecConfigInfo;
+ iDecConfigInfo = NULL;
+ // iOutputVideoBuffer is not used with decspecinfo
+ }
+
+ if ( !iProcessingBuffer )
+ {
+ // we must have stopped due to pausetimer in audiothreadproxysession; no need to save the buffer, it was already saved
+ return;
+ }
+
+ if ( iProcessingBuffer->LastBuffer() )
+ {
+ PRINT((_L("CCMRAudioInput::ReturnBuffer(), last data buffer given to sink; sending an event to inform completion")));
+ TMMFEvent event (KMMFEventCategoryPlaybackComplete, KErrNone);
+ iEventHandler.SendEventToClient(event);
+ }
+
+ // enter restricted area
+ iMutexObj.Wait();
+ TInt err = KErrNone;
+ if ( iSrcNumUnreadBytes <= 0 )
+ {
+ TRAP(err,iOutputEmptied->PutL( reinterpret_cast<TAny*>(iProcessingBuffer)));
+ if ( err == KErrNone )
+ {
+ PRINT((_L("CCMRAudioInput::ReturnBuffer() save buffer %x to iOutputEmptied"),iProcessingBuffer));
+ // reset
+ iProcessingIndex = 0;
+ iProcessingBuffer = NULL;
+ if (iOutputFilled && !iOutputFilled->IsEmpty())
+ {
+ /* take the next into processing */
+ iProcessingBuffer = reinterpret_cast<CMMFDataBuffer*>(iOutputFilled->Get());
+ iProcessingIndex = 0;
+ iSrcNumUnreadBytes = iProcessingBuffer->BufferSize();
+ PRINT((_L("CCMRAudioInput::ReturnBuffer() started processing a new buffer %x from iOutputFilled"),iProcessingBuffer));
+ }
+ }
+ else
+ {
+ // Can't store in fifo; however, aBuffer was stored to iOutputBuffer already, and iProcessingBuffer is a member
+ // signal the error after got out of mutex
+ PRINT((_L("CCMRAudioInput::ReturnBuffer() putting buffer to fifo failed, deallocate the buffer")));
+ delete iProcessingBuffer;
+ iProcessingBuffer = NULL;
+ }
+ }
+ // leave restricted area
+ iMutexObj.Signal();
+
+ if ( err != KErrNone )
+ {
+ // leave postponed here to get out of mutex
+ PRINT((_L("CCMRAudioInput::ReturnBuffer() report GeneralError event with error code %d"), err));
+ TMMFEvent event(KMMFEventCategoryVideoRecorderGeneralError, err);
+ iEventHandler.SendEventToClient(event);
+ }
+
+ PRINT((_L("CCMRAudioInput::ReturnBuffer() out")));
+
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::ConfigDevSoundL
+// Check DevSound capabilities before configuring. If sampling rate is not
+// supported by DevSound, select the next highest sampling rate supported.
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::ConfigDevSoundL()
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() in")));
+ MMMFAudioInput* audioInput = static_cast<MMMFAudioInput*>(iMMFDataSource);
+ CMMFDevSound* devSound = &audioInput->SoundDevice();
+
+ // Set Audio Routing API to use default mic only.
+ // Create CAudioInput (errors trapped as this is optional feature from adaptation).
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL(), Audio Routing in")));
+ CAudioInput* audioRoutingInput = NULL;
+ TRAPD(audioRoutingError, audioRoutingInput = CAudioInput::NewL( *devSound ));
+ CleanupStack::PushL(audioRoutingInput);
+ if ( audioRoutingError == KErrNone )
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL(), Audio Routing API created")));
+ RArray<CAudioInput::TAudioInputPreference> inputArray;
+ if ( inputArray.Append( CAudioInput::EDefaultMic ) == KErrNone )
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL(), Audio Routing API input array set to default mic.")));
+ // Set Audio Input
+ if ( audioRoutingInput )
+ {
+ TRAP(audioRoutingError, audioRoutingInput->SetAudioInputL( inputArray.Array( ) ));
+ if ( audioRoutingError )
+ {
+ // if KErrNotSupported the devsound implementation probably doesn't support custom interface.
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL(), Audio Routing API SetAudioInputL failed: %d"), audioRoutingError));
+ }
+ else
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL(), Audio Routing API set to default mic.")));
+ }
+ }
+ }
+ else
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL(), Audio Routing API input array set to default mic failed.")));
+ }
+ inputArray.Close();
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL(), Audio Routing out")));
+ }
+ CleanupStack::PopAndDestroy(audioRoutingInput);
+
+ // Query DevSound capabilities and Try to use DevSound sample rate and
+ // mono/stereo capability
+ TMMFCapabilities devSoundCaps = devSound->Capabilities();
+ // get current config
+ TMMFCapabilities devSoundConfig = devSound->Config();
+
+ // Default PCM16
+ devSoundConfig.iEncoding = EMMFSoundEncoding16BitPCM;
+
+ // 1 = Monophonic and 2 == Stereo
+ TInt channels = iCodecData->GetNumChannels();
+ if ((channels == 2) && (devSoundCaps.iChannels & EMMFStereo))
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() stereo recording")));
+ devSoundConfig.iChannels = channels;
+ }
+ else if (devSoundCaps.iChannels & EMMFMono)
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() mono recording")));
+ devSoundConfig.iChannels = 1;
+ }
+ else
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() unsupported channel configuration requested")));
+ User::Leave( KErrNotSupported );
+ }
+
+ if ( iCodecData->GetNumChannels() != devSoundConfig.iChannels )
+ {
+ iCodecData->SetChannelModeL(devSoundCaps.iChannels);
+ }
+
+ // Check for std sample rates.
+ TInt sampleRate = iCodecData->GetSampleRate();
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() got samplerate: %d from codec"), sampleRate));
+
+ // At the moment only 8 and 16 kHz is supported. If we'll get codecs with other sampling rates, this must be modified
+ if ((sampleRate == 8000) && (devSoundCaps.iRate & EMMFSampleRate8000Hz))
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() using sample rate 8000")));
+ devSoundConfig.iRate = EMMFSampleRate8000Hz;
+ }
+ else if ((sampleRate == 16000) && (devSoundCaps.iRate & EMMFSampleRate16000Hz))
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() using sample rate 16000")));
+ devSoundConfig.iRate = EMMFSampleRate16000Hz;
+ }
+ else if ((sampleRate == 24000) && (devSoundCaps.iRate & EMMFSampleRate24000Hz))
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() using sample rate 24000")));
+ devSoundConfig.iRate = EMMFSampleRate24000Hz;
+ }
+ else if ((sampleRate == 32000) && (devSoundCaps.iRate & EMMFSampleRate32000Hz))
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() using sample rate 32000")));
+ devSoundConfig.iRate = EMMFSampleRate32000Hz;
+ }
+ else if ((sampleRate == 48000) && (devSoundCaps.iRate & EMMFSampleRate48000Hz))
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() using sample rate 48000")));
+ devSoundConfig.iRate = EMMFSampleRate48000Hz;
+ }
+ else
+ {
+ // try to set the codec to 16k samplerate.
+ if ( (sampleRate >= 16000) && (devSoundCaps.iRate & EMMFSampleRate16000Hz) )
+ {
+ // this one leaves if the rate is not supported
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() unsupported audio samplerate - trying 16k")));
+ iCodecData->SetBitRateL( 32000 );
+ iCodecData->SetSampleRateL( 16000 );
+ devSoundConfig.iRate = EMMFSampleRate16000Hz;
+ }
+ else if ( devSoundCaps.iRate & EMMFSampleRate8000Hz)
+ {
+ // this one leaves if the rate is not supported
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() unsupported audio samplerate - trying 8k")));
+ iCodecData->SetBitRateL( 16000 );
+ iCodecData->SetSampleRateL( 8000 );
+ devSoundConfig.iRate = EMMFSampleRate8000Hz;
+ }
+ else
+ {
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() unsupported sample rate %d"), sampleRate));
+ User::Leave( KErrNotSupported );
+ }
+ }
+ devSound->SetConfigL(devSoundConfig);
+ PRINT((_L("CCMRAudioInput::ConfigDevSoundL() out")));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::UpdateTimeL
+//
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::UpdateTimeL()
+ {
+ PRINT((_L("CCMRAudioInput::UpdateTimeL() in")));
+ MMMFAudioInput* audioInput = static_cast<MMMFAudioInput*>(iMMFDataSource);
+ CMMFDevSound* devSound = &audioInput->SoundDevice();
+ TInt sampleRate = iCodecData->GetSampleRate();
+
+ if ( sampleRate )
+ {
+ TInt64 samples = devSound->SamplesRecorded();
+ PRINT((_L("CCMRAudioInput::UpdateTimeL() samples recorded %d"),I64INT(samples)));
+
+ samples = samples * 1000000;
+ samples = samples / sampleRate;
+ iLatestTimeStamp = samples + iTimeStampWhenPaused.Int64();
+ }
+ else
+ {
+ iLatestTimeStamp = 0;
+ }
+
+ // only add start delay if we haven't been paused. Only add delay after first audio available
+ if ( (iTimeStampWhenPaused == 0) && (iLatestTimeStamp != 0) )
+ {
+ TInt initialDelay = 0;
+ // Add A/V sync constant to timestamp
+ if ( iConfig && iConfig->IsICMConfigDataAvailable() )
+ {
+ PRINT((_L("CCMRAudioInput::UpdateTimeL(), using ICM setting value for AVsync delay")));
+ initialDelay = iConfig->VideoQualitySettings().iAVSyncStartDelay;
+ }
+ else
+ {
+ PRINT((_L("CCMRAudioInput::UpdateTimeL(), using old setting value for AVsync delay")));
+ initialDelay = KCMRInitialVideoAudioTimeSyncDC;
+ }
+
+ if ( initialDelay < 0 )
+ {
+ if ( iLatestTimeStamp > -( initialDelay*1000) )
+ {
+ iLatestTimeStamp = iLatestTimeStamp.Int64() + ( initialDelay*1000 );
+ }
+ else
+ {
+ iLatestTimeStamp = 0;
+ }
+ }
+ else
+ {
+ iLatestTimeStamp = iLatestTimeStamp.Int64() + ( initialDelay*1000 );
+ }
+ }
+
+ if ( iLatestTimeStamp != 0 )
+ {
+ iTimeWhenSamplesUpdated.UniversalTime();
+ iSamplesUpdatedAfterStart = ETrue;
+ }
+ PRINT((_L("CCMRAudioInput::UpdateTimeL() out")));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::InitializeComplete
+//
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::InitializeComplete(TInt aError)
+ {
+ PRINT((_L("CCMRAudioInput::InitializeComplete() in, error:%d"), aError));
+ TInt error = aError;
+ if ( error == KErrNone )
+ {
+ MMMFAudioInput* audioInput = static_cast<MMMFAudioInput*>(iMMFDataSource);
+ PRINT((_L("CCMRAudioInput::InitializeComplete() SetPrioritySettings")));
+ audioInput->SoundDevice().SetPrioritySettings(iPrioritySettings);
+ PRINT((_L("CCMRAudioInput::InitializeComplete() ConfigDevSoundL")));
+ TRAP(error, ConfigDevSoundL());
+ if (error == KErrNone)
+ {
+ PRINT((_L("CCMRAudioInput::InitializeComplete() AllocateInputBuffersL")));
+ TRAP(error, AllocateInputBuffersL());
+ }
+ else
+ {
+ PRINT((_L("CCMRAudioInput::InitializeComplete() ConfigDevSoundL, error=%d"), error));
+ }
+ }
+ PRINT((_L("CCMRAudioInput::InitializeComplete() SendEventToClient KMMFEventCategoryAudioLoadingComplete, error: %d"), error));
+ TMMFEvent event(KMMFEventCategoryAudioLoadingComplete, error);
+ iEventHandler.SendEventToClient(event);
+ PRINT((_L("CCMRAudioInput::InitializeComplete() out")));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::ToneFinished
+//
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::ToneFinished(TInt aError)
+ {
+ PRINT((_L("CCMRAudioInput::ToneFinished(), error:%d"), aError));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::BufferToBeFilled
+//
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::BufferToBeFilled(CMMFBuffer* /*aBuffer*/)
+ {
+ PRINT((_L("CCMRAudioInput::BufferToBeFilled()")));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::PlayError
+//
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::PlayError(TInt aError)
+ {
+ PRINT((_L("CCMRAudioInput::PlayError(), error:%d"), aError));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::BufferToBeEmptied
+//
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::BufferToBeEmptied(CMMFBuffer* aBuffer)
+ {
+ PRINT((_L("CCMRAudioInput::BufferToBeEmptied()")));
+ TInt error = KErrNone;
+ TRAP(error, BufferFilledL(aBuffer));
+ if (error != KErrNone)
+ {
+ TMMFEvent event (KMMFEventCategoryPlaybackComplete, error);
+ SendEventToClient( event );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::RecordError
+//
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::RecordError(TInt aError)
+ {
+ PRINT((_L("CCMRAudioInput::RecordError(), error=%d"), aError));
+ TMMFEvent event (KMMFEventCategoryPlaybackComplete, aError);
+ iEventHandler.SendEventToClient(event);
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::ConvertError
+//
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::ConvertError(TInt aError)
+ {
+ PRINT((_L("CCMRAudioInput::ConvertError(), error:%d"), aError));
+ }
+
+// -----------------------------------------------------------------------------
+// CCMRAudioInput::DeviceMessage
+//
+// -----------------------------------------------------------------------------
+//
+void CCMRAudioInput::DeviceMessage(TUid /*aMessageType*/, const TDesC8& /*aMsg*/)
+ {
+ PRINT((_L("CCMRAudioInput::DeviceMessage()")));
+ }
+
+
+// End of file
+
+