Changeset 415


Ignore:
Timestamp:
Apr 28, 2006 1:00:26 AM (19 years ago)
Author:
bennylp
Message:

Implement simple frame replay based packet lost concealment

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/sound_port.c

    r411 r415  
    2020#include <pjmedia/errno.h> 
    2121#include <pj/assert.h> 
     22#include <pj/log.h> 
     23#include <pj/rand.h> 
    2224#include <pj/string.h>      /* pj_memset() */ 
     25 
     26 
     27//#define SIMULATE_LOST_PCT   10 
     28 
     29 
     30#define THIS_FILE           "sound_port.c" 
     31 
     32enum 
     33{ 
     34    PJMEDIA_PLC_ENABLED     = 1, 
     35}; 
     36 
     37#define DEFAULT_OPTIONS PJMEDIA_PLC_ENABLED 
     38 
     39 
    2340 
    2441struct pjmedia_snd_port 
     
    2946    pjmedia_dir          dir; 
    3047    pjmedia_port        *port; 
     48    unsigned             options; 
     49 
     50    void                *last_frame; 
     51    unsigned             last_frame_size; 
     52    unsigned             last_replay_count; 
    3153 
    3254    unsigned             clock_rate; 
     
    7496    pj_assert(frame.size == size); 
    7597 
     98#ifdef SIMULATE_LOST_PCT 
     99    /* Simulate packet lost */ 
     100    if (pj_rand() % 100 < SIMULATE_LOST_PCT) { 
     101        PJ_LOG(4,(THIS_FILE, "Frame dropped")); 
     102        goto no_frame; 
     103    } 
     104#endif 
     105 
     106    /* Keep frame if PLC is enabled. */ 
     107    if (snd_port->options & PJMEDIA_PLC_ENABLED) { 
     108        /* Must have the same length as last_frame_size */ 
     109        pj_assert(frame.size == snd_port->last_frame_size); 
     110 
     111        /* Copy frame to last_frame */ 
     112        pj_memcpy(snd_port->last_frame, output, snd_port->last_frame_size); 
     113 
     114        snd_port->last_replay_count = 0; 
     115    } 
     116 
    76117    return PJ_SUCCESS; 
    77118 
    78119no_frame: 
    79     pj_memset(output, 0, size); 
     120 
     121    /* Replay last frame if PLC is enabled */ 
     122    if ((snd_port->options & PJMEDIA_PLC_ENABLED) && 
     123        snd_port->last_replay_count < 8)  
     124    { 
     125 
     126        /* Must have the same length as last_frame_size */ 
     127        pj_assert(size == snd_port->last_frame_size); 
     128 
     129        /* Replay last frame */ 
     130        pj_memcpy(output, snd_port->last_frame, snd_port->last_frame_size); 
     131 
     132        /* Reduce replay frame signal level to half */ 
     133        if (snd_port->bits_per_sample == 16) { 
     134            unsigned i, count; 
     135            pj_int16_t *samp; 
     136 
     137            count = snd_port->last_frame_size / 2; 
     138            samp = (pj_int16_t *) snd_port->last_frame; 
     139 
     140            for (i=0; i<count; ++i) 
     141                samp[i] = (pj_int16_t) (samp[i] >> 2); 
     142 
     143        } 
     144 
     145#ifdef SIMULATE_LOST_PCT 
     146        PJ_LOG(4,(THIS_FILE, "Frame replayed")); 
     147#endif 
     148 
     149        ++snd_port->last_replay_count; 
     150 
     151    } else { 
     152 
     153        /* Just zero the frame */ 
     154        pj_memset(output, 0, size); 
     155 
     156    } 
     157 
     158 
    80159    return PJ_SUCCESS; 
    81160} 
     
    119198 * This may be called even when the sound stream has already been started. 
    120199 */ 
    121 static pj_status_t start_sound_device( pjmedia_snd_port *snd_port ) 
     200static pj_status_t start_sound_device( pj_pool_t *pool, 
     201                                       pjmedia_snd_port *snd_port ) 
    122202{ 
    123203    pj_status_t status; 
     
    167247        return status; 
    168248 
     249 
     250    /* If we have player components, allocate buffer to save the last 
     251     * frame played to the speaker. The last frame is used for packet 
     252     * lost concealment (PLC) algorithm. 
     253     */ 
     254    if ((snd_port->dir & PJMEDIA_DIR_PLAYBACK) && 
     255        (snd_port->options & PJMEDIA_PLC_ENABLED))  
     256    { 
     257 
     258        snd_port->last_frame_size = snd_port->samples_per_frame * 
     259                                    snd_port->channel_count * 
     260                                    snd_port->bits_per_sample / 8; 
     261        snd_port->last_frame = pj_pool_zalloc(pool,  
     262                                              snd_port->last_frame_size); 
     263    } 
     264 
    169265    /* Start sound stream. */ 
    170266    status = pjmedia_snd_stream_start(snd_port->snd_stream); 
     
    212308 
    213309    PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); 
    214     PJ_ASSERT_RETURN(options == 0, PJ_EINVAL); 
    215310 
    216311    snd_port = pj_pool_zalloc(pool, sizeof(pjmedia_snd_port)); 
     
    220315    snd_port->play_id = play_id; 
    221316    snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 
     317    snd_port->options = options | DEFAULT_OPTIONS; 
    222318    snd_port->clock_rate = clock_rate; 
    223319    snd_port->channel_count = channel_count; 
     
    227323    *p_port = snd_port; 
    228324 
     325 
    229326    /* Start sound device immediately. 
    230327     * If there's no port connected, the sound callback will return 
    231328     * empty signal. 
    232329     */ 
    233     return start_sound_device( snd_port ); 
     330    return start_sound_device( pool, snd_port ); 
    234331 
    235332} 
     
    250347 
    251348    PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); 
    252     PJ_ASSERT_RETURN(options == 0, PJ_EINVAL); 
    253349 
    254350    snd_port = pj_pool_zalloc(pool, sizeof(pjmedia_snd_port)); 
     
    257353    snd_port->rec_id = dev_id; 
    258354    snd_port->dir = PJMEDIA_DIR_CAPTURE; 
     355    snd_port->options = options | DEFAULT_OPTIONS; 
    259356    snd_port->clock_rate = clock_rate; 
    260357    snd_port->channel_count = channel_count; 
     
    268365     * empty signal. 
    269366     */ 
    270     return start_sound_device( snd_port ); 
     367    return start_sound_device( pool, snd_port ); 
    271368} 
    272369 
     
    287384 
    288385    PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); 
    289     PJ_ASSERT_RETURN(options == 0, PJ_EINVAL); 
    290386 
    291387    snd_port = pj_pool_zalloc(pool, sizeof(pjmedia_snd_port)); 
     
    294390    snd_port->play_id = dev_id; 
    295391    snd_port->dir = PJMEDIA_DIR_PLAYBACK; 
     392    snd_port->options = options | DEFAULT_OPTIONS; 
    296393    snd_port->clock_rate = clock_rate; 
    297394    snd_port->channel_count = channel_count; 
     
    305402     * empty signal. 
    306403     */ 
    307     return start_sound_device( snd_port ); 
     404    return start_sound_device( pool, snd_port ); 
    308405} 
    309406 
Note: See TracChangeset for help on using the changeset viewer.