Changeset 2416 for pjproject/trunk


Ignore:
Timestamp:
Jan 5, 2009 3:27:02 PM (16 years ago)
Author:
nanang
Message:

Ticket #680:

  • Fixed Symbian APS G.711 frame size variation issue.
  • Fixed APS implementation to regard 'samples_per_frame' setting.
  • Added APIs for u-law/a-law <-> PCM bulk conversions.
Location:
pjproject/trunk/pjmedia
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/include/pjmedia/alaw_ulaw.h

    r2394 r2416  
    140140#endif 
    141141 
     142/** 
     143 * Encode 16-bit linear PCM data to 8-bit U-Law data. 
     144 * 
     145 * @param dst       Destination buffer for 8-bit U-Law data. 
     146 * @param src       Source, 16-bit linear PCM data. 
     147 * @param len       Number of samples. 
     148 */ 
     149PJ_INLINE(void) pjmedia_ulaw_encode(pj_uint8_t *dst, const pj_int16_t *src,  
     150                                    pj_size_t len) 
     151{ 
     152    const pj_int16_t *end = src + len; 
     153     
     154    while (src < end) { 
     155        *dst++ = pjmedia_linear2ulaw(*src++); 
     156    } 
     157} 
     158 
     159/** 
     160 * Encode 16-bit linear PCM data to 8-bit A-Law data. 
     161 * 
     162 * @param dst       Destination buffer for 8-bit A-Law data. 
     163 * @param src       Source, 16-bit linear PCM data. 
     164 * @param len       Number of samples. 
     165 */ 
     166PJ_INLINE(void) pjmedia_alaw_encode(pj_uint8_t *dst, const pj_int16_t *src,  
     167                                    pj_size_t len) 
     168{ 
     169    const pj_int16_t *end = src + len; 
     170     
     171    while (src < end) { 
     172        *dst++ = pjmedia_linear2alaw(*src++); 
     173    } 
     174} 
     175 
     176/** 
     177 * Decode 8-bit U-Law data to 16-bit linear PCM data. 
     178 * 
     179 * @param dst       Destination buffer for 16-bit PCM data. 
     180 * @param src       Source, 8-bit U-Law data. 
     181 * @param len       Number of samples. 
     182 */ 
     183PJ_INLINE(void) pjmedia_ulaw_decode(pj_int16_t *dst, const pj_uint8_t *src,  
     184                                    pj_size_t len) 
     185{ 
     186    const pj_uint8_t *end = src + len; 
     187     
     188    while (src < end) { 
     189        *dst++ = pjmedia_ulaw2linear(*src++); 
     190    } 
     191} 
     192 
     193/** 
     194 * Decode 8-bit A-Law data to 16-bit linear PCM data. 
     195 * 
     196 * @param dst       Destination buffer for 16-bit PCM data. 
     197 * @param src       Source, 8-bit A-Law data. 
     198 * @param len       Number of samples. 
     199 */ 
     200PJ_INLINE(void) pjmedia_alaw_decode(pj_int16_t *dst, const pj_uint8_t *src,  
     201                                    pj_size_t len) 
     202{ 
     203    const pj_uint8_t *end = src + len; 
     204     
     205    while (src < end) { 
     206        *dst++ = pjmedia_alaw2linear(*src++); 
     207    } 
     208} 
     209 
    142210PJ_END_DECL 
    143211 
  • pjproject/trunk/pjmedia/src/pjmedia/symbian_sound_aps.cpp

    r2394 r2416  
    2323#include <pj/assert.h> 
    2424#include <pj/log.h> 
     25#include <pj/math.h> 
    2526#include <pj/os.h> 
    2627 
     
    268269 
    269270    static CPjAudioEngine *NewL(pjmedia_snd_stream *parent_strm, 
    270                                 pjmedia_dir dir, 
    271271                                pjmedia_snd_rec_cb rec_cb, 
    272272                                pjmedia_snd_play_cb play_cb, 
     
    280280private: 
    281281    CPjAudioEngine(pjmedia_snd_stream *parent_strm, 
    282                    pjmedia_dir dir, 
    283282                   pjmedia_snd_rec_cb rec_cb, 
    284283                   pjmedia_snd_play_cb play_cb, 
     
    300299    State                        state_; 
    301300    pjmedia_snd_stream          *parentStrm_; 
    302     pjmedia_dir                  dir_; 
    303301    pjmedia_snd_rec_cb           recCb_; 
    304302    pjmedia_snd_play_cb          playCb_; 
     
    317315    CQueueHandler               *iRecCommHandler; 
    318316    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; 
    319325}; 
    320326 
    321327 
     328pj_uint8_t CPjAudioEngine::aps_samples_per_frame = 0; 
     329 
     330 
    322331CPjAudioEngine* CPjAudioEngine::NewL(pjmedia_snd_stream *parent_strm, 
    323                                      pjmedia_dir dir, 
    324332                                     pjmedia_snd_rec_cb rec_cb, 
    325333                                     pjmedia_snd_play_cb play_cb, 
    326334                                     void *user_data) 
    327335{ 
    328     CPjAudioEngine* self = new (ELeave) CPjAudioEngine(parent_strm, dir, 
     336    CPjAudioEngine* self = new (ELeave) CPjAudioEngine(parent_strm, 
    329337                                                       rec_cb, play_cb, 
    330338                                                       user_data); 
     
    336344 
    337345CPjAudioEngine::CPjAudioEngine(pjmedia_snd_stream *parent_strm, 
    338                                pjmedia_dir dir, 
    339346                               pjmedia_snd_rec_cb rec_cb, 
    340347                               pjmedia_snd_play_cb play_cb, 
     
    342349      : state_(STATE_NULL), 
    343350        parentStrm_(parent_strm), 
    344         dir_(dir), 
    345351        recCb_(rec_cb), 
    346352        playCb_(play_cb), 
     
    364370 
    365371    if (state_ == STATE_READY) { 
    366         if (dir_ != PJMEDIA_DIR_PLAYBACK) { 
     372        if (parentStrm_->dir != PJMEDIA_DIR_PLAYBACK) { 
    367373            iReadQ.Close(); 
    368374            iReadCommQ.Close(); 
     
    474480    iSettings.iSettings.iSampleRate = EMMFSampleRate8000Hz; 
    475481    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; 
    476493} 
    477494 
     
    484501    iSession.SetVadMode(EFalse); 
    485502    iSession.SetPlc(EFalse); 
    486     iSession.SetEncoderMode(EALawOr20ms); 
    487     iSession.SetDecoderMode(EALawOr20ms); 
     503    iSession.SetEncoderMode(EULawOr30ms); 
     504    iSession.SetDecoderMode(EULawOr30ms); 
    488505    iSession.ActivateLoudspeaker(act_loudspeaker); 
    489506 
    490507    // Not only playback 
    491     if (dir_ != PJMEDIA_DIR_PLAYBACK) { 
     508    if (parentStrm_->dir != PJMEDIA_DIR_PLAYBACK) { 
    492509        iRecHandler = CQueueHandler::NewL(this, &iReadQ,  
    493510                                          CQueueHandler::ERecordQueue); 
    494511        iRecHandler->Start(); 
    495512        iSession.Read(); 
     513        TRACE_((THIS_FILE, "APS recorder started")); 
    496514    } 
    497515 
    498516    // Not only capture 
    499     if (dir_ != PJMEDIA_DIR_CAPTURE) { 
     517    if (parentStrm_->dir != PJMEDIA_DIR_CAPTURE) { 
    500518        iSession.Write(); 
     519        TRACE_((THIS_FILE, "APS player started")); 
    501520    } 
    502521 
     
    505524} 
    506525 
     526/////////////////////////////////////////////////////////// 
    507527// Inherited from MQueueHandlerObserver 
     528// 
     529 
    508530void CPjAudioEngine::InputStreamInitialized(const TInt aStatus) 
    509531{ 
     
    521543 
    522544    if (aStatus == KErrNone) { 
    523         if (dir_ == PJMEDIA_DIR_PLAYBACK) { 
     545        if (parentStrm_->dir == PJMEDIA_DIR_PLAYBACK) { 
    524546            state_ = STATE_READY; 
    525547            // Only playback, start directly 
     
    537559void CPjAudioEngine::RecCb(TAPSCommBuffer &buffer) 
    538560{ 
    539     pj_int16_t buf[160]; 
    540561    pj_assert(buffer.iBuffer[0] == 1 && buffer.iBuffer[1] == 0); 
    541562 
    542     for (int i=0; i<160; ++i) 
    543          buf[i] = pjmedia_alaw2linear(buffer.iBuffer[i+2]); 
    544  
    545     recCb_(userData_, 0, buf, sizeof(buf)); 
     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    } 
    546596} 
    547597 
    548598void CPjAudioEngine::PlayCb(TAPSCommBuffer &buffer) 
    549599{ 
    550     pj_int16_t buf[160]; 
    551  
    552     playCb_(userData_, 0, buf, sizeof(buf)); 
    553  
    554600    buffer.iCommand = CQueueHandler::EAPSPlayData; 
    555601    buffer.iStatus = 0; 
     
    557603    buffer.iBuffer.Append(1); 
    558604    buffer.iBuffer.Append(0); 
    559     for (int i=0; i<160; ++i) 
    560         buffer.iBuffer.Append(pjmedia_linear2alaw(buf[i])); 
     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,  
     623                    sizeof(parentStrm_->samples_per_frame<<1)); 
     624            play_buf_len = parentStrm_->samples_per_frame; 
     625            play_buf_start = 0; 
     626        } 
     627         
     628        unsigned tmp; 
     629         
     630        tmp = PJ_MIN(play_buf_len,  
     631                     CPjAudioEngine::aps_samples_per_frame - enc_len); 
     632        pjmedia_ulaw_encode((pj_uint8_t*)&play_buf[play_buf_start],  
     633                            &play_buf[play_buf_start],  
     634                            tmp); 
     635        buffer.iBuffer.Append((TUint8*)&play_buf[play_buf_start], tmp); 
     636        enc_len += tmp; 
     637        play_buf_len -= tmp; 
     638        play_buf_start += tmp; 
     639    } 
    561640 
    562641    iWriteQ.Send(buffer); 
    563642} 
     643 
     644// 
     645// End of inherited from MQueueHandlerObserver 
     646///////////////////////////////////////////////////////////// 
    564647 
    565648 
     
    642725 
    643726    // Create the audio engine. 
    644     TRAPD(err, strm->engine = CPjAudioEngine::NewL(strm, strm->dir,  
    645                                                    rec_cb, play_cb,  
     727    TRAPD(err, strm->engine = CPjAudioEngine::NewL(strm, rec_cb, play_cb,  
    646728                                                   user_data)); 
    647729    if (err != KErrNone) { 
Note: See TracChangeset for help on using the changeset viewer.