qtmobility/plugins/multimedia/symbian/openmaxal/mediarecorder/xarecordsessionimpl.cpp
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "xarecordsessionimpl.h"
#include "xarecordsessioncommon.h"
_LIT8(K8WAVMIMETYPE, "audio/x-wav");
/*
* These codec names are not part of AL. Hence we need to define names here.
* */
_LIT(KAUDIOCODECPCM, "pcm");
_LIT(KAUDIOCODECAMR, "amr");
_LIT(KAUDIOCODECAAC, "aac");
_LIT(KCONTAINERWAV, "wav");
_LIT(KCONTAINERWAVDESC, "wav container");
_LIT(KCONTAINERAMR, "amr-nb");
_LIT(KCONTAINERAMRDESC, "amr-nb File format");
_LIT(KCONTAINERMP4, "mp4");
_LIT(KCONTAINERMP4DESC, "mp4 container");
const TUint KRecordPosUpdatePeriod = 1000;
const TUint KMilliToHz = 1000;
const TUint KMaxNameLength = 256;
/* Local functions for callback registation */
void cbXAObjectItf(
XAObjectItf caller,
const void *pContext,
XAuint32 event,
XAresult result,
XAuint32 param,
void *pInterface);
void cbXARecordItf(
XARecordItf caller,
void *pContext,
XAuint32 event);
void cbXAAvailableAudioInputsChanged(
XAAudioIODeviceCapabilitiesItf caller,
void *pContext,
XAuint32 deviceID,
XAint32 numInputs,
XAboolean isNew);
XARecordSessionImpl::XARecordSessionImpl(XARecordObserver &parent)
:m_Parent(parent),
m_EOEngine(NULL),
m_MORecorder(NULL),
m_RecordItf(NULL),
m_AudioEncItf(NULL),
m_WAVMime(NULL),
m_URIName(NULL),
m_InputDeviceId(0),
m_ContainerType(0),
m_BitRate(0),
m_RateControl(0),
m_ChannelsOut(0),
m_SampleRate(0),
m_AudioIODevCapsItf(NULL),
m_AudioInputDeviceNames(NULL),
m_DefaultAudioInputDeviceNames(NULL),
m_AudioEncCapsItf(NULL)
{
TRACE_FUNCTION_ENTRY_EXIT;
}
XARecordSessionImpl::~XARecordSessionImpl()
{
TRACE_FUNCTION_ENTRY;
if (m_MORecorder)
(*m_MORecorder)->Destroy(m_MORecorder);
if (m_EOEngine)
(*m_EOEngine)->Destroy(m_EOEngine);
delete m_WAVMime;
delete m_URIName;
m_InputDeviceIDs.Close();
if (m_AudioInputDeviceNames)
m_AudioInputDeviceNames->Reset();
delete m_AudioInputDeviceNames;
m_DefaultInputDeviceIDs.Close();
if (m_DefaultAudioInputDeviceNames)
m_DefaultAudioInputDeviceNames->Reset();
delete m_DefaultAudioInputDeviceNames;
m_EncoderIds.Close();
m_EncoderNames.Close();
m_ContainerNames.Close();
m_ContainerDescs.Close();
TRACE_FUNCTION_EXIT;
}
TInt32 XARecordSessionImpl::postConstruct()
{
TRACE_FUNCTION_ENTRY;
XAEngineOption engineOption[] = { (XAuint32) XA_ENGINEOPTION_THREADSAFE, (XAuint32) XA_BOOLEAN_TRUE};
/* Create and realize Engine object */
TRACE_LOG(_L("XARecordSessionImpl: Creating Engine..."));
XAresult xa_result = xaCreateEngine (&m_EOEngine, 1, engineOption, 0, NULL, NULL);
TInt returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRACE_LOG(_L("XARecordSessionImpl: Realizing engine..."));
xa_result = (*m_EOEngine)->Realize(m_EOEngine, XA_BOOLEAN_FALSE);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRACE_LOG(_L("XARecordSessionImpl: OMX AL Engine realized successfully"));
XAEngineItf engineItf;
xa_result = (*m_EOEngine)->GetInterface(m_EOEngine, XA_IID_ENGINE, (void**) &engineItf);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
xa_result = (*m_EOEngine)->GetInterface(m_EOEngine,
XA_IID_AUDIOIODEVICECAPABILITIES,
(void**) &m_AudioIODevCapsItf);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
xa_result = (*m_AudioIODevCapsItf)->RegisterAvailableAudioInputsChangedCallback(
m_AudioIODevCapsItf,
cbXAAvailableAudioInputsChanged,
(void*)this);
xa_result = (*m_EOEngine)->GetInterface(
m_EOEngine,
XA_IID_AUDIOENCODERCAPABILITIES,
(void**) &m_AudioEncCapsItf);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRAP(returnValue, m_WAVMime = HBufC8::NewL(K8WAVMIMETYPE().Length() + 1));
RET_ERR_IF_ERR(returnValue);
TPtr8 ptr = m_WAVMime->Des();
ptr = K8WAVMIMETYPE(); // copy uri name into local variable
ptr.PtrZ(); // append zero terminator to end of URI
m_AudioInputDeviceNames = new CDesC16ArrayFlat(2);
if (m_AudioInputDeviceNames == NULL)
returnValue = KErrNoMemory;
RET_ERR_IF_ERR(returnValue);
m_DefaultAudioInputDeviceNames = new CDesC16ArrayFlat(2);
if (m_DefaultAudioInputDeviceNames == NULL)
returnValue = KErrNoMemory;
RET_ERR_IF_ERR(returnValue);
returnValue = initContainersList();
RET_ERR_IF_ERR(returnValue);
returnValue = initAudioEncodersList();
RET_ERR_IF_ERR(returnValue);
returnValue = initAudioInputDevicesList();
RET_ERR_IF_ERR(returnValue);
TRACE_FUNCTION_EXIT;
return returnValue;
}
TInt32 XARecordSessionImpl::setURI(const TDesC &aURI)
{
TRACE_FUNCTION_ENTRY;
/* This function will only get called when aURI is different than m_URIName
* and only when recorder is in stopped state.
* If the recorder object was created for a different URI (than aURI), we
* need to tear it down here.
*/
if (!m_URIName && m_MORecorder) {
(*m_MORecorder)->Destroy(m_MORecorder);
m_MORecorder = NULL;
m_RecordItf = NULL;
}
delete m_URIName;
m_URIName = NULL;
TRAPD(returnValue, m_URIName = HBufC8::NewL(aURI.Length()+1));
RET_ERR_IF_ERR(returnValue);
TPtr8 uriPtr = m_URIName->Des();
/* copy uri name into local variable */
uriPtr.Copy(aURI);
TRACE_FUNCTION_EXIT;
return returnValue;
}
TInt32 XARecordSessionImpl::record()
{
TRACE_FUNCTION_ENTRY;
TInt32 returnValue(KErrGeneral);
if (!m_MORecorder || !m_RecordItf) {
TRACE_LOG(_L("XARecordSessionImpl::Record: MORecorder/RecordItf is not created"));
returnValue = createMediaRecorderObject();
RET_ERR_IF_ERR(returnValue);
}
returnValue = setEncoderSettingsToMediaRecorder();
RET_ERR_IF_ERR(returnValue);
XAuint32 state;
XAresult xa_result = (*m_RecordItf)->GetRecordState(m_RecordItf, &state);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
if ((state == XA_RECORDSTATE_STOPPED)
|| (state == XA_RECORDSTATE_PAUSED)) {
TRACE_LOG(_L("XARecordSessionImpl::Record: Setting State to Recording..."));
xa_result = (*m_RecordItf)->SetRecordState(m_RecordItf, XA_RECORDSTATE_RECORDING);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRACE_LOG(_L("XARecordSessionImpl::Record: SetState to Recording"));
}
TRACE_FUNCTION_EXIT;
return returnValue;
}
TInt32 XARecordSessionImpl::pause()
{
TRACE_FUNCTION_ENTRY;
TInt32 returnValue(KErrGeneral);
if (!m_MORecorder || !m_RecordItf) {
TRACE_LOG(_L("XARecordSessionImpl::Record: MORecorder/RecordItf is not created"));
return returnValue;
}
XAuint32 state;
XAresult xa_result = (*m_RecordItf)->GetRecordState(m_RecordItf, &state);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
if ((state == XA_RECORDSTATE_STOPPED)
|| (state == XA_RECORDSTATE_RECORDING)) {
TRACE_LOG(_L("XARecordSessionImpl::Record: Setting State to Paused..."));
xa_result = (*m_RecordItf)->SetRecordState(m_RecordItf, XA_RECORDSTATE_PAUSED);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRACE_LOG(_L("XARecordSessionImpl::Record: SetState to Paused"));
}
TRACE_FUNCTION_EXIT;
return returnValue;
}
TInt32 XARecordSessionImpl::stop()
{
TRACE_FUNCTION_ENTRY;
TInt32 returnValue(KErrGeneral);
if (!m_MORecorder || !m_RecordItf) {
TRACE_LOG(_L("XARecordSessionImpl::Record: MORecorder/RecordItf is not created"));
return returnValue;
}
XAuint32 state;
XAresult xa_result = (*m_RecordItf)->GetRecordState(m_RecordItf, &state);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
if ((state == XA_RECORDSTATE_PAUSED)
|| (state == XA_RECORDSTATE_RECORDING)) {
TRACE_LOG(_L("XARecordSessionImpl::Record: Setting State to Stopped..."));
xa_result = (*m_RecordItf)->SetRecordState(m_RecordItf, XA_RECORDSTATE_STOPPED);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRACE_LOG(_L("XARecordSessionImpl::Record: SetState to Stopped"));
}
TRACE_FUNCTION_EXIT;
return returnValue;
}
TInt32 XARecordSessionImpl::duration(TInt64 &aDur)
{
TRACE_FUNCTION_ENTRY;
TInt32 returnValue(KErrGeneral);
if (!m_MORecorder || !m_RecordItf) {
TRACE_LOG(_L("XARecordSessionImpl::Duration: MORecoder/RecordItf is not created"));
return returnValue;
}
XAmillisecond milliSec;
XAresult xa_result = (*m_RecordItf)->GetPosition(m_RecordItf, &milliSec);
returnValue = mapError(xa_result, ETrue);
if (returnValue == KErrNone)
aDur = (TInt64)milliSec;
TRACE_FUNCTION_EXIT;
return returnValue;
}
void XARecordSessionImpl::cbMediaRecorder(
XAObjectItf /*caller*/,
const void */*pContext*/,
XAuint32 event,
XAresult result,
XAuint32 /*param*/,
void */*pInterface*/)
{
TRACE_FUNCTION_ENTRY;
switch (event) {
case XA_OBJECT_EVENT_RESOURCES_LOST:
m_Parent.cbRecordingStopped();
break;
case XA_OBJECT_EVENT_RUNTIME_ERROR: {
switch (result) {
case XA_RESULT_RESOURCE_LOST:
m_Parent.cbRecordingStopped();
break;
default:
break;
}; /* of switch (result) */
}
default:
break;
} /* of switch (event) */
TRACE_FUNCTION_EXIT;
}
void XARecordSessionImpl::cbRecordItf(
XARecordItf /*caller*/,
void */*pContext*/,
XAuint32 event)
{
TRACE_FUNCTION_ENTRY;
switch(event) {
case XA_RECORDEVENT_HEADATLIMIT:
TRACE_LOG(_L("XA_RECORDEVENT_HEADATLIMIT"));
break;
case XA_RECORDEVENT_HEADATMARKER:
TRACE_LOG(_L("XA_RECORDEVENT_HEADATMARKER"));
break;
case XA_RECORDEVENT_HEADATNEWPOS: {
TInt32 returnValue;
XAresult xa_result;
XAmillisecond milliSec;
xa_result = (*m_RecordItf)->GetPosition(m_RecordItf, &milliSec);
returnValue = mapError(xa_result, ETrue);
if (returnValue == KErrNone)
m_Parent.cbDurationChanged((TInt64)milliSec);
}
break;
case XA_RECORDEVENT_HEADMOVING:
TRACE_LOG(_L("XA_RECORDEVENT_HEADMOVING"));
m_Parent.cbRecordingStarted();
break;
case XA_RECORDEVENT_HEADSTALLED:
TRACE_LOG(_L("XA_RECORDEVENT_HEADSTALLED"));
break;
case XA_RECORDEVENT_BUFFER_FULL:
TRACE_LOG(_L("XA_RECORDEVENT_BUFFER_FULL"));
break;
default:
TRACE_LOG(_L("UNKNOWN RECORDEVENT EVENT"));
break;
} /* of switch(event) */
TRACE_FUNCTION_EXIT;
}
/* For QAudioEndpointSelector begin */
void XARecordSessionImpl::getAudioInputDeviceNames(RArray<TPtrC> &aArray)
{
TRACE_FUNCTION_ENTRY;
for(TInt index = 0; index < m_AudioInputDeviceNames->MdcaCount(); index++)
aArray.Append(m_AudioInputDeviceNames->MdcaPoint(index));
TRACE_FUNCTION_EXIT;
}
TInt32 XARecordSessionImpl::defaultAudioInputDevice(TPtrC &endPoint)
{
TRACE_FUNCTION_ENTRY;
TInt32 err(KErrGeneral);
if (m_DefaultAudioInputDeviceNames->MdcaCount() >= 0)
endPoint.Set(m_DefaultAudioInputDeviceNames->MdcaPoint(0));
TRACE_FUNCTION_EXIT;
return err;
}
TInt32 XARecordSessionImpl::activeAudioInputDevice(TPtrC &endPoint)
{
TRACE_FUNCTION_ENTRY;
TInt32 returnValue(KErrGeneral);
TBool found(EFalse);
TInt index = 0;
for(; index < m_InputDeviceIDs.Count(); index++) {
if (m_InputDeviceIDs[index] == m_InputDeviceId) {
found = ETrue;
break;
}
}
/* Comparing found with ETrue produces linker error */
if (found == true) {
endPoint.Set(m_AudioInputDeviceNames->MdcaPoint(index));
returnValue = KErrNone;
}
TRACE_FUNCTION_EXIT;
return returnValue;
}
TBool XARecordSessionImpl::setAudioInputDevice(const TDesC &aDevice)
{
TRACE_FUNCTION_ENTRY;
/* validate if we can set input device id */
TBool found(EFalse);
m_InputDeviceId = 0;
TInt index = 0;
for(; index < m_AudioInputDeviceNames->MdcaCount(); index++) {
if (m_AudioInputDeviceNames->MdcaPoint(index).Compare(aDevice) == 0) {
found = ETrue;
break;
}
}
if (found == true) {
m_InputDeviceId = m_InputDeviceIDs[index];
}
TRACE_FUNCTION_EXIT;
return found;
}
void XARecordSessionImpl::cbAvailableAudioInputsChanged(
XAAudioIODeviceCapabilitiesItf /*caller*/,
void */*pContext*/,
XAuint32 deviceID,
XAint32 /*numInputs*/,
XAboolean isNew)
{
TRACE_FUNCTION_ENTRY;
/* If a new device is added into the system, append it to available input list */
if (isNew == XA_BOOLEAN_TRUE) {
XAAudioInputDescriptor audioInputDescriptor;
m_InputDeviceIDs.Append(deviceID);
XAresult xa_result = (*m_AudioIODevCapsItf)->QueryAudioInputCapabilities(
m_AudioIODevCapsItf,
deviceID,
&audioInputDescriptor);
if ((mapError(xa_result, ETrue)) == KErrNone) {
TUint8* inDevNamePtr = audioInputDescriptor.deviceName;
TUint8* tempPtr = audioInputDescriptor.deviceName;
TInt32 inDevNameLength = 0;
while (*tempPtr++) inDevNameLength++;
TPtrC8 ptr(inDevNamePtr, inDevNameLength);
/* Convert 8 bit to 16 bit */
TBuf16<KMaxNameLength> name;
name.Copy(ptr);
/* Using TRAP with returnValue results in compiler error */
TRAP_IGNORE(m_AudioInputDeviceNames->AppendL(name));
}
}
else {
/* an available device has been removed from the the system, remove it from
* available input list and also default list */
TBool found(EFalse);
TInt index = 0;
for (; index < m_InputDeviceIDs.Count(); index++) {
if (deviceID == m_InputDeviceIDs[index]) {
found = ETrue;
break;
}
}
if (found == true) {
m_InputDeviceIDs.Remove(index);
m_AudioInputDeviceNames->Delete(index);
}
if (deviceID == m_InputDeviceId)
m_InputDeviceId = 0;
found = EFalse;
for (index = 0; index < m_DefaultInputDeviceIDs.Count(); index++) {
if (deviceID == m_DefaultInputDeviceIDs[index]) {
found = ETrue;
break;
}
}
if (found == true) {
m_DefaultInputDeviceIDs.Remove(index);
m_DefaultAudioInputDeviceNames->Delete(index);
}
}
m_Parent.cbAvailableAudioInputsChanged();
TRACE_FUNCTION_EXIT;
}
/* For QAudioEndpointSelector end */
/* For QAudioEncoderControl begin */
const RArray<TPtrC>& XARecordSessionImpl::getAudioEncoderNames()
{
TRACE_FUNCTION_ENTRY_EXIT;
return m_EncoderNames;
}
TInt32 XARecordSessionImpl::getSampleRates(
const TDesC& aEncoder,
RArray<TInt32> &aSampleRates,
TBool &aIsContinuous)
{
TRACE_FUNCTION_ENTRY;
aSampleRates.Reset();
aIsContinuous = EFalse;
XAuint32 encoderId = 0;
TBool found(EFalse);
for (TInt index = 0; index < m_EncoderIds.Count(); index++) {
if (m_EncoderNames[index].Compare(aEncoder) == 0) {
found = ETrue;
encoderId = m_EncoderIds[index];
break;
}
}
TInt32 returnValue(KErrGeneral);
if (found == false)
return returnValue;
XAuint32 numCaps = 0;
XAAudioCodecDescriptor codecDesc;
XAresult xa_result = (*m_AudioEncCapsItf)->GetAudioEncoderCapabilities(
m_AudioEncCapsItf,
encoderId,
&numCaps,
&codecDesc);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
/* TODO What do we do if we have more than one caps?? */
aIsContinuous = codecDesc.isFreqRangeContinuous;
if (aIsContinuous) {
aSampleRates.Append(codecDesc.minSampleRate / KMilliToHz);
aSampleRates.Append(codecDesc.maxSampleRate / KMilliToHz);
}
else {
XAuint32 numSRSupported = codecDesc.numSampleRatesSupported;
XAmilliHertz *pSampleRatesSupported(NULL);
pSampleRatesSupported = codecDesc.pSampleRatesSupported;
for (TInt index = 0; index < numSRSupported; index++)
aSampleRates.Append((*(pSampleRatesSupported + index)) / KMilliToHz);
}
TRACE_FUNCTION_EXIT;
return returnValue;
}
TInt32 XARecordSessionImpl::getBitrates(
const TDesC& aEncoder,
RArray<TUint32> &aBitrates)
{
TRACE_FUNCTION_ENTRY;
aBitrates.Reset();
XAuint32 encoderId = 0;
TBool found(EFalse);
for (TInt index = 0; index < m_EncoderIds.Count(); index++) {
if (m_EncoderNames[index].Compare(aEncoder) == 0) {
found = ETrue;
encoderId = m_EncoderIds[index];
break;
}
}
TInt32 returnValue(KErrNotSupported);
if (found == false)
return returnValue;
returnValue = getBitratesByAudioCodecID(encoderId, aBitrates);
TRACE_FUNCTION_EXIT;
return returnValue;
}
/* For QAudioEncoderControl end */
/* For QMediaContainerControl begin */
const RArray<TPtrC>& XARecordSessionImpl::getContainerNames()
{
TRACE_FUNCTION_ENTRY_EXIT;
return m_ContainerNames;
}
const RArray<TPtrC>& XARecordSessionImpl::getContainerDescs()
{
TRACE_FUNCTION_ENTRY_EXIT;
return m_ContainerDescs;
}
/* For QMediaContainerControl end */
void XARecordSessionImpl::resetEncoderAttributes()
{
m_ContainerType = 0;
m_AudioEncoderId = 0;
m_ProfileSetting = 0;
m_BitRate = 0;
m_ChannelsOut = 0;
m_SampleRate = 0;
m_RateControl = 0;
}
void XARecordSessionImpl::setContainerType(const TDesC &aURI)
{
TRACE_FUNCTION_ENTRY;
if (aURI.Compare(KCONTAINERWAV()) == 0)
m_ContainerType = XA_CONTAINERTYPE_WAV;
else if (aURI.Compare(KCONTAINERAMR()) == 0)
m_ContainerType = XA_CONTAINERTYPE_AMR;
else if (aURI.Compare(KCONTAINERMP4()) == 0)
m_ContainerType = XA_CONTAINERTYPE_MP4;
TRACE_FUNCTION_EXIT;
}
TBool XARecordSessionImpl::setCodec(const TDesC &aCodec)
{
TRACE_FUNCTION_ENTRY;
TBool returnValue(EFalse);
if (aCodec.Compare(KAUDIOCODECPCM()) == 0) {
m_AudioEncoderId = XA_AUDIOCODEC_PCM;
m_ProfileSetting = XA_AUDIOPROFILE_PCM;
returnValue = ETrue;
}
else if (aCodec.Compare(KAUDIOCODECAAC()) == 0) {
m_AudioEncoderId = XA_AUDIOCODEC_AAC;
m_ProfileSetting = XA_AUDIOPROFILE_AAC_AAC;
returnValue = ETrue;
}
else if (aCodec.Compare(KAUDIOCODECAMR()) == 0) {
m_AudioEncoderId = XA_AUDIOCODEC_AMR;
m_ProfileSetting = XA_AUDIOPROFILE_AMR;
returnValue = ETrue;
}
TRACE_FUNCTION_EXIT;
return returnValue;
}
void XARecordSessionImpl::setBitRate(TUint32 aBitRate) {
TRACE_FUNCTION_ENTRY;
m_BitRate = aBitRate;
TRACE_FUNCTION_EXIT;
}
void XARecordSessionImpl::setChannels(TUint32 aChannels) {
TRACE_FUNCTION_ENTRY;
m_ChannelsOut = aChannels;
TRACE_FUNCTION_EXIT;
}
void XARecordSessionImpl::setOptimalChannelCount() {
TRACE_FUNCTION_ENTRY;
m_ChannelsOut = 0xffffffff;
TRACE_FUNCTION_EXIT;
}
void XARecordSessionImpl::setSampleRate(TUint32 aSampleRate) {
TRACE_FUNCTION_ENTRY;
/* convert Hz to MilliHz */
m_SampleRate = aSampleRate * KMilliToHz;
TRACE_FUNCTION_EXIT;
}
void XARecordSessionImpl::setOptimalSampleRate() {
TRACE_FUNCTION_ENTRY;
m_SampleRate = 0xffffffff;
TRACE_FUNCTION_EXIT;
}
TInt32 XARecordSessionImpl::setCBRMode()
{
TRACE_FUNCTION_ENTRY;
m_RateControl = XA_RATECONTROLMODE_CONSTANTBITRATE;
TRACE_FUNCTION_EXIT;
return KErrNone;
}
TInt32 XARecordSessionImpl::setVBRMode()
{
TRACE_FUNCTION_ENTRY;
m_RateControl = XA_RATECONTROLMODE_VARIABLEBITRATE;
TRACE_FUNCTION_EXIT;
return KErrNone;
}
void XARecordSessionImpl::setVeryLowQuality()
{
/* Set to very low quality encoder preset */
RArray<TUint32> bitrates;
TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates);
if ((res == KErrNone) && (bitrates.Count() > 0) ) {
/* Sort the array and pick the lowest bit rate */
bitrates.SortUnsigned();
m_BitRate = bitrates[0];
}
}
void XARecordSessionImpl::setLowQuality()
{
/* Set to low quality encoder preset */
RArray<TUint32> bitrates;
TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates);
if ((res == KErrNone) && (bitrates.Count() > 0)) {
/* Sort the array and pick the low quality bit rate */
bitrates.SortUnsigned();
m_BitRate = bitrates[bitrates.Count()*1/4];
}
}
void XARecordSessionImpl::setNormalQuality()
{
/* Set to normal quality encoder preset */
RArray<TUint32> bitrates;
TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates);
if ((res == KErrNone) && (bitrates.Count() > 0)) {
/* Sort the array and pick the middle range bit rate */
bitrates.SortUnsigned();
m_BitRate = bitrates[bitrates.Count()/2];
}
}
void XARecordSessionImpl::setHighQuality()
{
/* Set to high quality encoder preset */
RArray<TUint32> bitrates;
TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates);
if ((res == KErrNone) && (bitrates.Count() > 0)) {
/* Sort the array and pick the high quality bit rate */
bitrates.SortUnsigned();
m_BitRate = bitrates[bitrates.Count()*3/4];
}
}
void XARecordSessionImpl::setVeryHighQuality()
{
/* Set to very high quality encoder preset */
RArray<TUint32> bitrates;
TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates);
if ((res == KErrNone) && (bitrates.Count() > 0)) {
/* Sort the array and pick the highest bit rate */
bitrates.SortUnsigned();
m_BitRate = bitrates[bitrates.Count()-1];
}
}
/* Internal function */
TInt32 XARecordSessionImpl::createMediaRecorderObject()
{
TRACE_FUNCTION_ENTRY;
if (!m_EOEngine)
return KErrGeneral;
TInt32 returnValue(KErrNone);
TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject"));
if (!m_MORecorder && !m_RecordItf) {
/* Setup the data source */
m_LocatorMic.locatorType = XA_DATALOCATOR_IODEVICE;
m_LocatorMic.deviceType = XA_IODEVICE_AUDIOINPUT;
m_LocatorMic.deviceID = m_InputDeviceId;
m_LocatorMic.device = NULL;
m_DataSource.pLocator = (void*) &m_LocatorMic;
m_DataSource.pFormat = NULL;
/* Setup the data sink structure */
m_Uri.locatorType = XA_DATALOCATOR_URI;
/* append zero terminator to end of URI */
TPtr8 uriPtr = m_URIName->Des();
m_Uri.URI = (XAchar*) uriPtr.PtrZ();
m_Mime.formatType = XA_DATAFORMAT_MIME;
m_Mime.containerType = XA_CONTAINERTYPE_WAV;
TPtr8 mimeTypePtr(m_WAVMime->Des());
m_Mime.mimeType = (XAchar*)mimeTypePtr.Ptr();
m_DataSink.pLocator = (void*) &m_Uri;
m_DataSink.pFormat = (void*) &m_Mime;
/* Init arrays required[] and iidArray[] */
XAboolean required[MAX_NUMBER_INTERFACES];
XAInterfaceID iidArray[MAX_NUMBER_INTERFACES];
for (TInt32 i = 0; i < MAX_NUMBER_INTERFACES; i++) {
required[i] = XA_BOOLEAN_FALSE;
iidArray[i] = XA_IID_NULL;
}
XAuint32 noOfInterfaces = 0;
required[noOfInterfaces] = XA_BOOLEAN_FALSE;
iidArray[noOfInterfaces] = XA_IID_RECORD;
noOfInterfaces++;
required[noOfInterfaces] = XA_BOOLEAN_FALSE;
iidArray[noOfInterfaces] = XA_IID_AUDIOENCODER;
noOfInterfaces++;
XAEngineItf engineItf;
XAresult xa_result = (*m_EOEngine)->GetInterface(m_EOEngine, XA_IID_ENGINE, (void**) &engineItf);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Create Media Recorder..."));
/* Create recorder with NULL for a the image/video source, since this is for audio-only recording */
xa_result = (*engineItf)->CreateMediaRecorder(
engineItf,
&m_MORecorder,
&m_DataSource,
NULL,
&m_DataSink,
noOfInterfaces,
iidArray,
required);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Realize Media Recorder..."));
xa_result = (*m_MORecorder)->Realize(m_MORecorder, XA_BOOLEAN_FALSE);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Register Callback on recorder..."));
xa_result = (*m_MORecorder)->RegisterCallback(m_MORecorder, cbXAObjectItf, (void*)this);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Getting Record Interface..."));
xa_result = (*m_MORecorder)->GetInterface(m_MORecorder, XA_IID_RECORD, &m_RecordItf);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Registering Callback on record Interface..."));
xa_result = (*m_RecordItf)->RegisterCallback(m_RecordItf, cbXARecordItf, (void*)this);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: SetPositionUpdatePeriod on record Interface..."));
xa_result = (*m_RecordItf)->SetPositionUpdatePeriod(m_RecordItf, (XAmillisecond)KRecordPosUpdatePeriod);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: SetCallbackEventsMask on record Interface..."));
xa_result = (*m_RecordItf)->SetCallbackEventsMask(m_RecordItf, XA_RECORDEVENT_HEADATNEWPOS |
XA_RECORDEVENT_HEADMOVING |
XA_RECORDEVENT_HEADSTALLED);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Getting Audio Encoder Interface..."));
xa_result = (*m_MORecorder)->GetInterface(m_MORecorder, XA_IID_AUDIOENCODER, &m_AudioEncItf);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
}
TRACE_FUNCTION_EXIT;
return returnValue;
}
TInt32 XARecordSessionImpl::mapError(XAresult xa_err, TBool debPrn)
{
TInt32 returnValue(KErrGeneral);
switch(xa_err) {
case XA_RESULT_SUCCESS:
returnValue = KErrNone;
break;
case XA_RESULT_PRECONDITIONS_VIOLATED:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_PRECONDITIONS_VIOLATED"));
break;
case XA_RESULT_PARAMETER_INVALID:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_PARAMETER_INVALID"));
break;
case XA_RESULT_MEMORY_FAILURE:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_MEMORY_FAILURE"));
break;
case XA_RESULT_RESOURCE_ERROR:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_RESOURCE_ERROR"));
break;
case XA_RESULT_RESOURCE_LOST:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_RESOURCE_LOST"));
break;
case XA_RESULT_IO_ERROR:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_IO_ERROR"));
break;
case XA_RESULT_BUFFER_INSUFFICIENT:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_BUFFER_INSUFFICIENT"));
break;
case XA_RESULT_CONTENT_CORRUPTED:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_CONTENT_CORRUPTED"));
break;
case XA_RESULT_CONTENT_UNSUPPORTED:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_CONTENT_UNSUPPORTED"));
break;
case XA_RESULT_CONTENT_NOT_FOUND:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_CONTENT_NOT_FOUND"));
break;
case XA_RESULT_PERMISSION_DENIED:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_PERMISSION_DENIED"));
break;
case XA_RESULT_FEATURE_UNSUPPORTED:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_FEATURE_UNSUPPORTED"));
break;
case XA_RESULT_INTERNAL_ERROR:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_INTERNAL_ERROR"));
break;
case XA_RESULT_UNKNOWN_ERROR:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_UNKNOWN_ERROR"));
break;
case XA_RESULT_OPERATION_ABORTED:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_OPERATION_ABORTED"));
break;
case XA_RESULT_CONTROL_LOST:
if (debPrn)
TRACE_LOG(_L("XA_RESULT_CONTROL_LOST"));
break;
default:
if (debPrn)
TRACE_LOG(_L("Unknown Error!!!"));
break;
}
return returnValue;
}
TInt32 XARecordSessionImpl::initContainersList()
{
TRACE_FUNCTION_ENTRY;
m_ContainerNames.Reset();
m_ContainerDescs.Reset();
m_ContainerNames.Append(KCONTAINERWAV());
m_ContainerNames.Append(KCONTAINERAMR());
m_ContainerNames.Append(KCONTAINERMP4());
m_ContainerDescs.Append(KCONTAINERWAVDESC());
m_ContainerDescs.Append(KCONTAINERAMRDESC());
m_ContainerDescs.Append(KCONTAINERMP4DESC());
TRACE_FUNCTION_EXIT;
return KErrNone;
}
TInt32 XARecordSessionImpl::initAudioEncodersList()
{
TRACE_FUNCTION_ENTRY;
m_EncoderIds.Reset();
m_EncoderNames.Reset();
XAuint32 encoderIds[MAX_NUMBER_ENCODERS];
for(TInt index = 0; index < MAX_NUMBER_ENCODERS; index++)
encoderIds[index] = 0;
XAuint32 numEncoders = MAX_NUMBER_ENCODERS;
XAresult xa_result = (*m_AudioEncCapsItf)->GetAudioEncoders(
m_AudioEncCapsItf,
&numEncoders,
encoderIds);
TInt32 returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
for (TInt index = 0; index < numEncoders; index++) {
m_EncoderIds.Append(encoderIds[index]);
switch (encoderIds[index]) {
case XA_AUDIOCODEC_PCM:
m_EncoderNames.Append(KAUDIOCODECPCM());
break;
case XA_AUDIOCODEC_AMR:
m_EncoderNames.Append(KAUDIOCODECAMR());
break;
case XA_AUDIOCODEC_AAC:
m_EncoderNames.Append(KAUDIOCODECAAC());
break;
default:
break;
};
}
TRACE_FUNCTION_EXIT;
return returnValue;
}
TInt32 XARecordSessionImpl::initAudioInputDevicesList()
{
TRACE_FUNCTION_ENTRY;
m_InputDeviceIDs.Reset();
XAuint32 deviceIds[MAX_NUMBER_INPUT_DEVICES];
for(TInt index = 0; index < MAX_NUMBER_INPUT_DEVICES; index++)
deviceIds[index] = 0;
XAint32 numInputs = MAX_NUMBER_INPUT_DEVICES;
XAresult xa_result = (*m_AudioIODevCapsItf)->GetAvailableAudioInputs(
m_AudioIODevCapsItf,
&numInputs,
deviceIds);
TInt32 returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
XAAudioInputDescriptor audioInputDescriptor;
for (TInt index = 0; index < numInputs; index++) {
m_InputDeviceIDs.Append(deviceIds[index]);
xa_result = (*m_AudioIODevCapsItf)->QueryAudioInputCapabilities(
m_AudioIODevCapsItf,
deviceIds[index],
&audioInputDescriptor);
returnValue = mapError(xa_result, ETrue);
if (returnValue != KErrNone)
continue;
TUint8 * inDevNamePtr = audioInputDescriptor.deviceName;
TUint8 * tempPtr = audioInputDescriptor.deviceName;
TInt32 inDevNameLength = 0;
while (*tempPtr++) inDevNameLength++;
TPtrC8 ptr(inDevNamePtr, inDevNameLength);
/* Convert 8 bit to 16 bit */
TBuf16<KMaxNameLength> name;
name.Copy(ptr);
/* Using TRAP with returnValue results in compiler error */
TRAPD(err2, m_AudioInputDeviceNames->AppendL(name));
returnValue = err2;
RET_ERR_IF_ERR(returnValue);
}
numInputs = MAX_NUMBER_INPUT_DEVICES;
for(TInt index = 0; index < MAX_NUMBER_INPUT_DEVICES; index++)
deviceIds[index] = 0;
xa_result = (*m_AudioIODevCapsItf)->GetDefaultAudioDevices(
m_AudioIODevCapsItf,
XA_DEFAULTDEVICEID_AUDIOINPUT,
&numInputs,
deviceIds);
returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
for (TInt index = 0; index < numInputs; index++) {
m_DefaultInputDeviceIDs.Append(deviceIds[index]);
xa_result = (*m_AudioIODevCapsItf)->QueryAudioInputCapabilities(
m_AudioIODevCapsItf,
deviceIds[index],
&audioInputDescriptor);
returnValue = mapError(xa_result, ETrue);
if (returnValue != KErrNone)
continue;
TUint8* inDevNamePtr = audioInputDescriptor.deviceName;
TUint8* tempPtr = audioInputDescriptor.deviceName;
TInt32 inDevNameLength = 0;
while (*tempPtr++) inDevNameLength++;
TPtrC8 ptr(inDevNamePtr, inDevNameLength);
/* Convert 8 bit to 16 bit */
TBuf16<KMaxNameLength> name;
name.Copy(ptr);
/* Using TRAP with returnValue results in compiler error */
TRAPD(err2, m_DefaultAudioInputDeviceNames->AppendL(name));
returnValue = err2;
RET_ERR_IF_ERR(returnValue);
}
TRACE_FUNCTION_EXIT;
return returnValue;
}
TInt32 XARecordSessionImpl::setEncoderSettingsToMediaRecorder()
{
TRACE_FUNCTION_EXIT;
/* Get current settings */
XAAudioEncoderSettings settings;
XAresult xa_result = (*m_AudioEncItf)->GetEncoderSettings(
m_AudioEncItf,
&settings);
TInt32 returnValue = mapError(xa_result, ETrue);
settings.encoderId = m_AudioEncoderId;
if (m_ChannelsOut != 0xffffffff)
settings.channelsOut = m_ChannelsOut;
if (m_SampleRate != 0xffffffff)
settings.sampleRate = m_SampleRate;
if (m_BitRate != 0)
settings.bitRate = m_BitRate;
if (m_RateControl != 0)
settings.rateControl = m_RateControl;
settings.profileSetting = m_ProfileSetting;
xa_result = (*m_AudioEncItf)->SetEncoderSettings(
m_AudioEncItf,
&settings);
returnValue = mapError(xa_result, ETrue);
TRACE_FUNCTION_EXIT;
return returnValue;
}
TInt32 XARecordSessionImpl::getBitratesByAudioCodecID(
XAuint32 encoderId,
RArray<TUint32> &aBitrates)
{
TRACE_FUNCTION_ENTRY;
if (!m_AudioEncCapsItf)
return KErrGeneral;
XAuint32 numCaps = 0;
XAAudioCodecDescriptor codecDesc;
XAresult xa_result = (*m_AudioEncCapsItf)->GetAudioEncoderCapabilities(
m_AudioEncCapsItf,
encoderId,
&numCaps,
&codecDesc);
TInt32 returnValue = mapError(xa_result, ETrue);
RET_ERR_IF_ERR(returnValue);
/* TODO What do we do if we have more than one caps?? */
if (codecDesc.isBitrateRangeContinuous == XA_BOOLEAN_TRUE) {
aBitrates.Append(codecDesc.minBitRate);
aBitrates.Append(codecDesc.maxBitRate);
}
else {
XAuint32 numBrSupported = codecDesc.numBitratesSupported;
XAuint32 * pBitratesSupported(NULL);
pBitratesSupported = codecDesc.pBitratesSupported;
TInt32 index = 0;
for (index = 0; index < numBrSupported; index++)
aBitrates.Append(*(pBitratesSupported + index));
}
TRACE_FUNCTION_ENTRY;
return returnValue;
}
/* Local function implementation */
void cbXAObjectItf(
XAObjectItf caller,
const void *pContext,
XAuint32 event,
XAresult result,
XAuint32 param,
void *pInterface)
{
if (pContext) {
((XARecordSessionImpl*)pContext)->cbMediaRecorder(
caller,
pContext,
event,
result,
param,
pInterface);
}
}
void cbXARecordItf(
XARecordItf caller,
void *pContext,
XAuint32 event)
{
if (pContext) {
((XARecordSessionImpl*)pContext)->cbRecordItf(
caller,
pContext,
event);
}
}
void cbXAAvailableAudioInputsChanged(
XAAudioIODeviceCapabilitiesItf caller,
void * pContext,
XAuint32 deviceID,
XAint32 numInputs,
XAboolean isNew)
{
if (pContext) {
((XARecordSessionImpl*)pContext)->cbAvailableAudioInputsChanged(
caller,
pContext,
deviceID,
numInputs,
isNew);
}
}