/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * 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 /*symbian audio stuff*/ #include #include #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; iOpen(&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; iopaque; 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; inum_buffers; i++) { ctx->buffers[i] = (char *)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 *) 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; free(dr); } #ifdef __cplusplus } #endif