×

Discussion Board

Results 1 to 7 of 7
  1. #1
    Registered User
    Join Date
    Mar 2003
    Posts
    31

    CMdaAudioOutputStream Not working with EXEDLL target

    I am trying to get streaming audio to work inside an EXEDLL program. I have looked at the example Wavegen program and got that code to compile and work. However I have noticed that CMdaAudioOutputStream will never produce a callback of MaoscOpenComplete() when used inside an EXEDLL program. The Wavegen program is an APP program which has all the extra class interface, which I do not need. Also APPs do not support global data which is why I am using an EXEDLL type of project.

    Below is the attached source code, much of it taken from the wavegen that demonstrates the problem. If you compile and link with the libraries:
    library euser.lib
    library cone.lib
    library avkon.lib
    library efsrv.lib
    library mediaclientaudiostream.lib
    library estlib.lib

    You will see the program starts without issuing panics and then sits in the while loop at line 686 waiting for the stream to become ready. As you can see I am even waiting idle for the stream manager to return a valid opened stream.

    My guess is that the Stream manager is not able to process the active objects attached to it due to some failure with the EXEDLL target type. However I am at a loss to fix this. The solution to use an APP type of project is not a viable one for this project for the reasons stated above.

    Martin Piper

    Code:
    // CMdaAudioOutputStream Not working with EXEDLL target
    
    #include <e32base.h>
    #include <e32cons.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <basched.h>
    #include <eikapp.h>
    #include <eikdoc.h>
    #include <aknnotewrappers.h>    // for CAknInformationNote
    #include <eikenv.h>             // for CEikonEnv
    #include <eikdef.h>
    #include <e32math.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
    
    
    // CONSTANTS
    
    // waveform generator buffer size
    const TInt KBufferSize = 8192;
    
    // slider max values
    const TInt KVolSliderLength	= 10;
    const TInt KFreqSliderLength = 10;
    
    const TInt KInitialWaveform = 0;
    const TInt KInitialVolume = 1;
    const TInt KInitialFreq = 5;
    
    // max pulse amplitude - used in waveform generation
    const TInt KPulseAmplitude = 26213;
    
    
    // FORWARD DECLARATIONS
    
    class CWaveGenerator;
    class CEikonEnv;
    
    //
    // CStreamAudioEngine - audio ouput stream engine, uses CMdaAudioOutputStream
    // and implements the callback functions from MMdaAudioOutputStreamCallback.
    //
    class CStreamAudioEngine : public CBase, public MMdaAudioOutputStreamCallback
    {
    public:
    
    enum TEngineStatus
    {
    EEngineNotReady,
    EEngineReady,
    EEnginePlaying
    };
    
    static CStreamAudioEngine* NewL();
    
    ~CStreamAudioEngine();
    void PlayL();
    void StopL();
    
    // switches between two buffers
    TBool SwitchBuffer(TBool aBufGenerator);
    
    // 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 TInt Frequency();
    inline TInt Waveform();
    inline void SetFrequency(TInt aFreq);
    inline void SetWaveform(TInt aForm);
    inline TBool StreamReady();
    
    void SetVolume(TInt aVol);
    
    
    protected:
    // protected contructor
    CStreamAudioEngine();
    // 2nd phase constructor
    void ConstructL();
    // read the pcm sound data from a file to buffer
    void LoadFileL();
    // displays error messages
    void ShowErrorMsg(TInt aResourceBuf, TInt aError);
    
    private:
    TInt iForm;                 // waveform type
    TInt iFreq;                 // frequency
    TInt iVolume;               // volume
    TInt iVolStep;
    TInt iFileSize;             // size of the pcm sound file (and buffer)
    TBool iFileOK;              // indicates if file has been successfully read to buffer
    TEngineStatus iStatus;      // engine status
    TBool iPlayFile;            // which buffer is currently in use
    
    TPtr8 iDescBuf;             // a descriptor that encapsulates the two buffers
    
    TUint8* iGenBuffer;         // buffer for generated pcm waves
    TUint8* iPCMBuffer;         // buffer for pcm sound data (from a file)
    
    CMdaAudioOutputStream* iStream;
    TMdaAudioDataSettings iSettings;
    
    CWaveGenerator* iWaveGen;
    CEikonEnv* iEnv;
    };
    
    
    //
    // CWaveGenerator - the wave generator class.
    //
    class CWaveGenerator : public CBase
    {
    public:
    enum EWaveform
    {
    ERandom = 0,
    ESquare
    };
    
    CWaveGenerator();
    ~CWaveGenerator();
    void Generate(EWaveform aForm, TInt aFreq, TDes8& aDescBuf);
    
    private:
    void Random(TDes8& aDescBuf);
    void Square(TInt aFreq, TDes8& aDescBuf);
    inline void WriteToBuf(TDes8& aDescBuf, TInt aOffset, TInt aValue);
    
    private:
    TInt iPhase;
    TInt iSign;
    };
    
    
    // INLINES
    
    inline TInt CStreamAudioEngine::Volume() { return iVolume; }
    inline TInt CStreamAudioEngine::Frequency() { return iFreq; }
    inline TInt CStreamAudioEngine::Waveform() { return iForm; }
    inline void CStreamAudioEngine::SetFrequency(TInt aFreq) { iFreq = aFreq; }
    inline void CStreamAudioEngine::SetWaveform(TInt aForm) { iForm = aForm; }
    inline TBool CStreamAudioEngine::StreamReady() { return (iStatus == EEngineReady)?ETrue:EFalse; }
    
    // writes 2 bytes to buffer in LSB order
    inline void CWaveGenerator::WriteToBuf(TDes8& aDescBuf, TInt aOffset, TInt aValue)
    {
    aDescBuf[aOffset] = (TUint8)(aValue & 0x00ff);
    aDescBuf[aOffset+1] = (TUint8)((aValue & 0xff00)>>8);
    }
    
    
    
    //
    // wavegen_engine.cpp
    //
    // Copyright (C) 2002 Nokia Corporation. All rights reserved.
    //
    ///////////////////////////////////////////////////////////////////////////////
    
    // LITERALS
    
    // path and name for the pcm sound file
    _LIT(KPCMFilename, "\\system\\apps\\wavegen\\sound1.pcm");
    
    //
    // CStreamAudioEngine class
    //
    /*
    -------------------------------------------------------------------------------
    
    CStreamAudioEngine
    
    Description: Constructor
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    CStreamAudioEngine::CStreamAudioEngine()
    :iForm(KInitialWaveform),
    iFreq(KInitialFreq),
    iVolume(KInitialVolume),
    iVolStep(0),
    iFileSize(0),
    iFileOK(EFalse),
    iStatus(EEngineNotReady),
    iPlayFile(ETrue),
    iDescBuf(0,0)
    {
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    ~CStreamAudioEngine
    
    Description: Destructor
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    CStreamAudioEngine::~CStreamAudioEngine()
    {
    delete iStream;
    delete iGenBuffer;
    delete iPCMBuffer;
    delete iWaveGen;
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    NewL
    
    Description: static NewL function for creating a new instance of the engine
    
    Return value: CStreamAudioEngine*
    
    -------------------------------------------------------------------------------
    */
    CStreamAudioEngine* CStreamAudioEngine::NewL()
    {
    CStreamAudioEngine* self = new (ELeave) CStreamAudioEngine();
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(); // self
    return self;
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    ConstructL
    
    Description: 2nd phase constructor for the engine
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    void CStreamAudioEngine::ConstructL()
    {
    // get the Eikon environment
    iEnv = CEikonEnv::Static();
    
    // load the pcm file to buffer
    LoadFileL();
    
    // create new wave generator object and a buffer for it
    iWaveGen = new (ELeave) CWaveGenerator();
    iGenBuffer = new (ELeave) TUint8[KBufferSize];
    
    // create and initialize output stream
    iStream = CMdaAudioOutputStream::NewL(*this);
    iStream->Open(&iSettings);
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    MaoscOpenComplete
    
    Description: implementation for MaoscOpenComplete callback function. called
    when the audio streaming object in the server has been opened.
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    void CStreamAudioEngine::MaoscOpenComplete(TInt aError)
    {
    if (aError==KErrNone)
    {
    // set stream properties to 16bit,8KHz mono
    iStream->SetAudioPropertiesL(TMdaAudioDataSettings::ESampleRate8000Hz,
    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);
    
    iStatus = EEngineReady;
    }
    //    else
    //        ShowErrorMsg("Cannot open file", aError);
    
    // display error msg if opening the pcm file failed
    if(!iFileOK)
    {
    iPlayFile = EFalse;
    //        ShowErrorMsg("Cannot open file 2", KErrNotFound);
    }
    
    // select the correct buffer
    SwitchBuffer(iPlayFile);
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    MaoscBufferCopied
    
    Description: implementation for MaoscBufferCopied callback function. called
    when the buffer has been copied to the server.
    
    Parameters:  error value that will indicate if the copy succeeded and a
    reference to the buffer that has been copied.
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    void CStreamAudioEngine::MaoscBufferCopied(TInt aError, const TDesC8& /*aBuffer*/)
    {
    // if a single file (buffer) is played, return immediately
    if(iPlayFile)
    {
    return;
    }
    
    // a continuous wave is being played: fill the buffer and write it to
    // stream. the error value will be KErrNone only if the previous buffer was
    // successfully copied (if Stop has been called, aError is KErrAbort)
    if (aError==KErrNone)
    {
    iWaveGen->Generate((CWaveGenerator::EWaveform)iForm, iFreq, iDescBuf);
    iStream->WriteL(iDescBuf);
    }
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    MaoscPlayComplete
    
    Description: implementation for MaoscPlayComplete callback function. called
    when the end of the sound data has been reached (or the
    playing has stopped for some other reason).
    
    Parameters:  error value that will indicate if the buffer was successfully
    copied and the end of the sound data was reached
    (KErrUnderFlow).
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    void CStreamAudioEngine::MaoscPlayComplete(TInt /*aError*/)
    {
    iStatus = EEngineReady;
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    PlayL
    
    Description: starts playing the sound by writing the buffer to server.
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    void CStreamAudioEngine::PlayL()
    {
    if(iStatus == EEngineReady)
    {
    iStatus = EEnginePlaying;
    
    // if we're playing a pcm from a file, the buffer already
    // contains the sound data. Otherwise, fill the buffer with
    // generated waveform.
    if(!iPlayFile)
    iWaveGen->Generate((CWaveGenerator::EWaveform)iForm, iFreq, iDescBuf);
    
    // write the buffer to server. the playing starts immediately.
    iStream->WriteL(iDescBuf);
    }
    }
    
    /*
    -------------------------------------------------------------------------------
    
    StopL
    
    Description: stops the stream from playing. any data in the buffers will
    be discarded. the buffer copied call backs will all be called
    with the error value indicating the buffer was not copied, and
    then the play complete call back will be called.
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    void CStreamAudioEngine::StopL()
    {
    iStream->Stop();
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    SetVolume
    
    Description: sets the volume. the CMdaAudioOutputStream::SetVolume() can
    be used to change the volume both before or during playback.
    the parameter should be between 0 and the value returned by
    CMdaAudioOutputStream::MaxVolume()
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    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);
    
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    LoadFileL
    
    Description: allocates a new buffer and reads a pcm sound data into it from
    a file.
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    void CStreamAudioEngine::LoadFileL()
    {
    RFs fs;
    RFile file;
    
    CleanupClosePushL(fs);
    User::LeaveIfError(fs.Connect());
    
    CleanupClosePushL(file);
    TInt fileErr = file.Open(fs,KPCMFilename,EFileRead|EFileShareReadersOnly);
    
    if(fileErr == KErrNone)
    {
    file.Size(iFileSize);
    iPCMBuffer=new (ELeave) TUint8[iFileSize];
    iDescBuf.Set(iPCMBuffer,iFileSize,iFileSize);
    file.Read(iDescBuf);
    iFileOK = ETrue;
    }
    
    CleanupStack::PopAndDestroy(2); // fs, file
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    SwitchBuffer
    
    Description: switches the buffer between wave generator and pcm file buffer
    
    Return value: TBool (ETrue if successful, EFalse if failed)
    
    -------------------------------------------------------------------------------
    */
    TBool CStreamAudioEngine::SwitchBuffer(TBool aFileBuf)
    {
    if(aFileBuf)
    {
    if(iFileOK)
    iDescBuf.Set(iPCMBuffer,iFileSize,iFileSize);
    else
    return EFalse;
    }
    else
    iDescBuf.Set(iGenBuffer,KBufferSize,KBufferSize);
    
    iPlayFile = aFileBuf;
    return ETrue;
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    ShowErrorMsg
    
    Description: shows the aError error value along with a text from resource
    file.
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    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);
    }
    
    
    //
    // CWaveGenerator class
    //
    /*
    -------------------------------------------------------------------------------
    
    CWaveGenerator
    
    Description: Constructor
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    CWaveGenerator::CWaveGenerator()
    :iPhase(0), iSign(1)
    {
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    ~CWaveGenerator
    
    Description: Destructor
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    CWaveGenerator::~CWaveGenerator()
    {
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    Generate
    
    Description: fills the buffer with the selected waveform and frequency
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    void CWaveGenerator::Generate(EWaveform aForm, TInt aFreq, TDes8& aDescBuf)
    {
    switch(aForm)
    {
    case ERandom:
    // random noise (frequency value has no effect)
    Random(aDescBuf);
    break;
    case ESquare:
    // square (pulse) waveform with a certain frequency
    Square(aFreq, aDescBuf);
    default:
    break;
    }
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    Random
    
    Description: fills the buffer with random noise.
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    void CWaveGenerator::Random(TDes8& aDescBuf)
    {
    TUint32 randVal;
    TInt len = aDescBuf.Length();
    for(TInt i=0; i<len; i+=2)
    {
    randVal = Math::Random();
    WriteToBuf(aDescBuf,i,randVal);
    }
    }
    
    
    /*
    -------------------------------------------------------------------------------
    
    Square
    
    Description: fills the buffer with square wave of selected frequency.
    the aFreq parameter is the value of the frequency slider
    control.
    
    Return value: N/A
    
    -------------------------------------------------------------------------------
    */
    void CWaveGenerator::Square(TInt aFreq, TDes8& aDescBuf)
    {
    TInt i=0, wave;
    TInt len = aDescBuf.Length();
    TInt halfWave = (KFreqSliderLength - aFreq) * 10;
    if(!halfWave) halfWave = 4;
    
    //complete the last wave if needed to prevent skipping
    if(iPhase)
    {
    for(;iPhase>0; i+=2, iPhase--)
    WriteToBuf(aDescBuf,i,KPulseAmplitude * iSign);
    iSign *= -1;
    }
    
    for(wave = halfWave; i<len; i+=2)
    {
    WriteToBuf(aDescBuf,i,KPulseAmplitude * iSign);
    if(!(--wave))
    {
    wave = halfWave;
    iSign *= -1;
    }
    }
    // store the remainder of last wave
    iPhase = wave % halfWave;
    }
    
    
    // This is where the code really starts for the emulator and the real phone...
    void GameAPICoreEntry(void)
    {
    CStreamAudioEngine *iEngine = CStreamAudioEngine::NewL();
    
    while (iEngine->StreamReady() == false)
    {
    User::After(10);
    printf("Waiting for stream...\n");
    }
    
    printf("Stream play\n");
    
    iEngine->PlayL();
    
    while(1)
    {
    }
    }
    
    #ifdef __WINS__
    
    EXPORT_C TInt InitEmulator() // main function called by the emulator software
    {
    __UHEAP_MARK;
    CTrapCleanup* cleanup=CTrapCleanup::New(); // get clean-up stack
    TRAPD(error,GameAPICoreEntry()); // more initialization, then do example
    delete cleanup; // destroy clean-up stack
    __UHEAP_MARKEND;
    
    // Exit avoids panic on exit :)
    User::Exit(0);
    
    return KErrNone;
    }
    
    int GLDEF_C E32Dll(TDllReason)
    {
    return(KErrNone);
    }
    
    #else
    
    GLDEF_C TInt E32Main() // main function called by E32
    {
    __UHEAP_MARK;
    CTrapCleanup* cleanup=CTrapCleanup::New(); // get clean-up stack
    TRAPD(error,GameAPICoreEntry()); // more initialization, then do example
    delete cleanup; // destroy clean-up stack
    __UHEAP_MARKEND;
    
    // Exit avoids panic on exit :)
    User::Exit(0);
    
    return KErrNone; // and return
    }
    
    #endif

  2. #2
    Registered User
    Join Date
    Mar 2003
    Posts
    3

    RE: CMdaAudioOutputStream Not working with EXEDLL target

    The more I look at this problem by putting in debug prints the more I think the OS isn't designed to operate the sound streaming in this way. Would one of the OS technical people care to comment?
    I am getting a lot of 'unsupported feature' panics, which can't be right...
    Allocating a scheduler and making this the default one doesn't seem to work on the emulator either. However on the phone without allocating a scheduler a panic is raised... Very odd.

  3. #3
    Registered User
    Join Date
    Mar 2003
    Posts
    31

    RE: CMdaAudioOutputStream Not working with EXEDLL target

    The problem has been fixed.
    It took a bit of working around but the solution works on the emulator and the real phone.
    The solution really highlights an oversight in the Symbian/Nokia documentation as the solution is not described anywhere.
    Here is the solution described for others who might find it useful to know.
    The problem occurs because an EXEDLL type of project either has CActiveScheduler but not started under WINS and no CActiveScheduler on the phone.
    The solution to this you might think is to allocate a CActiveScheduler and all will be happy. Not so since doing this will mean you have your program stop when you use the Start() method. Not something you want to happen in an EXE.
    The solution for this is to create an RThread, Resume() it and use this new thread.
    Since the thread is a new thread you need to allocate a new CTrapCleanup and a CActiveScheduler. Once these have been allocated you can then allocate a new CMdaAudioOutputStream (which needs a CActiveSchedular to work). I found using a CPeriodic to give me some control over the audio stream was handy. Not forgetting to use the scedular Start() method to enable the active objects.


    I do not think the documentation explains that it is necessary to use these steps when using a project type of EXEDLL. Since games will definitely want to use EXEDLL for backwards compatibility with existing code and porting something should be added. With my experiments with graphics for games the APP type of project just didn't offer fast enough screen update and this is why I chose to use an EXEDLL project type. Using an EXEDLL enables me to control writes to the "screen" and this produces a faster frame rate.

    Personally I think there should be a released API that builds with the EXEDLL type and gives a barebones screen, sound and keyboard/joypad example to promote games with decent framerates.

  4. #4
    Regular Contributor
    Join Date
    Apr 2003
    Location
    china
    Posts
    181

    can you give us your example code ?

    thx

  5. #5
    Registered User
    Join Date
    Nov 2003
    Posts
    33

    hi, fnagaton

    I have encountered the same problem as yours, and I have tried to resolve it following your hints but failed. Could you give me some suggestions? Thank you very much!

    With my regards!
    Cormen

    here is my codes:

    ////////////////////////////////
    // commonframework.h
    //
    // Copyright (c) 1997-2000 Symbian Ltd. All rights reserved.
    //

    #ifndef __EUSTD_H
    #define __EUSTD_H

    #include <e32base.h>
    #include <e32cons.h>

    _LIT(KTxtEPOC32EX,"EPOC32EX");
    _LIT(KTxtExampleCode,"E32 SDK Example Code");
    _LIT(KFormatFailed,"failed: leave code=%d");
    _LIT(KTxtOK,"ok");
    _LIT(KTxtPressAnyKey," [press any key]");

    // public
    LOCAL_D CConsoleBase* console; // write all your messages to this
    LOCAL_C void doExampleL(); // code this function for the real example

    // private
    LOCAL_C void callExampleL(); // initialize with cleanup stack, then do example

    GLDEF_C TInt E32Main() // main function called by E32
    {
    __UHEAP_MARK;
    CTrapCleanup* cleanup=CTrapCleanup::New(); // get clean-up stack
    TRAPD(error,callExampleL()); // more initialization, then do example
    __ASSERT_ALWAYS(!error,User::Panic(KTxtEPOC32EX,error));
    delete cleanup; // destroy clean-up stack
    __UHEAP_MARKEND;
    return 0; // and return
    }

    LOCAL_C void callExampleL() // initialize and call example code under cleanup stack
    {
    console=Console::NewL(KTxtExampleCode,TSize(KConsFullScreen,KConsFullScreen));
    CleanupStack::PushL(console);
    TRAPD(error,doExampleL()); // perform example function
    if (error)
    console->Printf(KFormatFailed, error);
    else
    console->Printf(KTxtOK);
    console->Printf(KTxtPressAnyKey);
    console->Getch(); // get and ignore character
    CleanupStack::PopAndDestroy(); // close console
    }

    #endif

    //////////////////////////////////////
    /*
    * MySound.cpp
    */
    #include "CommonFramework.h" // standard example stuff
    #include "StreamAudioEngine.h" //play pcm file
    /*
    LOCAL_C void doExampleL()
    {
    CStreamAudioEngine* iEng = CStreamAudioEngine::NewL();
    iEng->PlayL();
    delete iEng;
    }
    */

    // do the example

    LOCAL_C void doExampleL()
    {
    // make and install the active scheduler
    CActiveScheduler* scheduler = new (ELeave) CActiveScheduler;
    CleanupStack::PushL(scheduler); // push to clean-up stack
    CActiveScheduler::Install(scheduler); // install as active scheduler

    CStreamAudioEngine* iEng = CStreamAudioEngine::NewL();
    iEng->PlayL();
    delete iEng;

    CActiveScheduler::Start();

    CleanupStack::PopAndDestroy(); // scheduler
    }


    //end of MySound.cpp
    ///////////////////////////////////////////////////////////////////////
    /*
    *StreamAudioEngine.cpp
    */

    #include <eikdef.h>
    #include <e32math.h>
    #include <stdio.h>
    #include "StreamAudioEngine.h"
    // LITERALS
    // path and name for the pcm sound file
    #ifdef __WINS__
    const char* KPCMFilename = "c:\\system\\apps\\mtts\\play.pcm";
    #else
    const char* KPCMFilename = "e:\\system\\apps\\mtts\\play.pcm";
    #endif


    CStreamAudioEngine::CStreamAudioEngine():
    iVolume(KInitialVolume),
    iVolStep(0),
    iFileSize(0),
    iFileOK(EFalse),
    iStatus(EEngineNotReady),
    iDescBuf(0,0)
    {
    }
    /*
    -------------------------------------------------------------------------------
    */
    CStreamAudioEngine::~CStreamAudioEngine()
    {
    delete iStream;
    delete iPCMBuffer;
    }

    /*
    -------------------------------------------------------------------------------
    */
    CStreamAudioEngine* CStreamAudioEngine::NewL()
    {
    CStreamAudioEngine* self = new (ELeave) CStreamAudioEngine();
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(); // self
    return self;
    }

    /*
    -------------------------------------------------------------------------------
    */
    void CStreamAudioEngine::ConstructL()
    {
    iPCMBuffer = NULL;
    // 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
    iStream->SetAudioPropertiesL(TMdaAudioDataSettings::ESampleRate8000Hz,
    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);
    iStatus = EEngineReady;
    }
    else
    printf("MaoscOpen failed.");
    iDescBuf.Set(iPCMBuffer,iFileSize,iFileSize);
    }
    /*
    -------------------------------------------------------------------------------
    */
    void CStreamAudioEngine::MaoscBufferCopied(TInt /*aError*/, const TDesC8& /*aBuffer*/)
    {
    return;
    }
    /*
    -------------------------------------------------------------------------------
    */
    void CStreamAudioEngine::MaoscPlayComplete(TInt /*aError*/)
    {
    iStatus = EEngineReady;
    }
    /*
    -------------------------------------------------------------------------------
    */
    void CStreamAudioEngine::PlayL()
    {
    // load the pcm file to buffer
    LoadFileL();
    if(iStatus == EEngineReady)
    {
    iStatus = EEnginePlaying;

    // if we're playing a pcm from a file, the buffer already
    // contains the sound data.

    // write the buffer to server. the playing starts immediately.
    iStream->WriteL(iDescBuf);
    }
    }

    /*
    -------------------------------------------------------------------------------
    */
    void CStreamAudioEngine::StopL()
    {
    iStream->Stop();
    }
    /*
    -------------------------------------------------------------------------------
    */
    void CStreamAudioEngine::LoadFileL()
    {
    FILE * fpPcm = fopen(KPCMFilename,"rb");
    if(fpPcm != NULL)
    {
    fseek(fpPcm,0,SEEK_END);
    iFileSize = ftell(fpPcm);
    if (iPCMBuffer) {
    delete iPCMBuffer;
    iPCMBuffer = NULL;
    }
    iPCMBuffer = new (ELeave)TUint8[iFileSize];
    iDescBuf.Set(iPCMBuffer,iFileSize,iFileSize);
    fseek(fpPcm,0,SEEK_SET);
    fread(iPCMBuffer,1,iFileSize,fpPcm);
    fclose(fpPcm);
    iFileOK = ETrue;
    }
    else
    iFileOK = EFalse;
    }

    //end of StreamAudioEngine.cpp

  6. #6
    Registered User
    Join Date
    Nov 2003
    Posts
    33
    And I have tried to modified it in this way, and I failed too.

    // EUSTD.H
    //
    // Copyright (c) 1997-2000 Symbian Ltd. All rights reserved.
    //

    #ifndef __EUSTD_H
    #define __EUSTD_H

    #include <e32std.h>
    #include <e32cons.h>
    #include <e32base.h>

    _LIT(KTxtEPOC32EX,"EPOC32EX");
    _LIT(KTxtExampleCode,"E32 SDK Example Code");
    _LIT(KFormatFailed,"failed: leave code=%d");
    _LIT(KTxtOK,"ok");
    _LIT(KTxtPressAnyKey," [press any key]");

    // public
    LOCAL_D CConsoleBase* console; // write all your messages to this
    LOCAL_C void doExampleL(); // code this function for the real example

    // private
    LOCAL_C void callExampleL(); // initialize with cleanup stack, then do example
    LOCAL_C TInt StartThread();
    GLDEF_C TInt ThreadFunction(TAny* anArg);

    GLDEF_C TInt E32Main() // main function called by E32
    {
    __UHEAP_MARK;
    CTrapCleanup* cleanup=CTrapCleanup::New(); // get clean-up stack
    TRAPD(error,callExampleL()); // more initialization, then do example
    __ASSERT_ALWAYS(!error,User::Panic(KTxtEPOC32EX,error));
    delete cleanup; // destroy clean-up stack
    __UHEAP_MARKEND;
    return 0; // and return
    }

    LOCAL_C void callExampleL() // initialize and call example code under cleanup stack
    {
    console=Console::NewL(KTxtExampleCode,TSize(KConsFullScreen,KConsFullScreen));
    CleanupStack::PushL(console);
    /*
    TRAPD(error,doExampleL()); // perform example function
    */
    TInt err = StartThread();
    if (KErrNone != err)
    console->Printf(KFormatFailed, err);
    else
    console->Printf(KTxtOK);

    console->Printf(KTxtPressAnyKey);
    console->Getch(); // get and ignore character

    CleanupStack::PopAndDestroy(); // close console
    }

    LOCAL_C TInt StartThread()
    {
    RThread thread;
    RSemaphore semaphore;
    TInt res;
    semaphore.CreateLocal(0); // create a semaphore so we know when thread finished
    _LIT(KTxtThread,"FibThread");
    res=thread.Create(KTxtThread, // create new server thread
    ThreadFunction, // thread's main function
    KDefaultStackSize,
    0x1000,
    0x1000,
    &semaphore // passed as TAny* argument to thread function
    );

    if (res==KErrNone) // thread created ok - now start it going
    {
    thread.SetPriority(EPriorityNormal);
    thread.Resume(); // start it going
    semaphore.Wait(); // wait until it's initialized
    thread.Close(); // we're no longer interested in the other thread
    }
    else // thread not created ok
    {
    thread.Close(); // therefore we've no further interest in it
    }

    semaphore.Close();
    return res;
    }

    GLDEF_C TInt ThreadFunction(TAny* anArg)
    {
    CTrapCleanup* cA=CTrapCleanup::New(); // get clean-up stack

    // convert argument into semaphore reference
    RSemaphore& semaphore=*(RSemaphore *)anArg;

    TRAPD(error,doExampleL()); // perform example function
    // signal that we've started
    semaphore.Signal();

    delete cA;
    // finished
    return(KErrNone);
    }

    #endif

    /*
    * MySound.cpp
    */
    #include "CommonFramework.h" // standard example stuff
    #include "StreamAudioEngine.h" //play pcm file

    class ActiveObj : public CActive
    {
    private:
    TRequestStatus iStatus;
    public:
    ActiveObj() : CActive(EPriorityLow)
    {
    CActiveScheduler::Add(this);
    SetActive();
    TRequestStatus* status = &iStatus ;
    User::RequestComplete(status, KErrNone) ;
    }

    void RunL()
    {
    // start up audio stream

    delete this;
    }
    };

    // do the example

    LOCAL_C void doExampleL()
    {
    // make and install the active scheduler
    CActiveScheduler* scheduler = new (ELeave) CActiveScheduler;
    CleanupStack::PushL(scheduler); // push to clean-up stack
    CActiveScheduler::Install(scheduler); // install as active scheduler

    CStreamAudioEngine* iEng = CStreamAudioEngine::NewL();

    while (iEng->StreamReady() == false)
    {
    User::After(10);
    _LIT(KTxtWaiting,"Waiting for engin ready...");
    console->Printf(KTxtWaiting);
    }

    iEng->PlayL();
    delete iEng;

    CActiveScheduler::Start();
    CleanupStack::PopAndDestroy(); // scheduler
    }

    //end of MySound.cpp

  7. #7
    Registered User
    Join Date
    Oct 2004
    Posts
    17

    Re: CMdaAudioOutputStream Not working with EXEDLL target

    Hi ,

    I have made an exe which plays audio successfully. I need to launch it from an app, and close it from an app.

    My one question is:

    1. How in this great wide world do we stop the exe?

    How is using RThread helping? I have made an exe (not exedll), in almost same way as your code has it, but I haven't used any RThread. Just made an ActiveScheduler, Installed it and started it.

    Is it possible to stop an exe from inside the app?

    Thanks in advance,
    Sudha

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •