root/modules/epoc_hw/epoc_aout.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. Open
  2. Close
  3. MaoscOpenComplete
  4. MaoscBufferCopied
  5. MaoscPlayComplete
  6. EAUD_Setup
  7. EAUD_Shutdown
  8. EAUD_ConfigureOutput
  9. EAUD_WriteAudio
  10. EAUD_Play
  11. EAUD_SetVolume
  12. EAUD_SetPan
  13. EAUD_QueryOutputSampleRate
  14. EAUD_GetAudioDelay
  15. EAUD_GetTotalBufferTime
  16. EPOC_aout_new
  17. EPOC_aout_del

/*
 *                      GPAC - Multimedia Framework C SDK
 *
 *                      Authors: Jean Le Feuvre
 *                      Copyright (c) Telecom ParisTech 2000-2012
 *                                      All rights reserved
 *
 *  This file is part of GPAC / wave audio render module
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  GPAC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */


#include <gpac/modules/audio_out.h>
/*symbian audio stuff*/
#include <mdaaudiooutputstream.h>
#include <mda/common/audio.h>

#define EPOC_MAX_BUFFERS        8

enum {
        EPOC_AUDIO_INIT = 0,
        EPOC_AUDIO_OPEN,
        EPOC_AUDIO_PLAY,
        EPOC_AUDIO_ERROR,
};

class EPOCAudio : public MMdaAudioOutputStreamCallback
{
public:
        EPOCAudio();
        virtual ~EPOCAudio();

        virtual void MaoscOpenComplete( TInt aError );
        virtual void MaoscBufferCopied( TInt aError, const TDesC8& a_Buffer);
        virtual void MaoscPlayComplete( TInt );

        GF_Err Open(u32 sample_rate, Bool stereo);
        void Close(Bool and_wait);

        CMdaAudioOutputStream* m_stream;
        TMdaAudioDataSettings m_settings;
        u32 state;

        /*desired config*/
        u32 cfg_num_buffers, cfg_total_duration, init_vol, init_pan;
        /*actual config*/
        u32 num_buffers, total_duration, buffer_len;

        /*audio buffers*/
        char *buffers[EPOC_MAX_BUFFERS];
        TPtrC8 sent_buffers[EPOC_MAX_BUFFERS];
        u32 buffer_size;
        u32 current_buffer, nb_buffers_queued;
};

EPOCAudio::EPOCAudio()
{
        u32 i;
        m_stream = NULL;
        for (i=0; i<EPOC_MAX_BUFFERS; i++) buffers[i] = NULL;
        state = EPOC_AUDIO_INIT;
        num_buffers = 0;
        init_vol = 100;
}

EPOCAudio::~EPOCAudio()
{
        if (m_stream) {
                delete m_stream;
        }
}

GF_Err EPOCAudio::Open(u32 sample_rate, Bool stereo)
{
        TInt res = 0;
        u32 count;
        TMdaAudioDataSettings::TAudioCaps epoc_sr;


        switch (sample_rate) {
        case 8000:
                epoc_sr = TMdaAudioDataSettings::ESampleRate8000Hz;
                break;
        case 11025:
                epoc_sr = TMdaAudioDataSettings::ESampleRate11025Hz;
                break;
        case 12000:
                epoc_sr = TMdaAudioDataSettings::ESampleRate12000Hz;
                break;
        case 16000:
                epoc_sr = TMdaAudioDataSettings::ESampleRate16000Hz;
                break;
        case 22050:
                epoc_sr = TMdaAudioDataSettings::ESampleRate22050Hz;
                break;
        case 24000:
                epoc_sr = TMdaAudioDataSettings::ESampleRate24000Hz;
                break;
        case 32000:
                epoc_sr = TMdaAudioDataSettings::ESampleRate32000Hz;
                break;
        case 44100:
                epoc_sr = TMdaAudioDataSettings::ESampleRate44100Hz;
                break;
        case 48000:
                epoc_sr = TMdaAudioDataSettings::ESampleRate48000Hz;
                break;
        default:
                return GF_NOT_SUPPORTED;
        }

        state = EPOC_AUDIO_INIT;

        gf_sleep(10);
        TRAP(res, m_stream = CMdaAudioOutputStream::NewL(*this) );
        if ((res!=KErrNone) || !m_stream) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[EPOCAudio] Cannot create output audio stream\n"));
                return GF_IO_ERR;
        }
        m_stream->Open(&m_settings);

        /*wait for ack - if not getting it in 50*40 = 2sec, abort*/
        count = 50;
        while (count) {
                if (state == EPOC_AUDIO_OPEN) break;
                else if (state == EPOC_AUDIO_ERROR) {
                        return GF_IO_ERR;
                }
                gf_sleep(40);

                TInt error;
                CActiveScheduler::RunIfReady(error, CActive::EPriorityIdle);
                count--;
        }
        if (state != EPOC_AUDIO_OPEN) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[EPOCAudio] Failed to open sound device - is it present?\n"));
                return GF_NOT_SUPPORTED;
        }

        TRAP(res, m_stream->SetAudioPropertiesL(epoc_sr, stereo ? TMdaAudioDataSettings::EChannelsStereo : TMdaAudioDataSettings::EChannelsMono) );
        m_stream->SetPriority(EPriorityAbsoluteHigh, EMdaPriorityPreferenceTime );
        m_stream->SetVolume(init_vol * m_stream->MaxVolume() / 100);

        current_buffer = nb_buffers_queued = 0;

        GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[EPOCAudio] output audio stream ready - sample rate %d - %d channels\n", sample_rate, stereo ? 2 : 1));
        return GF_OK;
}

