Ignore:
Timestamp:
Feb 21, 2009 2:21:59 PM (15 years ago)
Author:
bennylp
Message:

Updated libraries and applications to use the new Audio Device API

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_port.c

    r2460 r2468  
    2323#include <pjmedia/echo.h> 
    2424#include <pjmedia/errno.h> 
    25 #include <pjmedia/plc.h> 
    2625#include <pj/assert.h> 
    2726#include <pj/log.h> 
     
    2928#include <pj/string.h>      /* pj_memset() */ 
    3029 
    31 //#define SIMULATE_LOST_PCT   20 
    3230#define AEC_TAIL            128     /* default AEC length in ms */ 
    3331#define AEC_SUSPEND_LIMIT   5       /* seconds of no activity   */ 
     
    4139    int                  rec_id; 
    4240    int                  play_id; 
    43     pjmedia_snd_stream  *snd_stream; 
     41    pj_uint32_t          aud_caps; 
     42    pjmedia_aud_param    aud_param; 
     43    pjmedia_aud_stream  *aud_stream; 
    4444    pjmedia_dir          dir; 
    4545    pjmedia_port        *port; 
    46  
    47     pjmedia_echo_state  *ec_state; 
    48     unsigned             aec_tail_len; 
    49  
    50     pj_bool_t            ec_suspended; 
    51     unsigned             ec_suspend_count; 
    52     unsigned             ec_suspend_limit; 
    53  
    54     pjmedia_plc         *plc; 
    5546 
    5647    unsigned             clock_rate; 
     
    5849    unsigned             samples_per_frame; 
    5950    unsigned             bits_per_sample; 
    60     pjmedia_snd_setting  setting; 
    61  
    62 #if PJMEDIA_SOUND_USE_DELAYBUF 
    63     pjmedia_delay_buf   *delay_buf; 
    64 #endif 
    65  
    66     /* Encoded sound emulation */ 
    67 #if !defined(PJMEDIA_SND_SUPPORT_OPEN2) || !PJMEDIA_SND_SUPPORT_OPEN2 
    68     unsigned             frm_buf_size; 
    69     pj_uint8_t          *put_frm_buf; 
    70     pj_uint8_t          *get_frm_buf; 
    71 #endif 
     51 
     52    /* software ec */ 
     53    pjmedia_echo_state  *ec_state; 
     54    unsigned             ec_options; 
     55    unsigned             ec_tail_len; 
     56    pj_bool_t            ec_suspended; 
     57    unsigned             ec_suspend_count; 
     58    unsigned             ec_suspend_limit; 
    7259}; 
    7360 
     
    7663 * played. 
    7764 */ 
    78 static pj_status_t play_cb(/* in */   void *user_data, 
    79                            /* in */   pj_uint32_t timestamp, 
    80                            /* out */  void *output, 
    81                            /* out */  unsigned size) 
     65static pj_status_t play_cb(void *user_data, pjmedia_frame *frame) 
    8266{ 
    8367    pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 
    8468    pjmedia_port *port; 
    85     pjmedia_frame frame; 
     69    unsigned required_size = frame->size; 
    8670    pj_status_t status; 
    8771 
     
    9074        goto no_frame; 
    9175 
    92     frame.buf = output; 
    93     frame.size = size; 
    94     frame.timestamp.u32.hi = 0; 
    95     frame.timestamp.u32.lo = timestamp; 
    96  
    97 #if PJMEDIA_SOUND_USE_DELAYBUF 
    98     if (snd_port->delay_buf) { 
    99         status = pjmedia_delay_buf_get(snd_port->delay_buf, (pj_int16_t*)output); 
    100         if (status != PJ_SUCCESS) 
    101             pj_bzero(output, size); 
    102  
    103         frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
    104         pjmedia_port_put_frame(port, &frame); 
    105  
    106 #ifdef TEST_OVERFLOW_UNDERFLOW 
    107         { 
    108             static int count = 1; 
    109             if (++count % 10 == 0) { 
    110                 status = pjmedia_delay_buf_get(snd_port->delay_buf,  
    111                                                (pj_int16_t*)output); 
    112                 if (status != PJ_SUCCESS) 
    113                     pj_bzero(output, size); 
    114  
    115                 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
    116                 pjmedia_port_put_frame(port, &frame); 
    117             } 
    118         } 
    119 #endif 
    120  
    121     } 
    122 #endif 
    123  
    124     status = pjmedia_port_get_frame(port, &frame); 
     76    status = pjmedia_port_get_frame(port, frame); 
    12577    if (status != PJ_SUCCESS) 
    12678        goto no_frame; 
    12779 
    128     if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO) 
     80    if (frame->type != PJMEDIA_FRAME_TYPE_AUDIO) 
    12981        goto no_frame; 
    13082 
    13183    /* Must supply the required samples */ 
    132     pj_assert(frame.size == size); 
    133  
    134 #ifdef SIMULATE_LOST_PCT 
    135     /* Simulate packet lost */ 
    136     if (pj_rand() % 100 < SIMULATE_LOST_PCT) { 
    137         PJ_LOG(4,(THIS_FILE, "Frame dropped")); 
    138         goto no_frame; 
    139     } 
    140 #endif 
    141  
    142     if (snd_port->plc) 
    143         pjmedia_plc_save(snd_port->plc, (pj_int16_t*) output); 
     84    PJ_UNUSED_ARG(required_size); 
     85    pj_assert(frame->size == required_size); 
    14486 
    14587    if (snd_port->ec_state) { 
     
    15092        } 
    15193        snd_port->ec_suspend_count = 0; 
    152         pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)output); 
     94        pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf); 
    15395    } 
    15496 
     
    166108        if (snd_port->ec_state) { 
    167109            /* To maintain correct delay in EC */ 
    168             pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)output); 
    169         } 
    170     } 
    171  
    172     /* Apply PLC */ 
    173     if (snd_port->plc) { 
    174  
    175         pjmedia_plc_generate(snd_port->plc, (pj_int16_t*) output); 
    176 #ifdef SIMULATE_LOST_PCT 
    177         PJ_LOG(4,(THIS_FILE, "Lost frame generated")); 
    178 #endif 
    179     } else { 
    180         pj_bzero(output, size); 
    181     } 
    182  
     110            pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf); 
     111        } 
     112    } 
    183113 
    184114    return PJ_SUCCESS; 
     
    190120 * frame. 
    191121 */ 
    192 static pj_status_t rec_cb(/* in */   void *user_data, 
    193                           /* in */   pj_uint32_t timestamp, 
    194                           /* in */   void *input, 
    195                           /* in*/    unsigned size) 
     122static pj_status_t rec_cb(void *user_data, pjmedia_frame *frame) 
    196123{ 
    197124    pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 
    198125    pjmedia_port *port; 
    199     pjmedia_frame frame; 
    200126 
    201127    port = snd_port->port; 
     
    205131    /* Cancel echo */ 
    206132    if (snd_port->ec_state && !snd_port->ec_suspended) { 
    207         pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) input, 0); 
    208     } 
    209  
    210 #if PJMEDIA_SOUND_USE_DELAYBUF 
    211     if (snd_port->delay_buf) { 
    212         pjmedia_delay_buf_put(snd_port->delay_buf, (pj_int16_t*)input); 
    213     } else { 
    214         frame.buf = (void*)input; 
    215         frame.size = size; 
    216         frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
    217         frame.timestamp.u32.lo = timestamp; 
    218  
    219         pjmedia_port_put_frame(port, &frame); 
    220     } 
    221 #else 
    222     frame.buf = (void*)input; 
    223     frame.size = size; 
    224     frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
    225     frame.timestamp.u32.lo = timestamp; 
    226  
    227     pjmedia_port_put_frame(port, &frame); 
    228 #endif 
     133        pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) frame->buf, 0); 
     134    } 
     135 
     136    pjmedia_port_put_frame(port, frame); 
    229137 
    230138    return PJ_SUCCESS; 
     
    235143 * played. This version is for non-PCM data. 
    236144 */ 
    237 static pj_status_t play_cb_ext(/* in */   void *user_data, 
    238                                /* in */   pj_uint32_t timestamp, 
    239                                /* out */  void *output, 
    240                                /* out */  unsigned size) 
    241 { 
    242 #if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0 
    243     /* This is the version to use when the sound device supports 
    244      * open2(). 
    245      */ 
     145static pj_status_t play_cb_ext(void *user_data, pjmedia_frame *frame) 
     146{ 
    246147    pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 
    247     pjmedia_port *port; 
    248     pjmedia_frame *frame = (pjmedia_frame*) output; 
    249     pj_status_t status; 
    250  
    251     PJ_UNUSED_ARG(size); 
    252     PJ_UNUSED_ARG(timestamp); 
    253  
    254     port = snd_port->port; 
     148    pjmedia_port *port = snd_port->port; 
     149 
    255150    if (port == NULL) { 
    256151        frame->type = PJMEDIA_FRAME_TYPE_NONE; 
     
    258153    } 
    259154 
    260     status = pjmedia_port_get_frame(port, frame); 
    261  
    262     return status; 
    263 #else 
    264     /* This is the emulation version */ 
    265     pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 
    266     pjmedia_port *port = snd_port->port; 
    267     pjmedia_frame_ext *fx = (pjmedia_frame_ext*) snd_port->get_frm_buf; 
    268     pj_status_t status; 
    269  
    270     if (port==NULL) { 
    271         goto no_frame; 
    272     } 
    273  
    274     pj_bzero(fx, sizeof(*fx)); 
    275     fx->base.type = PJMEDIA_FRAME_TYPE_NONE; 
    276     fx->base.buf = ((pj_uint8_t*)fx) + sizeof(*fx); 
    277     fx->base.size = snd_port->frm_buf_size - sizeof(*fx); 
    278     fx->base.timestamp.u32.hi = 0; 
    279     fx->base.timestamp.u32.lo = timestamp; 
    280  
    281     status = pjmedia_port_get_frame(port, &fx->base); 
    282     if (status != PJ_SUCCESS) 
    283         goto no_frame; 
    284  
    285     if (fx->base.type == PJMEDIA_FRAME_TYPE_AUDIO) { 
    286         pj_assert(fx->base.size == size); 
    287         pj_memcpy(output, fx->base.buf, size); 
    288     } else if (fx->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) { 
    289         void (*decoder)(pj_int16_t*, const pj_uint8_t*, pj_size_t) = NULL; 
    290         unsigned i, size_decoded; 
    291  
    292         switch (snd_port->setting.format.id) { 
    293         case PJMEDIA_FORMAT_PCMA: 
    294             decoder = &pjmedia_alaw_decode; 
    295             break; 
    296         case PJMEDIA_FORMAT_PCMU: 
    297             decoder = &pjmedia_ulaw_decode; 
    298             break; 
    299         default: 
    300             PJ_LOG(1,(THIS_FILE, "Unsupported format %d",  
    301                       snd_port->setting.format.id)); 
    302             goto no_frame; 
    303         } 
    304  
    305         if (fx->samples_cnt > size>>1) { 
    306             PJ_LOG(4,(THIS_FILE, "Frame too large by %d samples",  
    307                       fx->samples_cnt - (size>>1))); 
    308         } else if (fx->samples_cnt < size>>1) { 
    309             PJ_LOG(4,(THIS_FILE, "Not enough frame by %d samples",  
    310                       (size>>1) - fx->samples_cnt)); 
    311         } 
    312  
    313         for (i=0, size_decoded=0;  
    314              i<fx->subframe_cnt && size_decoded<size;  
    315              ++i)  
    316         { 
    317             pjmedia_frame_ext_subframe *subfrm; 
    318  
    319             subfrm = pjmedia_frame_ext_get_subframe(fx, i);          
    320  
    321             if (!subfrm || subfrm->bitlen==0) 
    322                 continue; 
    323  
    324             if ((subfrm->bitlen>>3) > (int)(size-size_decoded)) { 
    325                 subfrm->bitlen = (pj_uint16_t)((size-size_decoded) << 3); 
    326             } 
    327  
    328             (*decoder)((short*)((pj_uint8_t*)output + size_decoded), 
    329                        subfrm->data, subfrm->bitlen>>3); 
    330  
    331             size_decoded += (subfrm->bitlen>>3) << 1; 
    332         } 
    333  
    334         if (size_decoded < size) { 
    335             pj_bzero((pj_uint8_t*)output + size_decoded, size-size_decoded); 
    336         } 
    337  
    338     } else { 
    339         goto no_frame; 
    340     } 
    341  
    342     return PJ_SUCCESS; 
    343  
    344 no_frame: 
    345     pj_bzero(output, size); 
    346     return PJ_SUCCESS; 
    347  
    348 #endif  /* PJMEDIA_SND_SUPPORT_OPEN2 */ 
     155    pjmedia_port_get_frame(port, frame); 
     156 
     157    return PJ_SUCCESS; 
    349158} 
    350159 
     
    354163 * frame. This version is for non-PCM data. 
    355164 */ 
    356 static pj_status_t rec_cb_ext(/* in */   void *user_data, 
    357                               /* in */   pj_uint32_t timestamp, 
    358                               /* in */   void *input, 
    359                               /* in*/    unsigned size) 
    360 { 
    361 #if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0 
    362     /* This is the version to use when the sound device supports 
    363      * open2(). 
    364      */ 
     165static pj_status_t rec_cb_ext(void *user_data, pjmedia_frame *frame) 
     166{ 
    365167    pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 
    366168    pjmedia_port *port; 
    367     pjmedia_frame *frame = (pjmedia_frame*)input; 
    368  
    369     PJ_UNUSED_ARG(size); 
    370     PJ_UNUSED_ARG(timestamp); 
    371169 
    372170    port = snd_port->port; 
     
    377175 
    378176    return PJ_SUCCESS; 
    379 #else 
    380     pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 
    381     pjmedia_port *port = snd_port->port; 
    382     pjmedia_frame_ext *fx = (pjmedia_frame_ext*) snd_port->put_frm_buf; 
    383     void (*encoder)(pj_uint8_t*, const pj_int16_t*, pj_size_t) = NULL; 
    384  
    385     if (port==NULL) 
    386         return PJ_SUCCESS; 
    387  
    388     pj_bzero(fx, sizeof(*fx)); 
    389     fx->base.buf = NULL; 
    390     fx->base.size = snd_port->frm_buf_size - sizeof(*fx); 
    391     fx->base.type = PJMEDIA_FRAME_TYPE_EXTENDED; 
    392     fx->base.timestamp.u32.lo = timestamp; 
    393  
    394     switch (snd_port->setting.format.id) { 
    395     case PJMEDIA_FORMAT_PCMA: 
    396         encoder = &pjmedia_alaw_encode; 
    397         break; 
    398     case PJMEDIA_FORMAT_PCMU: 
    399         encoder = &pjmedia_ulaw_encode; 
    400         break; 
    401     default: 
    402         PJ_LOG(1,(THIS_FILE, "Unsupported format %d",  
    403                   snd_port->setting.format.id)); 
    404         return PJ_SUCCESS; 
    405     } 
    406  
    407     (*encoder)((pj_uint8_t*)input, (pj_int16_t*)input, size >> 1); 
    408  
    409     pjmedia_frame_ext_append_subframe(fx, input, (size >> 1) << 3,  
    410                                       size >> 1); 
    411     pjmedia_port_put_frame(port, &fx->base); 
    412  
    413     return PJ_SUCCESS; 
    414 #endif 
    415177} 
    416178 
     
    422184                                       pjmedia_snd_port *snd_port ) 
    423185{ 
    424     pjmedia_snd_rec_cb snd_rec_cb; 
    425     pjmedia_snd_play_cb snd_play_cb; 
     186    pjmedia_aud_rec_cb snd_rec_cb; 
     187    pjmedia_aud_play_cb snd_play_cb; 
     188    pjmedia_aud_param param_copy; 
    426189    pj_status_t status; 
    427190 
    428191    /* Check if sound has been started. */ 
    429     if (snd_port->snd_stream != NULL) 
     192    if (snd_port->aud_stream != NULL) 
    430193        return PJ_SUCCESS; 
    431194 
     
    435198                     PJ_EBUG); 
    436199 
    437     if (snd_port->setting.format.id == PJMEDIA_FORMAT_L16) { 
     200    /* Get device caps */ 
     201    if (snd_port->aud_param.dir & PJMEDIA_DIR_CAPTURE) { 
     202        pjmedia_aud_dev_info dev_info; 
     203 
     204        status = pjmedia_aud_dev_get_info(snd_port->aud_param.rec_id,  
     205                                          &dev_info); 
     206        if (status != PJ_SUCCESS) 
     207            return status; 
     208 
     209        snd_port->aud_caps = dev_info.caps; 
     210    } else { 
     211        snd_port->aud_caps = 0; 
     212    } 
     213 
     214    /* Process EC settings */ 
     215    pj_memcpy(&param_copy, &snd_port->aud_param, sizeof(param_copy)); 
     216    if (param_copy.flags & PJMEDIA_AUD_DEV_CAP_EC) { 
     217        /* EC is wanted */ 
     218        if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) { 
     219            /* Device supports EC */ 
     220            /* Nothing to do */ 
     221        } else { 
     222            /* Device doesn't support EC, remove EC settings from 
     223             * device parameters 
     224             */ 
     225            param_copy.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC | 
     226                                  PJMEDIA_AUD_DEV_CAP_EC_TAIL); 
     227        } 
     228    } 
     229 
     230    /* Use different callback if format is not PCM */ 
     231    if (snd_port->aud_param.ext_fmt.id == PJMEDIA_FORMAT_L16) { 
    438232        snd_rec_cb = &rec_cb; 
    439233        snd_play_cb = &play_cb; 
     
    443237    } 
    444238 
    445 #if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0 
    446     status = pjmedia_snd_open2( snd_port->dir, 
    447                                 snd_port->rec_id,  
    448                                 snd_port->play_id, 
    449                                 snd_port->clock_rate, 
    450                                 snd_port->channel_count, 
    451                                 snd_port->samples_per_frame, 
    452                                 snd_port->bits_per_sample, 
    453                                 snd_rec_cb, 
    454                                 snd_play_cb, 
    455                                 snd_port, 
    456                                 &snd_port->setting, 
    457                                 &snd_port->snd_stream); 
    458 #else 
    459     status = pjmedia_snd_open(  snd_port->rec_id,  
    460                                 snd_port->play_id, 
    461                                 snd_port->clock_rate, 
    462                                 snd_port->channel_count, 
    463                                 snd_port->samples_per_frame, 
    464                                 snd_port->bits_per_sample, 
    465                                 snd_rec_cb, 
    466                                 snd_play_cb, 
    467                                 snd_port, 
    468                                 &snd_port->snd_stream); 
    469 #endif 
     239    /* Open the device */ 
     240    status = pjmedia_aud_stream_create(&param_copy, 
     241                                       snd_rec_cb, 
     242                                       snd_play_cb, 
     243                                       snd_port, 
     244                                       &snd_port->aud_stream); 
    470245 
    471246    if (status != PJ_SUCCESS) 
    472247        return status; 
    473  
    474  
    475 #ifdef SIMULATE_LOST_PCT 
    476     snd_port->setting.plc = PJ_TRUE; 
    477 #endif 
    478  
    479     /* If we have player components, allocate buffer to save the last 
    480      * frame played to the speaker. The last frame is used for packet 
    481      * lost concealment (PLC) algorithm. 
    482      */ 
    483     if ((snd_port->dir & PJMEDIA_DIR_PLAYBACK) && 
    484         (snd_port->setting.plc))  
    485     { 
    486         status = pjmedia_plc_create(pool, snd_port->clock_rate,  
    487                                     snd_port->samples_per_frame *  
    488                                         snd_port->channel_count, 
    489                                     0, &snd_port->plc); 
    490         if (status != PJ_SUCCESS) { 
    491             PJ_LOG(4,(THIS_FILE, "Unable to create PLC")); 
    492             snd_port->plc = NULL; 
    493         } 
    494     } 
    495248 
    496249    /* Inactivity limit before EC is suspended. */ 
     
    499252                                  snd_port->samples_per_frame); 
    500253 
     254    /* Create software EC if parameter specifies EC but device  
     255     * doesn't support EC 
     256     */ 
     257    if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC) && 
     258        (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)==0) 
     259    { 
     260        if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) { 
     261            snd_port->aud_param.flags |= PJMEDIA_AUD_DEV_CAP_EC_TAIL; 
     262            snd_port->aud_param.ec_tail_ms = AEC_TAIL; 
     263            PJ_LOG(4,(THIS_FILE, "AEC tail is set to default %u ms", 
     264                                 snd_port->aud_param.ec_tail_ms)); 
     265        } 
     266             
     267        status = pjmedia_snd_port_set_ec(snd_port, pool,  
     268                                         snd_port->aud_param.ec_tail_ms, 0); 
     269        if (status != PJ_SUCCESS) { 
     270            pjmedia_aud_stream_destroy(snd_port->aud_stream); 
     271            snd_port->aud_stream = NULL; 
     272            return status; 
     273        } 
     274    } 
     275 
    501276    /* Start sound stream. */ 
    502     status = pjmedia_snd_stream_start(snd_port->snd_stream); 
     277    status = pjmedia_aud_stream_start(snd_port->aud_stream); 
    503278    if (status != PJ_SUCCESS) { 
    504         pjmedia_snd_stream_close(snd_port->snd_stream); 
    505         snd_port->snd_stream = NULL; 
     279        pjmedia_aud_stream_destroy(snd_port->aud_stream); 
     280        snd_port->aud_stream = NULL; 
    506281        return status; 
    507282    } 
     
    518293{ 
    519294    /* Check if we have sound stream device. */ 
    520     if (snd_port->snd_stream) { 
    521         pjmedia_snd_stream_stop(snd_port->snd_stream); 
    522         pjmedia_snd_stream_close(snd_port->snd_stream); 
    523         snd_port->snd_stream = NULL; 
     295    if (snd_port->aud_stream) { 
     296        pjmedia_aud_stream_stop(snd_port->aud_stream); 
     297        pjmedia_aud_stream_destroy(snd_port->aud_stream); 
     298        snd_port->aud_stream = NULL; 
    524299    } 
    525300 
     
    547322                                             pjmedia_snd_port **p_port) 
    548323{ 
    549     pjmedia_snd_port *snd_port; 
     324    pjmedia_aud_param param; 
     325    pj_status_t status; 
    550326 
    551327    PJ_UNUSED_ARG(options); 
    552328 
    553     PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); 
    554  
    555     snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port); 
    556     PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM); 
    557  
    558     snd_port->rec_id = rec_id; 
    559     snd_port->play_id = play_id; 
    560     snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 
    561     snd_port->clock_rate = clock_rate; 
    562     snd_port->channel_count = channel_count; 
    563     snd_port->samples_per_frame = samples_per_frame; 
    564     snd_port->bits_per_sample = bits_per_sample; 
    565      
    566 #if PJMEDIA_SOUND_USE_DELAYBUF 
    567     do { 
    568         pj_status_t status; 
    569         unsigned ptime; 
    570      
    571         ptime = samples_per_frame * 1000 / (clock_rate * channel_count); 
    572      
    573         status = pjmedia_delay_buf_create(pool, "snd_buff",  
    574                                           clock_rate, samples_per_frame, 
    575                                           channel_count, 
    576                                           PJMEDIA_SOUND_BUFFER_COUNT * ptime, 
    577                                           0, &snd_port->delay_buf); 
    578         PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
    579     } while (0); 
    580 #endif 
    581  
    582     *p_port = snd_port; 
    583  
    584  
    585     /* Start sound device immediately. 
    586      * If there's no port connected, the sound callback will return 
    587      * empty signal. 
    588      */ 
    589     return start_sound_device( pool, snd_port ); 
    590  
     329    status = pjmedia_aud_dev_default_param(rec_id, &param); 
     330    if (status != PJ_SUCCESS) 
     331        return status; 
     332 
     333    param.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 
     334    param.rec_id = rec_id; 
     335    param.play_id = play_id; 
     336    param.clock_rate = clock_rate; 
     337    param.channel_count = channel_count; 
     338    param.samples_per_frame = samples_per_frame; 
     339    param.bits_per_sample = bits_per_sample; 
     340 
     341    return pjmedia_snd_port_create2(pool, &param, p_port); 
    591342} 
    592343 
     
    603354                                                 pjmedia_snd_port **p_port) 
    604355{ 
    605     pjmedia_snd_port *snd_port; 
     356    pjmedia_aud_param param; 
     357    pj_status_t status; 
    606358 
    607359    PJ_UNUSED_ARG(options); 
    608360 
    609     PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); 
    610  
    611     snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port); 
    612     PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM); 
    613  
    614     snd_port->rec_id = dev_id; 
    615     snd_port->dir = PJMEDIA_DIR_CAPTURE; 
    616     snd_port->clock_rate = clock_rate; 
    617     snd_port->channel_count = channel_count; 
    618     snd_port->samples_per_frame = samples_per_frame; 
    619     snd_port->bits_per_sample = bits_per_sample; 
    620  
    621     *p_port = snd_port; 
    622  
    623     /* Start sound device immediately. 
    624      * If there's no port connected, the sound callback will return 
    625      * empty signal. 
    626      */ 
    627     return start_sound_device( pool, snd_port ); 
     361    status = pjmedia_aud_dev_default_param(dev_id, &param); 
     362    if (status != PJ_SUCCESS) 
     363        return status; 
     364 
     365    param.dir = PJMEDIA_DIR_CAPTURE; 
     366    param.rec_id = dev_id; 
     367    param.clock_rate = clock_rate; 
     368    param.channel_count = channel_count; 
     369    param.samples_per_frame = samples_per_frame; 
     370    param.bits_per_sample = bits_per_sample; 
     371 
     372    return pjmedia_snd_port_create2(pool, &param, p_port); 
    628373} 
    629374 
     
    641386                                                    pjmedia_snd_port **p_port) 
    642387{ 
     388    pjmedia_aud_param param; 
     389    pj_status_t status; 
     390 
     391    PJ_UNUSED_ARG(options); 
     392 
     393    status = pjmedia_aud_dev_default_param(dev_id, &param); 
     394    if (status != PJ_SUCCESS) 
     395        return status; 
     396 
     397    param.dir = PJMEDIA_DIR_PLAYBACK; 
     398    param.play_id = dev_id; 
     399    param.clock_rate = clock_rate; 
     400    param.channel_count = channel_count; 
     401    param.samples_per_frame = samples_per_frame; 
     402    param.bits_per_sample = bits_per_sample; 
     403 
     404    return pjmedia_snd_port_create2(pool, &param, p_port); 
     405} 
     406 
     407 
     408/* 
     409 * Create sound port. 
     410 */ 
     411PJ_DEF(pj_status_t) pjmedia_snd_port_create2(pj_pool_t *pool, 
     412                                             const pjmedia_aud_param *prm, 
     413                                             pjmedia_snd_port **p_port) 
     414{ 
    643415    pjmedia_snd_port *snd_port; 
    644416 
    645     PJ_UNUSED_ARG(options); 
    646  
    647     PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); 
     417    PJ_ASSERT_RETURN(pool && prm && p_port, PJ_EINVAL); 
    648418 
    649419    snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port); 
    650420    PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM); 
    651421 
    652     snd_port->play_id = dev_id; 
    653     snd_port->dir = PJMEDIA_DIR_PLAYBACK; 
    654     snd_port->clock_rate = clock_rate; 
    655     snd_port->channel_count = channel_count; 
    656     snd_port->samples_per_frame = samples_per_frame; 
    657     snd_port->bits_per_sample = bits_per_sample; 
    658  
     422    snd_port->dir = prm->dir; 
     423    snd_port->rec_id = prm->rec_id; 
     424    snd_port->play_id = prm->play_id; 
     425    snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 
     426    snd_port->clock_rate = prm->clock_rate; 
     427    snd_port->channel_count = prm->channel_count; 
     428    snd_port->samples_per_frame = prm->samples_per_frame; 
     429    snd_port->bits_per_sample = prm->bits_per_sample; 
     430    pj_memcpy(&snd_port->aud_param, prm, sizeof(*prm)); 
     431     
    659432    *p_port = snd_port; 
     433 
    660434 
    661435    /* Start sound device immediately. 
     
    664438     */ 
    665439    return start_sound_device( pool, snd_port ); 
    666 } 
    667  
    668  
    669 /* 
    670  * Create bidirectional port. 
    671  */ 
    672 PJ_DEF(pj_status_t) pjmedia_snd_port_create2(pj_pool_t *pool, 
    673                                              pjmedia_dir dir, 
    674                                              int rec_id, 
    675                                              int play_id, 
    676                                              unsigned clock_rate, 
    677                                              unsigned channel_count, 
    678                                              unsigned samples_per_frame, 
    679                                              unsigned bits_per_sample, 
    680                                              const pjmedia_snd_setting *setting, 
    681                                              pjmedia_snd_port **p_port) 
    682 { 
    683     pjmedia_snd_port *snd_port; 
    684  
    685     PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); 
    686  
    687     snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port); 
    688     PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM); 
    689  
    690     snd_port->dir = dir; 
    691     snd_port->rec_id = rec_id; 
    692     snd_port->play_id = play_id; 
    693     snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 
    694     snd_port->clock_rate = clock_rate; 
    695     snd_port->channel_count = channel_count; 
    696     snd_port->samples_per_frame = samples_per_frame; 
    697     snd_port->bits_per_sample = bits_per_sample; 
    698     pj_memcpy(&snd_port->setting, setting, sizeof(*setting)); 
    699      
    700 #if PJMEDIA_SOUND_USE_DELAYBUF 
    701     if (snd_port->setting.format.u32 == PJMEDIA_FORMAT_L16) { 
    702         pj_status_t status; 
    703         unsigned ptime; 
    704      
    705         ptime = samples_per_frame * 1000 / (clock_rate * channel_count); 
    706      
    707         status = pjmedia_delay_buf_create(pool, "snd_buff",  
    708                                           clock_rate, samples_per_frame, 
    709                                           channel_count, 
    710                                           PJMEDIA_SOUND_BUFFER_COUNT * ptime, 
    711                                           0, &snd_port->delay_buf); 
    712         PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
    713     } 
    714 #endif 
    715  
    716 #if !defined(PJMEDIA_SND_SUPPORT_OPEN2) || PJMEDIA_SND_SUPPORT_OPEN2==0 
    717     /* For devices that doesn't support open2(), enable simulation */ 
    718     if (snd_port->setting.format.id != PJMEDIA_FORMAT_L16) { 
    719         snd_port->frm_buf_size = sizeof(pjmedia_frame_ext) +  
    720                                  (samples_per_frame << 1) + 
    721                                  16 * sizeof(pjmedia_frame_ext_subframe); 
    722         snd_port->put_frm_buf = (pj_uint8_t*) 
    723                                 pj_pool_alloc(pool, snd_port->frm_buf_size); 
    724         snd_port->get_frm_buf = (pj_uint8_t*) 
    725                                 pj_pool_alloc(pool, snd_port->frm_buf_size); 
    726     } 
    727 #endif 
    728  
    729     *p_port = snd_port; 
    730  
    731  
    732     /* Start sound device immediately. 
    733      * If there's no port connected, the sound callback will return 
    734      * empty signal. 
    735      */ 
    736     return start_sound_device( pool, snd_port ); 
    737440 
    738441} 
     
    753456 * Retrieve the sound stream associated by this sound device port. 
    754457 */ 
    755 PJ_DEF(pjmedia_snd_stream*) pjmedia_snd_port_get_snd_stream( 
     458PJ_DEF(pjmedia_aud_stream*) pjmedia_snd_port_get_snd_stream( 
    756459                                                pjmedia_snd_port *snd_port) 
    757460{ 
    758461    PJ_ASSERT_RETURN(snd_port, NULL); 
    759     return snd_port->snd_stream; 
    760 } 
    761  
    762  
    763 /* 
    764  * Enable AEC 
     462    return snd_port->aud_stream; 
     463} 
     464 
     465 
     466/* 
     467 * Change EC settings. 
    765468 */ 
    766469PJ_DEF(pj_status_t) pjmedia_snd_port_set_ec( pjmedia_snd_port *snd_port, 
     
    769472                                             unsigned options) 
    770473{ 
    771     pjmedia_snd_stream_info si; 
     474    pjmedia_aud_param prm; 
    772475    pj_status_t status; 
    773476 
     
    777480                     PJ_EINVALIDOP); 
    778481 
    779     /* Sound port must have 16bits per sample */ 
    780     PJ_ASSERT_RETURN(snd_port->bits_per_sample == 16, 
    781                      PJ_EINVALIDOP); 
    782  
    783     /* Destroy AEC */ 
    784     if (snd_port->ec_state) { 
    785         pjmedia_echo_destroy(snd_port->ec_state); 
    786         snd_port->ec_state = NULL; 
    787     } 
    788  
    789     snd_port->aec_tail_len = tail_ms; 
    790  
    791     if (tail_ms != 0) { 
    792         unsigned delay_ms; 
    793  
    794         status = pjmedia_snd_stream_get_info(snd_port->snd_stream, &si); 
     482    /* Determine whether we use device or software EC */ 
     483    if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) { 
     484        /* We use device EC */ 
     485        pj_bool_t ec_enabled; 
     486 
     487        /* Query EC status */ 
     488        status = pjmedia_aud_stream_get_cap(snd_port->aud_stream, 
     489                                            PJMEDIA_AUD_DEV_CAP_EC, 
     490                                            &ec_enabled); 
    795491        if (status != PJ_SUCCESS) 
    796             si.rec_latency = si.play_latency = 0; 
    797  
    798         //No need to add input latency in the latency calculation, 
    799         //since actual input latency should be zero. 
    800         //delay_ms = (si.rec_latency + si.play_latency) * 1000 / 
    801         //         snd_port->clock_rate; 
    802         delay_ms = si.play_latency * 1000 / snd_port->clock_rate; 
    803         status = pjmedia_echo_create2(pool, snd_port->clock_rate,  
    804                                       snd_port->channel_count, 
    805                                       snd_port->samples_per_frame,  
    806                                       tail_ms, delay_ms, 
    807                                       options, &snd_port->ec_state); 
    808         if (status != PJ_SUCCESS) 
     492            return status; 
     493 
     494        if (tail_ms != 0) { 
     495            /* Change EC setting */ 
     496 
     497            if (!ec_enabled) { 
     498                /* Enable EC first */ 
     499                pj_bool_t value = PJ_TRUE; 
     500                status = pjmedia_aud_stream_set_cap(snd_port->aud_stream,  
     501                                                    PJMEDIA_AUD_DEV_CAP_EC, 
     502                                                    &value); 
     503                if (status != PJ_SUCCESS) 
     504                    return status; 
     505            } 
     506 
     507            if ((snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) { 
     508                /* Device does not support setting EC tail */ 
     509                return PJMEDIA_EAUD_INVCAP; 
     510            } 
     511 
     512            return pjmedia_aud_stream_set_cap(snd_port->aud_stream, 
     513                                              PJMEDIA_AUD_DEV_CAP_EC_TAIL, 
     514                                              &tail_ms); 
     515 
     516        } else if (ec_enabled) { 
     517            /* Disable EC */ 
     518            pj_bool_t value = PJ_FALSE; 
     519            return pjmedia_aud_stream_set_cap(snd_port->aud_stream,  
     520                                              PJMEDIA_AUD_DEV_CAP_EC, 
     521                                              &value); 
     522        } else { 
     523            /* Request to disable EC but EC has been disabled */ 
     524            /* Do nothing */ 
     525            return PJ_SUCCESS; 
     526        } 
     527 
     528    } else { 
     529        /* We use software EC */ 
     530        /* Sound port must have 16bits per sample */ 
     531        PJ_ASSERT_RETURN(snd_port->bits_per_sample == 16, 
     532                         PJ_EINVALIDOP); 
     533 
     534        /* Check if there is change in parameters */ 
     535        if (tail_ms==snd_port->ec_tail_len && options==snd_port->ec_options) { 
     536            PJ_LOG(5,(THIS_FILE, "pjmedia_snd_port_set_ec() ignored, no " 
     537                                 "change in settings")); 
     538            return PJ_SUCCESS; 
     539        } 
     540 
     541        /* Destroy AEC */ 
     542        if (snd_port->ec_state) { 
     543            pjmedia_echo_destroy(snd_port->ec_state); 
    809544            snd_port->ec_state = NULL; 
    810         else 
    811             snd_port->ec_suspended = PJ_FALSE; 
    812     } else { 
    813         PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the " 
    814                              "sound port")); 
    815         status = PJ_SUCCESS; 
     545        } 
     546 
     547        snd_port->ec_options = options; 
     548        snd_port->ec_tail_len = tail_ms; 
     549 
     550        if (tail_ms != 0) { 
     551            unsigned delay_ms; 
     552 
     553            status = pjmedia_aud_stream_get_param(snd_port->aud_stream, &prm); 
     554            if (status != PJ_SUCCESS) 
     555                prm.input_latency_ms = prm.output_latency_ms = 0; 
     556 
     557            //No need to add input latency in the latency calculation, 
     558            //since actual input latency should be zero. 
     559            //delay_ms = (si.rec_latency + si.play_latency) * 1000 / 
     560            //     snd_port->clock_rate; 
     561            delay_ms = prm.output_latency_ms; 
     562            status = pjmedia_echo_create2(pool, snd_port->clock_rate,  
     563                                          snd_port->channel_count, 
     564                                          snd_port->samples_per_frame,  
     565                                          tail_ms, delay_ms, 
     566                                          options, &snd_port->ec_state); 
     567            if (status != PJ_SUCCESS) 
     568                snd_port->ec_state = NULL; 
     569            else 
     570                snd_port->ec_suspended = PJ_FALSE; 
     571        } else { 
     572            PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the " 
     573                                 "sound port")); 
     574            status = PJ_SUCCESS; 
     575        } 
    816576    } 
    817577 
     
    825585{ 
    826586    PJ_ASSERT_RETURN(snd_port && p_length, PJ_EINVAL); 
    827     *p_length =  snd_port->ec_state ? snd_port->aec_tail_len : 0; 
    828     return PJ_SUCCESS; 
    829 } 
    830  
     587 
     588    /* Determine whether we use device or software EC */ 
     589    if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) { 
     590        /* We use device EC */ 
     591        pj_bool_t ec_enabled; 
     592        pj_status_t status; 
     593 
     594        /* Query EC status */ 
     595        status = pjmedia_aud_stream_get_cap(snd_port->aud_stream, 
     596                                            PJMEDIA_AUD_DEV_CAP_EC, 
     597                                            &ec_enabled); 
     598        if (status != PJ_SUCCESS) 
     599            return status; 
     600 
     601        if (!ec_enabled) { 
     602            *p_length = 0; 
     603        } else if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC_TAIL) { 
     604            /* Get device EC tail */ 
     605            status = pjmedia_aud_stream_get_cap(snd_port->aud_stream, 
     606                                                PJMEDIA_AUD_DEV_CAP_EC_TAIL, 
     607                                                p_length); 
     608            if (status != PJ_SUCCESS) 
     609                return status; 
     610        } else { 
     611            /* Just use default */ 
     612            *p_length = AEC_TAIL; 
     613        } 
     614 
     615    } else { 
     616        /* We use software EC */ 
     617        *p_length =  snd_port->ec_state ? snd_port->ec_tail_len : 0; 
     618    } 
     619    return PJ_SUCCESS; 
     620} 
    831621 
    832622 
Note: See TracChangeset for help on using the changeset viewer.