Discussion Board
Plyaing AMR file using MMF framework.
2005-08-17, 15:19
#1
Regular Contributor
Hi all,
I tried to play amr using CMdaAudioPlayerUtility class, which works only in Emulator.
I am downloading the AMR data from the server which is put to the descriptor array. Then I want to play this from the descriptor.
I really appreciate any help regarding this.
Regards,
shagor
Nokia Developer Expert
you should use streaming instead. CMdaAudioPlayerUtility will have proablems with AMR in quite many target devices.
yucca
Thanks yucca.
2005-08-18, 08:15
#3
Regular Contributor
Could you please provide me some example code. I have been trying to solve this problem for long time. Hope you would send some code for streaming technique for playing amr .
Nokia Developer Expert
here's a sample code for playing buffers with streaming:
// CStreamPlayEngine class
//
/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
*/
CStreamPlayEngine::CStreamPlayEngine(MRectPlayCallBack* aCallBack)
:iCallBack(aCallBack),iVolume(10),iReadSize(0)
,iPlayError(KErrNone),iStatus(EEngineReady),iPlayBuffer(NULL)
{
}
/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
*/
CStreamPlayEngine::~CStreamPlayEngine()
{
Stop();
delete iStream;
iStream = NULL;
delete iOCodec;
iOCodec = NULL;
delete iPcm16Buffer;
iPcm16Buffer = NULL;
delete iAmrBuffer;
iAmrBuffer = NULL;
delete iTmpBuffer;
iTmpBuffer = NULL;
delete iPlayBuffer;
iPlayBuffer = NULL;
iBuffer.ResetAndDestroy();
}
/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
*/
CStreamPlayEngine* CStreamPlayEngine::NewL(MRectPlayCallBack* aCallBack)
{
CStreamPlayEngine* self = new (ELeave) CStreamPlayEngine(aCallBack);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(); // self
return self;
}
/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
*/
const TInt KAdvancedUidCodecAMRToPCM16 = 0x101FAF67;
void CStreamPlayEngine::ConstructL()
{
iEnv = CEikonEnv::Static();
}
/*
-------------------------------------------------------------------------------
implement any callbacks in here..
-------------------------------------------------------------------------------
*/
void CStreamPlayEngine::SetengineState(TInt aNewState)
{
if(iPlayBuffer && iCallBack)
{
TPoint AudioLength(iReadSize,iPlayBuffer->Des().Length());
TPoint PlayState(iStatus,aNewState);
iStatus = aNewState;
iCallBack->StateChange(PlayState,iPlayError,AudioLength,this);
}
}
/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
*/
void CStreamPlayEngine::ReStartL()
{
Stop();
delete iStream;
iStream = NULL;
delete iTmpBuffer;
iTmpBuffer = NULL;
iTmpBuffer = HBufC8::NewL(KPcmBufferSize);
delete iOCodec;
iOCodec = NULL;
iOCodec = CMMFCodec::NewL(TUid::Uid(KAdvancedUidCodecAMRToPCM16));
delete iPcm16Buffer;
iPcm16Buffer = NULL;
iPcm16Buffer = CMMFDescriptorBuffer::NewL(KPcmBufferSize);
delete iAmrBuffer;
iAmrBuffer = NULL;
iAmrBuffer = CMMFDescriptorBuffer::NewL(KAmrBufferSize);
iPlayError = KErrNone;
SetengineState(EEngineReady);
LoadFileL();
iStream = CMdaAudioOutputStream::NewL(*this);
iStream->Open(&iSettings);
}
/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
*/
void CStreamPlayEngine::MaoscOpenComplete(TInt aError)
{
iPlayError = aError;
if (aError==KErrNone && iStream)
{
iSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate8000Hz;
iSettings.iChannels = TMdaAudioDataSettings::EChannelsMono;
// iSettings.iVolume = ((iStream->MaxVolume() * iVolume) / 10);
iStream->SetAudioPropertiesL(iSettings.iSampleRate,iSettings.iChannels);
SetVolume(iVolume);
iStream->SetPriority(EPriorityNormal, EMdaPriorityPreferenceNone);
SetengineState(EEnginePlaying);
iStream->WriteL(*iBuffer[0]);//iPlayBuffer->Des());//
}
else
{
SetengineState(iStatus);// keep the state
}
}
/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
*/
void CStreamPlayEngine::MaoscBufferCopied(TInt aError, const TDesC8& aBuffer)
{
iPlayError = aError;
if(aError == KErrNone && iStream)
{
if (&aBuffer == iBuffer[0])
{
iCurrIndex = 0;
SetengineState(EEnginePlaying);
if((*iBuffer[1]).Length())
{
iStream->WriteL(*iBuffer[1]);
ReadFromFromL(0);
}
else
{
SetengineState(EEngineReady);
}
}
else// if (&aBuffer == iBuffer[1])
{
iCurrIndex = 1;
SetengineState(EEnginePlaying);
if((*iBuffer[0]).Length())
{
iStream->WriteL(*iBuffer[0]);
ReadFromFromL(1);
}
else
{
SetengineState(EEngineReady);
}
}
}
else
{
SetengineState(EEngineReady);
}
}
/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
*/
void CStreamPlayEngine::MaoscPlayComplete(TInt aError)
{
iPlayError = aError;
if (aError == KErrUnderflow)
{
if(iPlayBuffer->Des().Length() > iReadSize)
{
iCurrIndex = 0;
for (TInt index = 0; index < iBuffer.Count(); index++)
{
ReadFromFromL(index);
}
iStream->WriteL(*iBuffer[0]);
}
else
{
SetengineState(EEngineReady);
}
}
else if(aError == KErrCancel)
{
SetengineState(EEngineReady);
}
else
{
SetengineState(EEngineReady);
}
}
/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
*/
void CStreamPlayEngine::PlayL(const TDesC8& aPlayBuffer)
{
iReadSize = 0;
delete iPlayBuffer;
iPlayBuffer = NULL;
iPlayBuffer = HBufC8::NewL(aPlayBuffer.Length());
iPlayBuffer->Des().Copy(aPlayBuffer);
ReStartL();
}
/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
*/
void CStreamPlayEngine::Stop()
{
if(iStatus == EEnginePlaying)
{
if(iStream)
iStream->Stop();
}
iPlayError = KErrNone;
SetengineState(EEngineReady);
}
/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
*/
void CStreamPlayEngine::SetVolume(TInt aVol)
{
iVolume = aVol;
if(iVolume < 0)
iVolume = 0;
else if(iVolume > 10)
iVolume = 10;
if(iStream)
{
iStream->SetVolume(((iStream->MaxVolume() * iVolume) / 10));
}
}
/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
*/
void CStreamPlayEngine::ReadFromFromL(TInt aBufferIndex)
{
if(aBufferIndex ==0 || aBufferIndex == 1 && iPlayBuffer)
{
(*iBuffer[aBufferIndex]).FillZ();
(*iBuffer[aBufferIndex]).Zero();
if((iPlayBuffer->Des().Length() > iReadSize) && iTmpBuffer)
{
TInt ReadFor(KAmrBufferSize);
if(iPlayBuffer->Des().Length() < (iReadSize + ReadFor))
{
ReadFor = iPlayBuffer->Des().Length() - iReadSize;
}
/* if(iReadSize < 6)
{
iReadSize = 6;
}
*/
iTmpBuffer->Des().Copy(iPlayBuffer->Des().Mid(iReadSize,ReadFor));
iReadSize = iReadSize + ReadFor;
ConvertAmr2PcmL(iTmpBuffer->Des(),(*iBuffer[aBufferIndex]));
}
}
}
/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
*/
void CStreamPlayEngine::LoadFileL()
{
iBuffer.ResetAndDestroy();
TDes8* buffer = new(ELeave) TBuf8<KPcmBufferSize>;
buffer->SetMax();
CleanupStack::PushL(buffer);
User::LeaveIfError(iBuffer.Append(buffer));
CleanupStack::Pop(buffer);
buffer = new(ELeave) TBuf8<KPcmBufferSize>;
buffer->SetMax();
CleanupStack::PushL(buffer);
User::LeaveIfError(iBuffer.Append(buffer));
CleanupStack::Pop(buffer);
iReadSize = 0;
iCurrIndex = 0;
for (TInt index = 0; index < iBuffer.Count(); index++)
{
ReadFromFromL(index);
}
}
/*
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
*/
void CStreamPlayEngine::ConvertAmr2PcmL(const TDesC8& aAmrData,TDes8& aDestBuffer)
{
iAmrBuffer->Data().Copy(aAmrData);
TBool OkMai(EFalse);
TCodecProcessResult result = iOCodec->ProcessL(*iAmrBuffer,*iPcm16Buffer);
if((result.iStatus == TCodecProcessResult::EProcessComplete))
{
OkMai = ETrue;
aDestBuffer.Copy(iPcm16Buffer->Data());
}
else
{
// should we report error.
}
}
Nokia Developer Expert
and here's the header:
class CStreamPlayEngine : public CBase, public MMdaAudioOutputStreamCallback
{
public:
static CStreamPlayEngine* NewL(MRectPlayCallBack* aCallBack);
~CStreamPlayEngine();
void PlayL(const TDesC8& aPlayBuffer);
void Stop();
// from MMdaAudioOutputStreamCallback
virtual void MaoscOpenComplete(TInt aError);
virtual void MaoscBufferCopied(TInt aError, const TDesC8& aBuffer);
virtual void MaoscPlayComplete(TInt aError);
// inline gets and sets
inline TInt Volume();
inline TBool StreamReady();
void SetVolume(TInt aVol);
protected:
void SetengineState(TInt aNewState);
void ConvertAmr2PcmL(const TDesC8& aAmrData,TDes8& aDestBuffer);
void ReStartL();
TInt GetSampltRate();
CStreamPlayEngine(MRectPlayCallBack* aCallBack);
void ConstructL();
void LoadFileL();
void ReadFromFromL(TInt aBufferIndex);
private:
MRectPlayCallBack* iCallBack;
TInt iVolume; // volume
TInt iReadSize,iCurrIndex,iPlayError; // size of the pcm sound file (and buffer)
TInt iStatus; // engine status
RPointerArray<TDes8> iBuffer;
CMdaAudioOutputStream* iStream;
TMdaAudioDataSettings iSettings;
CEikonEnv* iEnv;
CMMFCodec* iOCodec;
CMMFDescriptorBuffer* iPcm16Buffer;
CMMFDescriptorBuffer* iAmrBuffer;
HBufC8* iTmpBuffer;
HBufC8* iPlayBuffer;
};
// INLINES
inline TInt CStreamPlayEngine::Volume() { return iVolume; }
inline TBool CStreamPlayEngine::StreamReady() { return (iStatus == EEngineReady)?ETrue:EFalse; }
yucca
I don't know how to thank you.
2005-08-18, 11:15
#6
Regular Contributor
Hello yucca,
I really appreciate for your kindness. However I tried to put your code in my application. I have been facing some problem. I have got few questions:
In this method, ConvertAmr2PcmL(const TDesC8& aAmrData,TDes8& aDestBuffer)
I get : result.iStatus EDstNotFilled
TCodecProcessResult result = iOCodec->ProcessL(*iAmrBuffer,*iPcm16Buffer);;
So it's not playing amr file.
If you want I can send you the whole application. I guess it would be easier for you to point out the problem.
Hope to hearing from you.
Regards,
shagor
Nokia Developer Expert
you are propably having the aMR mode wrong. There is quite nice post in NewLC about the different modes & stuff with AMR, so maybe you should search it for more information.
Basically, make the AMR file in CMR 0 and mode AMR 4.75, and then you will have AMR frame size of 13 bytes, which is just right for this code. You could also try figuring out the frame size from the AMR header, and then reading right size frames from the file.
yucca
Thanks for your prompt reply.
2005-08-18, 11:59
#8
Regular Contributor
#include <amrcodec.h>
TAmrEncParams params;
params.iMode = 0;
iOCodec->ConfigureL(TUid::Uid(0x101FAF67),(const TDesC8&)params );
TCodecProcessResult result = iOCodec->ProcessL(*iAmrBuffer,*iPcm16Buffer);
I used the above technique for Configuring. I get error "Feature not supported(-5). It gets this error as soon as it calls ConfigureL(..).
I don't know what to do.
I put the whole application including one test.amr file in the following location:
http://users.evtek.fi/~muhammki/AudioStreamExample.zip
It would be so kind of you to take a look the application.
I used: Symbian OS: 7.0s
SDK 2.0
Nokia Developer Expert
what does the ConfigureL function do ? I can see using it in the sample code, so do you really need to use it ?
yucca
Regular Contributor
I guess, ConfigureL has something to do with amr mode stuff. You can leave that thing.
Have you got the application working? Please inform me.
Regards,
shagor
Regular Contributor
The main thing of playing AMR using streaming is to cut the 6-Bytes header from the begining of AMR file.
Regards,
shagor
Re: Plyaing AMR file using MMF framework.
2005-09-01, 10:35
#12
Registered User
Hi ,
If I want to play AMR from a Descriptor , should I remove the 6 byte as well?
Posting Permissions
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
Forum Rules