void EPOCAudio::Close(Bool and_wait)
{
        u32 i;
        if (m_stream) {
                if (state==EPOC_AUDIO_PLAY) {
#if 0
                        m_stream->Stop();

                        while (0 && and_wait) {

                                if (state != EPOC_AUDIO_PLAY) break;
                                gf_sleep(1);

                                TInt error;
                                CActiveScheduler::RunIfReady(error, CActive::EPriorityIdle);
                        }
#endif
                }
                delete m_stream;
                m_stream = NULL;
        }
        for (i=0; i<num_buffers; i++) {
                if (buffers[i]) gf_free(buffers[i]);
                buffers[i] = NULL;
        }
        num_buffers = 0;
        state = EPOC_AUDIO_INIT;
        GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[EPOCAudio] output audio stream closed\n"));
}

void EPOCAudio::MaoscOpenComplete(TInt aError)
{
        if (aError) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[EPOCAudio] Failed to open sound device - error %d\n", aError));
        } else {
                GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[EPOCAudio] Sound device opened\n", aError));
                state = EPOC_AUDIO_OPEN;
        }
}

void EPOCAudio::MaoscBufferCopied(TInt aError, const TDesC8& a_Buffer)
{
        assert(nb_buffers_queued);
        nb_buffers_queued--;
        state = nb_buffers_queued ? EPOC_AUDIO_PLAY : EPOC_AUDIO_OPEN;
}

void EPOCAudio::MaoscPlayComplete(TInt aError)
{
        if (aError) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[EPOCAudio] Playback stopped due to error %d\n", aError));
                state = EPOC_AUDIO_ERROR;
        } else {
                GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[EPOCAudio] Playback stopped due to user request\n"));
                state = EPOC_AUDIO_OPEN;
        }
}


static GF_Err EAUD_Setup(GF_AudioOutput *dr, void *os_handle, u32 num_buffers, u32 total_duration)
{
        EPOCAudio *ctx = (EPOCAudio *)dr->opaque;
        ctx->cfg_num_buffers = MAX(num_buffers, EPOC_MAX_BUFFERS);
        ctx->cfg_total_duration = total_duration;
        return GF_OK;
}

static void EAUD_Shutdown(GF_AudioOutput *dr)
{
        EPOCAudio *ctx = (EPOCAudio *)dr->opaque;
        ctx->Close(1);
}


/*we assume what was asked is what we got*/
static GF_Err EAUD_ConfigureOutput(GF_AudioOutput *dr, u32 *SampleRate, u32 *NbChannels, u32 *nbBitsPerSample, u32 channel_cfg)
{
        u32 snd_align, bps, i;
        GF_Err e;
        EPOCAudio *ctx = (EPOCAudio *)dr->opaque;

        ctx->Close(1);

        *nbBitsPerSample = 16;
        if (*NbChannels > 2) *NbChannels = 2;

        e = ctx->Open(*SampleRate, (*NbChannels ==2) ? 1 : 0);
        if (e) return e;

        snd_align = *NbChannels * 2;
        bps = snd_align **SampleRate;

        if (ctx->cfg_total_duration) {
                ctx->num_buffers = ctx->cfg_num_buffers;
                ctx->buffer_size = (bps*ctx->cfg_total_duration/1000) / ctx->num_buffers;
        } else {
                ctx->num_buffers = 4;
                /*use 25 ms buffers*/
                ctx->buffer_size = bps / 40;
        }
        ctx->buffer_size /= snd_align;
        ctx->buffer_size *= snd_align;

        ctx->buffer_len = ctx->buffer_size * 1000 / bps;
        ctx->total_duration = ctx->buffer_len * ctx->num_buffers;

        for (i=0; i<ctx->num_buffers; i++) {
                ctx->buffers[i] = (char *)gf_malloc(sizeof(char)*ctx->buffer_size);
        }
        GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[EPOCAudio] Output audio stream configured - %d buffers of %d ms each\n", ctx->num_buffers, ctx->buffer_len));

        return GF_OK;
}

