mp3播放引擎头文件
#if !defined(__WAVEGEN_ENGINE_H__)
#define __WAVEGEN_ENGINE_H__
#if !defined(__MDA_COMMON_AUDIO_H__)
#include <mda/common/audio.h>
#endif
#if !defined(__MDA_CLIENT_UTILITY_H__)
#include <Mda/Client/Utility.h>
#endif
#if !defined(__MDA_COMMON_RESOURCE_H__)
#include <Mda/Common/Resource.h>
#endif
#if !defined(__MDAAUDIOOUTPUTSTREAM_H__)
#include <MdaAudioOutputStream.h>
#endif
const TInt KVolSliderLength = 10;
const TInt KInitialVolume = 9;
const TInt KNumBuf = 2;
const TInt KBufferSize = 5000;
class CEikonEnv;
class CMP3DecodeEngine;
class CStreamAudioEngine : public CBase, public MMdaAudioOutputStreamCallback
{
public:
enum TEngineStatus
{
EEngineNotReady,
EEngineReady,
EEngineToPause,
EEnginePause,
EEnginePlaying
};
static CStreamAudioEngine* NewL();
~CStreamAudioEngine();
void PlayL();
void Pause();
void StopL();
void SetRepeat(TBool aRepeat);
void OpenL(TFileName aFileName);
virtual void MaoscOpenComplete(TInt aError);
virtual void MaoscBufferCopied(TInt aError, const TDesC8& aBuffer);
virtual void MaoscPlayComplete(TInt aError);
inline TInt Volume();
inline TBool StreamReady();
inline TBool StreamPlaying();
inline TBool StreamPause();
inline TBool StreamRepeat();
void SetVolume(TInt aVol);
protected:
// protected contructor
CStreamAudioEngine(/*CWaveGenAppUi& aAppUi*/);
// 2nd phase constructor
void ConstructL();
// displays error messages
void ShowErrorMsg(TInt aResourceBuf, TInt aError);
private:
void NextBuffer(const TDesC8& aBuffer);
TInt iVolume; // volume
TInt iVolStep;
TBool iFileOK; // indicates if file has been successfully read to buffer
TEngineStatus iMp3Status; // engine status
TBool iPlayFile; // which buffer is currently in use
TBool iRepeat;
TUint16* aa;
TPtr imp3Buf;
TBool iStart;
TBuf8<KBufferSize> iBufList[KNumBuf];
CMdaAudioOutputStream* iStream;
//CMdaAudioOutputStream* iStream1;
TMdaAudioDataSettings iSettings;
CEikonEnv* iEnv;
CMP3DecodeEngine * imp3;
RFs fss;
TFileName tFullFileName;
TInt fm;
TInt bufx;
};
// INLINES
inline TInt CStreamAudioEngine::Volume() { return iVolume; }
inline TBool CStreamAudioEngine::StreamReady() { return (iMp3Status == EEngineReady)?ETrue:EFalse; }
inline TBool CStreamAudioEngine::StreamPlaying() { return (iMp3Status == EEnginePlaying)?ETrue:EFalse; }
inline TBool CStreamAudioEngine::StreamPause() { return (iMp3Status == EEnginePause)?ETrue:EFalse; }
inline TBool CStreamAudioEngine::StreamRepeat(){ return iRepeat; }
// writes 2 bytes to buffer in LSB order
#endif
mp3播放引擎实现文件,使用了两个缓冲区交替解码。
#include <eikenv.h>
#include <eikapp.h>
#include <eikdef.h>
#include <e32math.h>
#include "mp3_engine.h"
#include "MP3DecodeEngine.h"
CStreamAudioEngine::CStreamAudioEngine()
:iVolume(KInitialVolume),
iVolStep(0),
iFileOK(EFalse),
iMp3Status(EEngineNotReady),
iPlayFile(ETrue),
iRepeat(EFalse),
imp3Buf(0,0),
iStart(EFalse),
fm(0),
bufx(0)
{
}
CStreamAudioEngine::~CStreamAudioEngine()
{
delete iStream;
delete [] aa;
delete imp3;
fss.Close();
}
CStreamAudioEngine* CStreamAudioEngine::NewL()
{
CStreamAudioEngine* self = new (ELeave) CStreamAudioEngine();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(); // self
return self;
}
void CStreamAudioEngine::ConstructL()
{
// get the Eikon environment
iEnv = CEikonEnv::Static();
imp3=CMP3DecodeEngine::NewL();
iFileOK = EFalse;
aa=new (ELeave) TUint16[2400];//缓冲区,存储单帧内容,大小不定, 最好设的足够大,不然会报错
imp3Buf.Set(aa,2400,2400);
fss.Connect();
// create and initialize output stream
iStream = CMdaAudioOutputStream::NewL(*this);
iStream->Open(&iSettings);
}
void CStreamAudioEngine::MaoscOpenComplete(TInt aError)
{
if (aError==KErrNone)
{
// set stream properties to 16bit,8KHz mono EChannelsMono EChannelsStereo
//因为解码后的内容为单声道,所以一定要用TMdaAudioDataSettings::EChannelsMono,另外采样率要和imp3->SetResampleRate设置的一致
iStream->SetAudioPropertiesL(TMdaAudioDataSettings::ESampleRate44100Hz,
TMdaAudioDataSettings::EChannelsMono);
// set the appropriate volume step. values for the target
// device are scaled down to get the optimal volume level
#if defined(__WINS__)
// for emulator (MaxVolume == 65535)
iVolStep = iStream->MaxVolume() / KVolSliderLength;
#else
// for target device (MaxVolume == 9)
iVolStep = iStream->MaxVolume() / (KVolSliderLength-1);
#endif
iStream->SetVolume(iVolStep * KInitialVolume);
iStream->SetPriority(EPriorityNormal, EMdaPriorityPreferenceNone);
iMp3Status = EEngineReady;
}
else
ShowErrorMsg(R_WAVEGEN_ERROR_OPENCOMPLETE, aError);
// PlayL();
}
void CStreamAudioEngine::MaoscBufferCopied(TInt aError, const TDesC8& aBuffer)
{
// if a single file (buffer) is played, return immediately
if(aError==KErrNone || aError==KErrAbort)
{
if(iMp3Status==EEngineToPause)
{
iMp3Status=EEnginePause;
iStream->Stop();
return;
}
if(iMp3Status==EEnginePause)
{
return;
}
if(iPlayFile )
{
if(iMp3Status==EEnginePlaying && iFileOK)
{
NextBuffer(aBuffer);
}
return;
}
}
else
{
// if(iMp3Status!=EEngineReady)
// {
iMp3Status=EEnginePause;
// iStream->Stop();
// }
// User::Invariant();
}
}
void CStreamAudioEngine::MaoscPlayComplete(TInt aError)
{
if (aError==KErrNone || aError==KErrCancel)
{
if(iMp3Status == EEnginePlaying)
{
bufx=0;
iFileOK=EFalse;
iStart=EFalse;
iMp3Status = EEngineReady;
imp3->CloseFile();
iBufList[0].SetLength(0);
iBufList[1].SetLength(0);
}
}
else
{
iMp3Status=EEnginePause;
// if(iMp3Status == EEnginePlaying)
// {
// iMp3Status=EEnginePause;
// iStream->Stop();
// }
// User::Invariant();
}
}
void CStreamAudioEngine::PlayL()
{
if(iMp3Status == EEngineReady || iMp3Status == EEnginePause)
{
iMp3Status = EEnginePlaying;
if(!iFileOK)
{
imp3->OpenFile(fss,tFullFileName);
imp3->SetResampleRate(44100);
imp3->DecodeStart();
iFileOK=ETrue;
}
if(!iStart)
{
imp3->DecodeOneFrame(imp3Buf);
iBufList[0].Copy((TUint8*)imp3Buf.Ptr(),imp3Buf.Length()*2);
imp3->DecodeOneFrame(imp3Buf);
iBufList[1].Copy((TUint8*)imp3Buf.Ptr(),imp3Buf.Length()*2);
}
else
{
imp3->DecodeOneFrame(imp3Buf);
iBufList[1].Copy((TUint8*)imp3Buf.Ptr(),imp3Buf.Length()*2);
}
iStream->WriteL(iBufList[bufx]);
if(bufx==0)
bufx=1;
else
bufx=0;
iStart=ETrue;
if(imp3->GetFilePosition()==imp3->GetFileLength())
{
imp3->CloseFile();
if(iRepeat)
{
imp3->OpenFile(fss,tFullFileName);
imp3->SetResampleRate(44100);
imp3->DecodeStart();
}
else
{
iFileOK=EFalse;
}
}
}
}
void CStreamAudioEngine::Pause()
{
iMp3Status = EEngineToPause;
}
void CStreamAudioEngine::StopL()
{
bufx=0;
iFileOK=EFalse;
iStart=EFalse;
iMp3Status = EEngineReady;
iStream->Stop();
imp3->CloseFile();
iBufList[0].SetLength(0);
iBufList[1].SetLength(0);
}
void CStreamAudioEngine::SetRepeat(TBool aRepeat)
{
iRepeat=aRepeat;
}
void CStreamAudioEngine::OpenL(TFileName aFileName)
{
if(iMp3Status == EEnginePlaying || iMp3Status == EEnginePause)
{
StopL();
}
tFullFileName = aFileName;
PlayL();
}
void CStreamAudioEngine::SetVolume(TInt aVol)
{
iVolume = aVol;
// if value has changed, pass it directly to audiostream object.
if((iVolume * iVolStep) != iStream->Volume())
iStream->SetVolume(iVolume * iVolStep);
}
void CStreamAudioEngine::ShowErrorMsg(TInt aResourceBuf, TInt aError)
{
TBuf<16> errorNum;
TBuf<128> rDes;
errorNum.Num(aError);
iEnv->ReadResource(rDes, aResourceBuf);
rDes.Append(errorNum);
CAknInformationNote* dlg = new(ELeave)CAknInformationNote();
dlg->ExecuteLD(rDes);
}
void CStreamAudioEngine::NextBuffer(const TDesC8& aBuffer)
{
//assume the buffer is already there!
iStream->WriteL(iBufList[bufx]);
if(bufx==0)
bufx=1;
else
bufx=0;
if(imp3->GetFilePosition()==imp3->GetFileLength())
{
imp3->CloseFile();
if(iRepeat)
{
imp3->OpenFile(fss,tFullFileName);
imp3->SetResampleRate(44100);
imp3->DecodeStart();
}
else
{
iFileOK=EFalse;
}
}
ASSERT(iBufList[bufx]==aBuffer);
iBufList[bufx].SetLength(0);
imp3->DecodeOneFrame(imp3Buf);
iBufList[bufx].Copy((TUint8*)imp3Buf.Ptr(),imp3Buf.Length()*2);
}
最后,因为MP3DecodeDLL的代码里CMP3DecodeEngine::CloseFile()没有内容,需要自己修改添加,否则会产生内存泄漏。可能是我使用的MP3DecodeDLL版本的问题