1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195 |
- /*
- * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
- * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include <pjmedia-audiodev/audiodev_imp.h>
- #include <pjmedia-audiodev/errno.h>
- #include <pjmedia/alaw_ulaw.h>
- #include <pj/assert.h>
- #include <pj/log.h>
- #include <pj/math.h>
- #include <pj/os.h>
- #include <pj/string.h>
- #if PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA
- /*
- * This file provides sound implementation for Symbian Audio Streaming
- * device. Application using this sound abstraction must link with:
- * - mediaclientaudiostream.lib, and
- * - mediaclientaudioinputstream.lib
- */
- #include <mda/common/audio.h>
- #include <mdaaudiooutputstream.h>
- #include <mdaaudioinputstream.h>
- #define THIS_FILE "symb_mda_dev.c"
- #define BITS_PER_SAMPLE 16
- #define BYTES_PER_SAMPLE (BITS_PER_SAMPLE/8)
- #if 1
- # define TRACE_(st) PJ_LOG(3, st)
- #else
- # define TRACE_(st)
- #endif
- /* MDA factory */
- struct mda_factory
- {
- pjmedia_aud_dev_factory base;
- pj_pool_t *pool;
- pj_pool_factory *pf;
- pjmedia_aud_dev_info dev_info;
- };
- /* Forward declaration of internal engine. */
- class CPjAudioInputEngine;
- class CPjAudioOutputEngine;
- /* MDA stream. */
- struct mda_stream
- {
- // Base
- pjmedia_aud_stream base; /**< Base class. */
-
- // Pool
- pj_pool_t *pool; /**< Memory pool. */
- // Common settings.
- pjmedia_aud_param param; /**< Stream param. */
- // Audio engine
- CPjAudioInputEngine *in_engine; /**< Record engine. */
- CPjAudioOutputEngine *out_engine; /**< Playback engine. */
- };
- /* Prototypes */
- static pj_status_t factory_init(pjmedia_aud_dev_factory *f);
- static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f);
- static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f);
- static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f);
- static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
- unsigned index,
- pjmedia_aud_dev_info *info);
- static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
- unsigned index,
- pjmedia_aud_param *param);
- static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
- const pjmedia_aud_param *param,
- pjmedia_aud_rec_cb rec_cb,
- pjmedia_aud_play_cb play_cb,
- void *user_data,
- pjmedia_aud_stream **p_aud_strm);
- static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
- pjmedia_aud_param *param);
- static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
- pjmedia_aud_dev_cap cap,
- void *value);
- static pj_status_t stream_set_cap(pjmedia_aud_stream *strm,
- pjmedia_aud_dev_cap cap,
- const void *value);
- static pj_status_t stream_start(pjmedia_aud_stream *strm);
- static pj_status_t stream_stop(pjmedia_aud_stream *strm);
- static pj_status_t stream_destroy(pjmedia_aud_stream *strm);
- /* Operations */
- static pjmedia_aud_dev_factory_op factory_op =
- {
- &factory_init,
- &factory_destroy,
- &factory_get_dev_count,
- &factory_get_dev_info,
- &factory_default_param,
- &factory_create_stream,
- &factory_refresh
- };
- static pjmedia_aud_stream_op stream_op =
- {
- &stream_get_param,
- &stream_get_cap,
- &stream_set_cap,
- &stream_start,
- &stream_stop,
- &stream_destroy
- };
- /*
- * Convert clock rate to Symbian's TMdaAudioDataSettings capability.
- */
- static TInt get_clock_rate_cap(unsigned clock_rate)
- {
- switch (clock_rate) {
- case 8000: return TMdaAudioDataSettings::ESampleRate8000Hz;
- case 11025: return TMdaAudioDataSettings::ESampleRate11025Hz;
- case 12000: return TMdaAudioDataSettings::ESampleRate12000Hz;
- case 16000: return TMdaAudioDataSettings::ESampleRate16000Hz;
- case 22050: return TMdaAudioDataSettings::ESampleRate22050Hz;
- case 24000: return TMdaAudioDataSettings::ESampleRate24000Hz;
- case 32000: return TMdaAudioDataSettings::ESampleRate32000Hz;
- case 44100: return TMdaAudioDataSettings::ESampleRate44100Hz;
- case 48000: return TMdaAudioDataSettings::ESampleRate48000Hz;
- case 64000: return TMdaAudioDataSettings::ESampleRate64000Hz;
- case 96000: return TMdaAudioDataSettings::ESampleRate96000Hz;
- default:
- return 0;
- }
- }
- /*
- * Convert number of channels into Symbian's TMdaAudioDataSettings capability.
- */
- static TInt get_channel_cap(unsigned channel_count)
- {
- switch (channel_count) {
- case 1: return TMdaAudioDataSettings::EChannelsMono;
- case 2: return TMdaAudioDataSettings::EChannelsStereo;
- default:
- return 0;
- }
- }
- /*
- * Utility: print sound device error
- */
- static void snd_perror(const char *title, TInt rc)
- {
- PJ_LOG(1,(THIS_FILE, "%s: error code %d", title, rc));
- }
-
- //////////////////////////////////////////////////////////////////////////////
- //
- /*
- * Implementation: Symbian Input Stream.
- */
- class CPjAudioInputEngine : public CBase, MMdaAudioInputStreamCallback
- {
- public:
- enum State
- {
- STATE_INACTIVE,
- STATE_ACTIVE,
- };
- ~CPjAudioInputEngine();
- static CPjAudioInputEngine *NewL(struct mda_stream *parent_strm,
- pjmedia_aud_rec_cb rec_cb,
- void *user_data);
- static CPjAudioInputEngine *NewLC(struct mda_stream *parent_strm,
- pjmedia_aud_rec_cb rec_cb,
- void *user_data);
- pj_status_t StartRecord();
- void Stop();
- pj_status_t SetGain(TInt gain) {
- if (iInputStream_) {
- iInputStream_->SetGain(gain);
- return PJ_SUCCESS;
- } else
- return PJ_EINVALIDOP;
- }
-
- TInt GetGain() {
- if (iInputStream_) {
- return iInputStream_->Gain();
- } else
- return PJ_EINVALIDOP;
- }
- TInt GetMaxGain() {
- if (iInputStream_) {
- return iInputStream_->MaxGain();
- } else
- return PJ_EINVALIDOP;
- }
-
- private:
- State state_;
- struct mda_stream *parentStrm_;
- pjmedia_aud_rec_cb recCb_;
- void *userData_;
- CMdaAudioInputStream *iInputStream_;
- HBufC8 *iStreamBuffer_;
- TPtr8 iFramePtr_;
- TInt lastError_;
- pj_uint32_t timeStamp_;
- CActiveSchedulerWait startAsw_;
- // cache variable
- // to avoid calculating frame length repeatedly
- TInt frameLen_;
-
- // sometimes recorded size != requested framesize, so let's
- // provide a buffer to make sure the rec callback returning
- // framesize as requested.
- TUint8 *frameRecBuf_;
- TInt frameRecBufLen_;
- CPjAudioInputEngine(struct mda_stream *parent_strm,
- pjmedia_aud_rec_cb rec_cb,
- void *user_data);
- void ConstructL();
- TPtr8 & GetFrame();
-
- public:
- virtual void MaiscOpenComplete(TInt aError);
- virtual void MaiscBufferCopied(TInt aError, const TDesC8 &aBuffer);
- virtual void MaiscRecordComplete(TInt aError);
- };
- CPjAudioInputEngine::CPjAudioInputEngine(struct mda_stream *parent_strm,
- pjmedia_aud_rec_cb rec_cb,
- void *user_data)
- : state_(STATE_INACTIVE), parentStrm_(parent_strm),
- recCb_(rec_cb), userData_(user_data),
- iInputStream_(NULL), iStreamBuffer_(NULL), iFramePtr_(0, 0),
- lastError_(KErrNone), timeStamp_(0),
- frameLen_(parent_strm->param.samples_per_frame *
- BYTES_PER_SAMPLE),
- frameRecBuf_(NULL), frameRecBufLen_(0)
- {
- }
- CPjAudioInputEngine::~CPjAudioInputEngine()
- {
- Stop();
- delete iStreamBuffer_;
- iStreamBuffer_ = NULL;
-
- delete [] frameRecBuf_;
- frameRecBuf_ = NULL;
- frameRecBufLen_ = 0;
- }
- void CPjAudioInputEngine::ConstructL()
- {
- iStreamBuffer_ = HBufC8::NewL(frameLen_);
- CleanupStack::PushL(iStreamBuffer_);
- frameRecBuf_ = new TUint8[frameLen_*2];
- CleanupStack::PushL(frameRecBuf_);
- }
- CPjAudioInputEngine *CPjAudioInputEngine::NewLC(struct mda_stream *parent,
- pjmedia_aud_rec_cb rec_cb,
- void *user_data)
- {
- CPjAudioInputEngine* self = new (ELeave) CPjAudioInputEngine(parent,
- rec_cb,
- user_data);
- CleanupStack::PushL(self);
- self->ConstructL();
- return self;
- }
- CPjAudioInputEngine *CPjAudioInputEngine::NewL(struct mda_stream *parent,
- pjmedia_aud_rec_cb rec_cb,
- void *user_data)
- {
- CPjAudioInputEngine *self = NewLC(parent, rec_cb, user_data);
- CleanupStack::Pop(self->frameRecBuf_);
- CleanupStack::Pop(self->iStreamBuffer_);
- CleanupStack::Pop(self);
- return self;
- }
- pj_status_t CPjAudioInputEngine::StartRecord()
- {
- // Ignore command if recording is in progress.
- if (state_ == STATE_ACTIVE)
- return PJ_SUCCESS;
- // According to Nokia's AudioStream example, some 2nd Edition, FP2 devices
- // (such as Nokia 6630) require the stream to be reconstructed each time
- // before calling Open() - otherwise the callback never gets called.
- // For uniform behavior, lets just delete/re-create the stream for all
- // devices.
- // Destroy existing stream.
- if (iInputStream_) delete iInputStream_;
- iInputStream_ = NULL;
- // Create the stream.
- TRAPD(err, iInputStream_ = CMdaAudioInputStream::NewL(*this));
- if (err != KErrNone)
- return PJ_RETURN_OS_ERROR(err);
- // Initialize settings.
- TMdaAudioDataSettings iStreamSettings;
- iStreamSettings.iChannels =
- get_channel_cap(parentStrm_->param.channel_count);
- iStreamSettings.iSampleRate =
- get_clock_rate_cap(parentStrm_->param.clock_rate);
- pj_assert(iStreamSettings.iChannels != 0 &&
- iStreamSettings.iSampleRate != 0);
- PJ_LOG(4,(THIS_FILE, "Opening sound device for capture, "
- "clock rate=%d, channel count=%d..",
- parentStrm_->param.clock_rate,
- parentStrm_->param.channel_count));
-
- // Open stream.
- lastError_ = KRequestPending;
- iInputStream_->Open(&iStreamSettings);
-
- #if defined(PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START) && \
- PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START != 0
-
- startAsw_.Start();
-
- #endif
-
- // Success
- PJ_LOG(4,(THIS_FILE, "Sound capture started."));
- return PJ_SUCCESS;
- }
- void CPjAudioInputEngine::Stop()
- {
- // If capture is in progress, stop it.
- if (iInputStream_ && state_ == STATE_ACTIVE) {
- lastError_ = KRequestPending;
- iInputStream_->Stop();
- // Wait until it's actually stopped
- while (lastError_ == KRequestPending)
- pj_symbianos_poll(-1, 100);
- }
- if (iInputStream_) {
- delete iInputStream_;
- iInputStream_ = NULL;
- }
-
- if (startAsw_.IsStarted()) {
- startAsw_.AsyncStop();
- }
-
- state_ = STATE_INACTIVE;
- }
- TPtr8 & CPjAudioInputEngine::GetFrame()
- {
- //iStreamBuffer_->Des().FillZ(frameLen_);
- iFramePtr_.Set((TUint8*)(iStreamBuffer_->Ptr()), frameLen_, frameLen_);
- return iFramePtr_;
- }
- void CPjAudioInputEngine::MaiscOpenComplete(TInt aError)
- {
- if (startAsw_.IsStarted()) {
- startAsw_.AsyncStop();
- }
-
- lastError_ = aError;
- if (aError != KErrNone) {
- snd_perror("Error in MaiscOpenComplete()", aError);
- return;
- }
- /* Apply input volume setting if specified */
- if (parentStrm_->param.flags &
- PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING)
- {
- stream_set_cap(&parentStrm_->base,
- PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING,
- &parentStrm_->param.input_vol);
- }
- // set stream priority to normal and time sensitive
- iInputStream_->SetPriority(EPriorityNormal,
- EMdaPriorityPreferenceTime);
- // Read the first frame.
- TPtr8 & frm = GetFrame();
- TRAPD(err2, iInputStream_->ReadL(frm));
- if (err2) {
- PJ_LOG(4,(THIS_FILE, "Exception in iInputStream_->ReadL()"));
- lastError_ = err2;
- return;
- }
- // input stream opened succesfully, set status to Active
- state_ = STATE_ACTIVE;
- }
- void CPjAudioInputEngine::MaiscBufferCopied(TInt aError,
- const TDesC8 &aBuffer)
- {
- lastError_ = aError;
- if (aError != KErrNone) {
- snd_perror("Error in MaiscBufferCopied()", aError);
- return;
- }
- if (frameRecBufLen_ || aBuffer.Length() < frameLen_) {
- pj_memcpy(frameRecBuf_ + frameRecBufLen_, (void*) aBuffer.Ptr(), aBuffer.Length());
- frameRecBufLen_ += aBuffer.Length();
- }
- if (frameRecBufLen_) {
- while (frameRecBufLen_ >= frameLen_) {
- pjmedia_frame f;
-
- f.type = PJMEDIA_FRAME_TYPE_AUDIO;
- f.buf = frameRecBuf_;
- f.size = frameLen_;
- f.timestamp.u32.lo = timeStamp_;
- f.bit_info = 0;
-
- // Call the callback.
- recCb_(userData_, &f);
- // Increment timestamp.
- timeStamp_ += parentStrm_->param.samples_per_frame;
- frameRecBufLen_ -= frameLen_;
- pj_memmove(frameRecBuf_, frameRecBuf_+frameLen_, frameRecBufLen_);
- }
- } else {
- pjmedia_frame f;
-
- f.type = PJMEDIA_FRAME_TYPE_AUDIO;
- f.buf = (void*)aBuffer.Ptr();
- f.size = aBuffer.Length();
- f.timestamp.u32.lo = timeStamp_;
- f.bit_info = 0;
-
- // Call the callback.
- recCb_(userData_, &f);
-
- // Increment timestamp.
- timeStamp_ += parentStrm_->param.samples_per_frame;
- }
- // Record next frame
- TPtr8 & frm = GetFrame();
- TRAPD(err2, iInputStream_->ReadL(frm));
- if (err2) {
- PJ_LOG(4,(THIS_FILE, "Exception in iInputStream_->ReadL()"));
- }
- }
- void CPjAudioInputEngine::MaiscRecordComplete(TInt aError)
- {
- lastError_ = aError;
- state_ = STATE_INACTIVE;
- if (aError != KErrNone && aError != KErrCancel) {
- snd_perror("Error in MaiscRecordComplete()", aError);
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- /*
- * Implementation: Symbian Output Stream.
- */
- class CPjAudioOutputEngine : public CBase, MMdaAudioOutputStreamCallback
- {
- public:
- enum State
- {
- STATE_INACTIVE,
- STATE_ACTIVE,
- };
- ~CPjAudioOutputEngine();
- static CPjAudioOutputEngine *NewL(struct mda_stream *parent_strm,
- pjmedia_aud_play_cb play_cb,
- void *user_data);
- static CPjAudioOutputEngine *NewLC(struct mda_stream *parent_strm,
- pjmedia_aud_play_cb rec_cb,
- void *user_data);
- pj_status_t StartPlay();
- void Stop();
- pj_status_t SetVolume(TInt vol) {
- if (iOutputStream_) {
- iOutputStream_->SetVolume(vol);
- return PJ_SUCCESS;
- } else
- return PJ_EINVALIDOP;
- }
-
- TInt GetVolume() {
- if (iOutputStream_) {
- return iOutputStream_->Volume();
- } else
- return PJ_EINVALIDOP;
- }
- TInt GetMaxVolume() {
- if (iOutputStream_) {
- return iOutputStream_->MaxVolume();
- } else
- return PJ_EINVALIDOP;
- }
- private:
- State state_;
- struct mda_stream *parentStrm_;
- pjmedia_aud_play_cb playCb_;
- void *userData_;
- CMdaAudioOutputStream *iOutputStream_;
- TUint8 *frameBuf_;
- unsigned frameBufSize_;
- TPtrC8 frame_;
- TInt lastError_;
- unsigned timestamp_;
- CActiveSchedulerWait startAsw_;
- CPjAudioOutputEngine(struct mda_stream *parent_strm,
- pjmedia_aud_play_cb play_cb,
- void *user_data);
- void ConstructL();
- virtual void MaoscOpenComplete(TInt aError);
- virtual void MaoscBufferCopied(TInt aError, const TDesC8& aBuffer);
- virtual void MaoscPlayComplete(TInt aError);
- };
- CPjAudioOutputEngine::CPjAudioOutputEngine(struct mda_stream *parent_strm,
- pjmedia_aud_play_cb play_cb,
- void *user_data)
- : state_(STATE_INACTIVE), parentStrm_(parent_strm), playCb_(play_cb),
- userData_(user_data), iOutputStream_(NULL), frameBuf_(NULL),
- lastError_(KErrNone), timestamp_(0)
- {
- }
- void CPjAudioOutputEngine::ConstructL()
- {
- frameBufSize_ = parentStrm_->param.samples_per_frame *
- BYTES_PER_SAMPLE;
- frameBuf_ = new TUint8[frameBufSize_];
- }
- CPjAudioOutputEngine::~CPjAudioOutputEngine()
- {
- Stop();
- delete [] frameBuf_;
- }
- CPjAudioOutputEngine *
- CPjAudioOutputEngine::NewLC(struct mda_stream *parent_strm,
- pjmedia_aud_play_cb play_cb,
- void *user_data)
- {
- CPjAudioOutputEngine* self = new (ELeave) CPjAudioOutputEngine(parent_strm,
- play_cb,
- user_data);
- CleanupStack::PushL(self);
- self->ConstructL();
- return self;
- }
- CPjAudioOutputEngine *
- CPjAudioOutputEngine::NewL(struct mda_stream *parent_strm,
- pjmedia_aud_play_cb play_cb,
- void *user_data)
- {
- CPjAudioOutputEngine *self = NewLC(parent_strm, play_cb, user_data);
- CleanupStack::Pop(self);
- return self;
- }
- pj_status_t CPjAudioOutputEngine::StartPlay()
- {
- // Ignore command if playing is in progress.
- if (state_ == STATE_ACTIVE)
- return PJ_SUCCESS;
-
- // Destroy existing stream.
- if (iOutputStream_) delete iOutputStream_;
- iOutputStream_ = NULL;
-
- // Create the stream
- TRAPD(err, iOutputStream_ = CMdaAudioOutputStream::NewL(*this));
- if (err != KErrNone)
- return PJ_RETURN_OS_ERROR(err);
-
- // Initialize settings.
- TMdaAudioDataSettings iStreamSettings;
- iStreamSettings.iChannels =
- get_channel_cap(parentStrm_->param.channel_count);
- iStreamSettings.iSampleRate =
- get_clock_rate_cap(parentStrm_->param.clock_rate);
- pj_assert(iStreamSettings.iChannels != 0 &&
- iStreamSettings.iSampleRate != 0);
-
- PJ_LOG(4,(THIS_FILE, "Opening sound device for playback, "
- "clock rate=%d, channel count=%d..",
- parentStrm_->param.clock_rate,
- parentStrm_->param.channel_count));
- // Open stream.
- lastError_ = KRequestPending;
- iOutputStream_->Open(&iStreamSettings);
-
- #if defined(PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START) && \
- PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START != 0
-
- startAsw_.Start();
-
- #endif
- // Success
- PJ_LOG(4,(THIS_FILE, "Sound playback started"));
- return PJ_SUCCESS;
- }
- void CPjAudioOutputEngine::Stop()
- {
- // Stop stream if it's playing
- if (iOutputStream_ && state_ != STATE_INACTIVE) {
- lastError_ = KRequestPending;
- iOutputStream_->Stop();
- // Wait until it's actually stopped
- while (lastError_ == KRequestPending)
- pj_symbianos_poll(-1, 100);
- }
-
- if (iOutputStream_) {
- delete iOutputStream_;
- iOutputStream_ = NULL;
- }
-
- if (startAsw_.IsStarted()) {
- startAsw_.AsyncStop();
- }
-
- state_ = STATE_INACTIVE;
- }
- void CPjAudioOutputEngine::MaoscOpenComplete(TInt aError)
- {
- if (startAsw_.IsStarted()) {
- startAsw_.AsyncStop();
- }
- lastError_ = aError;
-
- if (aError==KErrNone) {
- // set stream properties, 16bit 8KHz mono
- TMdaAudioDataSettings iSettings;
- iSettings.iChannels =
- get_channel_cap(parentStrm_->param.channel_count);
- iSettings.iSampleRate =
- get_clock_rate_cap(parentStrm_->param.clock_rate);
- iOutputStream_->SetAudioPropertiesL(iSettings.iSampleRate,
- iSettings.iChannels);
- /* Apply output volume setting if specified */
- if (parentStrm_->param.flags &
- PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING)
- {
- stream_set_cap(&parentStrm_->base,
- PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
- &parentStrm_->param.output_vol);
- } else {
- // set volume to 1/2th of stream max volume
- iOutputStream_->SetVolume(iOutputStream_->MaxVolume()/2);
- }
-
- // set stream priority to normal and time sensitive
- iOutputStream_->SetPriority(EPriorityNormal,
- EMdaPriorityPreferenceTime);
- // Call callback to retrieve frame from upstream.
- pjmedia_frame f;
- pj_status_t status;
-
- f.type = PJMEDIA_FRAME_TYPE_AUDIO;
- f.buf = frameBuf_;
- f.size = frameBufSize_;
- f.timestamp.u32.lo = timestamp_;
- f.bit_info = 0;
- status = playCb_(this->userData_, &f);
- if (status != PJ_SUCCESS) {
- this->Stop();
- return;
- }
- if (f.type != PJMEDIA_FRAME_TYPE_AUDIO)
- pj_bzero(frameBuf_, frameBufSize_);
-
- // Increment timestamp.
- timestamp_ += (frameBufSize_ / BYTES_PER_SAMPLE);
- // issue WriteL() to write the first audio data block,
- // subsequent calls to WriteL() will be issued in
- // MMdaAudioOutputStreamCallback::MaoscBufferCopied()
- // until whole data buffer is written.
- frame_.Set(frameBuf_, frameBufSize_);
- iOutputStream_->WriteL(frame_);
- // output stream opened succesfully, set status to Active
- state_ = STATE_ACTIVE;
- } else {
- snd_perror("Error in MaoscOpenComplete()", aError);
- }
- }
- void CPjAudioOutputEngine::MaoscBufferCopied(TInt aError,
- const TDesC8& aBuffer)
- {
- PJ_UNUSED_ARG(aBuffer);
- if (aError==KErrNone) {
- // Buffer successfully written, feed another one.
- // Call callback to retrieve frame from upstream.
- pjmedia_frame f;
- pj_status_t status;
-
- f.type = PJMEDIA_FRAME_TYPE_AUDIO;
- f.buf = frameBuf_;
- f.size = frameBufSize_;
- f.timestamp.u32.lo = timestamp_;
- f.bit_info = 0;
- status = playCb_(this->userData_, &f);
- if (status != PJ_SUCCESS) {
- this->Stop();
- return;
- }
- if (f.type != PJMEDIA_FRAME_TYPE_AUDIO)
- pj_bzero(frameBuf_, frameBufSize_);
-
- // Increment timestamp.
- timestamp_ += (frameBufSize_ / BYTES_PER_SAMPLE);
- // Write to playback stream.
- frame_.Set(frameBuf_, frameBufSize_);
- iOutputStream_->WriteL(frame_);
- } else if (aError==KErrAbort) {
- // playing was aborted, due to call to CMdaAudioOutputStream::Stop()
- state_ = STATE_INACTIVE;
- } else {
- // error writing data to output
- lastError_ = aError;
- state_ = STATE_INACTIVE;
- snd_perror("Error in MaoscBufferCopied()", aError);
- }
- }
- void CPjAudioOutputEngine::MaoscPlayComplete(TInt aError)
- {
- lastError_ = aError;
- state_ = STATE_INACTIVE;
- if (aError != KErrNone && aError != KErrCancel) {
- snd_perror("Error in MaoscPlayComplete()", aError);
- }
- }
- /****************************************************************************
- * Factory operations
- */
- /*
- * C compatible declaration of MDA factory.
- */
- PJ_BEGIN_DECL
- PJ_DECL(pjmedia_aud_dev_factory*) pjmedia_symb_mda_factory(pj_pool_factory *pf);
- PJ_END_DECL
- /*
- * Init Symbian audio driver.
- */
- pjmedia_aud_dev_factory* pjmedia_symb_mda_factory(pj_pool_factory *pf)
- {
- struct mda_factory *f;
- pj_pool_t *pool;
- pool = pj_pool_create(pf, "symb_aud", 1000, 1000, NULL);
- f = PJ_POOL_ZALLOC_T(pool, struct mda_factory);
- f->pf = pf;
- f->pool = pool;
- f->base.op = &factory_op;
- return &f->base;
- }
- /* API: init factory */
- static pj_status_t factory_init(pjmedia_aud_dev_factory *f)
- {
- struct mda_factory *af = (struct mda_factory*)f;
- pj_ansi_strcpy(af->dev_info.name, "Symbian Audio");
- af->dev_info.default_samples_per_sec = 8000;
- af->dev_info.caps = PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING |
- PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
- af->dev_info.input_count = 1;
- af->dev_info.output_count = 1;
- PJ_LOG(4, (THIS_FILE, "Symb Mda initialized"));
- return PJ_SUCCESS;
- }
- /* API: destroy factory */
- static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f)
- {
- struct mda_factory *af = (struct mda_factory*)f;
- pj_pool_t *pool = af->pool;
- af->pool = NULL;
- pj_pool_release(pool);
- PJ_LOG(4, (THIS_FILE, "Symbian Mda destroyed"));
-
- return PJ_SUCCESS;
- }
- /* API: refresh the device list */
- static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f)
- {
- PJ_UNUSED_ARG(f);
- return PJ_ENOTSUP;
- }
- /* API: get number of devices */
- static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f)
- {
- PJ_UNUSED_ARG(f);
- return 1;
- }
- /* API: get device info */
- static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
- unsigned index,
- pjmedia_aud_dev_info *info)
- {
- struct mda_factory *af = (struct mda_factory*)f;
- PJ_ASSERT_RETURN(index == 0, PJMEDIA_EAUD_INVDEV);
- pj_memcpy(info, &af->dev_info, sizeof(*info));
- return PJ_SUCCESS;
- }
- /* API: create default device parameter */
- static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
- unsigned index,
- pjmedia_aud_param *param)
- {
- struct mda_factory *af = (struct mda_factory*)f;
- PJ_ASSERT_RETURN(index == 0, PJMEDIA_EAUD_INVDEV);
- pj_bzero(param, sizeof(*param));
- param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
- param->rec_id = index;
- param->play_id = index;
- param->clock_rate = af->dev_info.default_samples_per_sec;
- param->channel_count = 1;
- param->samples_per_frame = af->dev_info.default_samples_per_sec * 20 / 1000;
- param->bits_per_sample = BITS_PER_SAMPLE;
- // Don't set the flags without specifying the flags value.
- //param->flags = af->dev_info.caps;
- return PJ_SUCCESS;
- }
- /* API: create stream */
- static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
- const pjmedia_aud_param *param,
- pjmedia_aud_rec_cb rec_cb,
- pjmedia_aud_play_cb play_cb,
- void *user_data,
- pjmedia_aud_stream **p_aud_strm)
- {
- struct mda_factory *mf = (struct mda_factory*)f;
- pj_pool_t *pool;
- struct mda_stream *strm;
- /* Can only support 16bits per sample raw PCM format. */
- PJ_ASSERT_RETURN(param->bits_per_sample == BITS_PER_SAMPLE, PJ_EINVAL);
- PJ_ASSERT_RETURN((param->flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT)==0 ||
- param->ext_fmt.id == PJMEDIA_FORMAT_L16,
- PJ_ENOTSUP);
-
- /* It seems that MDA recorder only supports for mono channel. */
- PJ_ASSERT_RETURN(param->channel_count == 1, PJ_EINVAL);
- /* Create and Initialize stream descriptor */
- pool = pj_pool_create(mf->pf, "symb_aud_dev", 1000, 1000, NULL);
- PJ_ASSERT_RETURN(pool, PJ_ENOMEM);
- strm = PJ_POOL_ZALLOC_T(pool, struct mda_stream);
- strm->pool = pool;
- strm->param = *param;
- // Create the output stream.
- if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
- TRAPD(err, strm->out_engine = CPjAudioOutputEngine::NewL(strm, play_cb,
- user_data));
- if (err != KErrNone) {
- pj_pool_release(pool);
- return PJ_RETURN_OS_ERROR(err);
- }
- }
- // Create the input stream.
- if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
- TRAPD(err, strm->in_engine = CPjAudioInputEngine::NewL(strm, rec_cb,
- user_data));
- if (err != KErrNone) {
- strm->in_engine = NULL;
- delete strm->out_engine;
- strm->out_engine = NULL;
- pj_pool_release(pool);
- return PJ_RETURN_OS_ERROR(err);
- }
- }
-
- /* Done */
- strm->base.op = &stream_op;
- *p_aud_strm = &strm->base;
- return PJ_SUCCESS;
- }
- /* API: Get stream info. */
- static pj_status_t stream_get_param(pjmedia_aud_stream *s,
- pjmedia_aud_param *pi)
- {
- struct mda_stream *strm = (struct mda_stream*)s;
- PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
- pj_memcpy(pi, &strm->param, sizeof(*pi));
-
- /* Update the output volume setting */
- if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
- &pi->output_vol) == PJ_SUCCESS)
- {
- pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
- }
-
- /* Update the input volume setting */
- if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING,
- &pi->input_vol) == PJ_SUCCESS)
- {
- pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING;
- }
-
- return PJ_SUCCESS;
- }
- /* API: get capability */
- static pj_status_t stream_get_cap(pjmedia_aud_stream *s,
- pjmedia_aud_dev_cap cap,
- void *pval)
- {
- struct mda_stream *strm = (struct mda_stream*)s;
- pj_status_t status = PJ_ENOTSUP;
- PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
- switch (cap) {
- case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
- if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
- PJ_ASSERT_RETURN(strm->in_engine, PJ_EINVAL);
-
- TInt max_gain = strm->in_engine->GetMaxGain();
- TInt gain = strm->in_engine->GetGain();
-
- if (max_gain > 0 && gain >= 0) {
- *(unsigned*)pval = gain * 100 / max_gain;
- status = PJ_SUCCESS;
- } else {
- status = PJMEDIA_EAUD_NOTREADY;
- }
- }
- break;
- case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
- if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
- PJ_ASSERT_RETURN(strm->out_engine, PJ_EINVAL);
-
- TInt max_vol = strm->out_engine->GetMaxVolume();
- TInt vol = strm->out_engine->GetVolume();
-
- if (max_vol > 0 && vol >= 0) {
- *(unsigned*)pval = vol * 100 / max_vol;
- status = PJ_SUCCESS;
- } else {
- status = PJMEDIA_EAUD_NOTREADY;
- }
- }
- break;
- default:
- break;
- }
-
- return status;
- }
- /* API: set capability */
- static pj_status_t stream_set_cap(pjmedia_aud_stream *s,
- pjmedia_aud_dev_cap cap,
- const void *pval)
- {
- struct mda_stream *strm = (struct mda_stream*)s;
- pj_status_t status = PJ_ENOTSUP;
- PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
- switch (cap) {
- case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
- if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
- PJ_ASSERT_RETURN(strm->in_engine, PJ_EINVAL);
-
- TInt max_gain = strm->in_engine->GetMaxGain();
- if (max_gain > 0) {
- TInt gain;
-
- gain = *(unsigned*)pval * max_gain / 100;
- status = strm->in_engine->SetGain(gain);
- } else {
- status = PJMEDIA_EAUD_NOTREADY;
- }
- }
- break;
- case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
- if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
- PJ_ASSERT_RETURN(strm->out_engine, PJ_EINVAL);
-
- TInt max_vol = strm->out_engine->GetMaxVolume();
- if (max_vol > 0) {
- TInt vol;
-
- vol = *(unsigned*)pval * max_vol / 100;
- status = strm->out_engine->SetVolume(vol);
- } else {
- status = PJMEDIA_EAUD_NOTREADY;
- }
- }
- break;
- default:
- break;
- }
-
- return status;
- }
- /* API: Start stream. */
- static pj_status_t stream_start(pjmedia_aud_stream *strm)
- {
- struct mda_stream *stream = (struct mda_stream*)strm;
- PJ_ASSERT_RETURN(stream, PJ_EINVAL);
- if (stream->out_engine) {
- pj_status_t status;
- status = stream->out_engine->StartPlay();
- if (status != PJ_SUCCESS)
- return status;
- }
-
- if (stream->in_engine) {
- pj_status_t status;
- status = stream->in_engine->StartRecord();
- if (status != PJ_SUCCESS)
- return status;
- }
- return PJ_SUCCESS;
- }
- /* API: Stop stream. */
- static pj_status_t stream_stop(pjmedia_aud_stream *strm)
- {
- struct mda_stream *stream = (struct mda_stream*)strm;
- PJ_ASSERT_RETURN(stream, PJ_EINVAL);
- if (stream->in_engine) {
- stream->in_engine->Stop();
- }
-
- if (stream->out_engine) {
- stream->out_engine->Stop();
- }
- return PJ_SUCCESS;
- }
- /* API: Destroy stream. */
- static pj_status_t stream_destroy(pjmedia_aud_stream *strm)
- {
- struct mda_stream *stream = (struct mda_stream*)strm;
- PJ_ASSERT_RETURN(stream, PJ_EINVAL);
- stream_stop(strm);
- delete stream->in_engine;
- stream->in_engine = NULL;
- delete stream->out_engine;
- stream->out_engine = NULL;
- pj_pool_t *pool;
- pool = stream->pool;
- if (pool) {
- stream->pool = NULL;
- pj_pool_release(pool);
- }
- return PJ_SUCCESS;
- }
- #endif /* PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA */
|