Changeset 5255 for pjproject/trunk/pjmedia/src/pjmedia-audiodev/audiodev.c
- Timestamp:
- Mar 10, 2016 5:02:07 AM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia-audiodev/audiodev.c
r4879 r5255 20 20 #include <pjmedia-audiodev/audiodev_imp.h> 21 21 #include <pj/assert.h> 22 #include <pj/errno.h>23 #include <pj/log.h>24 #include <pj/pool.h>25 #include <pj/string.h>26 22 27 23 #define THIS_FILE "audiodev.c" 28 29 #define DEFINE_CAP(name, info) {name, info}30 31 /* Capability names */32 static struct cap_info33 {34 const char *name;35 const char *info;36 } cap_infos[] =37 {38 DEFINE_CAP("ext-fmt", "Extended/non-PCM format"),39 DEFINE_CAP("latency-in", "Input latency/buffer size setting"),40 DEFINE_CAP("latency-out", "Output latency/buffer size setting"),41 DEFINE_CAP("vol-in", "Input volume setting"),42 DEFINE_CAP("vol-out", "Output volume setting"),43 DEFINE_CAP("meter-in", "Input meter"),44 DEFINE_CAP("meter-out", "Output meter"),45 DEFINE_CAP("route-in", "Input routing"),46 DEFINE_CAP("route-out", "Output routing"),47 DEFINE_CAP("aec", "Accoustic echo cancellation"),48 DEFINE_CAP("aec-tail", "Tail length setting for AEC"),49 DEFINE_CAP("vad", "Voice activity detection"),50 DEFINE_CAP("cng", "Comfort noise generation"),51 DEFINE_CAP("plg", "Packet loss concealment")52 };53 54 55 /*56 * The device index seen by application and driver is different.57 *58 * At application level, device index is index to global list of device.59 * At driver level, device index is index to device list on that particular60 * factory only.61 */62 #define MAKE_DEV_ID(f_id, index) (((f_id & 0xFFFF) << 16) | (index & 0xFFFF))63 #define GET_INDEX(dev_id) ((dev_id) & 0xFFFF)64 #define GET_FID(dev_id) ((dev_id) >> 16)65 #define DEFAULT_DEV_ID 066 24 67 25 … … 115 73 #endif 116 74 117 #define MAX_DRIVERS 16118 #define MAX_DEVS 64119 120 121 /* driver structure */122 struct driver123 {124 /* Creation function */125 pjmedia_aud_dev_factory_create_func_ptr create;126 /* Factory instance */127 pjmedia_aud_dev_factory *f;128 char name[32]; /* Driver name */129 unsigned dev_cnt; /* Number of devices */130 unsigned start_idx; /* Start index in global list */131 int rec_dev_idx;/* Default capture device. */132 int play_dev_idx;/* Default playback device */133 int dev_idx; /* Default device. */134 };135 136 /* The audio subsystem */137 static struct aud_subsys138 {139 unsigned init_count; /* How many times init() is called */140 pj_pool_factory *pf; /* The pool factory. */141 142 unsigned drv_cnt; /* Number of drivers. */143 struct driver drv[MAX_DRIVERS]; /* Array of drivers. */144 145 unsigned dev_cnt; /* Total number of devices. */146 pj_uint32_t dev_list[MAX_DEVS];/* Array of device IDs. */147 148 } aud_subsys;149 150 /* API: get capability name/info */151 PJ_DEF(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,152 const char **p_desc)153 {154 const char *desc;155 unsigned i;156 157 if (p_desc==NULL) p_desc = &desc;158 159 for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {160 if ((1 << i)==cap)161 break;162 }163 164 if (i==PJ_ARRAY_SIZE(cap_infos)) {165 *p_desc = "??";166 return "??";167 }168 169 *p_desc = cap_infos[i].info;170 return cap_infos[i].name;171 }172 173 static pj_status_t get_cap_pointer(const pjmedia_aud_param *param,174 pjmedia_aud_dev_cap cap,175 void **ptr,176 unsigned *size)177 {178 #define FIELD_INFO(name) *ptr = (void*)¶m->name; \179 *size = sizeof(param->name)180 181 switch (cap) {182 case PJMEDIA_AUD_DEV_CAP_EXT_FORMAT:183 FIELD_INFO(ext_fmt);184 break;185 case PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY:186 FIELD_INFO(input_latency_ms);187 break;188 case PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY:189 FIELD_INFO(output_latency_ms);190 break;191 case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:192 FIELD_INFO(input_vol);193 break;194 case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:195 FIELD_INFO(output_vol);196 break;197 case PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE:198 FIELD_INFO(input_route);199 break;200 case PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE:201 FIELD_INFO(output_route);202 break;203 case PJMEDIA_AUD_DEV_CAP_EC:204 FIELD_INFO(ec_enabled);205 break;206 case PJMEDIA_AUD_DEV_CAP_EC_TAIL:207 FIELD_INFO(ec_tail_ms);208 break;209 /* vad is no longer in "fmt" in 2.0.210 case PJMEDIA_AUD_DEV_CAP_VAD:211 FIELD_INFO(ext_fmt.vad);212 break;213 */214 case PJMEDIA_AUD_DEV_CAP_CNG:215 FIELD_INFO(cng_enabled);216 break;217 case PJMEDIA_AUD_DEV_CAP_PLC:218 FIELD_INFO(plc_enabled);219 break;220 default:221 return PJMEDIA_EAUD_INVCAP;222 }223 224 #undef FIELD_INFO225 226 return PJ_SUCCESS;227 }228 229 /* API: set cap value to param */230 PJ_DEF(pj_status_t) pjmedia_aud_param_set_cap( pjmedia_aud_param *param,231 pjmedia_aud_dev_cap cap,232 const void *pval)233 {234 void *cap_ptr;235 unsigned cap_size;236 pj_status_t status;237 238 status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);239 if (status != PJ_SUCCESS)240 return status;241 242 pj_memcpy(cap_ptr, pval, cap_size);243 param->flags |= cap;244 245 return PJ_SUCCESS;246 }247 248 /* API: get cap value from param */249 PJ_DEF(pj_status_t) pjmedia_aud_param_get_cap( const pjmedia_aud_param *param,250 pjmedia_aud_dev_cap cap,251 void *pval)252 {253 void *cap_ptr;254 unsigned cap_size;255 pj_status_t status;256 257 status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);258 if (status != PJ_SUCCESS)259 return status;260 261 if ((param->flags & cap) == 0) {262 pj_bzero(cap_ptr, cap_size);263 return PJMEDIA_EAUD_INVCAP;264 }265 266 pj_memcpy(pval, cap_ptr, cap_size);267 return PJ_SUCCESS;268 }269 270 /* Internal: init driver */271 static pj_status_t init_driver(unsigned drv_idx, pj_bool_t refresh)272 {273 struct driver *drv = &aud_subsys.drv[drv_idx];274 pjmedia_aud_dev_factory *f;275 unsigned i, dev_cnt;276 pj_status_t status;277 278 if (!refresh && drv->create) {279 /* Create the factory */280 f = (*drv->create)(aud_subsys.pf);281 if (!f)282 return PJ_EUNKNOWN;283 284 /* Call factory->init() */285 status = f->op->init(f);286 if (status != PJ_SUCCESS) {287 f->op->destroy(f);288 return status;289 }290 } else {291 f = drv->f;292 }293 294 if (!f)295 return PJ_EUNKNOWN;296 297 /* Get number of devices */298 dev_cnt = f->op->get_dev_count(f);299 if (dev_cnt + aud_subsys.dev_cnt > MAX_DEVS) {300 PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because"301 " there are too many devices",302 aud_subsys.dev_cnt + dev_cnt - MAX_DEVS));303 dev_cnt = MAX_DEVS - aud_subsys.dev_cnt;304 }305 306 /* enabling this will cause pjsua-lib initialization to fail when there307 * is no sound device installed in the system, even when pjsua has been308 * run with --null-audio309 *310 if (dev_cnt == 0) {311 f->op->destroy(f);312 return PJMEDIA_EAUD_NODEV;313 }314 */315 316 /* Fill in default devices */317 drv->play_dev_idx = drv->rec_dev_idx =318 drv->dev_idx = PJMEDIA_AUD_INVALID_DEV;319 for (i=0; i<dev_cnt; ++i) {320 pjmedia_aud_dev_info info;321 322 status = f->op->get_dev_info(f, i, &info);323 if (status != PJ_SUCCESS) {324 f->op->destroy(f);325 return status;326 }327 328 if (drv->name[0]=='\0') {329 /* Set driver name */330 pj_ansi_strncpy(drv->name, info.driver, sizeof(drv->name));331 drv->name[sizeof(drv->name)-1] = '\0';332 }333 334 if (drv->play_dev_idx < 0 && info.output_count) {335 /* Set default playback device */336 drv->play_dev_idx = i;337 }338 if (drv->rec_dev_idx < 0 && info.input_count) {339 /* Set default capture device */340 drv->rec_dev_idx = i;341 }342 if (drv->dev_idx < 0 && info.input_count &&343 info.output_count)344 {345 /* Set default capture and playback device */346 drv->dev_idx = i;347 }348 349 if (drv->play_dev_idx >= 0 && drv->rec_dev_idx >= 0 &&350 drv->dev_idx >= 0)351 {352 /* Done. */353 break;354 }355 }356 357 /* Register the factory */358 drv->f = f;359 drv->f->sys.drv_idx = drv_idx;360 drv->start_idx = aud_subsys.dev_cnt;361 drv->dev_cnt = dev_cnt;362 363 /* Register devices to global list */364 for (i=0; i<dev_cnt; ++i) {365 aud_subsys.dev_list[aud_subsys.dev_cnt++] = MAKE_DEV_ID(drv_idx, i);366 }367 368 return PJ_SUCCESS;369 }370 371 /* Internal: deinit driver */372 static void deinit_driver(unsigned drv_idx)373 {374 struct driver *drv = &aud_subsys.drv[drv_idx];375 376 if (drv->f) {377 drv->f->op->destroy(drv->f);378 drv->f = NULL;379 }380 381 pj_bzero(drv, sizeof(*drv));382 drv->play_dev_idx = drv->rec_dev_idx =383 drv->dev_idx = PJMEDIA_AUD_INVALID_DEV;384 }385 75 386 76 /* API: Initialize the audio subsystem. */ … … 389 79 unsigned i; 390 80 pj_status_t status; 81 pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys(); 391 82 392 83 /* Allow init() to be called multiple times as long as there is matching 393 84 * number of shutdown(). 394 85 */ 395 if (aud_subsys .init_count++ != 0) {86 if (aud_subsys->init_count++ != 0) { 396 87 return PJ_SUCCESS; 397 88 } … … 404 95 405 96 /* Init */ 406 aud_subsys .pf = pf;407 aud_subsys .drv_cnt = 0;408 aud_subsys .dev_cnt = 0;97 aud_subsys->pf = pf; 98 aud_subsys->drv_cnt = 0; 99 aud_subsys->dev_cnt = 0; 409 100 410 101 /* Register creation functions */ 411 102 #if PJMEDIA_AUDIO_DEV_HAS_OPENSL 412 aud_subsys .drv[aud_subsys.drv_cnt++].create = &pjmedia_opensl_factory;103 aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_opensl_factory; 413 104 #endif 414 105 #if PJMEDIA_AUDIO_DEV_HAS_ANDROID_JNI 415 aud_subsys .drv[aud_subsys.drv_cnt++].create = &pjmedia_android_factory;106 aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_android_factory; 416 107 #endif 417 108 #if PJMEDIA_AUDIO_DEV_HAS_BB10 418 aud_subsys .drv[aud_subsys.drv_cnt++].create = &pjmedia_bb10_factory;109 aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_bb10_factory; 419 110 #endif 420 111 #if PJMEDIA_AUDIO_DEV_HAS_ALSA 421 aud_subsys .drv[aud_subsys.drv_cnt++].create = &pjmedia_alsa_factory;112 aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_alsa_factory; 422 113 #endif 423 114 #if PJMEDIA_AUDIO_DEV_HAS_COREAUDIO 424 aud_subsys .drv[aud_subsys.drv_cnt++].create = &pjmedia_coreaudio_factory;115 aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_coreaudio_factory; 425 116 #endif 426 117 #if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO 427 aud_subsys .drv[aud_subsys.drv_cnt++].create = &pjmedia_pa_factory;118 aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_pa_factory; 428 119 #endif 429 120 #if PJMEDIA_AUDIO_DEV_HAS_WMME 430 aud_subsys .drv[aud_subsys.drv_cnt++].create = &pjmedia_wmme_factory;121 aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_wmme_factory; 431 122 #endif 432 123 #if PJMEDIA_AUDIO_DEV_HAS_BDIMAD 433 aud_subsys .drv[aud_subsys.drv_cnt++].create = &pjmedia_bdimad_factory;124 aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_bdimad_factory; 434 125 #endif 435 126 #if PJMEDIA_AUDIO_DEV_HAS_SYMB_VAS 436 aud_subsys .drv[aud_subsys.drv_cnt++].create = &pjmedia_symb_vas_factory;127 aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_symb_vas_factory; 437 128 #endif 438 129 #if PJMEDIA_AUDIO_DEV_HAS_SYMB_APS 439 aud_subsys .drv[aud_subsys.drv_cnt++].create = &pjmedia_aps_factory;130 aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_aps_factory; 440 131 #endif 441 132 #if PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA 442 aud_subsys .drv[aud_subsys.drv_cnt++].create = &pjmedia_symb_mda_factory;133 aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_symb_mda_factory; 443 134 #endif 444 135 #if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO 445 aud_subsys .drv[aud_subsys.drv_cnt++].create = &pjmedia_null_audio_factory;136 aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_null_audio_factory; 446 137 #endif 447 138 448 139 /* Initialize each factory and build the device ID list */ 449 for (i=0; i<aud_subsys .drv_cnt; ++i) {450 status = init_driver(i, PJ_FALSE);140 for (i=0; i<aud_subsys->drv_cnt; ++i) { 141 status = pjmedia_aud_driver_init(i, PJ_FALSE); 451 142 if (status != PJ_SUCCESS) { 452 deinit_driver(i);143 pjmedia_aud_driver_deinit(i); 453 144 continue; 454 145 } 455 146 } 456 147 457 return aud_subsys .dev_cnt ? PJ_SUCCESS : status;148 return aud_subsys->dev_cnt ? PJ_SUCCESS : status; 458 149 } 459 150 … … 463 154 { 464 155 pj_status_t status; 465 466 if (aud_subsys.init_count == 0) 156 pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys(); 157 158 if (aud_subsys->init_count == 0) 467 159 return PJMEDIA_EAUD_INIT; 468 160 469 aud_subsys .drv[aud_subsys.drv_cnt].create = adf;470 status = init_driver(aud_subsys.drv_cnt, PJ_FALSE);161 aud_subsys->drv[aud_subsys->drv_cnt].create = adf; 162 status = pjmedia_aud_driver_init(aud_subsys->drv_cnt, PJ_FALSE); 471 163 if (status == PJ_SUCCESS) { 472 aud_subsys .drv_cnt++;164 aud_subsys->drv_cnt++; 473 165 } else { 474 deinit_driver(aud_subsys.drv_cnt);166 pjmedia_aud_driver_deinit(aud_subsys->drv_cnt); 475 167 } 476 168 … … 483 175 { 484 176 unsigned i, j; 485 486 if (aud_subsys.init_count == 0) 177 pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys(); 178 179 if (aud_subsys->init_count == 0) 487 180 return PJMEDIA_EAUD_INIT; 488 181 489 for (i=0; i<aud_subsys .drv_cnt; ++i) {490 struct driver *drv = &aud_subsys.drv[i];182 for (i=0; i<aud_subsys->drv_cnt; ++i) { 183 pjmedia_aud_driver *drv = &aud_subsys->drv[i]; 491 184 492 185 if (drv->create == adf) { 493 186 for (j = drv->start_idx; j < drv->start_idx + drv->dev_cnt; j++) 494 187 { 495 aud_subsys .dev_list[j] = (pj_uint32_t)PJMEDIA_AUD_INVALID_DEV;188 aud_subsys->dev_list[j] = (pj_uint32_t)PJMEDIA_AUD_INVALID_DEV; 496 189 } 497 190 498 deinit_driver(i);191 pjmedia_aud_driver_deinit(i); 499 192 return PJ_SUCCESS; 500 193 } … … 507 200 PJ_DEF(pj_pool_factory*) pjmedia_aud_subsys_get_pool_factory(void) 508 201 { 509 return aud_subsys.pf; 202 pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys(); 203 return aud_subsys->pf; 510 204 } 511 205 … … 514 208 { 515 209 unsigned i; 210 pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys(); 516 211 517 212 /* Allow shutdown() to be called multiple times as long as there is matching 518 213 * number of init(). 519 214 */ 520 if (aud_subsys .init_count == 0) {215 if (aud_subsys->init_count == 0) { 521 216 return PJ_SUCCESS; 522 217 } 523 --aud_subsys .init_count;524 525 if (aud_subsys .init_count == 0) {526 for (i=0; i<aud_subsys .drv_cnt; ++i) {527 deinit_driver(i);218 --aud_subsys->init_count; 219 220 if (aud_subsys->init_count == 0) { 221 for (i=0; i<aud_subsys->drv_cnt; ++i) { 222 pjmedia_aud_driver_deinit(i); 528 223 } 529 224 530 aud_subsys .pf = NULL;225 aud_subsys->pf = NULL; 531 226 } 532 227 return PJ_SUCCESS; 533 228 } 534 535 /* API: Refresh the list of sound devices installed in the system. */536 PJ_DEF(pj_status_t) pjmedia_aud_dev_refresh(void)537 {538 unsigned i;539 540 aud_subsys.dev_cnt = 0;541 for (i=0; i<aud_subsys.drv_cnt; ++i) {542 struct driver *drv = &aud_subsys.drv[i];543 544 if (drv->f && drv->f->op->refresh) {545 pj_status_t status = drv->f->op->refresh(drv->f);546 if (status != PJ_SUCCESS) {547 PJ_PERROR(4, (THIS_FILE, status, "Unable to refresh device "548 "list for %s", drv->name));549 }550 }551 init_driver(i, PJ_TRUE);552 }553 return PJ_SUCCESS;554 }555 556 /* API: Get the number of sound devices installed in the system. */557 PJ_DEF(unsigned) pjmedia_aud_dev_count(void)558 {559 return aud_subsys.dev_cnt;560 }561 562 /* Internal: convert local index to global device index */563 static pj_status_t make_global_index(unsigned drv_idx,564 pjmedia_aud_dev_index *id)565 {566 if (*id < 0) {567 return PJ_SUCCESS;568 }569 570 /* Check that factory still exists */571 PJ_ASSERT_RETURN(aud_subsys.drv[drv_idx].f, PJ_EBUG);572 573 /* Check that device index is valid */574 PJ_ASSERT_RETURN(*id>=0 && *id<(int)aud_subsys.drv[drv_idx].dev_cnt,575 PJ_EBUG);576 577 *id += aud_subsys.drv[drv_idx].start_idx;578 return PJ_SUCCESS;579 }580 581 /* Internal: lookup device id */582 static pj_status_t lookup_dev(pjmedia_aud_dev_index id,583 pjmedia_aud_dev_factory **p_f,584 unsigned *p_local_index)585 {586 int f_id, index;587 588 if (id < 0) {589 unsigned i;590 591 if (id == PJMEDIA_AUD_INVALID_DEV)592 return PJMEDIA_EAUD_INVDEV;593 594 for (i=0; i<aud_subsys.drv_cnt; ++i) {595 struct driver *drv = &aud_subsys.drv[i];596 if (drv->dev_idx >= 0) {597 id = drv->dev_idx;598 make_global_index(i, &id);599 break;600 } else if (id==PJMEDIA_AUD_DEFAULT_CAPTURE_DEV &&601 drv->rec_dev_idx >= 0)602 {603 id = drv->rec_dev_idx;604 make_global_index(i, &id);605 break;606 } else if (id==PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV &&607 drv->play_dev_idx >= 0)608 {609 id = drv->play_dev_idx;610 make_global_index(i, &id);611 break;612 }613 }614 615 if (id < 0) {616 return PJMEDIA_EAUD_NODEFDEV;617 }618 }619 620 f_id = GET_FID(aud_subsys.dev_list[id]);621 index = GET_INDEX(aud_subsys.dev_list[id]);622 623 if (f_id < 0 || f_id >= (int)aud_subsys.drv_cnt)624 return PJMEDIA_EAUD_INVDEV;625 626 if (index < 0 || index >= (int)aud_subsys.drv[f_id].dev_cnt)627 return PJMEDIA_EAUD_INVDEV;628 629 *p_f = aud_subsys.drv[f_id].f;630 *p_local_index = (unsigned)index;631 632 return PJ_SUCCESS;633 634 }635 636 /* API: Get device information. */637 PJ_DEF(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_index id,638 pjmedia_aud_dev_info *info)639 {640 pjmedia_aud_dev_factory *f;641 unsigned index;642 pj_status_t status;643 644 PJ_ASSERT_RETURN(info && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);645 PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);646 647 status = lookup_dev(id, &f, &index);648 if (status != PJ_SUCCESS)649 return status;650 651 return f->op->get_dev_info(f, index, info);652 }653 654 /* API: find device */655 PJ_DEF(pj_status_t) pjmedia_aud_dev_lookup( const char *drv_name,656 const char *dev_name,657 pjmedia_aud_dev_index *id)658 {659 pjmedia_aud_dev_factory *f = NULL;660 unsigned drv_idx, dev_idx;661 662 PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);663 PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);664 665 for (drv_idx=0; drv_idx<aud_subsys.drv_cnt; ++drv_idx) {666 if (!pj_ansi_stricmp(drv_name, aud_subsys.drv[drv_idx].name)) {667 f = aud_subsys.drv[drv_idx].f;668 break;669 }670 }671 672 if (!f)673 return PJ_ENOTFOUND;674 675 for (dev_idx=0; dev_idx<aud_subsys.drv[drv_idx].dev_cnt; ++dev_idx) {676 pjmedia_aud_dev_info info;677 pj_status_t status;678 679 status = f->op->get_dev_info(f, dev_idx, &info);680 if (status != PJ_SUCCESS)681 return status;682 683 if (!pj_ansi_stricmp(dev_name, info.name))684 break;685 }686 687 if (dev_idx==aud_subsys.drv[drv_idx].dev_cnt)688 return PJ_ENOTFOUND;689 690 *id = dev_idx;691 make_global_index(drv_idx, id);692 693 return PJ_SUCCESS;694 }695 696 /* API: Initialize the audio device parameters with default values for the697 * specified device.698 */699 PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,700 pjmedia_aud_param *param)701 {702 pjmedia_aud_dev_factory *f;703 unsigned index;704 pj_status_t status;705 706 PJ_ASSERT_RETURN(param && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);707 PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);708 709 status = lookup_dev(id, &f, &index);710 if (status != PJ_SUCCESS)711 return status;712 713 status = f->op->default_param(f, index, param);714 if (status != PJ_SUCCESS)715 return status;716 717 /* Normalize device IDs */718 make_global_index(f->sys.drv_idx, ¶m->rec_id);719 make_global_index(f->sys.drv_idx, ¶m->play_id);720 721 return PJ_SUCCESS;722 }723 724 /* API: Open audio stream object using the specified parameters. */725 PJ_DEF(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_param *prm,726 pjmedia_aud_rec_cb rec_cb,727 pjmedia_aud_play_cb play_cb,728 void *user_data,729 pjmedia_aud_stream **p_aud_strm)730 {731 pjmedia_aud_dev_factory *rec_f=NULL, *play_f=NULL, *f=NULL;732 pjmedia_aud_param param;733 pj_status_t status;734 735 PJ_ASSERT_RETURN(prm && prm->dir && p_aud_strm, PJ_EINVAL);736 PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);737 PJ_ASSERT_RETURN(prm->dir==PJMEDIA_DIR_CAPTURE ||738 prm->dir==PJMEDIA_DIR_PLAYBACK ||739 prm->dir==PJMEDIA_DIR_CAPTURE_PLAYBACK,740 PJ_EINVAL);741 742 /* Must make copy of param because we're changing device ID */743 pj_memcpy(¶m, prm, sizeof(param));744 745 /* Normalize rec_id */746 if (param.dir & PJMEDIA_DIR_CAPTURE) {747 unsigned index;748 749 if (param.rec_id < 0)750 param.rec_id = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV;751 752 status = lookup_dev(param.rec_id, &rec_f, &index);753 if (status != PJ_SUCCESS)754 return status;755 756 param.rec_id = index;757 f = rec_f;758 }759 760 /* Normalize play_id */761 if (param.dir & PJMEDIA_DIR_PLAYBACK) {762 unsigned index;763 764 if (param.play_id < 0)765 param.play_id = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;766 767 status = lookup_dev(param.play_id, &play_f, &index);768 if (status != PJ_SUCCESS)769 return status;770 771 param.play_id = index;772 f = play_f;773 }774 775 PJ_ASSERT_RETURN(f != NULL, PJ_EBUG);776 777 /* For now, rec_id and play_id must belong to the same factory */778 PJ_ASSERT_RETURN((param.dir != PJMEDIA_DIR_CAPTURE_PLAYBACK) ||779 (rec_f == play_f),780 PJMEDIA_EAUD_INVDEV);781 782 /* Create the stream */783 status = f->op->create_stream(f, ¶m, rec_cb, play_cb,784 user_data, p_aud_strm);785 if (status != PJ_SUCCESS)786 return status;787 788 /* Assign factory id to the stream */789 (*p_aud_strm)->sys.drv_idx = f->sys.drv_idx;790 return PJ_SUCCESS;791 }792 793 /* API: Get the running parameters for the specified audio stream. */794 PJ_DEF(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,795 pjmedia_aud_param *param)796 {797 pj_status_t status;798 799 PJ_ASSERT_RETURN(strm && param, PJ_EINVAL);800 PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);801 802 status = strm->op->get_param(strm, param);803 if (status != PJ_SUCCESS)804 return status;805 806 /* Normalize device id's */807 make_global_index(strm->sys.drv_idx, ¶m->rec_id);808 make_global_index(strm->sys.drv_idx, ¶m->play_id);809 810 return PJ_SUCCESS;811 }812 813 /* API: Get the value of a specific capability of the audio stream. */814 PJ_DEF(pj_status_t) pjmedia_aud_stream_get_cap(pjmedia_aud_stream *strm,815 pjmedia_aud_dev_cap cap,816 void *value)817 {818 return strm->op->get_cap(strm, cap, value);819 }820 821 /* API: Set the value of a specific capability of the audio stream. */822 PJ_DEF(pj_status_t) pjmedia_aud_stream_set_cap(pjmedia_aud_stream *strm,823 pjmedia_aud_dev_cap cap,824 const void *value)825 {826 return strm->op->set_cap(strm, cap, value);827 }828 829 /* API: Start the stream. */830 PJ_DEF(pj_status_t) pjmedia_aud_stream_start(pjmedia_aud_stream *strm)831 {832 return strm->op->start(strm);833 }834 835 /* API: Stop the stream. */836 PJ_DEF(pj_status_t) pjmedia_aud_stream_stop(pjmedia_aud_stream *strm)837 {838 return strm->op->stop(strm);839 }840 841 /* API: Destroy the stream. */842 PJ_DEF(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm)843 {844 return strm->op->destroy(strm);845 }846 847
Note: See TracChangeset
for help on using the changeset viewer.