static void EAUD_WriteAudio(GF_AudioOutput *dr)
{
        EPOCAudio *ctx = (EPOCAudio *)dr->opaque;

        /*no buffers available...*/
        if (ctx->nb_buffers_queued == ctx->num_buffers) {
                GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[EPOCAudio] Audio queue full - yielding to app\n"));
                User::After(0);
                TInt error;
                CActiveScheduler::RunIfReady(error, CActive::EPriorityIdle);
                return;
        }

        while (ctx->nb_buffers_queued < ctx->num_buffers) {
                u32 written = dr->FillBuffer(dr->audio_renderer, ctx->buffers[ctx->current_buffer], ctx->buffer_size);
                //GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[EPOCAudio] Filling audio buffer %d / %d\n", ctx->current_buffer, ctx->num_buffers));
                if (!written) return;

                ctx->sent_buffers[ctx->current_buffer].Set((const TText8 *) ctx->buffers[ctx->current_buffer], written);

                ctx->nb_buffers_queued++;
                ctx->m_stream->WriteL(ctx->sent_buffers[ctx->current_buffer]);
                ctx->current_buffer = (ctx->current_buffer + 1) % ctx->num_buffers;
        }
}

static void EAUD_Play(GF_AudioOutput *dr, u32 PlayType)
{
}

static void EAUD_SetVolume(GF_AudioOutput *dr, u32 Volume)
{
        EPOCAudio *ctx = (EPOCAudio *)dr->opaque;
        ctx->init_vol = Volume;
        if (ctx->m_stream)
                ctx->m_stream->SetVolume(ctx->init_vol * ctx->m_stream->MaxVolume() / 100);
}

static void EAUD_SetPan(GF_AudioOutput *dr, u32 Pan)
{
}


static GF_Err EAUD_QueryOutputSampleRate(GF_AudioOutput *dr, u32 *desired_samplerate, u32 *NbChannels, u32 *nbBitsPerSample)
{
        *nbBitsPerSample = 16;
        if (*NbChannels > 2) *NbChannels = 2;
        return GF_OK;
}

static u32 EAUD_GetAudioDelay(GF_AudioOutput *dr)
{
        EPOCAudio *ctx = (EPOCAudio *)dr->opaque;
        return ctx->current_buffer*ctx->buffer_len;
}

static u32 EAUD_GetTotalBufferTime(GF_AudioOutput *dr)
{
        EPOCAudio *ctx = (EPOCAudio *)dr->opaque;
        return ctx->total_duration;
}


#ifdef __cplusplus
extern "C" {
#endif

void *EPOC_aout_new()
{
        GF_AudioOutput *driv;
        driv = (GF_AudioOutput *) gf_malloc(sizeof(GF_AudioOutput));
        memset(driv, 0, sizeof(GF_AudioOutput));
        GF_REGISTER_MODULE_INTERFACE(driv, GF_AUDIO_OUTPUT_INTERFACE, "EPOC Audio Output", "gpac distribution")

        driv->Setup = EAUD_Setup;
        driv->Shutdown = EAUD_Shutdown;
        driv->ConfigureOutput = EAUD_ConfigureOutput;
        driv->GetAudioDelay = EAUD_GetAudioDelay;
        driv->GetTotalBufferTime = EAUD_GetTotalBufferTime;
        driv->SetVolume = EAUD_SetVolume;
        driv->SetPan = EAUD_SetPan;
        driv->Play = EAUD_Play;
        driv->QueryOutputSampleRate = EAUD_QueryOutputSampleRate;
        driv->WriteAudio = EAUD_WriteAudio;

        driv->SelfThreaded = 0;
        driv->opaque = new EPOCAudio();

        return driv;
}

void EPOC_aout_del(void *ifce)
{
        GF_AudioOutput *dr = (GF_AudioOutput *) ifce;
        EPOCAudio *ctx = (EPOCAudio*)dr->opaque;
        delete ctx;
        gf_free(dr);
}

#ifdef __cplusplus
}
#endif


/* [<][>][^][v][top][bottom][index][help] */