Ignore:
Timestamp:
Jan 28, 2009 6:03:12 PM (12 years ago)
Author:
nanang
Message:

Initial sources of APS-direct.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/symbian_sound_aps.cpp

    r2418 r2434  
    1818 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
    1919 */ 
     20#include <pjmedia/symbian_sound_aps.h> 
    2021#include <pjmedia/sound.h> 
    2122#include <pjmedia/alaw_ulaw.h> 
     
    2627#include <pj/os.h> 
    2728 
     29#if PJMEDIA_SOUND_IMPLEMENTATION == PJMEDIA_SOUND_SYMB_APS_SOUND 
     30 
    2831#include <e32msgqueue.h> 
    2932#include <sounddevice.h> 
     
    4649#endif 
    4750 
    48 static pjmedia_snd_dev_info symbian_snd_dev_info =  
     51static pjmedia_snd_dev_info symbian_snd_dev_info = 
    4952{ 
    5053    "Symbian Sound Device (APS)", 
     
    5760extern TPtrC                APP_UID; 
    5861 
    59 /* Default setting for loudspeaker */ 
    60 static pj_bool_t act_loudspeaker = PJ_FALSE; 
     62/* Default setting */ 
     63static pjmedia_snd_aps_setting def_setting; 
     64 
     65/* APS G.711 frame length */ 
     66static pj_uint8_t aps_g711_frame_len; 
     67 
     68/* Pool factory */ 
     69static pj_pool_factory *snd_pool_factory; 
    6170 
    6271/* Forward declaration of CPjAudioEngine */ 
    6372class CPjAudioEngine; 
    6473 
    65 /*  
    66  * PJMEDIA Sound Stream instance  
     74/* 
     75 * PJMEDIA Sound Stream instance 
    6776 */ 
    6877struct pjmedia_snd_stream 
    6978{ 
    7079    // Pool 
    71     pj_pool_t                   *pool; 
     80    pj_pool_t           *pool; 
    7281 
    7382    // Common settings. 
    74     pjmedia_dir                  dir; 
    75     unsigned                     clock_rate; 
    76     unsigned                     channel_count; 
    77     unsigned                     samples_per_frame; 
     83    pjmedia_dir          dir; 
     84    unsigned             clock_rate; 
     85    unsigned             channel_count; 
     86    unsigned             samples_per_frame; 
     87    pjmedia_snd_rec_cb   rec_cb; 
     88    pjmedia_snd_play_cb  play_cb; 
     89    void                *user_data; 
    7890 
    7991    // Audio engine 
    80     CPjAudioEngine              *engine; 
     92    CPjAudioEngine      *engine; 
     93 
     94    pj_timestamp         ts_play; 
     95    pj_timestamp         ts_rec; 
     96 
     97    pj_int16_t          *play_buf; 
     98    pj_uint16_t          play_buf_len; 
     99    pj_uint16_t          play_buf_start; 
     100    pj_int16_t          *rec_buf; 
     101    pj_uint16_t          rec_buf_len; 
    81102}; 
    82  
    83 static pj_pool_factory *snd_pool_factory; 
    84103 
    85104 
     
    87106 * Utility: print sound device error 
    88107 */ 
    89 static void snd_perror(const char *title, TInt rc)  
     108static void snd_perror(const char *title, TInt rc) 
    90109{ 
    91110    PJ_LOG(1,(THIS_FILE, "%s (error code=%d)", title, rc)); 
    92111} 
    93   
     112 
    94113////////////////////////////////////////////////////////////////////////////// 
    95114// 
    96115 
     116typedef void(*PjAudioCallback)(TAPSCommBuffer &buf, void *user_data); 
     117 
    97118/** 
    98119 * Abstract class for handler of callbacks from APS client. 
     
    101122{ 
    102123public: 
     124    MQueueHandlerObserver(PjAudioCallback RecCb_, PjAudioCallback PlayCb_, 
     125                          void *UserData_) 
     126    : RecCb(RecCb_), PlayCb(PlayCb_), UserData(UserData_) 
     127    {} 
     128 
    103129    virtual void InputStreamInitialized(const TInt aStatus) = 0; 
    104130    virtual void OutputStreamInitialized(const TInt aStatus) = 0; 
    105131    virtual void NotifyError(const TInt aError) = 0; 
    106132 
    107     virtual void RecCb(TAPSCommBuffer &buffer) = 0; 
    108     virtual void PlayCb(TAPSCommBuffer &buffer) = 0; 
     133public: 
     134    PjAudioCallback RecCb; 
     135    PjAudioCallback PlayCb; 
     136    void *UserData; 
    109137}; 
    110138 
     
    133161    }; 
    134162 
    135     static CQueueHandler* NewL(MQueueHandlerObserver* aObserver,  
    136                                RMsgQueue<TAPSCommBuffer>* aQ,  
     163    static CQueueHandler* NewL(MQueueHandlerObserver* aObserver, 
     164                               RMsgQueue<TAPSCommBuffer>* aQ, 
     165                               RMsgQueue<TAPSCommBuffer>* aWriteQ, 
    137166                               TQueueHandlerType aType) 
    138167    { 
    139         CQueueHandler* self = new (ELeave) CQueueHandler(aObserver, aQ, aType); 
     168        CQueueHandler* self = new (ELeave) CQueueHandler(aObserver, aQ, aWriteQ, 
     169                                                         aType); 
    140170        CleanupStack::PushL(self); 
    141171        self->ConstructL(); 
     
    155185private: 
    156186    // Constructor 
    157     CQueueHandler(MQueueHandlerObserver* aObserver,  
    158                   RMsgQueue<TAPSCommBuffer>* aQ,  
    159                   TQueueHandlerType aType)  
     187    CQueueHandler(MQueueHandlerObserver* aObserver, 
     188                  RMsgQueue<TAPSCommBuffer>* aQ, 
     189                  RMsgQueue<TAPSCommBuffer>* aWriteQ, 
     190                  TQueueHandlerType aType) 
    160191        : CActive(CActive::EPriorityHigh), 
    161           iQ(aQ), iObserver(aObserver), iType(aType) 
     192          iQ(aQ), iWriteQ(aWriteQ), iObserver(aObserver), iType(aType) 
    162193    { 
    163194        CActiveScheduler::Add(this); 
     
    178209            iObserver->NotifyError(iStatus.Int()); 
    179210            return; 
    180         }     
     211        } 
    181212 
    182213        TAPSCommBuffer buffer; 
     
    191222        case ERecordQueue: 
    192223            if (buffer.iCommand == EAPSRecordData) { 
    193                 iObserver->RecCb(buffer); 
     224                iObserver->RecCb(buffer, iObserver->UserData); 
     225            } else { 
     226                iObserver->NotifyError(buffer.iStatus); 
    194227            } 
    195228            break; 
     
    200233                case EAPSPlayData: 
    201234                    if (buffer.iStatus == KErrUnderflow) { 
    202                         iObserver->PlayCb(buffer); 
     235                        iObserver->PlayCb(buffer, iObserver->UserData); 
     236                        iWriteQ->Send(buffer); 
    203237                    } 
    204238                    break; 
     
    225259                // sent from the APS main thread through EPlayCommQueue 
    226260                case EAPSRecorderInitialize: 
    227                     if (buffer.iStatus == KErrNone) { 
    228                         iObserver->InputStreamInitialized(buffer.iStatus); 
    229                         break; 
    230                     } 
    231261                case EAPSRecordData: 
     262                default: 
    232263                    iObserver->NotifyError(buffer.iStatus); 
    233                     break; 
    234                 default: 
    235264                    break; 
    236265            } 
     
    246275    } 
    247276 
     277    TInt RunError(TInt) { 
     278        return 0; 
     279    } 
     280 
    248281    // Data 
    249282    RMsgQueue<TAPSCommBuffer>   *iQ;   // (not owned) 
     283    RMsgQueue<TAPSCommBuffer>   *iWriteQ;   // (not owned) 
    250284    MQueueHandlerObserver       *iObserver; // (not owned) 
    251285    TQueueHandlerType            iType; 
    252286}; 
    253287 
     288/* 
     289 * Audio setting for CPjAudioEngine. 
     290 */ 
     291class CPjAudioSetting 
     292{ 
     293public: 
     294    TFourCC              fourcc; 
     295    TAPSCodecMode        mode; 
     296    TBool                plc; 
     297    TBool                vad; 
     298    TBool                cng; 
     299    TBool                loudspk; 
     300}; 
    254301 
    255302/* 
     
    269316 
    270317    static CPjAudioEngine *NewL(pjmedia_snd_stream *parent_strm, 
    271                                 pjmedia_snd_rec_cb rec_cb, 
    272                                 pjmedia_snd_play_cb play_cb, 
    273                                 void *user_data); 
     318                                PjAudioCallback rec_cb, 
     319                                PjAudioCallback play_cb, 
     320                                void *user_data, 
     321                                const CPjAudioSetting &setting); 
    274322 
    275323    TInt StartL(); 
     
    280328private: 
    281329    CPjAudioEngine(pjmedia_snd_stream *parent_strm, 
    282                    pjmedia_snd_rec_cb rec_cb, 
    283                    pjmedia_snd_play_cb play_cb, 
    284                    void *user_data); 
     330                   PjAudioCallback rec_cb, 
     331                   PjAudioCallback play_cb, 
     332                   void *user_data, 
     333                   const CPjAudioSetting &setting); 
    285334    void ConstructL(); 
    286      
     335 
    287336    TInt InitPlayL(); 
    288337    TInt InitRecL(); 
    289338    TInt StartStreamL(); 
    290      
     339 
    291340    // Inherited from MQueueHandlerObserver 
    292341    virtual void InputStreamInitialized(const TInt aStatus); 
     
    294343    virtual void NotifyError(const TInt aError); 
    295344 
    296     virtual void RecCb(TAPSCommBuffer &buffer); 
    297     virtual void PlayCb(TAPSCommBuffer &buffer); 
    298  
    299345    State                        state_; 
    300346    pjmedia_snd_stream          *parentStrm_; 
    301     pjmedia_snd_rec_cb           recCb_; 
    302     pjmedia_snd_play_cb          playCb_; 
    303     void                        *userData_; 
    304     pj_uint32_t                  TsPlay_; 
    305     pj_uint32_t                  TsRec_; 
     347    CPjAudioSetting              setting_; 
    306348 
    307349    RAPSSession                  iSession; 
    308     TAPSInitSettings             iSettings; 
     350    TAPSInitSettings             iPlaySettings; 
     351    TAPSInitSettings             iRecSettings; 
     352 
    309353    RMsgQueue<TAPSCommBuffer>    iReadQ; 
    310354    RMsgQueue<TAPSCommBuffer>    iReadCommQ; 
     
    315359    CQueueHandler               *iRecCommHandler; 
    316360    CQueueHandler               *iRecHandler; 
    317      
    318     static pj_uint8_t            aps_samples_per_frame; 
    319      
    320     pj_int16_t                  *play_buf; 
    321     pj_uint16_t                  play_buf_len; 
    322     pj_uint16_t                  play_buf_start; 
    323     pj_int16_t                  *rec_buf; 
    324     pj_uint16_t                  rec_buf_len; 
    325361}; 
    326362 
    327363 
    328 pj_uint8_t CPjAudioEngine::aps_samples_per_frame = 0; 
    329  
    330  
    331364CPjAudioEngine* CPjAudioEngine::NewL(pjmedia_snd_stream *parent_strm, 
    332                                      pjmedia_snd_rec_cb rec_cb, 
    333                                      pjmedia_snd_play_cb play_cb, 
    334                                      void *user_data) 
     365                                     PjAudioCallback rec_cb, 
     366                                     PjAudioCallback play_cb, 
     367                                     void *user_data, 
     368                                     const CPjAudioSetting &setting) 
    335369{ 
    336370    CPjAudioEngine* self = new (ELeave) CPjAudioEngine(parent_strm, 
    337371                                                       rec_cb, play_cb, 
    338                                                        user_data); 
     372                                                       user_data, 
     373                                                       setting); 
    339374    CleanupStack::PushL(self); 
    340375    self->ConstructL(); 
     
    344379 
    345380CPjAudioEngine::CPjAudioEngine(pjmedia_snd_stream *parent_strm, 
    346                                pjmedia_snd_rec_cb rec_cb, 
    347                                pjmedia_snd_play_cb play_cb, 
    348                                void *user_data)  
    349       : state_(STATE_NULL), 
     381                               PjAudioCallback rec_cb, 
     382                               PjAudioCallback play_cb, 
     383                               void *user_data, 
     384                               const CPjAudioSetting &setting) 
     385      : MQueueHandlerObserver(rec_cb, play_cb, user_data), 
     386        state_(STATE_NULL), 
    350387        parentStrm_(parent_strm), 
    351         recCb_(rec_cb), 
    352         playCb_(play_cb), 
    353         userData_(user_data), 
     388        setting_(setting), 
    354389        iPlayCommHandler(0), 
    355390        iRecCommHandler(0), 
     
    362397    Stop(); 
    363398 
     399    delete iRecHandler; 
    364400    delete iPlayCommHandler; 
    365     iPlayCommHandler = NULL; 
    366401    delete iRecCommHandler; 
    367     iRecCommHandler = NULL; 
     402 
     403    // On some devices, immediate closing after stopping may cause APS server 
     404    // panic KERN-EXEC 0, so let's wait for sometime before really closing 
     405    // the client session. 
     406    TTime start, now; 
     407    enum { APS_CLOSE_WAIT_TIME = 200 }; 
     408    start.UniversalTime(); 
     409    now.UniversalTime(); 
     410    while (now.MicroSecondsFrom(start) < APS_CLOSE_WAIT_TIME * 1000) { 
     411        pj_symbianos_poll(-1, APS_CLOSE_WAIT_TIME); 
     412        now.UniversalTime(); 
     413    } 
    368414 
    369415    iSession.Close(); 
     
    384430        return 0; 
    385431 
    386     TInt err = iSession.InitializePlayer(iSettings); 
     432    TInt err = iSession.InitializePlayer(iPlaySettings); 
    387433    if (err != KErrNone) { 
    388434        snd_perror("Failed to initialize player", err); 
     
    391437 
    392438    // Open message queues for the output stream 
    393     TBuf<128> buf2 = iSettings.iGlobal; 
     439    TBuf<128> buf2 = iPlaySettings.iGlobal; 
    394440    buf2.Append(_L("PlayQueue")); 
    395     TBuf<128> buf3 = iSettings.iGlobal; 
     441    TBuf<128> buf3 = iPlaySettings.iGlobal; 
    396442    buf3.Append(_L("PlayCommQueue")); 
    397443 
     
    402448 
    403449    // Construct message queue handler 
    404     iPlayCommHandler = CQueueHandler::NewL(this, 
    405                                            &iWriteCommQ, 
     450    iPlayCommHandler = CQueueHandler::NewL(this, &iWriteCommQ, &iWriteQ, 
    406451                                           CQueueHandler::EPlayCommQueue); 
    407452 
     
    418463 
    419464    // Initialize input stream device 
    420     TInt err = iSession.InitializeRecorder(iSettings); 
    421     if (err != KErrNone) { 
     465    TInt err = iSession.InitializeRecorder(iRecSettings); 
     466    if (err != KErrNone && err != KErrAlreadyExists) { 
    422467        snd_perror("Failed to initialize recorder", err); 
    423468        return err; 
    424469    } 
    425470 
    426     TBuf<128> buf1 = iSettings.iGlobal; 
     471    TBuf<128> buf1 = iRecSettings.iGlobal; 
    427472    buf1.Append(_L("RecordQueue")); 
    428     TBuf<128> buf4 = iSettings.iGlobal; 
     473    TBuf<128> buf4 = iRecSettings.iGlobal; 
    429474    buf4.Append(_L("RecordCommQueue")); 
    430475 
     
    437482 
    438483    // Construct message queue handlers 
    439     iRecCommHandler = CQueueHandler::NewL(this, 
    440                                           &iReadCommQ, 
     484    iRecHandler = CQueueHandler::NewL(this, &iReadQ, NULL, 
     485                                      CQueueHandler::ERecordQueue); 
     486    iRecCommHandler = CQueueHandler::NewL(this, &iReadCommQ, NULL, 
    441487                                          CQueueHandler::ERecordCommQueue); 
    442488 
    443489    // Start observing APS callbacks from on input stream message queue 
     490    iRecHandler->Start(); 
    444491    iRecCommHandler->Start(); 
    445      
     492 
    446493    return 0; 
    447494} 
     
    449496TInt CPjAudioEngine::StartL() 
    450497{ 
    451     TInt err = iSession.Connect(); 
    452     if (err != KErrNone && err != KErrAlreadyExists) 
    453         return err; 
    454  
    455498    if (state_ == STATE_READY) 
    456499        return StartStreamL(); 
    457500 
    458     // Even if only capturer are opened, playback thread of APS Server need  
     501    // Even if only capturer are opened, playback thread of APS Server need 
    459502    // to be run(?). Since some messages will be delivered via play comm queue. 
    460503    return InitPlayL(); 
     
    463506void CPjAudioEngine::Stop() 
    464507{ 
    465     iSession.Stop(); 
    466  
    467     delete iRecHandler; 
    468     iRecHandler = NULL; 
    469  
    470     state_ = STATE_READY; 
     508    if (state_ == STATE_STREAMING) { 
     509        iSession.Stop(); 
     510        state_ = STATE_READY; 
     511        TRACE_((THIS_FILE, "Streaming stopped")); 
     512    } 
    471513} 
    472514 
    473515void CPjAudioEngine::ConstructL() 
    474516{ 
    475     iSettings.iFourCC               = TFourCC(KMCPFourCCIdG711); 
    476     iSettings.iGlobal               = APP_UID; 
    477     iSettings.iPriority             = TMdaPriority(100); 
    478     iSettings.iPreference           = TMdaPriorityPreference(0x05210001); 
    479     iSettings.iSettings.iChannels   = EMMFMono; 
    480     iSettings.iSettings.iSampleRate = EMMFSampleRate8000Hz; 
    481     iSettings.iSettings.iVolume     = 0; 
    482      
    483     /* play_buf size is samples per frame of parent stream. */ 
    484     play_buf = (pj_int16_t*)pj_pool_alloc(parentStrm_->pool,  
    485                                           parentStrm_->samples_per_frame << 1); 
    486     play_buf_len = 0; 
    487     play_buf_start = 0; 
    488      
    489     /* rec_buf size is samples per frame of parent stream. */ 
    490     rec_buf  = (pj_int16_t*)pj_pool_alloc(parentStrm_->pool,  
    491                                           parentStrm_->samples_per_frame << 1); 
    492     rec_buf_len = 0; 
     517    // Recorder settings 
     518    iRecSettings.iFourCC                = setting_.fourcc; 
     519    iRecSettings.iGlobal                = APP_UID; 
     520    iRecSettings.iPriority              = TMdaPriority(100); 
     521    iRecSettings.iPreference            = TMdaPriorityPreference(0x05210001); 
     522    iRecSettings.iSettings.iChannels    = EMMFMono; 
     523    iRecSettings.iSettings.iSampleRate  = EMMFSampleRate8000Hz; 
     524 
     525    // Player settings 
     526    iPlaySettings.iFourCC               = setting_.fourcc; 
     527    iPlaySettings.iGlobal               = APP_UID; 
     528    iPlaySettings.iPriority             = TMdaPriority(100); 
     529    iPlaySettings.iPreference           = TMdaPriorityPreference(0x05220001); 
     530    iPlaySettings.iSettings.iChannels   = EMMFMono; 
     531    iPlaySettings.iSettings.iSampleRate = EMMFSampleRate8000Hz; 
     532    iPlaySettings.iSettings.iVolume     = 0; 
     533 
     534    User::LeaveIfError(iSession.Connect()); 
    493535} 
    494536 
     
    498540        return 0; 
    499541 
    500     iSession.SetCng(EFalse); 
    501     iSession.SetVadMode(EFalse); 
    502     iSession.SetPlc(EFalse); 
    503     iSession.SetEncoderMode(EULawOr30ms); 
    504     iSession.SetDecoderMode(EULawOr30ms); 
    505     iSession.ActivateLoudspeaker(act_loudspeaker); 
    506  
    507     // Not only playback 
    508     if (parentStrm_->dir != PJMEDIA_DIR_PLAYBACK) { 
    509         iRecHandler = CQueueHandler::NewL(this, &iReadQ,  
    510                                           CQueueHandler::ERecordQueue); 
    511         iRecHandler->Start(); 
    512         iSession.Read(); 
    513         TRACE_((THIS_FILE, "APS recorder started")); 
    514     } 
     542    iSession.SetCng(setting_.cng); 
     543    iSession.SetVadMode(setting_.vad); 
     544    iSession.SetPlc(setting_.plc); 
     545    iSession.SetEncoderMode(setting_.mode); 
     546    iSession.SetDecoderMode(setting_.mode); 
     547    iSession.ActivateLoudspeaker(setting_.loudspk); 
    515548 
    516549    // Not only capture 
    517550    if (parentStrm_->dir != PJMEDIA_DIR_CAPTURE) { 
    518551        iSession.Write(); 
    519         TRACE_((THIS_FILE, "APS player started")); 
     552        TRACE_((THIS_FILE, "Player streaming started")); 
     553    } 
     554 
     555    // Not only playback 
     556    if (parentStrm_->dir != PJMEDIA_DIR_PLAYBACK) { 
     557        iSession.Read(); 
     558        TRACE_((THIS_FILE, "Recorder streaming started")); 
    520559    } 
    521560 
     
    557596} 
    558597 
    559 void CPjAudioEngine::RecCb(TAPSCommBuffer &buffer) 
    560 { 
    561     pj_assert(buffer.iBuffer[0] == 1 && buffer.iBuffer[1] == 0); 
    562  
    563     /* Detect the recorder G.711 frame size, player frame size will follow  
    564      * this recorder frame size.  
    565      */ 
    566     if (CPjAudioEngine::aps_samples_per_frame == 0) { 
    567         CPjAudioEngine::aps_samples_per_frame = buffer.iBuffer.Length() < 160? 
    568                                                  80 : 160; 
    569         TRACE_((THIS_FILE, "Detected APS G.711 frame size = %u samples",  
    570                 CPjAudioEngine::aps_samples_per_frame)); 
    571     } 
    572  
    573     /* Decode APS buffer (coded in G.711) and put the PCM result into rec_buf. 
    574      * Whenever rec_buf is full, call parent stream callback.   
    575      */  
    576     unsigned dec_len = 0; 
    577  
    578     while (dec_len < CPjAudioEngine::aps_samples_per_frame) { 
    579         unsigned tmp; 
    580  
    581         tmp = PJ_MIN(parentStrm_->samples_per_frame - rec_buf_len,  
    582                      CPjAudioEngine::aps_samples_per_frame - dec_len); 
    583         pjmedia_ulaw_decode(&rec_buf[rec_buf_len],  
    584                             buffer.iBuffer.Ptr() + 2 + dec_len,  
    585                             tmp); 
    586         rec_buf_len += tmp; 
    587         dec_len += tmp; 
    588          
    589         pj_assert(rec_buf_len <= parentStrm_->samples_per_frame); 
    590          
    591         if (rec_buf_len == parentStrm_->samples_per_frame) { 
    592             recCb_(userData_, 0, rec_buf, rec_buf_len << 1); 
    593             rec_buf_len = 0; 
    594         } 
    595     } 
    596 } 
    597  
    598 void CPjAudioEngine::PlayCb(TAPSCommBuffer &buffer) 
    599 { 
    600     buffer.iCommand = CQueueHandler::EAPSPlayData; 
    601     buffer.iStatus = 0; 
    602     buffer.iBuffer.Zero(); 
    603     buffer.iBuffer.Append(1); 
    604     buffer.iBuffer.Append(0); 
    605  
    606     /* Send 10ms silence frame if frame size hasn't been known. */ 
    607     if (CPjAudioEngine::aps_samples_per_frame == 0) { 
    608         pjmedia_zero_samples(play_buf, 80); 
    609         pjmedia_ulaw_encode((pj_uint8_t*)play_buf, play_buf, 80); 
    610         buffer.iBuffer.Append((TUint8*)play_buf, 80); 
    611         iWriteQ.Send(buffer); 
    612         return; 
    613     } 
    614      
    615     unsigned enc_len = 0; 
    616      
    617     /* Call parent stream callback to get PCM samples to play, 
    618      * encode the PCM samples into G.711 and put it into APS buffer.  
    619      */ 
    620     while (enc_len < CPjAudioEngine::aps_samples_per_frame) { 
    621         if (play_buf_len == 0) { 
    622             playCb_(userData_, 0, play_buf, parentStrm_->samples_per_frame<<1); 
    623             play_buf_len = parentStrm_->samples_per_frame; 
    624             play_buf_start = 0; 
    625         } 
    626          
    627         unsigned tmp; 
    628          
    629         tmp = PJ_MIN(play_buf_len,  
    630                      CPjAudioEngine::aps_samples_per_frame - enc_len); 
    631         pjmedia_ulaw_encode((pj_uint8_t*)&play_buf[play_buf_start],  
    632                             &play_buf[play_buf_start],  
    633                             tmp); 
    634         buffer.iBuffer.Append((TUint8*)&play_buf[play_buf_start], tmp); 
    635         enc_len += tmp; 
    636         play_buf_len -= tmp; 
    637         play_buf_start += tmp; 
    638     } 
    639  
    640     iWriteQ.Send(buffer); 
    641 } 
    642  
    643598// 
    644599// End of inherited from MQueueHandlerObserver 
     
    650605    if (state_ == STATE_READY || state_ == STATE_STREAMING) { 
    651606        iSession.ActivateLoudspeaker(active); 
     607        TRACE_((THIS_FILE, "Loudspeaker on/off: %d", active)); 
    652608        return KErrNone; 
    653609    } 
     
    658614 
    659615 
     616static void RecCbPcm(TAPSCommBuffer &buf, void *user_data) 
     617{ 
     618    pjmedia_snd_stream *strm = (pjmedia_snd_stream*) user_data; 
     619 
     620    pj_assert(buf.iBuffer[0] == 1 && buf.iBuffer[1] == 0); 
     621 
     622    /* Detect the recorder G.711 frame size, player frame size will follow 
     623     * this recorder frame size. 
     624     */ 
     625    if (aps_g711_frame_len == 0) { 
     626        aps_g711_frame_len = buf.iBuffer.Length() < 160? 80 : 160; 
     627        TRACE_((THIS_FILE, "Detected APS G.711 frame size = %u samples", 
     628                aps_g711_frame_len)); 
     629    } 
     630 
     631    /* Decode APS buffer (coded in G.711) and put the PCM result into rec_buf. 
     632     * Whenever rec_buf is full, call parent stream callback. 
     633     */ 
     634    unsigned dec_len = 0; 
     635 
     636    while (dec_len < aps_g711_frame_len) { 
     637        unsigned tmp; 
     638 
     639        tmp = PJ_MIN(strm->samples_per_frame - strm->rec_buf_len, 
     640                     aps_g711_frame_len - dec_len); 
     641        pjmedia_ulaw_decode(&strm->rec_buf[strm->rec_buf_len], 
     642                            buf.iBuffer.Ptr() + 2 + dec_len, 
     643                            tmp); 
     644        strm->rec_buf_len += tmp; 
     645        dec_len += tmp; 
     646 
     647        pj_assert(strm->rec_buf_len <= strm->samples_per_frame); 
     648 
     649        if (strm->rec_buf_len == strm->samples_per_frame) { 
     650            strm->rec_cb(strm->user_data, 0, strm->rec_buf, 
     651                         strm->rec_buf_len << 1); 
     652            strm->rec_buf_len = 0; 
     653        } 
     654    } 
     655} 
     656 
     657static void PlayCbPcm(TAPSCommBuffer &buf, void *user_data) 
     658{ 
     659    pjmedia_snd_stream *strm = (pjmedia_snd_stream*) user_data; 
     660    unsigned g711_frame_len = aps_g711_frame_len; 
     661 
     662    buf.iCommand = CQueueHandler::EAPSPlayData; 
     663    buf.iStatus = 0; 
     664    buf.iBuffer.Zero(); 
     665    buf.iBuffer.Append(1); 
     666    buf.iBuffer.Append(0); 
     667 
     668    /* Assume frame size is 10ms if frame size hasn't been known. */ 
     669    if (g711_frame_len == 0) 
     670        g711_frame_len = 80; 
     671 
     672    /* Call parent stream callback to get PCM samples to play, 
     673     * encode the PCM samples into G.711 and put it into APS buffer. 
     674     */ 
     675    unsigned enc_len = 0; 
     676    while (enc_len < g711_frame_len) { 
     677        if (strm->play_buf_len == 0) { 
     678            strm->play_cb(strm->user_data, 0, strm->play_buf, 
     679                          strm->samples_per_frame<<1); 
     680            strm->play_buf_len = strm->samples_per_frame; 
     681            strm->play_buf_start = 0; 
     682        } 
     683 
     684        unsigned tmp; 
     685 
     686        tmp = PJ_MIN(strm->play_buf_len, g711_frame_len - enc_len); 
     687        pjmedia_ulaw_encode((pj_uint8_t*)&strm->play_buf[strm->play_buf_start], 
     688                            &strm->play_buf[strm->play_buf_start], 
     689                            tmp); 
     690        buf.iBuffer.Append((TUint8*)&strm->play_buf[strm->play_buf_start], tmp); 
     691        enc_len += tmp; 
     692        strm->play_buf_len -= tmp; 
     693        strm->play_buf_start += tmp; 
     694    } 
     695} 
     696 
     697static void RecCb(TAPSCommBuffer &buf, void *user_data) 
     698{ 
     699} 
     700 
     701static void PlayCb(TAPSCommBuffer &buf, void *user_data) 
     702{ 
     703} 
     704 
    660705/* 
    661706 * Initialize sound subsystem. 
     
    664709{ 
    665710    snd_pool_factory = factory; 
     711 
     712    def_setting.format.u32 = PJMEDIA_FOURCC_L16; 
     713    def_setting.mode = 0; 
     714    def_setting.bitrate = 128000; 
     715    def_setting.plc = PJ_FALSE; 
     716    def_setting.vad = PJ_FALSE; 
     717    def_setting.cng = PJ_FALSE; 
     718    def_setting.loudspk = PJ_FALSE; 
     719 
    666720    return PJ_SUCCESS; 
    667721} 
     
    701755    pj_pool_t *pool; 
    702756    pjmedia_snd_stream *strm; 
     757    CPjAudioSetting setting; 
     758    PjAudioCallback aps_rec_cb; 
     759    PjAudioCallback aps_play_cb; 
    703760 
    704761    PJ_ASSERT_RETURN(p_snd_strm, PJ_EINVAL); 
    705     PJ_ASSERT_RETURN(clock_rate == 8000 && channel_count == 1 &&  
     762    PJ_ASSERT_RETURN(clock_rate == 8000 && channel_count == 1 && 
    706763                     bits_per_sample == 16, PJ_ENOTSUP); 
    707764    PJ_ASSERT_RETURN((dir == PJMEDIA_DIR_CAPTURE_PLAYBACK && rec_cb && play_cb) 
     
    710767                     PJ_EINVAL); 
    711768 
    712     pool = pj_pool_create(snd_pool_factory, POOL_NAME, POOL_SIZE, POOL_INC,  
     769    pool = pj_pool_create(snd_pool_factory, POOL_NAME, POOL_SIZE, POOL_INC, 
    713770                          NULL); 
    714771    if (!pool) 
    715772        return PJ_ENOMEM; 
    716773 
    717     strm = (pjmedia_snd_stream*) pj_pool_zalloc(pool,  
     774    strm = (pjmedia_snd_stream*) pj_pool_zalloc(pool, 
    718775                                                sizeof(pjmedia_snd_stream)); 
    719776    strm->dir = dir; 
     
    723780    strm->samples_per_frame = samples_per_frame; 
    724781 
     782    /* Set audio engine settings. */ 
     783    if (def_setting.format.u32 == PJMEDIA_FOURCC_G711U || 
     784        def_setting.format.u32 == PJMEDIA_FOURCC_L16) 
     785    { 
     786        setting.fourcc = TFourCC(KMCPFourCCIdG711); 
     787    } else { 
     788        setting.fourcc = TFourCC(def_setting.format.u32); 
     789    } 
     790 
     791    if (def_setting.format.u32 == PJMEDIA_FOURCC_AMR) 
     792    { 
     793        setting.mode = (TAPSCodecMode)def_setting.bitrate; 
     794    } else if (def_setting.format.u32 == PJMEDIA_FOURCC_G711U || 
     795               def_setting.format.u32 == PJMEDIA_FOURCC_L16   || 
     796              (def_setting.format.u32 == PJMEDIA_FOURCC_ILBC  && 
     797               def_setting.mode == 30)) 
     798    { 
     799        setting.mode = EULawOr30ms; 
     800    } else { 
     801        setting.mode = EALawOr20ms; 
     802    } 
     803 
     804    setting.vad = def_setting.vad; 
     805    setting.plc = def_setting.plc; 
     806    setting.cng = def_setting.cng; 
     807    setting.loudspk = def_setting.loudspk; 
     808 
     809    if (def_setting.format.u32 == PJMEDIA_FOURCC_AMR || 
     810        def_setting.format.u32 == PJMEDIA_FOURCC_G711A || 
     811        def_setting.format.u32 == PJMEDIA_FOURCC_G711U || 
     812        def_setting.format.u32 == PJMEDIA_FOURCC_G729 || 
     813        def_setting.format.u32 == PJMEDIA_FOURCC_ILBC) 
     814    { 
     815        aps_play_cb = &PlayCb; 
     816        aps_rec_cb  = &RecCb; 
     817    } else { 
     818        aps_play_cb = &PlayCbPcm; 
     819        aps_rec_cb  = &RecCbPcm; 
     820    } 
     821 
    725822    // Create the audio engine. 
    726     TRAPD(err, strm->engine = CPjAudioEngine::NewL(strm, rec_cb, play_cb,  
    727                                                    user_data)); 
     823    TRAPD(err, strm->engine = CPjAudioEngine::NewL(strm, 
     824                                                   aps_rec_cb, aps_play_cb, 
     825                                                   strm, setting)); 
    728826    if (err != KErrNone) { 
    729         pj_pool_release(pool);   
     827        pj_pool_release(pool); 
    730828        return PJ_RETURN_OS_ERROR(err); 
    731829    } 
     830 
     831    strm->rec_cb = rec_cb; 
     832    strm->play_cb = play_cb; 
     833    strm->user_data = user_data; 
     834 
     835    /* play_buf size is samples per frame. */ 
     836    strm->play_buf = (pj_int16_t*)pj_pool_alloc(pool, samples_per_frame << 1); 
     837    strm->play_buf_len = 0; 
     838    strm->play_buf_start = 0; 
     839 
     840    /* rec_buf size is samples per frame. */ 
     841    strm->rec_buf  = (pj_int16_t*)pj_pool_alloc(pool, samples_per_frame << 1); 
     842    strm->rec_buf_len = 0; 
    732843 
    733844    // Done. 
     
    753864    PJ_ASSERT_RETURN(index == 0, PJ_EINVAL); 
    754865 
    755     return sound_open(PJMEDIA_DIR_CAPTURE, clock_rate, channel_count,  
     866    return sound_open(PJMEDIA_DIR_CAPTURE, clock_rate, channel_count, 
    756867                      samples_per_frame, bits_per_sample, rec_cb, NULL, 
    757868                      user_data, p_snd_strm); 
     
    770881    PJ_ASSERT_RETURN(index == 0, PJ_EINVAL); 
    771882 
    772     return sound_open(PJMEDIA_DIR_PLAYBACK, clock_rate, channel_count,  
     883    return sound_open(PJMEDIA_DIR_PLAYBACK, clock_rate, channel_count, 
    773884                      samples_per_frame, bits_per_sample, NULL, play_cb, 
    774885                      user_data, p_snd_strm); 
     
    790901    PJ_ASSERT_RETURN(play_id == 0 && rec_id == 0, PJ_EINVAL); 
    791902 
    792     return sound_open(PJMEDIA_DIR_CAPTURE_PLAYBACK, clock_rate, channel_count,  
     903    return sound_open(PJMEDIA_DIR_CAPTURE_PLAYBACK, clock_rate, channel_count, 
    793904                      samples_per_frame, bits_per_sample, rec_cb, play_cb, 
    794905                      user_data, p_snd_strm); 
     
    822933{ 
    823934    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); 
    824      
     935 
    825936    if (stream->engine) { 
    826937        TInt err = stream->engine->StartL(); 
     
    828939            return PJ_RETURN_OS_ERROR(err); 
    829940    } 
    830          
     941 
    831942    return PJ_SUCCESS; 
    832943} 
     
    836947{ 
    837948    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); 
    838      
     949 
    839950    if (stream->engine) { 
    840951        stream->engine->Stop(); 
    841952    } 
    842      
     953 
    843954    return PJ_SUCCESS; 
    844955} 
     
    848959{ 
    849960    pj_pool_t *pool; 
    850      
     961 
    851962    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); 
    852      
    853     if (stream->engine) { 
    854         delete stream->engine; 
    855         stream->engine = NULL; 
    856     } 
     963 
     964    delete stream->engine; 
     965    stream->engine = NULL; 
    857966 
    858967    pool = stream->pool; 
    859     if (pool) {  
     968    if (pool) { 
    860969        stream->pool = NULL; 
    861970        pj_pool_release(pool); 
    862971    } 
    863      
     972 
    864973    return PJ_SUCCESS; 
    865974} 
     
    876985 * Set sound latency. 
    877986 */ 
    878 PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency,  
     987PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency, 
    879988                                            unsigned output_latency) 
    880989{ 
     
    890999 */ 
    8911000PJ_DEF(pj_status_t) pjmedia_snd_aps_activate_loudspeaker( 
    892                                         pjmedia_snd_stream *stream,  
     1001                                        pjmedia_snd_stream *stream, 
    8931002                                        pj_bool_t active) 
    8941003{ 
    8951004    if (stream == NULL) { 
    896         act_loudspeaker = active; 
     1005        def_setting.loudspk = active; 
    8971006    } else { 
    8981007        if (stream->engine == NULL) 
     
    9061015    return PJ_SUCCESS; 
    9071016} 
     1017 
     1018/** 
     1019 * Set a codec and its settings to be used on the next sound device session. 
     1020 */ 
     1021PJ_DEF(pj_status_t) pjmedia_snd_aps_modify_setting( 
     1022                                    const pjmedia_snd_aps_setting *setting) 
     1023{ 
     1024    PJ_ASSERT_RETURN(setting, PJ_EINVAL); 
     1025 
     1026    def_setting = *setting; 
     1027 
     1028    return PJ_SUCCESS; 
     1029} 
     1030 
     1031#endif // PJMEDIA_SOUND_IMPLEMENTATION == PJMEDIA_SOUND_SYMB_APS_SOUND 
Note: See TracChangeset for help on using the changeset viewer.