diff options
author | Benny Prijono <bennylp@teluu.com> | 2007-08-31 15:04:52 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2007-08-31 15:04:52 +0000 |
commit | b2ce067a55ee3eab4b80e48b3e83eefc02b8ade6 (patch) | |
tree | aa428fefd97ce7bd17f5ecc0078809d1750c77aa | |
parent | 73fb6a5d604c925429aff2a618b8acc74f0cf702 (diff) |
Continuing ticket #2: initial test with Symbian sound device implementation. Callback works, but not in full duplex
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1428 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r-- | build.symbian/symsndtest.mmp | 26 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/symbian_sound.cpp | 200 | ||||
-rw-r--r-- | pjsip-apps/src/symsndtest/app_main.cpp | 338 | ||||
-rw-r--r-- | pjsip-apps/src/symsndtest/main_symbian.cpp | 153 |
4 files changed, 614 insertions, 103 deletions
diff --git a/build.symbian/symsndtest.mmp b/build.symbian/symsndtest.mmp new file mode 100644 index 00000000..ad659f9f --- /dev/null +++ b/build.symbian/symsndtest.mmp @@ -0,0 +1,26 @@ +TARGET symsndtest.exe +TARGETTYPE exe +UID 0x100039CE 0x10004287 +VENDORID 0x70000001 + +SOURCEPATH ..\pjsip-apps\src\symsndtest + +MACRO PJ_M_I386=1 +MACRO PJ_SYMBIAN=1 +MACRO PJ_DLL=1 + +// Test files + +SOURCE app_main.cpp +SOURCE main_symbian.cpp + +SYSTEMINCLUDE ..\pjlib\include +SYSTEMINCLUDE ..\pjmedia\include + +SYSTEMINCLUDE \epoc32\include +SYSTEMINCLUDE \epoc32\include\libc + +LIBRARY charconv.lib euser.lib estlib.lib eexe.lib +LIBRARY symbian_audio.lib pjlib.lib ecrt0.lib +CAPABILITY None + diff --git a/pjmedia/src/pjmedia/symbian_sound.cpp b/pjmedia/src/pjmedia/symbian_sound.cpp index c2db57b5..ee49f487 100644 --- a/pjmedia/src/pjmedia/symbian_sound.cpp +++ b/pjmedia/src/pjmedia/symbian_sound.cpp @@ -115,13 +115,21 @@ static TInt get_channel_cap(unsigned channel_count) } +/* + * 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 MMdaAudioInputStreamCallback +class CPjAudioInputEngine : public CBase, MMdaAudioInputStreamCallback { public: enum State @@ -143,7 +151,7 @@ public: pj_status_t StartRecord(); void Stop(); -public: +private: State state_; pjmedia_snd_stream *parentStrm_; pjmedia_snd_rec_cb recCb_; @@ -158,6 +166,7 @@ public: pjmedia_snd_rec_cb rec_cb, void *user_data); void ConstructL(); + TPtr8 & GetFrame(); public: virtual void MaiscOpenComplete(TInt aError); @@ -171,7 +180,7 @@ CPjAudioInputEngine::CPjAudioInputEngine(pjmedia_snd_stream *parent_strm, pjmedia_snd_rec_cb rec_cb, void *user_data) : state_(STATE_INACTIVE), parentStrm_(parent_strm), recCb_(rec_cb), - iInputStream_(NULL), iStreamBuffer_(NULL), iFramePtr_(NULL, 0), + iInputStream_(NULL), iStreamBuffer_(NULL), iFramePtr_(0, 0), userData_(user_data), lastError_(KErrNone), timeStamp_(0) { } @@ -180,13 +189,14 @@ CPjAudioInputEngine::~CPjAudioInputEngine() { Stop(); delete iStreamBuffer_; + iStreamBuffer_ = NULL; } void CPjAudioInputEngine::ConstructL() { - iStreamBuffer_ = HBufC8::NewMaxL(parentStrm_->samples_per_frame * - parentStrm_->channel_count * - BYTES_PER_SAMPLE); + iStreamBuffer_ = HBufC8::NewL(parentStrm_->samples_per_frame * + parentStrm_->channel_count * + BYTES_PER_SAMPLE); } CPjAudioInputEngine *CPjAudioInputEngine::NewLC(pjmedia_snd_stream *parent, @@ -241,18 +251,6 @@ pj_status_t CPjAudioInputEngine::StartRecord() pj_assert(iStreamSettings.iChannels != 0 && iStreamSettings.iSampleRate != 0); - // Create timeout timer to wait for Open to complete - RTimer timer; - TRequestStatus reqStatus; - TInt rc; - - rc = timer.CreateLocal(); - if (rc != KErrNone) { - delete iInputStream_; - iInputStream_ = NULL; - return PJ_RETURN_OS_ERROR(rc); - } - PJ_LOG(4,(THIS_FILE, "Opening sound device for capture, " "clock rate=%d, channel count=%d..", parentStrm_->clock_rate, @@ -261,40 +259,7 @@ pj_status_t CPjAudioInputEngine::StartRecord() // Open stream. lastError_ = KRequestPending; iInputStream_->Open(&iStreamSettings); - - // Wait until callback is called. - if (lastError_ == KRequestPending) { - timer.After(reqStatus, 5 * 1000 * 1000); - - do { - User::WaitForAnyRequest(); - } while (lastError_==KRequestPending && reqStatus==KRequestPending); - - if (reqStatus==KRequestPending) - timer.Cancel(); - } - - // Close timer - timer.Close(); - // Handle timeout - if (lastError_ == KRequestPending) { - iInputStream_->Stop(); - delete iInputStream_; - iInputStream_ = NULL; - return PJ_ETIMEDOUT; - } - else if (lastError_ != KErrNone) { - // Handle failure. - delete iInputStream_; - iInputStream_ = NULL; - return PJ_RETURN_OS_ERROR(lastError_); - } - - // Feed the first frame. - iFramePtr_ = iStreamBuffer_->Des(); - iInputStream_->ReadL(iFramePtr_); - // Success PJ_LOG(4,(THIS_FILE, "Sound capture started.")); return PJ_SUCCESS; @@ -322,17 +287,44 @@ void CPjAudioInputEngine::Stop() } +TPtr8 & CPjAudioInputEngine::GetFrame() +{ + TInt l = parentStrm_->samples_per_frame * + parentStrm_->channel_count * + BYTES_PER_SAMPLE; + iStreamBuffer_->Des().FillZ(l); + iFramePtr_.Set((TUint8*)(iStreamBuffer_->Ptr()), l, l); + return iFramePtr_; +} + void CPjAudioInputEngine::MaiscOpenComplete(TInt aError) { lastError_ = aError; + if (aError != KErrNone) { + snd_perror("Error in MaiscOpenComplete()", aError); + return; + } + + // 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()")); + } } void CPjAudioInputEngine::MaiscBufferCopied(TInt aError, const TDesC8 &aBuffer) { lastError_ = aError; - if (aError != KErrNone) + if (aError != KErrNone) { + snd_perror("Error in MaiscBufferCopied()", aError); return; + } // Call the callback. recCb_(userData_, timeStamp_, (void*)aBuffer.Ptr(), aBuffer.Size()); @@ -341,8 +333,11 @@ void CPjAudioInputEngine::MaiscBufferCopied(TInt aError, timeStamp_ += (aBuffer.Size() * BYTES_PER_SAMPLE); // Record next frame - iFramePtr_ = iStreamBuffer_->Des(); - iInputStream_->ReadL(iFramePtr_); + TPtr8 & frm = GetFrame(); + TRAPD(err2, iInputStream_->ReadL(frm)); + if (err2) { + PJ_LOG(4,(THIS_FILE, "Exception in iInputStream_->ReadL()")); + } } @@ -350,6 +345,9 @@ void CPjAudioInputEngine::MaiscRecordComplete(TInt aError) { lastError_ = aError; state_ = STATE_INACTIVE; + if (aError != KErrNone) { + snd_perror("Error in MaiscRecordComplete()", aError); + } } @@ -361,7 +359,7 @@ void CPjAudioInputEngine::MaiscRecordComplete(TInt aError) * Implementation: Symbian Output Stream. */ -class CPjAudioOutputEngine : public MMdaAudioOutputStreamCallback +class CPjAudioOutputEngine : public CBase, MMdaAudioOutputStreamCallback { public: enum State @@ -383,7 +381,7 @@ public: pj_status_t StartPlay(); void Stop(); -public: +private: State state_; pjmedia_snd_stream *parentStrm_; pjmedia_snd_play_cb playCb_; @@ -391,6 +389,7 @@ public: CMdaAudioOutputStream *iOutputStream_; TUint8 *frameBuf_; unsigned frameBufSize_; + TPtrC8 frame_; TInt lastError_; unsigned timestamp_; @@ -479,22 +478,11 @@ pj_status_t CPjAudioOutputEngine::StartPlay() "clock rate=%d, channel count=%d..", parentStrm_->clock_rate, parentStrm_->channel_count)); - + // Open stream. lastError_ = KRequestPending; iOutputStream_->Open(&iStreamSettings); - // Wait until callback is called. - while (lastError_ == KRequestPending) - pj_thread_sleep(100); - - // Handle failure. - if (lastError_ != KErrNone) { - delete iOutputStream_; - iOutputStream_ = NULL; - return PJ_RETURN_OS_ERROR(lastError_); - } - // Success PJ_LOG(4,(THIS_FILE, "Sound playback started")); return PJ_SUCCESS; @@ -560,9 +548,11 @@ void CPjAudioOutputEngine::MaoscOpenComplete(TInt aError) // subsequent calls to WriteL() will be issued in // MMdaAudioOutputStreamCallback::MaoscBufferCopied() // until whole data buffer is written. - TPtrC8 frame(frameBuf_, frameBufSize_); - iOutputStream_->WriteL(frame); - } + frame_.Set(frameBuf_, frameBufSize_); + iOutputStream_->WriteL(frame_); + } else { + snd_perror("Error in MaoscOpenComplete()", aError); + } } void CPjAudioOutputEngine::MaoscBufferCopied(TInt aError, @@ -586,8 +576,8 @@ void CPjAudioOutputEngine::MaoscBufferCopied(TInt aError, timestamp_ += (frameBufSize_ / BYTES_PER_SAMPLE); // Write to playback stream. - TPtrC8 frame(frameBuf_, frameBufSize_); - iOutputStream_->WriteL(frame); + frame_.Set(frameBuf_, frameBufSize_); + iOutputStream_->WriteL(frame_); } else if (aError==KErrAbort) { // playing was aborted, due to call to CMdaAudioOutputStream::Stop() @@ -596,6 +586,7 @@ void CPjAudioOutputEngine::MaoscBufferCopied(TInt aError, // error writing data to output lastError_ = aError; state_ = STATE_INACTIVE; + snd_perror("Error in MaoscBufferCopied()", aError); } } @@ -603,6 +594,9 @@ void CPjAudioOutputEngine::MaoscPlayComplete(TInt aError) { lastError_ = aError; state_ = STATE_INACTIVE; + if (aError != KErrNone) { + snd_perror("Error in MaoscPlayComplete()", aError); + } } @@ -655,6 +649,8 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index, pj_pool_t *pool; pjmedia_snd_stream *strm; + if (index==-1) index = 0; + PJ_ASSERT_RETURN(index == 0, PJ_EINVAL); PJ_ASSERT_RETURN(clock_rate && channel_count && samples_per_frame && bits_per_sample && rec_cb && p_snd_strm, PJ_EINVAL); @@ -671,15 +667,9 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index, strm->channel_count = channel_count; strm->samples_per_frame = samples_per_frame; - TMdaAudioDataSettings settings; - TInt clockRateCap, channelCountCap; - - clockRateCap = get_clock_rate_cap(clock_rate); - channelCountCap = get_channel_cap(channel_count); - PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL); - PJ_ASSERT_RETURN(clockRateCap != 0, PJ_EINVAL); - PJ_ASSERT_RETURN(channelCountCap != 0, PJ_EINVAL); + PJ_ASSERT_RETURN(get_clock_rate_cap(clock_rate) != 0, PJ_EINVAL); + PJ_ASSERT_RETURN(get_channel_cap(channel_count) != 0, PJ_EINVAL); // Create the input stream. TRAPD(err, strm->inEngine = CPjAudioInputEngine::NewL(strm, rec_cb, @@ -707,6 +697,8 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index, pj_pool_t *pool; pjmedia_snd_stream *strm; + if (index == -1) index = 0; + PJ_ASSERT_RETURN(index == 0, PJ_EINVAL); PJ_ASSERT_RETURN(clock_rate && channel_count && samples_per_frame && bits_per_sample && play_cb && p_snd_strm, PJ_EINVAL); @@ -723,15 +715,9 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index, strm->channel_count = channel_count; strm->samples_per_frame = samples_per_frame; - TMdaAudioDataSettings settings; - TInt clockRateCap, channelCountCap; - - clockRateCap = get_clock_rate_cap(clock_rate); - channelCountCap = get_channel_cap(channel_count); - PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL); - PJ_ASSERT_RETURN(clockRateCap != 0, PJ_EINVAL); - PJ_ASSERT_RETURN(channelCountCap != 0, PJ_EINVAL); + PJ_ASSERT_RETURN(get_clock_rate_cap(clock_rate) != 0, PJ_EINVAL); + PJ_ASSERT_RETURN(get_channel_cap(channel_count) != 0, PJ_EINVAL); // Create the output stream. TRAPD(err, strm->outEngine = CPjAudioOutputEngine::NewL(strm, play_cb, @@ -760,6 +746,9 @@ PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id, pj_pool_t *pool; pjmedia_snd_stream *strm; + if (rec_id == -1) rec_id = 0; + if (play_id == -1) play_id = 0; + PJ_ASSERT_RETURN(rec_id == 0 && play_id == 0, PJ_EINVAL); PJ_ASSERT_RETURN(clock_rate && channel_count && samples_per_frame && bits_per_sample && rec_cb && play_cb && p_snd_strm, @@ -777,15 +766,9 @@ PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id, strm->channel_count = channel_count; strm->samples_per_frame = samples_per_frame; - TMdaAudioDataSettings settings; - TInt clockRateCap, channelCountCap; - - clockRateCap = get_clock_rate_cap(clock_rate); - channelCountCap = get_channel_cap(channel_count); - PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL); - PJ_ASSERT_RETURN(clockRateCap != 0, PJ_EINVAL); - PJ_ASSERT_RETURN(channelCountCap != 0, PJ_EINVAL); + PJ_ASSERT_RETURN(get_clock_rate_cap(clock_rate) != 0, PJ_EINVAL); + PJ_ASSERT_RETURN(get_channel_cap(channel_count) != 0, PJ_EINVAL); // Create the output stream. TRAPD(err, strm->outEngine = CPjAudioOutputEngine::NewL(strm, play_cb, @@ -795,6 +778,17 @@ PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id, return PJ_RETURN_OS_ERROR(err); } + // Create the input stream. + TRAPD(err1, strm->inEngine = CPjAudioInputEngine::NewL(strm, rec_cb, + user_data)); + if (err1 != KErrNone) { + strm->inEngine = NULL; + delete strm->outEngine; + strm->outEngine = NULL; + pj_pool_release(pool); + return PJ_RETURN_OS_ERROR(err1); + } + // Done. *p_snd_strm = strm; return PJ_SUCCESS; @@ -807,18 +801,18 @@ PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream) PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); - if (stream->inEngine) { - status = stream->inEngine->StartRecord(); - if (status != PJ_SUCCESS) - return status; - } - if (stream->outEngine) { status = stream->outEngine->StartPlay(); if (status != PJ_SUCCESS) return status; } + if (stream->inEngine) { + status = stream->inEngine->StartRecord(); + if (status != PJ_SUCCESS) + return status; + } + return PJ_SUCCESS; } diff --git a/pjsip-apps/src/symsndtest/app_main.cpp b/pjsip-apps/src/symsndtest/app_main.cpp new file mode 100644 index 00000000..dcd6ed88 --- /dev/null +++ b/pjsip-apps/src/symsndtest/app_main.cpp @@ -0,0 +1,338 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2007 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 <pj/errno.h> +#include <pj/os.h> +#include <pj/log.h> +#include <pj/string.h> +#include <pj/unicode.h> +#include <e32cons.h> + +#define THIS_FILE "app_main.cpp" +#define CLOCK_RATE 8000 +#define CHANNEL_COUNT 1 +#define PTIME 100 +#define SAMPLES_PER_FRAME (2048) +#define BITS_PER_SAMPLE 16 + + +extern CConsoleBase* console; + +static pj_caching_pool cp; +static pjmedia_snd_stream *strm; +static unsigned rec_cnt, play_cnt; +static pj_time_val t_start; + + +/* Logging callback */ +static void log_writer(int level, const char *buf, unsigned len) +{ + static wchar_t buf16[PJ_LOG_MAX_SIZE]; + + PJ_UNUSED_ARG(level); + + pj_ansi_to_unicode(buf, len, buf16, PJ_ARRAY_SIZE(buf16)); + + TPtrC16 aBuf((const TUint16*)buf16, (TInt)len); + console->Write(aBuf); +} + +/* perror util */ +static void app_perror(const char *title, pj_status_t status) +{ + char errmsg[PJ_ERR_MSG_SIZE]; + pj_strerror(status, errmsg, sizeof(errmsg)); + PJ_LOG(1,(THIS_FILE, "Error: %s: %s", title, errmsg)); +} + +/* Application init */ +static pj_status_t app_init() +{ + unsigned i, count; + pj_status_t status; + + /* Redirect log */ + pj_log_set_log_func((void (*)(int,const char*,int)) &log_writer); + pj_log_set_decor(PJ_LOG_HAS_NEWLINE); + + /* Init pjlib */ + status = pj_init(); + if (status != PJ_SUCCESS) { + app_perror("pj_init()", status); + return status; + } + + pj_caching_pool_init(&cp, NULL, 0); + + /* Init sound subsystem */ + status = pjmedia_snd_init(&cp.factory); + if (status != PJ_SUCCESS) { + app_perror("pjmedia_snd_init()", status); + pj_caching_pool_destroy(&cp); + pj_shutdown(); + return status; + } + + count = pjmedia_snd_get_dev_count(); + PJ_LOG(3,(THIS_FILE, "Device count: %d", count)); + for (i=0; i<count; ++i) { + const pjmedia_snd_dev_info *info; + + info = pjmedia_snd_get_dev_info(i); + PJ_LOG(3, (THIS_FILE, "%d: %s %d/%d %dHz", + i, info->name, info->input_count, info->output_count, + info->default_samples_per_sec)); + } + + return PJ_SUCCESS; +} + + +/* Sound capture callback */ +static pj_status_t rec_cb(void *user_data, + pj_uint32_t timestamp, + void *input, + unsigned size) +{ + PJ_UNUSED_ARG(user_data); + PJ_UNUSED_ARG(timestamp); + PJ_UNUSED_ARG(input); + PJ_UNUSED_ARG(size); + + ++rec_cnt; + return PJ_SUCCESS; +} + +/* Play cb */ +static pj_status_t play_cb(void *user_data, + pj_uint32_t timestamp, + void *output, + unsigned size) +{ + PJ_UNUSED_ARG(user_data); + PJ_UNUSED_ARG(timestamp); + + pj_bzero(output, size); + + ++play_cnt; + return PJ_SUCCESS; +} + +/* Start sound */ +static pj_status_t snd_start(unsigned flag) +{ + pj_status_t status; + + if (strm != NULL) { + app_perror("snd already open", PJ_EINVALIDOP); + return PJ_EINVALIDOP; + } + + if (flag==PJMEDIA_DIR_CAPTURE_PLAYBACK) + status = pjmedia_snd_open(-1, -1, CLOCK_RATE, CHANNEL_COUNT, + SAMPLES_PER_FRAME, BITS_PER_SAMPLE, + &rec_cb, &play_cb, NULL, &strm); + else if (flag==PJMEDIA_DIR_CAPTURE) + status = pjmedia_snd_open_rec(-1, CLOCK_RATE, CHANNEL_COUNT, + SAMPLES_PER_FRAME, BITS_PER_SAMPLE, + &rec_cb, NULL, &strm); + else + status = pjmedia_snd_open_player(-1, CLOCK_RATE, CHANNEL_COUNT, + SAMPLES_PER_FRAME, BITS_PER_SAMPLE, + &play_cb, NULL, &strm); + + if (status != PJ_SUCCESS) { + app_perror("snd open", status); + return status; + } + + rec_cnt = play_cnt = 0; + pj_gettimeofday(&t_start); + + status = pjmedia_snd_stream_start(strm); + if (status != PJ_SUCCESS) { + app_perror("snd start", status); + pjmedia_snd_stream_close(strm); + strm = NULL; + return status; + } + + return PJ_SUCCESS; +} + +/* Stop sound */ +static pj_status_t snd_stop() +{ + pj_time_val now; + pj_status_t status; + + if (strm == NULL) { + app_perror("snd not open", PJ_EINVALIDOP); + return PJ_EINVALIDOP; + } + + status = pjmedia_snd_stream_close(strm); + strm = NULL; + + pj_gettimeofday(&now); + PJ_TIME_VAL_SUB(now, t_start); + + PJ_LOG(3,(THIS_FILE, "Duration: %d.%03d", now.sec, now.msec)); + PJ_LOG(3,(THIS_FILE, "Captured: %d", rec_cnt)); + PJ_LOG(3,(THIS_FILE, "Played: %d", play_cnt)); + + return status; +} + +/* Shutdown application */ +static void app_fini() +{ + if (strm) + snd_stop(); + + pjmedia_snd_deinit(); + pj_caching_pool_destroy(&cp); + pj_shutdown(); +} + + +//////////////////////////////////////////////////////////////////////////// +/* + * The interractive console UI + */ +#include <e32base.h> + +class ConsoleUI : public CActive +{ +public: + ConsoleUI(CActiveSchedulerWait *asw, CConsoleBase *con); + + // Run console UI + void Run(); + + // Stop + void Stop(); + +protected: + // Cancel asynchronous read. + void DoCancel(); + + // Implementation: called when read has completed. + void RunL(); + +private: + CActiveSchedulerWait *asw_; + CConsoleBase *con_; +}; + + +ConsoleUI::ConsoleUI(CActiveSchedulerWait *asw, CConsoleBase *con) +: CActive(EPriorityHigh), asw_(asw), con_(con) +{ + CActiveScheduler::Add(this); +} + +// Run console UI +void ConsoleUI::Run() +{ + con_->Read(iStatus); + SetActive(); +} + +// Stop console UI +void ConsoleUI::Stop() +{ + DoCancel(); +} + +// Cancel asynchronous read. +void ConsoleUI::DoCancel() +{ + con_->ReadCancel(); +} + +static void PrintMenu() +{ + PJ_LOG(3, (THIS_FILE, "\n\n" + "Menu:\n" + " b Start bidir sound\n" + " r Start recorder\n" + " p Start player\n" + " c Stop & close sound\n" + " q Quit\n")); +} + +// Implementation: called when read has completed. +void ConsoleUI::RunL() +{ + TKeyCode kc = con_->KeyCode(); + pj_bool_t reschedule = PJ_TRUE; + + switch (kc) { + case 'q': + asw_->AsyncStop(); + reschedule = PJ_FALSE; + break; + case 'b': + snd_start(PJMEDIA_DIR_CAPTURE_PLAYBACK); + break; + case 'r': + snd_start(PJMEDIA_DIR_CAPTURE); + break; + case 'p': + snd_start(PJMEDIA_DIR_PLAYBACK); + break; + case 'c': + snd_stop(); + break; + default: + PJ_LOG(3,(THIS_FILE, "Keycode '%c' (%d) is pressed", + kc, kc)); + break; + } + + PrintMenu(); + + if (reschedule) + Run(); +} + + +//////////////////////////////////////////////////////////////////////////// +int app_main() +{ + if (app_init() != PJ_SUCCESS) + return -1; + + // Run the UI + CActiveSchedulerWait *asw = new CActiveSchedulerWait; + ConsoleUI *con = new ConsoleUI(asw, console); + + con->Run(); + + PrintMenu(); + asw->Start(); + + delete con; + delete asw; + + app_fini(); + return 0; +} + diff --git a/pjsip-apps/src/symsndtest/main_symbian.cpp b/pjsip-apps/src/symsndtest/main_symbian.cpp new file mode 100644 index 00000000..8c4d8026 --- /dev/null +++ b/pjsip-apps/src/symsndtest/main_symbian.cpp @@ -0,0 +1,153 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2007 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 <e32std.h> +#include <e32base.h> +#include <e32std.h> +#include <e32cons.h> +#include <stdlib.h> + + +// Global Variables +CConsoleBase* console; + +int app_main(); + + +//////////////////////////////////////////////////////////////////////////// +class MyTask : public CActive +{ +public: + static MyTask *NewL(CActiveSchedulerWait *asw); + ~MyTask(); + void Start(); + +protected: + MyTask(CActiveSchedulerWait *asw); + void ConstructL(); + virtual void RunL(); + virtual void DoCancel(); + +private: + RTimer timer_; + CActiveSchedulerWait *asw_; +}; + +MyTask::MyTask(CActiveSchedulerWait *asw) +: CActive(EPriorityNormal), asw_(asw) +{ +} + +MyTask::~MyTask() +{ + timer_.Close(); +} + +void MyTask::ConstructL() +{ + timer_.CreateLocal(); + CActiveScheduler::Add(this); +} + +MyTask *MyTask::NewL(CActiveSchedulerWait *asw) +{ + MyTask *self = new (ELeave) MyTask(asw); + CleanupStack::PushL(self); + + self->ConstructL(); + + CleanupStack::Pop(self); + return self; +} + +void MyTask::Start() +{ + timer_.After(iStatus, 0); + SetActive(); +} + +void MyTask::RunL() +{ + int rc = app_main(); + asw_->AsyncStop(); +} + +void MyTask::DoCancel() +{ + +} + +//////////////////////////////////////////////////////////////////////////// + +LOCAL_C void DoStartL() +{ + CActiveScheduler *scheduler = new (ELeave) CActiveScheduler; + CleanupStack::PushL(scheduler); + CActiveScheduler::Install(scheduler); + + CActiveSchedulerWait *asw = new CActiveSchedulerWait; + CleanupStack::PushL(asw); + + MyTask *task = MyTask::NewL(asw); + task->Start(); + + asw->Start(); + + delete task; + + CleanupStack::Pop(asw); + delete asw; + + CActiveScheduler::Install(NULL); + CleanupStack::Pop(scheduler); + delete scheduler; +} + + +//////////////////////////////////////////////////////////////////////////// + +// E32Main() +GLDEF_C TInt E32Main() +{ + // Mark heap usage + __UHEAP_MARK; + + // Create cleanup stack + CTrapCleanup* cleanup = CTrapCleanup::New(); + + // Create output console + TRAPD(createError, console = Console::NewL(_L("Console"), TSize(KConsFullScreen,KConsFullScreen))); + if (createError) + return createError; + + TRAPD(startError, DoStartL()); + + console->Printf(_L("[press any key to close]\n")); + console->Getch(); + + delete console; + delete cleanup; + + CloseSTDLIB(); + + // Mark end of heap usage, detect memory leaks + __UHEAP_MARKEND; + return KErrNone; +} + |