diff options
author | Benny Prijono <bennylp@teluu.com> | 2009-03-12 18:11:37 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2009-03-12 18:11:37 +0000 |
commit | 1dacdee696b7591a6dcc0b3c1d0f41573e473168 (patch) | |
tree | 302b09dcd989c0c05cf09f6aebaa63d870b421b9 /pjmedia/src/pjmedia/symbian_sound_aps.cpp | |
parent | ba9d8ca28eb209571c0bd6a080a8bb03d0fa2d33 (diff) |
(Major) Task #737 and #738: integration of APS-Direct and Audiodev from aps-direct branch to trunk.
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2506 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia/src/pjmedia/symbian_sound_aps.cpp')
-rw-r--r-- | pjmedia/src/pjmedia/symbian_sound_aps.cpp | 920 |
1 files changed, 0 insertions, 920 deletions
diff --git a/pjmedia/src/pjmedia/symbian_sound_aps.cpp b/pjmedia/src/pjmedia/symbian_sound_aps.cpp deleted file mode 100644 index ea419c51..00000000 --- a/pjmedia/src/pjmedia/symbian_sound_aps.cpp +++ /dev/null @@ -1,920 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 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/sound.h> -#include <pjmedia/alaw_ulaw.h> -#include <pjmedia/errno.h> -#include <pjmedia/symbian_sound_aps.h> -#include <pj/assert.h> -#include <pj/log.h> -#include <pj/math.h> -#include <pj/os.h> - -#include <e32msgqueue.h> -#include <sounddevice.h> -#include <APSClientSession.h> - -////////////////////////////////////////////////////////////////////////////// -// - -#define THIS_FILE "symbian_sound_aps.cpp" - -#define BYTES_PER_SAMPLE 2 -#define POOL_NAME "SymbianSoundAps" -#define POOL_SIZE 512 -#define POOL_INC 512 - -#if 1 -# define TRACE_(st) PJ_LOG(3, st) -#else -# define TRACE_(st) -#endif - -static pjmedia_snd_dev_info symbian_snd_dev_info = -{ - "Symbian Sound Device (APS)", - 1, - 1, - 8000 -}; - -/* App UID to open global APS queues to communicate with the APS server. */ -extern TPtrC APP_UID; - -/* Default setting for loudspeaker */ -static pj_bool_t act_loudspeaker = PJ_FALSE; - -/* Forward declaration of CPjAudioEngine */ -class CPjAudioEngine; - -/* - * PJMEDIA Sound Stream instance - */ -struct pjmedia_snd_stream -{ - // Pool - pj_pool_t *pool; - - // Common settings. - pjmedia_dir dir; - unsigned clock_rate; - unsigned channel_count; - unsigned samples_per_frame; - - // Audio engine - CPjAudioEngine *engine; -}; - -static pj_pool_factory *snd_pool_factory; - - -/* - * 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)); -} - -////////////////////////////////////////////////////////////////////////////// -// - -/** - * Abstract class for handler of callbacks from APS client. - */ -class MQueueHandlerObserver -{ -public: - virtual void InputStreamInitialized(const TInt aStatus) = 0; - virtual void OutputStreamInitialized(const TInt aStatus) = 0; - virtual void NotifyError(const TInt aError) = 0; - - virtual void RecCb(TAPSCommBuffer &buffer) = 0; - virtual void PlayCb(TAPSCommBuffer &buffer) = 0; -}; - -/** - * Handler for communication and data queue. - */ -class CQueueHandler : public CActive -{ -public: - // Types of queue handler - enum TQueueHandlerType { - ERecordCommQueue, - EPlayCommQueue, - ERecordQueue, - EPlayQueue - }; - - // The order corresponds to the APS Server state, do not change! - enum TState { - EAPSPlayerInitialize = 1, - EAPSRecorderInitialize = 2, - EAPSPlayData = 3, - EAPSRecordData = 4, - EAPSPlayerInitComplete = 5, - EAPSRecorderInitComplete = 6 - }; - - static CQueueHandler* NewL(MQueueHandlerObserver* aObserver, - RMsgQueue<TAPSCommBuffer>* aQ, - TQueueHandlerType aType) - { - CQueueHandler* self = new (ELeave) CQueueHandler(aObserver, aQ, aType); - CleanupStack::PushL(self); - self->ConstructL(); - CleanupStack::Pop(self); - return self; - } - - // Destructor - ~CQueueHandler() { Cancel(); } - - // Start listening queue event - void Start() { - iQ->NotifyDataAvailable(iStatus); - SetActive(); - } - -private: - // Constructor - CQueueHandler(MQueueHandlerObserver* aObserver, - RMsgQueue<TAPSCommBuffer>* aQ, - TQueueHandlerType aType) - : CActive(CActive::EPriorityHigh), - iQ(aQ), iObserver(aObserver), iType(aType) - { - CActiveScheduler::Add(this); - - // use lower priority for comm queues - if ((iType == ERecordCommQueue) || (iType == EPlayCommQueue)) - SetPriority(CActive::EPriorityStandard); - } - - // Second phase constructor - void ConstructL() {} - - // Inherited from CActive - void DoCancel() { iQ->CancelDataAvailable(); } - - void RunL() { - if (iStatus != KErrNone) { - iObserver->NotifyError(iStatus.Int()); - return; - } - - TAPSCommBuffer buffer; - TInt ret = iQ->Receive(buffer); - - if (ret != KErrNone) { - iObserver->NotifyError(ret); - return; - } - - switch (iType) { - case ERecordQueue: - if (buffer.iCommand == EAPSRecordData) { - iObserver->RecCb(buffer); - } - break; - - // Callbacks from the APS main thread - case EPlayCommQueue: - switch (buffer.iCommand) { - case EAPSPlayData: - if (buffer.iStatus == KErrUnderflow) { - iObserver->PlayCb(buffer); - } - break; - case EAPSPlayerInitialize: - iObserver->NotifyError(buffer.iStatus); - break; - case EAPSPlayerInitComplete: - iObserver->OutputStreamInitialized(buffer.iStatus); - break; - case EAPSRecorderInitComplete: - iObserver->InputStreamInitialized(buffer.iStatus); - break; - default: - iObserver->NotifyError(buffer.iStatus); - break; - } - break; - - // Callbacks from the APS recorder thread - case ERecordCommQueue: - switch (buffer.iCommand) { - // The APS recorder thread will only report errors - // through this handler. All other callbacks will be - // sent from the APS main thread through EPlayCommQueue - case EAPSRecorderInitialize: - if (buffer.iStatus == KErrNone) { - iObserver->InputStreamInitialized(buffer.iStatus); - break; - } - case EAPSRecordData: - iObserver->NotifyError(buffer.iStatus); - break; - default: - break; - } - break; - - default: - break; - } - - // issue next request - iQ->NotifyDataAvailable(iStatus); - SetActive(); - } - - // Data - RMsgQueue<TAPSCommBuffer> *iQ; // (not owned) - MQueueHandlerObserver *iObserver; // (not owned) - TQueueHandlerType iType; -}; - - -/* - * Implementation: Symbian Input & Output Stream. - */ -class CPjAudioEngine : public CBase, MQueueHandlerObserver -{ -public: - enum State - { - STATE_NULL, - STATE_READY, - STATE_STREAMING - }; - - ~CPjAudioEngine(); - - static CPjAudioEngine *NewL(pjmedia_snd_stream *parent_strm, - pjmedia_snd_rec_cb rec_cb, - pjmedia_snd_play_cb play_cb, - void *user_data); - - TInt StartL(); - void Stop(); - - TInt ActivateSpeaker(TBool active); - -private: - CPjAudioEngine(pjmedia_snd_stream *parent_strm, - pjmedia_snd_rec_cb rec_cb, - pjmedia_snd_play_cb play_cb, - void *user_data); - void ConstructL(); - - TInt InitPlayL(); - TInt InitRecL(); - TInt StartStreamL(); - - // Inherited from MQueueHandlerObserver - virtual void InputStreamInitialized(const TInt aStatus); - virtual void OutputStreamInitialized(const TInt aStatus); - virtual void NotifyError(const TInt aError); - - virtual void RecCb(TAPSCommBuffer &buffer); - virtual void PlayCb(TAPSCommBuffer &buffer); - - State state_; - pjmedia_snd_stream *parentStrm_; - pjmedia_snd_rec_cb recCb_; - pjmedia_snd_play_cb playCb_; - void *userData_; - pj_uint32_t TsPlay_; - pj_uint32_t TsRec_; - - RAPSSession iSession; - TAPSInitSettings iSettings; - RMsgQueue<TAPSCommBuffer> iReadQ; - RMsgQueue<TAPSCommBuffer> iReadCommQ; - RMsgQueue<TAPSCommBuffer> iWriteQ; - RMsgQueue<TAPSCommBuffer> iWriteCommQ; - - CQueueHandler *iPlayCommHandler; - CQueueHandler *iRecCommHandler; - CQueueHandler *iRecHandler; - - static pj_uint8_t aps_samples_per_frame; - - pj_int16_t *play_buf; - pj_uint16_t play_buf_len; - pj_uint16_t play_buf_start; - pj_int16_t *rec_buf; - pj_uint16_t rec_buf_len; -}; - - -pj_uint8_t CPjAudioEngine::aps_samples_per_frame = 0; - - -CPjAudioEngine* CPjAudioEngine::NewL(pjmedia_snd_stream *parent_strm, - pjmedia_snd_rec_cb rec_cb, - pjmedia_snd_play_cb play_cb, - void *user_data) -{ - CPjAudioEngine* self = new (ELeave) CPjAudioEngine(parent_strm, - rec_cb, play_cb, - user_data); - CleanupStack::PushL(self); - self->ConstructL(); - CleanupStack::Pop(self); - return self; -} - -CPjAudioEngine::CPjAudioEngine(pjmedia_snd_stream *parent_strm, - pjmedia_snd_rec_cb rec_cb, - pjmedia_snd_play_cb play_cb, - void *user_data) - : state_(STATE_NULL), - parentStrm_(parent_strm), - recCb_(rec_cb), - playCb_(play_cb), - userData_(user_data), - iPlayCommHandler(0), - iRecCommHandler(0), - iRecHandler(0) -{ -} - -CPjAudioEngine::~CPjAudioEngine() -{ - Stop(); - - delete iPlayCommHandler; - iPlayCommHandler = NULL; - delete iRecCommHandler; - iRecCommHandler = NULL; - - // On some devices, immediate closing after stopping may cause APS server - // panic KERN-EXEC 0, so let's wait for sometime before really closing - // the client session. - TTime start, now; - enum { APS_CLOSE_WAIT_TIME = 200 }; /* in msecs */ - - start.UniversalTime(); - do { - pj_symbianos_poll(-1, APS_CLOSE_WAIT_TIME); - now.UniversalTime(); - } while (now.MicroSecondsFrom(start) < APS_CLOSE_WAIT_TIME * 1000); - - iSession.Close(); - - if (state_ == STATE_READY) { - if (parentStrm_->dir != PJMEDIA_DIR_PLAYBACK) { - iReadQ.Close(); - iReadCommQ.Close(); - } - iWriteQ.Close(); - iWriteCommQ.Close(); - } -} - -TInt CPjAudioEngine::InitPlayL() -{ - if (state_ == STATE_STREAMING || state_ == STATE_READY) - return 0; - - TInt err = iSession.InitializePlayer(iSettings); - if (err != KErrNone) { - snd_perror("Failed to initialize player", err); - return err; - } - - // Open message queues for the output stream - TBuf<128> buf2 = iSettings.iGlobal; - buf2.Append(_L("PlayQueue")); - TBuf<128> buf3 = iSettings.iGlobal; - buf3.Append(_L("PlayCommQueue")); - - while (iWriteQ.OpenGlobal(buf2)) - User::After(10); - while (iWriteCommQ.OpenGlobal(buf3)) - User::After(10); - - // Construct message queue handler - iPlayCommHandler = CQueueHandler::NewL(this, - &iWriteCommQ, - CQueueHandler::EPlayCommQueue); - - // Start observing APS callbacks on output stream message queue - iPlayCommHandler->Start(); - - return 0; -} - -TInt CPjAudioEngine::InitRecL() -{ - if (state_ == STATE_STREAMING || state_ == STATE_READY) - return 0; - - // Initialize input stream device - TInt err = iSession.InitializeRecorder(iSettings); - if (err != KErrNone) { - snd_perror("Failed to initialize recorder", err); - return err; - } - - TBuf<128> buf1 = iSettings.iGlobal; - buf1.Append(_L("RecordQueue")); - TBuf<128> buf4 = iSettings.iGlobal; - buf4.Append(_L("RecordCommQueue")); - - // Must wait for APS thread to finish creating message queues - // before we can open and use them. - while (iReadQ.OpenGlobal(buf1)) - User::After(10); - while (iReadCommQ.OpenGlobal(buf4)) - User::After(10); - - // Construct message queue handlers - iRecCommHandler = CQueueHandler::NewL(this, - &iReadCommQ, - CQueueHandler::ERecordCommQueue); - - // Start observing APS callbacks from on input stream message queue - iRecCommHandler->Start(); - - return 0; -} - -TInt CPjAudioEngine::StartL() -{ - TInt err = iSession.Connect(); - if (err != KErrNone && err != KErrAlreadyExists) - return err; - - if (state_ == STATE_READY) - return StartStreamL(); - - // Even if only capturer are opened, playback thread of APS Server need - // to be run(?). Since some messages will be delivered via play comm queue. - return InitPlayL(); -} - -void CPjAudioEngine::Stop() -{ - iSession.Stop(); - - delete iRecHandler; - iRecHandler = NULL; - - state_ = STATE_READY; -} - -void CPjAudioEngine::ConstructL() -{ - iSettings.iFourCC = TFourCC(KMCPFourCCIdG711); - iSettings.iGlobal = APP_UID; - iSettings.iPriority = TMdaPriority(100); - iSettings.iPreference = TMdaPriorityPreference(0x05210001); - iSettings.iSettings.iChannels = EMMFMono; - iSettings.iSettings.iSampleRate = EMMFSampleRate8000Hz; - iSettings.iSettings.iVolume = 0; - - /* play_buf size is samples per frame of parent stream. */ - play_buf = (pj_int16_t*)pj_pool_alloc(parentStrm_->pool, - parentStrm_->samples_per_frame << 1); - play_buf_len = 0; - play_buf_start = 0; - - /* rec_buf size is samples per frame of parent stream. */ - rec_buf = (pj_int16_t*)pj_pool_alloc(parentStrm_->pool, - parentStrm_->samples_per_frame << 1); - rec_buf_len = 0; -} - -TInt CPjAudioEngine::StartStreamL() -{ - if (state_ == STATE_STREAMING) - return 0; - - iSession.SetCng(EFalse); - iSession.SetVadMode(EFalse); - iSession.SetPlc(EFalse); - iSession.SetEncoderMode(EULawOr30ms); - iSession.SetDecoderMode(EULawOr30ms); - iSession.ActivateLoudspeaker(act_loudspeaker); - - // Not only playback - if (parentStrm_->dir != PJMEDIA_DIR_PLAYBACK) { - iRecHandler = CQueueHandler::NewL(this, &iReadQ, - CQueueHandler::ERecordQueue); - iRecHandler->Start(); - iSession.Read(); - TRACE_((THIS_FILE, "APS recorder started")); - } - - // Not only capture - if (parentStrm_->dir != PJMEDIA_DIR_CAPTURE) { - iSession.Write(); - TRACE_((THIS_FILE, "APS player started")); - } - - state_ = STATE_STREAMING; - return 0; -} - -/////////////////////////////////////////////////////////// -// Inherited from MQueueHandlerObserver -// - -void CPjAudioEngine::InputStreamInitialized(const TInt aStatus) -{ - TRACE_((THIS_FILE, "InputStreamInitialized %d", aStatus)); - - state_ = STATE_READY; - if (aStatus == KErrNone) { - StartStreamL(); - } -} - -void CPjAudioEngine::OutputStreamInitialized(const TInt aStatus) -{ - TRACE_((THIS_FILE, "OutputStreamInitialized %d", aStatus)); - - if (aStatus == KErrNone) { - if (parentStrm_->dir == PJMEDIA_DIR_PLAYBACK) { - state_ = STATE_READY; - // Only playback, start directly - StartStreamL(); - } else - InitRecL(); - } -} - -void CPjAudioEngine::NotifyError(const TInt aError) -{ - snd_perror("Error from CQueueHandler", aError); -} - -void CPjAudioEngine::RecCb(TAPSCommBuffer &buffer) -{ - pj_assert(buffer.iBuffer[0] == 1 && buffer.iBuffer[1] == 0); - - /* Detect the recorder G.711 frame size, player frame size will follow - * this recorder frame size. - */ - if (CPjAudioEngine::aps_samples_per_frame == 0) { - CPjAudioEngine::aps_samples_per_frame = buffer.iBuffer.Length() < 160? - 80 : 160; - TRACE_((THIS_FILE, "Detected APS G.711 frame size = %u samples", - CPjAudioEngine::aps_samples_per_frame)); - } - - /* Decode APS buffer (coded in G.711) and put the PCM result into rec_buf. - * Whenever rec_buf is full, call parent stream callback. - */ - unsigned dec_len = 0; - - while (dec_len < CPjAudioEngine::aps_samples_per_frame) { - unsigned tmp; - - tmp = PJ_MIN(parentStrm_->samples_per_frame - rec_buf_len, - CPjAudioEngine::aps_samples_per_frame - dec_len); - pjmedia_ulaw_decode(&rec_buf[rec_buf_len], - buffer.iBuffer.Ptr() + 2 + dec_len, - tmp); - rec_buf_len += tmp; - dec_len += tmp; - - pj_assert(rec_buf_len <= parentStrm_->samples_per_frame); - - if (rec_buf_len == parentStrm_->samples_per_frame) { - recCb_(userData_, 0, rec_buf, rec_buf_len << 1); - rec_buf_len = 0; - } - } -} - -void CPjAudioEngine::PlayCb(TAPSCommBuffer &buffer) -{ - buffer.iCommand = CQueueHandler::EAPSPlayData; - buffer.iStatus = 0; - buffer.iBuffer.Zero(); - buffer.iBuffer.Append(1); - buffer.iBuffer.Append(0); - - /* Send 10ms silence frame if frame size hasn't been known. */ - if (CPjAudioEngine::aps_samples_per_frame == 0) { - pjmedia_zero_samples(play_buf, 80); - pjmedia_ulaw_encode((pj_uint8_t*)play_buf, play_buf, 80); - buffer.iBuffer.Append((TUint8*)play_buf, 80); - iWriteQ.Send(buffer); - return; - } - - unsigned enc_len = 0; - - /* Call parent stream callback to get PCM samples to play, - * encode the PCM samples into G.711 and put it into APS buffer. - */ - while (enc_len < CPjAudioEngine::aps_samples_per_frame) { - if (play_buf_len == 0) { - playCb_(userData_, 0, play_buf, parentStrm_->samples_per_frame<<1); - play_buf_len = parentStrm_->samples_per_frame; - play_buf_start = 0; - } - - unsigned tmp; - - tmp = PJ_MIN(play_buf_len, - CPjAudioEngine::aps_samples_per_frame - enc_len); - pjmedia_ulaw_encode((pj_uint8_t*)&play_buf[play_buf_start], - &play_buf[play_buf_start], - tmp); - buffer.iBuffer.Append((TUint8*)&play_buf[play_buf_start], tmp); - enc_len += tmp; - play_buf_len -= tmp; - play_buf_start += tmp; - } - - iWriteQ.Send(buffer); -} - -// -// End of inherited from MQueueHandlerObserver -///////////////////////////////////////////////////////////// - - -TInt CPjAudioEngine::ActivateSpeaker(TBool active) -{ - if (state_ == STATE_READY || state_ == STATE_STREAMING) { - iSession.ActivateLoudspeaker(active); - return KErrNone; - } - return KErrNotReady; -} -////////////////////////////////////////////////////////////////////////////// -// - - -/* - * Initialize sound subsystem. - */ -PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory) -{ - snd_pool_factory = factory; - return PJ_SUCCESS; -} - -/* - * Get device count. - */ -PJ_DEF(int) pjmedia_snd_get_dev_count(void) -{ - /* Always return 1 */ - return 1; -} - -/* - * Get device info. - */ -PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index) -{ - /* Always return the default sound device */ - if (index == (unsigned)-1) - index = 0; - - PJ_ASSERT_RETURN(index==0, NULL); - return &symbian_snd_dev_info; -} - -static pj_status_t sound_open(pjmedia_dir dir, - unsigned clock_rate, - unsigned channel_count, - unsigned samples_per_frame, - unsigned bits_per_sample, - pjmedia_snd_rec_cb rec_cb, - pjmedia_snd_play_cb play_cb, - void *user_data, - pjmedia_snd_stream **p_snd_strm) -{ - pj_pool_t *pool; - pjmedia_snd_stream *strm; - - PJ_ASSERT_RETURN(p_snd_strm, PJ_EINVAL); - PJ_ASSERT_RETURN(clock_rate == 8000 && channel_count == 1 && - bits_per_sample == 16, PJ_ENOTSUP); - PJ_ASSERT_RETURN((dir == PJMEDIA_DIR_CAPTURE_PLAYBACK && rec_cb && play_cb) - || (dir == PJMEDIA_DIR_CAPTURE && rec_cb && !play_cb) - || (dir == PJMEDIA_DIR_PLAYBACK && !rec_cb && play_cb), - PJ_EINVAL); - - pool = pj_pool_create(snd_pool_factory, POOL_NAME, POOL_SIZE, POOL_INC, - NULL); - if (!pool) - return PJ_ENOMEM; - - strm = (pjmedia_snd_stream*) pj_pool_zalloc(pool, - sizeof(pjmedia_snd_stream)); - strm->dir = dir; - strm->pool = pool; - strm->clock_rate = clock_rate; - strm->channel_count = channel_count; - strm->samples_per_frame = samples_per_frame; - - // Create the audio engine. - TRAPD(err, strm->engine = CPjAudioEngine::NewL(strm, rec_cb, play_cb, - user_data)); - if (err != KErrNone) { - pj_pool_release(pool); - return PJ_RETURN_OS_ERROR(err); - } - - // Done. - *p_snd_strm = strm; - return PJ_SUCCESS; -} - - - -/* - * Open sound recorder stream. - */ -PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index, - unsigned clock_rate, - unsigned channel_count, - unsigned samples_per_frame, - unsigned bits_per_sample, - pjmedia_snd_rec_cb rec_cb, - void *user_data, - pjmedia_snd_stream **p_snd_strm) -{ - if (index < 0) index = 0; - PJ_ASSERT_RETURN(index == 0, PJ_EINVAL); - - return sound_open(PJMEDIA_DIR_CAPTURE, clock_rate, channel_count, - samples_per_frame, bits_per_sample, rec_cb, NULL, - user_data, p_snd_strm); -} - -PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index, - unsigned clock_rate, - unsigned channel_count, - unsigned samples_per_frame, - unsigned bits_per_sample, - pjmedia_snd_play_cb play_cb, - void *user_data, - pjmedia_snd_stream **p_snd_strm ) -{ - if (index < 0) index = 0; - PJ_ASSERT_RETURN(index == 0, PJ_EINVAL); - - return sound_open(PJMEDIA_DIR_PLAYBACK, clock_rate, channel_count, - samples_per_frame, bits_per_sample, NULL, play_cb, - user_data, p_snd_strm); -} - -PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id, - int play_id, - unsigned clock_rate, - unsigned channel_count, - unsigned samples_per_frame, - unsigned bits_per_sample, - pjmedia_snd_rec_cb rec_cb, - pjmedia_snd_play_cb play_cb, - void *user_data, - pjmedia_snd_stream **p_snd_strm) -{ - if (rec_id < 0) rec_id = 0; - if (play_id < 0) play_id = 0; - PJ_ASSERT_RETURN(play_id == 0 && rec_id == 0, PJ_EINVAL); - - return sound_open(PJMEDIA_DIR_CAPTURE_PLAYBACK, clock_rate, channel_count, - samples_per_frame, bits_per_sample, rec_cb, play_cb, - user_data, p_snd_strm); -} - -/* - * Get stream info. - */ -PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm, - pjmedia_snd_stream_info *pi) -{ - PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL); - - pj_bzero(pi, sizeof(*pi)); - pi->dir = strm->dir; - pi->play_id = 0; - pi->rec_id = 0; - pi->clock_rate = strm->clock_rate; - pi->channel_count = strm->channel_count; - pi->samples_per_frame = strm->samples_per_frame; - pi->bits_per_sample = BYTES_PER_SAMPLE * 8; - // latencies approximation (in samples) - pi->rec_latency = strm->samples_per_frame * 2; - pi->play_latency = strm->samples_per_frame * 2; - - return PJ_SUCCESS; -} - - -PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream) -{ - PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); - - if (stream->engine) { - TInt err = stream->engine->StartL(); - if (err != KErrNone) - return PJ_RETURN_OS_ERROR(err); - } - - return PJ_SUCCESS; -} - - -PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream) -{ - PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); - - if (stream->engine) { - stream->engine->Stop(); - } - - return PJ_SUCCESS; -} - - -PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream) -{ - pj_pool_t *pool; - - PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); - - if (stream->engine) { - delete stream->engine; - stream->engine = NULL; - } - - pool = stream->pool; - if (pool) { - stream->pool = NULL; - pj_pool_release(pool); - } - - return PJ_SUCCESS; -} - - -PJ_DEF(pj_status_t) pjmedia_snd_deinit(void) -{ - /* Nothing to do */ - return PJ_SUCCESS; -} - - -/* - * Set sound latency. - */ -PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency, - unsigned output_latency) -{ - /* Nothing to do */ - PJ_UNUSED_ARG(input_latency); - PJ_UNUSED_ARG(output_latency); - return PJ_SUCCESS; -} - - -/* - * Activate/deactivate loudspeaker. - */ -PJ_DEF(pj_status_t) pjmedia_snd_aps_activate_loudspeaker( - pjmedia_snd_stream *stream, - pj_bool_t active) -{ - if (stream == NULL) { - act_loudspeaker = active; - } else { - if (stream->engine == NULL) - return PJ_EINVAL; - - TInt err = stream->engine->ActivateSpeaker(active); - if (err != KErrNone) - return PJ_RETURN_OS_ERROR(err); - } - - return PJ_SUCCESS; -} |