在symbian中如何使用MP3DecodeDLL播放MP3

来源:互联网 发布:你见过最帅的男生知乎 编辑:程序博客网 时间:2024/05/22 04:57

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版本的问题