Ignore:
Timestamp:
Jun 4, 2009 6:48:49 PM (15 years ago)
Author:
nanang
Message:

Ticket #879:

  • Added pjmedia synchronizer port.
  • Updated affected components, i.e: sound port, AEC, conference bridge.
File:
1 edited

Legend:

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

    r2685 r2747  
    2020#include <pjmedia/sound_port.h> 
    2121#include <pjmedia/alaw_ulaw.h> 
    22 #include <pjmedia/delaybuf.h> 
    23 #include <pjmedia/echo.h> 
     22#include <pjmedia/echo_port.h> 
    2423#include <pjmedia/errno.h> 
     24#include <pjmedia/sync_port.h> 
    2525#include <pj/assert.h> 
    2626#include <pj/log.h> 
     
    2929 
    3030#define AEC_TAIL            128     /* default AEC length in ms */ 
    31 #define AEC_SUSPEND_LIMIT   5       /* seconds of no activity   */ 
    3231 
    3332#define THIS_FILE           "sound_port.c" 
    3433 
    35 //#define TEST_OVERFLOW_UNDERFLOW 
    36  
    3734struct pjmedia_snd_port 
    3835{ 
     36    pj_pool_t           *pool; 
    3937    int                  rec_id; 
    4038    int                  play_id; 
     
    4442    pjmedia_dir          dir; 
    4543    pjmedia_port        *port; 
     44    pjmedia_port        *dn_port; 
     45    pjmedia_port        *sync_port; 
    4646 
    4747    unsigned             clock_rate; 
     
    5151 
    5252    /* software ec */ 
    53     pjmedia_echo_state  *ec_state; 
     53    pjmedia_port        *echo_port; 
    5454    unsigned             ec_options; 
    5555    unsigned             ec_tail_len; 
    56     pj_bool_t            ec_suspended; 
    57     unsigned             ec_suspend_count; 
    58     unsigned             ec_suspend_limit; 
    5956}; 
    6057 
     
    7067    pj_status_t status; 
    7168 
    72     port = snd_port->port; 
     69    port = snd_port->dn_port; 
    7370    if (port == NULL) 
    7471        goto no_frame; 
     
    8380    /* Must supply the required samples */ 
    8481    pj_assert(frame->size == required_size); 
    85  
    86     if (snd_port->ec_state) { 
    87         if (snd_port->ec_suspended) { 
    88             snd_port->ec_suspended = PJ_FALSE; 
    89             //pjmedia_echo_state_reset(snd_port->ec_state); 
    90             PJ_LOG(4,(THIS_FILE, "EC activated")); 
    91         } 
    92         snd_port->ec_suspend_count = 0; 
    93         pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf); 
    94     } 
    9582 
    9683 
     
    10289    pj_bzero(frame->buf, frame->size); 
    10390 
    104     if (snd_port->ec_state && !snd_port->ec_suspended) { 
    105         ++snd_port->ec_suspend_count; 
    106         if (snd_port->ec_suspend_count > snd_port->ec_suspend_limit) { 
    107             snd_port->ec_suspended = PJ_TRUE; 
    108             PJ_LOG(4,(THIS_FILE, "EC suspended because of inactivity")); 
    109         } 
    110         if (snd_port->ec_state) { 
    111             /* To maintain correct delay in EC */ 
    112             pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf); 
    113         } 
    114     } 
    115  
    11691    return PJ_SUCCESS; 
    11792} 
     
    12398 */ 
    12499static pj_status_t rec_cb(void *user_data, pjmedia_frame *frame) 
     100{ 
     101    pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 
     102    pjmedia_port *port; 
     103 
     104    port = snd_port->dn_port; 
     105    if (port == NULL) 
     106        return PJ_SUCCESS; 
     107 
     108    pjmedia_port_put_frame(port, frame); 
     109 
     110    return PJ_SUCCESS; 
     111} 
     112 
     113/* 
     114 * The callback called by sound player when it needs more samples to be 
     115 * played. This version is for non-PCM data. 
     116 */ 
     117static pj_status_t play_cb_ext(void *user_data, pjmedia_frame *frame) 
     118{ 
     119    pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 
     120    pjmedia_port *port = snd_port->port; 
     121 
     122    if (port == NULL) { 
     123        frame->type = PJMEDIA_FRAME_TYPE_NONE; 
     124        return PJ_SUCCESS; 
     125    } 
     126 
     127    pjmedia_port_get_frame(port, frame); 
     128 
     129    return PJ_SUCCESS; 
     130} 
     131 
     132 
     133/* 
     134 * The callback called by sound recorder when it has finished capturing a 
     135 * frame. This version is for non-PCM data. 
     136 */ 
     137static pj_status_t rec_cb_ext(void *user_data, pjmedia_frame *frame) 
    125138{ 
    126139    pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 
     
    131144        return PJ_SUCCESS; 
    132145 
    133     /* Cancel echo */ 
    134     if (snd_port->ec_state && !snd_port->ec_suspended) { 
    135         pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) frame->buf, 0); 
    136     } 
    137  
    138     pjmedia_port_put_frame(port, frame); 
    139  
    140     return PJ_SUCCESS; 
    141 } 
    142  
    143 /* 
    144  * The callback called by sound player when it needs more samples to be 
    145  * played. This version is for non-PCM data. 
    146  */ 
    147 static pj_status_t play_cb_ext(void *user_data, pjmedia_frame *frame) 
    148 { 
    149     pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 
    150     pjmedia_port *port = snd_port->port; 
    151  
    152     if (port == NULL) { 
    153         frame->type = PJMEDIA_FRAME_TYPE_NONE; 
    154         return PJ_SUCCESS; 
    155     } 
    156  
    157     pjmedia_port_get_frame(port, frame); 
    158  
    159     return PJ_SUCCESS; 
    160 } 
    161  
    162  
    163 /* 
    164  * The callback called by sound recorder when it has finished capturing a 
    165  * frame. This version is for non-PCM data. 
    166  */ 
    167 static pj_status_t rec_cb_ext(void *user_data, pjmedia_frame *frame) 
    168 { 
    169     pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 
    170     pjmedia_port *port; 
    171  
    172     port = snd_port->port; 
    173     if (port == NULL) 
    174         return PJ_SUCCESS; 
    175  
    176146    pjmedia_port_put_frame(port, frame); 
    177147 
     
    183153 * This may be called even when the sound stream has already been started. 
    184154 */ 
    185 static pj_status_t start_sound_device( pj_pool_t *pool, 
    186                                        pjmedia_snd_port *snd_port ) 
     155static pj_status_t start_sound_device( pjmedia_snd_port *snd_port ) 
    187156{ 
    188157    pjmedia_aud_rec_cb snd_rec_cb; 
    189158    pjmedia_aud_play_cb snd_play_cb; 
    190     pjmedia_aud_param param_copy; 
     159    pjmedia_aud_param *param; 
    191160    pj_status_t status; 
    192161 
     
    200169                     PJ_EBUG); 
    201170 
     171    param = &snd_port->aud_param; 
     172 
    202173    /* Get device caps */ 
    203     if (snd_port->aud_param.dir & PJMEDIA_DIR_CAPTURE) { 
     174    if (param->dir & PJMEDIA_DIR_CAPTURE) { 
    204175        pjmedia_aud_dev_info dev_info; 
    205176 
    206         status = pjmedia_aud_dev_get_info(snd_port->aud_param.rec_id,  
    207                                           &dev_info); 
     177        status = pjmedia_aud_dev_get_info(param->rec_id, &dev_info); 
    208178        if (status != PJ_SUCCESS) 
    209179            return status; 
     
    214184    } 
    215185 
    216     /* Process EC settings */ 
    217     pj_memcpy(&param_copy, &snd_port->aud_param, sizeof(param_copy)); 
    218     if (param_copy.flags & PJMEDIA_AUD_DEV_CAP_EC) { 
    219         /* EC is wanted */ 
    220         if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) { 
    221             /* Device supports EC */ 
    222             /* Nothing to do */ 
    223         } else { 
    224             /* Device doesn't support EC, remove EC settings from 
    225              * device parameters 
    226              */ 
    227             param_copy.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC | 
    228                                   PJMEDIA_AUD_DEV_CAP_EC_TAIL); 
    229         } 
    230     } 
    231  
    232186    /* Use different callback if format is not PCM */ 
    233     if (snd_port->aud_param.ext_fmt.id == PJMEDIA_FORMAT_L16) { 
     187    if (param->ext_fmt.id == PJMEDIA_FORMAT_L16) { 
    234188        snd_rec_cb = &rec_cb; 
    235189        snd_play_cb = &play_cb; 
     
    240194 
    241195    /* Open the device */ 
    242     status = pjmedia_aud_stream_create(&param_copy, 
     196    status = pjmedia_aud_stream_create(param, 
    243197                                       snd_rec_cb, 
    244198                                       snd_play_cb, 
     
    248202    if (status != PJ_SUCCESS) 
    249203        return status; 
    250  
    251     /* Inactivity limit before EC is suspended. */ 
    252     snd_port->ec_suspend_limit = AEC_SUSPEND_LIMIT * 
    253                                  (snd_port->clock_rate /  
    254                                   snd_port->samples_per_frame); 
    255  
    256     /* Create software EC if parameter specifies EC but device  
    257      * doesn't support EC. Only do this if the format is PCM! 
    258      */ 
    259     if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC) && 
    260         (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)==0 && 
    261         param_copy.ext_fmt.id == PJMEDIA_FORMAT_PCM) 
    262     { 
    263         if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) { 
    264             snd_port->aud_param.flags |= PJMEDIA_AUD_DEV_CAP_EC_TAIL; 
    265             snd_port->aud_param.ec_tail_ms = AEC_TAIL; 
    266             PJ_LOG(4,(THIS_FILE, "AEC tail is set to default %u ms", 
    267                                  snd_port->aud_param.ec_tail_ms)); 
    268         } 
    269              
    270         status = pjmedia_snd_port_set_ec(snd_port, pool,  
    271                                          snd_port->aud_param.ec_tail_ms, 0); 
    272         if (status != PJ_SUCCESS) { 
    273             pjmedia_aud_stream_destroy(snd_port->aud_stream); 
    274             snd_port->aud_stream = NULL; 
    275             return status; 
    276         } 
    277     } 
    278204 
    279205    /* Start sound stream. */ 
     
    300226        pjmedia_aud_stream_destroy(snd_port->aud_stream); 
    301227        snd_port->aud_stream = NULL; 
    302     } 
    303  
    304     /* Destroy AEC */ 
    305     if (snd_port->ec_state) { 
    306         pjmedia_echo_destroy(snd_port->ec_state); 
    307         snd_port->ec_state = NULL; 
    308228    } 
    309229 
     
    421341    PJ_ASSERT_RETURN(pool && prm && p_port, PJ_EINVAL); 
    422342 
     343    pool = pj_pool_create(pool->factory, pool->obj_name, 256, 256, NULL); 
    423344    snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port); 
    424345    PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM); 
    425346 
     347    snd_port->pool = pool; 
    426348    snd_port->dir = prm->dir; 
    427349    snd_port->rec_id = prm->rec_id; 
     
    438360     * empty signal. 
    439361     */ 
    440     status = start_sound_device( pool, snd_port ); 
     362    status = start_sound_device( snd_port ); 
    441363    if (status != PJ_SUCCESS) { 
    442364        pjmedia_snd_port_destroy(snd_port); 
     
    454376PJ_DEF(pj_status_t) pjmedia_snd_port_destroy(pjmedia_snd_port *snd_port) 
    455377{ 
     378    pj_status_t status; 
     379 
    456380    PJ_ASSERT_RETURN(snd_port, PJ_EINVAL); 
    457381 
    458     return stop_sound_device(snd_port); 
     382    /* Stop sound port */ 
     383    status = stop_sound_device(snd_port); 
     384 
     385    /* Disconnect sound port */ 
     386    pjmedia_snd_port_disconnect(snd_port); 
     387 
     388    pj_pool_release(snd_port->pool); 
     389 
     390    return status; 
    459391} 
    460392 
     
    552484 
    553485        /* Destroy AEC */ 
    554         if (snd_port->ec_state) { 
    555             pjmedia_echo_destroy(snd_port->ec_state); 
    556             snd_port->ec_state = NULL; 
     486        if (snd_port->echo_port) { 
     487            pjmedia_port_destroy(snd_port->echo_port); 
     488            snd_port->echo_port = NULL; 
    557489        } 
    558490 
     
    565497            //     snd_port->clock_rate; 
    566498            delay_ms = prm.output_latency_ms; 
    567             status = pjmedia_echo_create2(pool, snd_port->clock_rate,  
    568                                           snd_port->channel_count, 
    569                                           snd_port->samples_per_frame,  
    570                                           tail_ms, delay_ms, 
    571                                           options, &snd_port->ec_state); 
     499            status = pjmedia_echo_port_create(pool, snd_port->port, 
     500                                              tail_ms, delay_ms, 
     501                                              options, &snd_port->echo_port); 
    572502            if (status != PJ_SUCCESS) 
    573                 snd_port->ec_state = NULL; 
    574             else 
    575                 snd_port->ec_suspended = PJ_FALSE; 
     503                snd_port->echo_port = NULL; 
    576504        } else { 
    577505            PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the " 
     
    623551    } else { 
    624552        /* We use software EC */ 
    625         *p_length =  snd_port->ec_state ? snd_port->ec_tail_len : 0; 
     553        *p_length =  snd_port->echo_port ? snd_port->ec_tail_len : 0; 
    626554    } 
    627555    return PJ_SUCCESS; 
     
    636564{ 
    637565    pjmedia_port_info *pinfo; 
     566    pjmedia_aud_param *param; 
     567    pjmedia_sync_param sync_param; 
     568    pj_status_t status; 
    638569 
    639570    PJ_ASSERT_RETURN(snd_port && port, PJ_EINVAL); 
     
    657588    /* Port is okay. */ 
    658589    snd_port->port = port; 
     590 
     591    /* Create software EC if parameter specifies EC but device  
     592     * doesn't support EC. Only do this if the format is PCM! 
     593     */ 
     594    param = &snd_port->aud_param; 
     595    if ((param->flags & PJMEDIA_AUD_DEV_CAP_EC) && 
     596        (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)==0 && 
     597        param->ext_fmt.id == PJMEDIA_FORMAT_PCM) 
     598    { 
     599        if ((param->flags & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) { 
     600            param->flags |= PJMEDIA_AUD_DEV_CAP_EC_TAIL; 
     601            param->ec_tail_ms = AEC_TAIL; 
     602            PJ_LOG(4,(THIS_FILE, "AEC tail is set to default %u ms", 
     603                                 param->ec_tail_ms)); 
     604        } 
     605             
     606        status = pjmedia_snd_port_set_ec(snd_port, snd_port->pool,  
     607                                         param->ec_tail_ms, 0); 
     608        if (status != PJ_SUCCESS) 
     609            return status; 
     610    } 
     611 
     612    /* Create sync port */ 
     613    pj_bzero(&sync_param, sizeof(sync_param)); 
     614    sync_param.options = PJMEDIA_SYNC_DONT_DESTROY_DN; 
     615    status = pjmedia_sync_port_create(snd_port->pool,  
     616                                      (snd_port->echo_port? 
     617                                       snd_port->echo_port:snd_port->port), 
     618                                      &sync_param, &snd_port->sync_port); 
     619    if (status != PJ_SUCCESS) 
     620        return status; 
     621 
     622    /* Update down port of sound port */ 
     623    snd_port->dn_port = snd_port->sync_port; 
     624 
    659625    return PJ_SUCCESS; 
    660626} 
     
    679645 
    680646    snd_port->port = NULL; 
    681  
    682     return PJ_SUCCESS; 
    683 } 
    684  
    685  
     647    snd_port->dn_port = NULL; 
     648 
     649    /* Destroy sync port */ 
     650    if (snd_port->sync_port) { 
     651        pjmedia_port_destroy(snd_port->sync_port); 
     652        snd_port->sync_port = NULL; 
     653    } 
     654 
     655    /* Destroy EC port */ 
     656    if (snd_port->echo_port) { 
     657        pjmedia_port_destroy(snd_port->echo_port); 
     658        snd_port->echo_port = NULL; 
     659        snd_port->ec_tail_len = 0; 
     660        snd_port->ec_options = 0; 
     661    } 
     662 
     663    return PJ_SUCCESS; 
     664} 
     665 
     666 
Note: See TracChangeset for help on using the changeset viewer.