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-audiodev/audiodev.c

    r2464 r2468  
    2020#include <pjmedia-audiodev/audiodev_imp.h> 
    2121#include <pj/errno.h> 
     22#include <pj/log.h> 
     23#include <pj/string.h> 
     24 
     25#define THIS_FILE   "audiodev.c" 
     26 
     27/* Capability names */ 
     28static struct cap_info 
     29{ 
     30    const char *name; 
     31    const char *info; 
     32} cap_infos[] =  
     33{ 
     34    {"ext-fmt",     "Extended/non-PCM format"}, 
     35    {"latency-in",  "Input latency/buffer size setting"}, 
     36    {"latency-out", "Output latency/buffer size setting"}, 
     37    {"vol-in",      "Input volume setting"}, 
     38    {"vol-out",     "Output volume setting"}, 
     39    {"meter-in",    "Input meter"}, 
     40    {"meter-out",   "Output meter"}, 
     41    {"route-in",    "Input routing"}, 
     42    {"route-out",   "Output routing"}, 
     43    {"aec",         "Accoustic echo cancellation"}, 
     44    {"aec-tail",    "Tail length setting for AEC"}, 
     45    {"vad",         "Voice activity detection"}, 
     46    {"cng",         "Comfort noise generation"}, 
     47    {"plg",         "Packet loss concealment"} 
     48}; 
     49 
    2250 
    2351/* 
    24  * The Device ID seen by application and driver is different.  
     52 * The device index seen by application and driver is different.  
    2553 * 
    26  * At application level, device ID is a 32bit value. The high 16bit contains 
    27  * the factory ID, and the low 16bit contains the device index in the  
    28  * specified factory. The device ID may also be -1 to denote default device. 
    29  * 
    30  * At driver level, device ID is a 16bit unsigned integer index. 
     54 * At application level, device index is index to global list of device. 
     55 * At driver level, device index is index to device list on that particular 
     56 * factory only. 
    3157 */ 
    3258#define MAKE_DEV_ID(f_id, index)   (((f_id & 0xFFFF) << 16) | (index & 0xFFFF)) 
     
    4167 
    4268#define MAX_DRIVERS     16 
     69#define MAX_DEVS        64 
     70 
     71/* typedef for factory creation function */ 
     72typedef pjmedia_aud_dev_factory*  (*create_func_ptr)(pj_pool_factory*); 
     73 
     74/* driver structure */ 
     75struct driver 
     76{ 
     77    create_func_ptr          create;    /* Creation function.               */ 
     78    pjmedia_aud_dev_factory *f;         /* Factory instance.                */ 
     79    char                     name[32];  /* Driver name                      */ 
     80    unsigned                 dev_cnt;   /* Number of devices                */ 
     81    unsigned                 start_idx; /* Start index in global list       */ 
     82}; 
    4383 
    4484/* The audio subsystem */ 
    4585static struct aud_subsys 
    4686{ 
    47     unsigned         init_count; 
    48     pj_pool_factory *pf; 
    49     unsigned         factory_cnt; 
    50  
    51     struct factory 
    52     { 
    53         pjmedia_aud_dev_factory*   (*create)(pj_pool_factory*); 
    54         pjmedia_aud_dev_factory     *f; 
    55  
    56     } factories[MAX_DRIVERS]; 
     87    unsigned         init_count;        /* How many times init() is called  */ 
     88    pj_pool_factory *pf;                /* The pool factory.                */ 
     89 
     90    unsigned         drv_cnt;           /* Number of drivers.               */ 
     91    struct driver    drv[MAX_DRIVERS];  /* Array of drivers.                */ 
     92 
     93    unsigned         dev_cnt;           /* Total number of devices.         */ 
     94    pj_uint32_t      dev_list[MAX_DEVS];/* Array of device IDs.             */ 
    5795 
    5896} aud_subsys; 
     
    74112 
    75113    aud_subsys.pf = pf; 
    76     aud_subsys.factory_cnt = 0; 
    77  
    78     aud_subsys.factories[aud_subsys.factory_cnt++].create = &pjmedia_pa_factory; 
    79     aud_subsys.factories[aud_subsys.factory_cnt++].create = &pjmedia_wmme_factory; 
    80  
    81     for (i=0; i<aud_subsys.factory_cnt; ++i) { 
     114    aud_subsys.drv_cnt = 0; 
     115    aud_subsys.dev_cnt = 0; 
     116 
     117    /* Register creation functions */ 
     118    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_pa_factory; 
     119    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_wmme_factory; 
     120 
     121    /* Initialize each factory and build the device ID list */ 
     122    for (i=0; i<aud_subsys.drv_cnt; ++i) { 
    82123        pjmedia_aud_dev_factory *f; 
    83  
    84         f = (*aud_subsys.factories[i].create)(pf); 
     124        pjmedia_aud_dev_info info; 
     125        unsigned j, dev_cnt; 
     126 
     127        /* Create the factory */ 
     128        f = (*aud_subsys.drv[i].create)(pf); 
    85129        if (!f) 
    86130            continue; 
    87131 
     132        /* Call factory->init() */ 
    88133        status = f->op->init(f); 
    89134        if (status != PJ_SUCCESS) { 
     
    92137        } 
    93138 
    94         aud_subsys.factories[i].f = f; 
    95         aud_subsys.factories[i].f->internal.id = i; 
    96     } 
    97  
    98     return aud_subsys.factory_cnt ? PJ_SUCCESS : status; 
     139        /* Build device list */ 
     140        dev_cnt = f->op->get_dev_count(f); 
     141        if (dev_cnt == 0) { 
     142            f->op->destroy(f); 
     143            continue; 
     144        } 
     145 
     146        /* Get one device info */ 
     147        status = f->op->get_dev_info(f, 0, &info); 
     148        if (status != PJ_SUCCESS) { 
     149            f->op->destroy(f); 
     150            continue; 
     151        } 
     152 
     153        /* Register the factory */ 
     154        aud_subsys.drv[i].f = f; 
     155        aud_subsys.drv[i].f->internal.id = i; 
     156        aud_subsys.drv[i].start_idx = aud_subsys.dev_cnt; 
     157        pj_ansi_strncpy(aud_subsys.drv[i].name, info.driver, 
     158                        sizeof(aud_subsys.drv[i].name)); 
     159        aud_subsys.drv[i].name[sizeof(aud_subsys.drv[i].name)-1] = '\0'; 
     160 
     161        /* Register devices */ 
     162        if (aud_subsys.dev_cnt + dev_cnt > MAX_DEVS) { 
     163            PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because" 
     164                                  " there are too many sound devices", 
     165                                  aud_subsys.dev_cnt + dev_cnt - MAX_DEVS)); 
     166            dev_cnt = MAX_DEVS - aud_subsys.dev_cnt; 
     167        } 
     168        for (j=0; j<dev_cnt; ++j) { 
     169            aud_subsys.dev_list[aud_subsys.dev_cnt++] = MAKE_DEV_ID(i, j); 
     170        } 
     171 
     172    } 
     173 
     174    return aud_subsys.drv_cnt ? PJ_SUCCESS : status; 
    99175} 
    100176 
     
    118194    --aud_subsys.init_count; 
    119195 
    120     for (i=0; i<aud_subsys.factory_cnt; ++i) { 
    121         pjmedia_aud_dev_factory *f = aud_subsys.factories[i].f; 
     196    for (i=0; i<aud_subsys.drv_cnt; ++i) { 
     197        pjmedia_aud_dev_factory *f = aud_subsys.drv[i].f; 
    122198 
    123199        if (!f) 
     
    125201 
    126202        f->op->destroy(f); 
    127         aud_subsys.factories[i].f = NULL; 
    128     } 
    129  
    130     return PJ_SUCCESS; 
     203        aud_subsys.drv[i].f = NULL; 
     204    } 
     205 
     206    return PJ_SUCCESS; 
     207} 
     208 
     209/* API: get capability name/info */ 
     210PJ_DEF(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap, 
     211                                             const char **p_desc) 
     212{ 
     213    char *desc; 
     214    unsigned i; 
     215 
     216    if (p_desc==NULL) p_desc = &desc; 
     217 
     218    for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) { 
     219        if ((1 << i)==cap) 
     220            break; 
     221    } 
     222 
     223    if (i==32) { 
     224        *p_desc = "??"; 
     225        return "??"; 
     226    } 
     227 
     228    *p_desc = cap_infos[i].info; 
     229    return cap_infos[i].name; 
    131230} 
    132231 
     
    134233PJ_DEF(unsigned) pjmedia_aud_dev_count(void) 
    135234{ 
    136     unsigned i, count = 0; 
    137  
    138     for (i=0; i<aud_subsys.factory_cnt; ++i) { 
    139         pjmedia_aud_dev_factory *f = aud_subsys.factories[i].f; 
    140  
    141         if (!f) 
    142             continue; 
    143  
    144         count += f->op->get_dev_count(f); 
    145     } 
    146  
    147     return count; 
    148 } 
    149  
    150 /* API: Enumerate device ID's. */ 
    151 PJ_DEF(unsigned) pjmedia_aud_dev_enum(unsigned max_count, 
    152                                       pjmedia_aud_dev_id ids[]) 
    153 { 
    154     unsigned i, count = 0; 
    155  
    156     for (i=0; i<aud_subsys.factory_cnt && count < max_count; ++i) { 
    157         pjmedia_aud_dev_factory *f = aud_subsys.factories[i].f; 
    158         unsigned j, fcount; 
    159  
    160         if (!f) 
    161             continue; 
    162  
    163         fcount = f->op->get_dev_count(f); 
    164         for (j=0; j<fcount && count<max_count; ++j) { 
    165             ids[count++] = MAKE_DEV_ID(i, j); 
    166         } 
    167     } 
    168  
    169     return count; 
    170 } 
    171  
     235    return aud_subsys.dev_cnt; 
     236} 
     237 
     238/* Internal: lookup device id */ 
     239static pj_status_t lookup_dev(pjmedia_aud_dev_index id, 
     240                              pjmedia_aud_dev_factory **p_f, 
     241                              unsigned *p_local_index) 
     242{ 
     243    int f_id, index; 
     244 
     245    if (id == PJMEDIA_AUD_DEV_DEFAULT) 
     246        id = DEFAULT_DEV_ID; 
     247 
     248    PJ_ASSERT_RETURN(id>=0 && id<(int)aud_subsys.dev_cnt,  
     249                     PJMEDIA_EAUD_INVDEV); 
     250 
     251    f_id = GET_FID(aud_subsys.dev_list[id]); 
     252    index = GET_INDEX(aud_subsys.dev_list[id]); 
     253 
     254    if (f_id < 0 || f_id >= (int)aud_subsys.drv_cnt) 
     255        return PJMEDIA_EAUD_INVDEV; 
     256 
     257    if (index < 0 || index >= (int)aud_subsys.drv[f_id].dev_cnt) 
     258        return PJMEDIA_EAUD_INVDEV; 
     259 
     260    *p_f = aud_subsys.drv[f_id].f; 
     261    *p_local_index = (unsigned)index; 
     262 
     263    return PJ_SUCCESS; 
     264 
     265} 
     266 
     267/* Internal: convert local index to global device index */ 
     268static pj_status_t make_global_index(pjmedia_aud_dev_factory *f, 
     269                                     pjmedia_aud_dev_index *id) 
     270{ 
     271    unsigned f_id = f->internal.id; 
     272 
     273    if (*id == PJMEDIA_AUD_DEV_DEFAULT) 
     274        return PJ_SUCCESS; 
     275 
     276    /* Check that factory still exists */ 
     277    PJ_ASSERT_RETURN(f, PJ_EBUG); 
     278 
     279    /* Check that device index is valid */ 
     280    PJ_ASSERT_RETURN(*id>=0 && *id<(int)aud_subsys.drv[f_id].dev_cnt, PJ_EBUG); 
     281 
     282    *id += aud_subsys.drv[f_id].start_idx; 
     283    return PJ_SUCCESS; 
     284} 
    172285 
    173286/* API: Get device information. */ 
    174 PJ_DEF(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_id id, 
     287PJ_DEF(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_index id, 
    175288                                             pjmedia_aud_dev_info *info) 
    176289{ 
    177290    pjmedia_aud_dev_factory *f; 
    178     int f_id, index; 
    179  
    180     if (id == PJMEDIA_AUD_DEV_DEFAULT_ID) 
    181         id = DEFAULT_DEV_ID; 
    182  
    183     f_id = GET_FID(id); 
    184     index = GET_INDEX(id); 
    185  
    186     if (f_id < 0 || f_id >= (int)aud_subsys.factory_cnt) 
    187         return PJMEDIA_EAUD_INVDEV; 
    188  
    189     f = aud_subsys.factories[f_id].f; 
    190     if (f == NULL) 
    191         return PJMEDIA_EAUD_INVDEV; 
     291    unsigned index; 
     292    pj_status_t status; 
     293 
     294    PJ_ASSERT_RETURN(info, PJ_EINVAL); 
     295 
     296    status = lookup_dev(id, &f, &index); 
     297    if (status != PJ_SUCCESS) 
     298        return status; 
    192299 
    193300    return f->op->get_dev_info(f, index, info); 
     301} 
     302 
     303/* API: find device */ 
     304PJ_DEF(pj_status_t) pjmedia_aud_dev_lookup( const char *drv_name, 
     305                                            const char *dev_name, 
     306                                            pjmedia_aud_dev_index *id) 
     307{ 
     308    pjmedia_aud_dev_factory *f = NULL; 
     309    unsigned i, j; 
     310 
     311    PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL); 
     312 
     313    for (i=0; i<aud_subsys.drv_cnt; ++i) { 
     314        if (!pj_ansi_stricmp(drv_name, aud_subsys.drv[i].name)) { 
     315            f = aud_subsys.drv[i].f; 
     316            break; 
     317        } 
     318    } 
     319 
     320    if (!f) 
     321        return PJ_ENOTFOUND; 
     322 
     323    for (j=0; j<aud_subsys.drv[i].dev_cnt; ++j) { 
     324        pjmedia_aud_dev_info info; 
     325        pj_status_t status; 
     326 
     327        status = f->op->get_dev_info(f, j, &info); 
     328        if (status != PJ_SUCCESS) 
     329            return status; 
     330 
     331        if (!pj_ansi_stricmp(dev_name, info.name)) 
     332            break; 
     333    } 
     334 
     335    if (j==aud_subsys.drv[i].dev_cnt) 
     336        return PJ_ENOTFOUND; 
     337 
     338    *id = j; 
     339    make_global_index(f, id); 
     340 
     341    return PJ_SUCCESS; 
    194342} 
    195343 
     
    197345 * specified device. 
    198346 */ 
    199 PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_id id, 
    200                                                   pjmedia_aud_dev_param *param) 
     347PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id, 
     348                                                  pjmedia_aud_param *param) 
    201349{ 
    202350    pjmedia_aud_dev_factory *f; 
    203     int f_id, index; 
     351    unsigned index; 
    204352    pj_status_t status; 
    205353 
    206     if (id == PJMEDIA_AUD_DEV_DEFAULT_ID) 
    207         id = DEFAULT_DEV_ID; 
    208  
    209     f_id = GET_FID(id); 
    210     index = GET_INDEX(id); 
    211  
    212     if (f_id < 0 || f_id >= (int)aud_subsys.factory_cnt) 
    213         return PJMEDIA_EAUD_INVDEV; 
    214  
    215     f = aud_subsys.factories[f_id].f; 
    216     if (f == NULL) 
    217         return PJMEDIA_EAUD_INVDEV; 
     354    PJ_ASSERT_RETURN(param, PJ_EINVAL); 
     355 
     356    status = lookup_dev(id, &f, &index); 
     357    if (status != PJ_SUCCESS) 
     358        return status; 
    218359 
    219360    status = f->op->default_param(f, index, param); 
     
    222363 
    223364    /* Normalize device IDs */ 
    224     if (param->rec_id != PJMEDIA_AUD_DEV_DEFAULT_ID) 
    225         param->rec_id = MAKE_DEV_ID(f_id, param->rec_id); 
    226     if (param->play_id != PJMEDIA_AUD_DEV_DEFAULT_ID) 
    227         param->play_id = MAKE_DEV_ID(f_id, param->play_id); 
     365    make_global_index(f, &param->rec_id); 
     366    make_global_index(f, &param->play_id); 
    228367 
    229368    return PJ_SUCCESS; 
     
    231370 
    232371/* API: Open audio stream object using the specified parameters. */ 
    233 PJ_DEF(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_dev_param *p, 
     372PJ_DEF(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_param *prm, 
    234373                                              pjmedia_aud_rec_cb rec_cb, 
    235374                                              pjmedia_aud_play_cb play_cb, 
     
    237376                                              pjmedia_aud_stream **p_aud_strm) 
    238377{ 
    239     pjmedia_aud_dev_factory *f; 
    240     pjmedia_aud_dev_param param; 
    241     int f_id; 
     378    pjmedia_aud_dev_factory *rec_f=NULL, *play_f=NULL, *f=NULL; 
     379    pjmedia_aud_param param; 
    242380    pj_status_t status; 
    243381 
     382    PJ_ASSERT_RETURN(prm && prm->dir && p_aud_strm, PJ_EINVAL); 
     383 
    244384    /* Must make copy of param because we're changing device ID */ 
    245     pj_memcpy(&param, p, sizeof(param)); 
    246  
    247     /* Set default device */ 
    248     if (param.rec_id == PJMEDIA_AUD_DEV_DEFAULT_ID)  
    249         param.rec_id = DEFAULT_DEV_ID; 
    250     if (param.play_id == PJMEDIA_AUD_DEV_DEFAULT_ID)  
    251         param.play_id = DEFAULT_DEV_ID; 
     385    pj_memcpy(&param, prm, sizeof(param)); 
     386 
     387    /* Normalize rec_id */ 
     388    if (param.dir & PJMEDIA_DIR_CAPTURE) { 
     389        unsigned index; 
     390 
     391        status = lookup_dev(param.rec_id, &rec_f, &index); 
     392        if (status != PJ_SUCCESS) 
     393            return status; 
     394 
     395        param.rec_id = index; 
     396        f = rec_f; 
     397    } 
     398 
     399    /* Normalize play_id */ 
     400    if (param.dir & PJMEDIA_DIR_PLAYBACK) { 
     401        unsigned index; 
     402 
     403        status = lookup_dev(param.play_id, &play_f, &index); 
     404        if (status != PJ_SUCCESS) 
     405            return status; 
     406 
     407        param.play_id = index; 
     408        f = play_f; 
     409 
     410        /* For now, rec_id and play_id must belong to the same factory */ 
     411        PJ_ASSERT_RETURN(rec_f == play_f, PJ_EINVAL); 
     412    } 
     413 
    252414     
    253     if (param.dir & PJMEDIA_DIR_CAPTURE) 
    254         f_id = GET_FID(param.rec_id); 
    255     else 
    256         f_id = GET_FID(param.play_id); 
    257  
    258     if (f_id < 0 || f_id >= (int)aud_subsys.factory_cnt) 
    259         return PJMEDIA_EAUD_INVDEV; 
    260      
    261     /* Normalize device id's */ 
    262     param.rec_id = GET_INDEX(param.rec_id); 
    263     param.play_id = GET_INDEX(param.play_id); 
    264  
    265     f = aud_subsys.factories[f_id].f; 
    266     if (f == NULL) 
    267         return PJMEDIA_EAUD_INVDEV; 
    268  
     415    /* Create the stream */ 
    269416    status = f->op->create_stream(f, &param, rec_cb, play_cb, 
    270417                                  user_data, p_aud_strm); 
     
    272419        return status; 
    273420 
    274     (*p_aud_strm)->factory = f; 
     421    /* Assign factory id to the stream */ 
     422    (*p_aud_strm)->factory_id = f->internal.id; 
    275423    return PJ_SUCCESS; 
    276424} 
     
    278426/* API: Get the running parameters for the specified audio stream. */ 
    279427PJ_DEF(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm, 
    280                                                  pjmedia_aud_dev_param *param) 
     428                                                 pjmedia_aud_param *param) 
    281429{ 
    282430    pj_status_t status; 
     
    287435 
    288436    /* Normalize device id's */ 
    289     if (param->rec_id != PJMEDIA_AUD_DEV_DEFAULT_ID) 
    290         param->rec_id = MAKE_DEV_ID(strm->factory->internal.id, param->rec_id); 
    291     if (param->play_id != PJMEDIA_AUD_DEV_DEFAULT_ID) 
    292         param->play_id = MAKE_DEV_ID(strm->factory->internal.id, param->play_id); 
     437    make_global_index(aud_subsys.drv[strm->factory_id].f, &param->rec_id); 
     438    make_global_index(aud_subsys.drv[strm->factory_id].f, &param->play_id); 
    293439 
    294440    return PJ_SUCCESS; 
Note: See TracChangeset for help on using the changeset viewer.