1
/* $Id: audiodev.c 4150 2012-06-01 04:29:56Z ming $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
#include <pjmedia-audiodev/audiodev_imp.h>
21
#include <pj/assert.h>
25
#include <pj/string.h>
27
#define THIS_FILE "audiodev.c"
29
#define DEFINE_CAP(name, info) {name, info}
31
/* Capability names */
32
static struct cap_info
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")
56
* The device index seen by application and driver is different.
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 particular
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 0
68
/* extern functions to create factories */
69
#if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
70
pjmedia_aud_dev_factory* pjmedia_pa_factory(pj_pool_factory *pf);
73
#if PJMEDIA_AUDIO_DEV_HAS_COREAUDIO
74
pjmedia_aud_dev_factory* pjmedia_coreaudio_factory(pj_pool_factory *pf);
77
#if PJMEDIA_AUDIO_DEV_HAS_ALSA
78
pjmedia_aud_dev_factory* pjmedia_alsa_factory(pj_pool_factory *pf);
81
#if PJMEDIA_AUDIO_DEV_HAS_BB10
82
pjmedia_aud_dev_factory* pjmedia_bb10_factory(pj_pool_factory *pf);
85
#if PJMEDIA_AUDIO_DEV_HAS_WMME
86
pjmedia_aud_dev_factory* pjmedia_wmme_factory(pj_pool_factory *pf);
89
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_VAS
90
pjmedia_aud_dev_factory* pjmedia_symb_vas_factory(pj_pool_factory *pf);
93
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_APS
94
pjmedia_aud_dev_factory* pjmedia_aps_factory(pj_pool_factory *pf);
97
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA
98
pjmedia_aud_dev_factory* pjmedia_symb_mda_factory(pj_pool_factory *pf);
101
#if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO
102
pjmedia_aud_dev_factory* pjmedia_null_audio_factory(pj_pool_factory *pf);
105
#define MAX_DRIVERS 16
109
/* driver structure */
112
/* Creation function */
113
pjmedia_aud_dev_factory_create_func_ptr create;
114
/* Factory instance */
115
pjmedia_aud_dev_factory *f;
116
char name[32]; /* Driver name */
117
unsigned dev_cnt; /* Number of devices */
118
unsigned start_idx; /* Start index in global list */
119
int rec_dev_idx;/* Default capture device. */
120
int play_dev_idx;/* Default playback device */
121
int dev_idx; /* Default device. */
124
/* The audio subsystem */
125
static struct aud_subsys
127
unsigned init_count; /* How many times init() is called */
128
pj_pool_factory *pf; /* The pool factory. */
130
unsigned drv_cnt; /* Number of drivers. */
131
struct driver drv[MAX_DRIVERS]; /* Array of drivers. */
133
unsigned dev_cnt; /* Total number of devices. */
134
pj_uint32_t dev_list[MAX_DEVS];/* Array of device IDs. */
138
/* API: get capability name/info */
139
PJ_DEF(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
145
if (p_desc==NULL) p_desc = &desc;
147
for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {
152
if (i==PJ_ARRAY_SIZE(cap_infos)) {
157
*p_desc = cap_infos[i].info;
158
return cap_infos[i].name;
161
static pj_status_t get_cap_pointer(const pjmedia_aud_param *param,
162
pjmedia_aud_dev_cap cap,
166
#define FIELD_INFO(name) *ptr = (void*)¶m->name; \
167
*size = sizeof(param->name)
170
case PJMEDIA_AUD_DEV_CAP_EXT_FORMAT:
173
case PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY:
174
FIELD_INFO(input_latency_ms);
176
case PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY:
177
FIELD_INFO(output_latency_ms);
179
case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
180
FIELD_INFO(input_vol);
182
case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
183
FIELD_INFO(output_vol);
185
case PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE:
186
FIELD_INFO(input_route);
188
case PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE:
189
FIELD_INFO(output_route);
191
case PJMEDIA_AUD_DEV_CAP_EC:
192
FIELD_INFO(ec_enabled);
194
case PJMEDIA_AUD_DEV_CAP_EC_TAIL:
195
FIELD_INFO(ec_tail_ms);
197
/* vad is no longer in "fmt" in 2.0.
198
case PJMEDIA_AUD_DEV_CAP_VAD:
199
FIELD_INFO(ext_fmt.vad);
202
case PJMEDIA_AUD_DEV_CAP_CNG:
203
FIELD_INFO(cng_enabled);
205
case PJMEDIA_AUD_DEV_CAP_PLC:
206
FIELD_INFO(plc_enabled);
209
return PJMEDIA_EAUD_INVCAP;
217
/* API: set cap value to param */
218
PJ_DEF(pj_status_t) pjmedia_aud_param_set_cap( pjmedia_aud_param *param,
219
pjmedia_aud_dev_cap cap,
226
status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
227
if (status != PJ_SUCCESS)
230
pj_memcpy(cap_ptr, pval, cap_size);
236
/* API: get cap value from param */
237
PJ_DEF(pj_status_t) pjmedia_aud_param_get_cap( const pjmedia_aud_param *param,
238
pjmedia_aud_dev_cap cap,
245
status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
246
if (status != PJ_SUCCESS)
249
if ((param->flags & cap) == 0) {
250
pj_bzero(cap_ptr, cap_size);
251
return PJMEDIA_EAUD_INVCAP;
254
pj_memcpy(pval, cap_ptr, cap_size);
258
/* Internal: init driver */
259
static pj_status_t init_driver(unsigned drv_idx, pj_bool_t refresh)
261
struct driver *drv = &aud_subsys.drv[drv_idx];
262
pjmedia_aud_dev_factory *f;
267
/* Create the factory */
268
f = (*drv->create)(aud_subsys.pf);
272
/* Call factory->init() */
273
status = f->op->init(f);
274
if (status != PJ_SUCCESS) {
282
/* Get number of devices */
283
dev_cnt = f->op->get_dev_count(f);
284
if (dev_cnt + aud_subsys.dev_cnt > MAX_DEVS) {
285
PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because"
286
" there are too many devices",
287
aud_subsys.dev_cnt + dev_cnt - MAX_DEVS));
288
dev_cnt = MAX_DEVS - aud_subsys.dev_cnt;
291
/* enabling this will cause pjsua-lib initialization to fail when there
292
* is no sound device installed in the system, even when pjsua has been
293
* run with --null-audio
297
return PJMEDIA_EAUD_NODEV;
301
/* Fill in default devices */
302
drv->play_dev_idx = drv->rec_dev_idx = drv->dev_idx = -1;
303
for (i=0; i<dev_cnt; ++i) {
304
pjmedia_aud_dev_info info;
306
status = f->op->get_dev_info(f, i, &info);
307
if (status != PJ_SUCCESS) {
312
if (drv->name[0]=='\0') {
313
/* Set driver name */
314
pj_ansi_strncpy(drv->name, info.driver, sizeof(drv->name));
315
drv->name[sizeof(drv->name)-1] = '\0';
318
if (drv->play_dev_idx < 0 && info.output_count) {
319
/* Set default playback device */
320
drv->play_dev_idx = i;
322
if (drv->rec_dev_idx < 0 && info.input_count) {
323
/* Set default capture device */
324
drv->rec_dev_idx = i;
326
if (drv->dev_idx < 0 && info.input_count &&
329
/* Set default capture and playback device */
333
if (drv->play_dev_idx >= 0 && drv->rec_dev_idx >= 0 &&
341
/* Register the factory */
343
drv->f->sys.drv_idx = drv_idx;
344
drv->start_idx = aud_subsys.dev_cnt;
345
drv->dev_cnt = dev_cnt;
347
/* Register devices to global list */
348
for (i=0; i<dev_cnt; ++i) {
349
aud_subsys.dev_list[aud_subsys.dev_cnt++] = MAKE_DEV_ID(drv_idx, i);
355
/* Internal: deinit driver */
356
static void deinit_driver(unsigned drv_idx)
358
struct driver *drv = &aud_subsys.drv[drv_idx];
361
drv->f->op->destroy(drv->f);
366
drv->play_dev_idx = drv->rec_dev_idx = drv->dev_idx = -1;
369
/* API: Initialize the audio subsystem. */
370
PJ_DEF(pj_status_t) pjmedia_aud_subsys_init(pj_pool_factory *pf)
375
/* Allow init() to be called multiple times as long as there is matching
376
* number of shutdown().
378
if (aud_subsys.init_count++ != 0) {
382
/* Register error subsystem */
383
status = pj_register_strerror(PJMEDIA_AUDIODEV_ERRNO_START,
385
&pjmedia_audiodev_strerror);
386
pj_assert(status == PJ_SUCCESS);
390
aud_subsys.drv_cnt = 0;
391
aud_subsys.dev_cnt = 0;
393
/* Register creation functions */
394
#if PJMEDIA_AUDIO_DEV_HAS_BB10
395
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_bb10_factory;
397
#if PJMEDIA_AUDIO_DEV_HAS_ALSA
398
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_alsa_factory;
400
#if PJMEDIA_AUDIO_DEV_HAS_COREAUDIO
401
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_coreaudio_factory;
403
#if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
404
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_pa_factory;
406
#if PJMEDIA_AUDIO_DEV_HAS_WMME
407
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_wmme_factory;
409
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_VAS
410
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_symb_vas_factory;
412
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_APS
413
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_aps_factory;
415
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA
416
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_symb_mda_factory;
418
#if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO
419
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_null_audio_factory;
422
/* Initialize each factory and build the device ID list */
423
for (i=0; i<aud_subsys.drv_cnt; ++i) {
424
status = init_driver(i, PJ_FALSE);
425
if (status != PJ_SUCCESS) {
431
return aud_subsys.dev_cnt ? PJ_SUCCESS : status;
434
/* API: register an audio device factory to the audio subsystem. */
436
pjmedia_aud_register_factory(pjmedia_aud_dev_factory_create_func_ptr adf)
440
if (aud_subsys.init_count == 0)
441
return PJMEDIA_EAUD_INIT;
443
aud_subsys.drv[aud_subsys.drv_cnt].create = adf;
444
status = init_driver(aud_subsys.drv_cnt, PJ_FALSE);
445
if (status == PJ_SUCCESS) {
446
aud_subsys.drv_cnt++;
448
deinit_driver(aud_subsys.drv_cnt);
454
/* API: unregister an audio device factory from the audio subsystem. */
456
pjmedia_aud_unregister_factory(pjmedia_aud_dev_factory_create_func_ptr adf)
460
if (aud_subsys.init_count == 0)
461
return PJMEDIA_EAUD_INIT;
463
for (i=0; i<aud_subsys.drv_cnt; ++i) {
464
struct driver *drv = &aud_subsys.drv[i];
466
if (drv->create == adf) {
467
for (j = drv->start_idx; j < drv->start_idx + drv->dev_cnt; j++)
469
aud_subsys.dev_list[j] = (pj_uint32_t)PJMEDIA_AUD_INVALID_DEV;
473
pj_bzero(drv, sizeof(*drv));
478
return PJMEDIA_EAUD_ERR;
481
/* API: get the pool factory registered to the audio subsystem. */
482
PJ_DEF(pj_pool_factory*) pjmedia_aud_subsys_get_pool_factory(void)
484
return aud_subsys.pf;
487
/* API: Shutdown the audio subsystem. */
488
PJ_DEF(pj_status_t) pjmedia_aud_subsys_shutdown(void)
492
/* Allow shutdown() to be called multiple times as long as there is matching
495
if (aud_subsys.init_count == 0) {
498
--aud_subsys.init_count;
500
if (aud_subsys.init_count == 0) {
501
for (i=0; i<aud_subsys.drv_cnt; ++i) {
505
aud_subsys.pf = NULL;
510
/* API: Refresh the list of sound devices installed in the system. */
511
PJ_DEF(pj_status_t) pjmedia_aud_dev_refresh(void)
515
aud_subsys.dev_cnt = 0;
516
for (i=0; i<aud_subsys.drv_cnt; ++i) {
517
struct driver *drv = &aud_subsys.drv[i];
519
if (drv->f && drv->f->op->refresh) {
520
pj_status_t status = drv->f->op->refresh(drv->f);
521
if (status != PJ_SUCCESS) {
522
PJ_PERROR(4, (THIS_FILE, status, "Unable to refresh device "
523
"list for %s", drv->name));
526
init_driver(i, PJ_TRUE);
531
/* API: Get the number of sound devices installed in the system. */
532
PJ_DEF(unsigned) pjmedia_aud_dev_count(void)
534
return aud_subsys.dev_cnt;
537
/* Internal: convert local index to global device index */
538
static pj_status_t make_global_index(unsigned drv_idx,
539
pjmedia_aud_dev_index *id)
545
/* Check that factory still exists */
546
PJ_ASSERT_RETURN(aud_subsys.drv[drv_idx].f, PJ_EBUG);
548
/* Check that device index is valid */
549
PJ_ASSERT_RETURN(*id>=0 && *id<(int)aud_subsys.drv[drv_idx].dev_cnt,
552
*id += aud_subsys.drv[drv_idx].start_idx;
556
/* Internal: lookup device id */
557
static pj_status_t lookup_dev(pjmedia_aud_dev_index id,
558
pjmedia_aud_dev_factory **p_f,
559
unsigned *p_local_index)
566
if (id == PJMEDIA_AUD_INVALID_DEV)
567
return PJMEDIA_EAUD_INVDEV;
569
for (i=0; i<aud_subsys.drv_cnt; ++i) {
570
struct driver *drv = &aud_subsys.drv[i];
571
if (drv->dev_idx >= 0) {
573
make_global_index(i, &id);
575
} else if (id==PJMEDIA_AUD_DEFAULT_CAPTURE_DEV &&
576
drv->rec_dev_idx >= 0)
578
id = drv->rec_dev_idx;
579
make_global_index(i, &id);
581
} else if (id==PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV &&
582
drv->play_dev_idx >= 0)
584
id = drv->play_dev_idx;
585
make_global_index(i, &id);
591
return PJMEDIA_EAUD_NODEFDEV;
595
f_id = GET_FID(aud_subsys.dev_list[id]);
596
index = GET_INDEX(aud_subsys.dev_list[id]);
598
if (f_id < 0 || f_id >= (int)aud_subsys.drv_cnt)
599
return PJMEDIA_EAUD_INVDEV;
601
if (index < 0 || index >= (int)aud_subsys.drv[f_id].dev_cnt)
602
return PJMEDIA_EAUD_INVDEV;
604
*p_f = aud_subsys.drv[f_id].f;
605
*p_local_index = (unsigned)index;
611
/* API: Get device information. */
612
PJ_DEF(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_index id,
613
pjmedia_aud_dev_info *info)
615
pjmedia_aud_dev_factory *f;
619
PJ_ASSERT_RETURN(info && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);
620
PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
622
status = lookup_dev(id, &f, &index);
623
if (status != PJ_SUCCESS)
626
return f->op->get_dev_info(f, index, info);
629
/* API: find device */
630
PJ_DEF(pj_status_t) pjmedia_aud_dev_lookup( const char *drv_name,
631
const char *dev_name,
632
pjmedia_aud_dev_index *id)
634
pjmedia_aud_dev_factory *f = NULL;
635
unsigned drv_idx, dev_idx;
637
PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);
638
PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
640
for (drv_idx=0; drv_idx<aud_subsys.drv_cnt; ++drv_idx) {
641
if (!pj_ansi_stricmp(drv_name, aud_subsys.drv[drv_idx].name)) {
642
f = aud_subsys.drv[drv_idx].f;
650
for (dev_idx=0; dev_idx<aud_subsys.drv[drv_idx].dev_cnt; ++dev_idx) {
651
pjmedia_aud_dev_info info;
654
status = f->op->get_dev_info(f, dev_idx, &info);
655
if (status != PJ_SUCCESS)
658
if (!pj_ansi_stricmp(dev_name, info.name))
662
if (dev_idx==aud_subsys.drv[drv_idx].dev_cnt)
666
make_global_index(drv_idx, id);
671
/* API: Initialize the audio device parameters with default values for the
674
PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
675
pjmedia_aud_param *param)
677
pjmedia_aud_dev_factory *f;
681
PJ_ASSERT_RETURN(param && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);
682
PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
684
status = lookup_dev(id, &f, &index);
685
if (status != PJ_SUCCESS)
688
status = f->op->default_param(f, index, param);
689
if (status != PJ_SUCCESS)
692
/* Normalize device IDs */
693
make_global_index(f->sys.drv_idx, ¶m->rec_id);
694
make_global_index(f->sys.drv_idx, ¶m->play_id);
699
/* API: Open audio stream object using the specified parameters. */
700
PJ_DEF(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_param *prm,
701
pjmedia_aud_rec_cb rec_cb,
702
pjmedia_aud_play_cb play_cb,
704
pjmedia_aud_stream **p_aud_strm)
706
pjmedia_aud_dev_factory *rec_f=NULL, *play_f=NULL, *f=NULL;
707
pjmedia_aud_param param;
710
PJ_ASSERT_RETURN(prm && prm->dir && p_aud_strm, PJ_EINVAL);
711
PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
712
PJ_ASSERT_RETURN(prm->dir==PJMEDIA_DIR_CAPTURE ||
713
prm->dir==PJMEDIA_DIR_PLAYBACK ||
714
prm->dir==PJMEDIA_DIR_CAPTURE_PLAYBACK,
717
/* Must make copy of param because we're changing device ID */
718
pj_memcpy(¶m, prm, sizeof(param));
720
/* Normalize rec_id */
721
if (param.dir & PJMEDIA_DIR_CAPTURE) {
724
if (param.rec_id < 0)
725
param.rec_id = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV;
727
status = lookup_dev(param.rec_id, &rec_f, &index);
728
if (status != PJ_SUCCESS)
731
param.rec_id = index;
735
/* Normalize play_id */
736
if (param.dir & PJMEDIA_DIR_PLAYBACK) {
739
if (param.play_id < 0)
740
param.play_id = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
742
status = lookup_dev(param.play_id, &play_f, &index);
743
if (status != PJ_SUCCESS)
746
param.play_id = index;
750
PJ_ASSERT_RETURN(f != NULL, PJ_EBUG);
752
/* For now, rec_id and play_id must belong to the same factory */
753
PJ_ASSERT_RETURN((param.dir != PJMEDIA_DIR_CAPTURE_PLAYBACK) ||
755
PJMEDIA_EAUD_INVDEV);
757
/* Create the stream */
758
status = f->op->create_stream(f, ¶m, rec_cb, play_cb,
759
user_data, p_aud_strm);
760
if (status != PJ_SUCCESS)
763
/* Assign factory id to the stream */
764
(*p_aud_strm)->sys.drv_idx = f->sys.drv_idx;
768
/* API: Get the running parameters for the specified audio stream. */
769
PJ_DEF(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,
770
pjmedia_aud_param *param)
774
PJ_ASSERT_RETURN(strm && param, PJ_EINVAL);
775
PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
777
status = strm->op->get_param(strm, param);
778
if (status != PJ_SUCCESS)
781
/* Normalize device id's */
782
make_global_index(strm->sys.drv_idx, ¶m->rec_id);
783
make_global_index(strm->sys.drv_idx, ¶m->play_id);
788
/* API: Get the value of a specific capability of the audio stream. */
789
PJ_DEF(pj_status_t) pjmedia_aud_stream_get_cap(pjmedia_aud_stream *strm,
790
pjmedia_aud_dev_cap cap,
793
return strm->op->get_cap(strm, cap, value);
796
/* API: Set the value of a specific capability of the audio stream. */
797
PJ_DEF(pj_status_t) pjmedia_aud_stream_set_cap(pjmedia_aud_stream *strm,
798
pjmedia_aud_dev_cap cap,
801
return strm->op->set_cap(strm, cap, value);
804
/* API: Start the stream. */
805
PJ_DEF(pj_status_t) pjmedia_aud_stream_start(pjmedia_aud_stream *strm)
807
return strm->op->start(strm);
810
/* API: Stop the stream. */
811
PJ_DEF(pj_status_t) pjmedia_aud_stream_stop(pjmedia_aud_stream *strm)
813
return strm->op->stop(strm);
816
/* API: Destroy the stream. */
817
PJ_DEF(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm)
819
return strm->op->destroy(strm);