blob: 275cf936f8a5f2cbfcf6e7bc9053883ef4379eb5 [file] [log] [blame]
Benny Prijono2cd64f82009-02-17 19:57:48 +00001/* $Id$ */
2/*
3 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
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.
10 *
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.
15 *
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
19 */
20#include <pjmedia-audiodev/audiodev_imp.h>
21#include <pj/errno.h>
Benny Prijono10454dc2009-02-21 14:21:59 +000022#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
Benny Prijono2cd64f82009-02-17 19:57:48 +000050
Benny Prijono598b01d2009-02-18 13:55:03 +000051/*
Benny Prijono10454dc2009-02-21 14:21:59 +000052 * The device index seen by application and driver is different.
Benny Prijono598b01d2009-02-18 13:55:03 +000053 *
Benny Prijono10454dc2009-02-21 14:21:59 +000054 * 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.
Benny Prijono598b01d2009-02-18 13:55:03 +000057 */
Benny Prijonoe3ebd552009-02-18 20:14:15 +000058#define MAKE_DEV_ID(f_id, index) (((f_id & 0xFFFF) << 16) | (index & 0xFFFF))
Benny Prijono2cd64f82009-02-17 19:57:48 +000059#define GET_INDEX(dev_id) ((dev_id) & 0xFFFF)
60#define GET_FID(dev_id) ((dev_id) >> 16)
Benny Prijono598b01d2009-02-18 13:55:03 +000061#define DEFAULT_DEV_ID 0
Benny Prijono2cd64f82009-02-17 19:57:48 +000062
63
Benny Prijono598b01d2009-02-18 13:55:03 +000064/* extern functions to create factories */
Benny Prijono2cd64f82009-02-17 19:57:48 +000065pjmedia_aud_dev_factory* pjmedia_pa_factory(pj_pool_factory *pf);
Benny Prijono598b01d2009-02-18 13:55:03 +000066pjmedia_aud_dev_factory* pjmedia_wmme_factory(pj_pool_factory *pf);
67
Benny Prijonoe3ebd552009-02-18 20:14:15 +000068#define MAX_DRIVERS 16
Benny Prijono10454dc2009-02-21 14:21:59 +000069#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 */
Benny Prijono96e74f32009-02-22 12:00:12 +000082 int rec_dev_idx;/* Default capture device. */
83 int play_dev_idx;/* Default playback device */
84 int dev_idx; /* Default device. */
Benny Prijono10454dc2009-02-21 14:21:59 +000085};
Benny Prijono2cd64f82009-02-17 19:57:48 +000086
Benny Prijonoe3ebd552009-02-18 20:14:15 +000087/* The audio subsystem */
88static struct aud_subsys
Benny Prijono2cd64f82009-02-17 19:57:48 +000089{
Benny Prijono10454dc2009-02-21 14:21:59 +000090 unsigned init_count; /* How many times init() is called */
91 pj_pool_factory *pf; /* The pool factory. */
Benny Prijono2cd64f82009-02-17 19:57:48 +000092
Benny Prijono10454dc2009-02-21 14:21:59 +000093 unsigned drv_cnt; /* Number of drivers. */
94 struct driver drv[MAX_DRIVERS]; /* Array of drivers. */
Benny Prijonoe3ebd552009-02-18 20:14:15 +000095
Benny Prijono10454dc2009-02-21 14:21:59 +000096 unsigned dev_cnt; /* Total number of devices. */
97 pj_uint32_t dev_list[MAX_DEVS];/* Array of device IDs. */
Benny Prijonoe3ebd552009-02-18 20:14:15 +000098
99} aud_subsys;
100
Benny Prijono2cd64f82009-02-17 19:57:48 +0000101
Benny Prijono96e74f32009-02-22 12:00:12 +0000102/* Internal: init driver */
103static pj_status_t init_driver(unsigned drv_idx)
104{
105 struct driver *drv = &aud_subsys.drv[drv_idx];
106 pjmedia_aud_dev_factory *f;
107 unsigned i, dev_cnt;
108 pj_status_t status;
109
110 /* Create the factory */
111 f = (*drv->create)(aud_subsys.pf);
112 if (!f)
113 return PJ_EUNKNOWN;
114
115 /* Call factory->init() */
116 status = f->op->init(f);
117 if (status != PJ_SUCCESS) {
118 f->op->destroy(f);
119 return status;
120 }
121
122 /* Get number of devices */
123 dev_cnt = f->op->get_dev_count(f);
124 if (dev_cnt + aud_subsys.dev_cnt > MAX_DEVS) {
125 PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because"
126 " there are too many devices",
127 aud_subsys.dev_cnt + dev_cnt - MAX_DEVS));
128 dev_cnt = MAX_DEVS - aud_subsys.dev_cnt;
129 }
130 if (dev_cnt == 0) {
131 f->op->destroy(f);
132 return PJMEDIA_EAUD_NODEV;
133 }
134
135 /* Fill in default devices */
136 drv->play_dev_idx = drv->rec_dev_idx = drv->dev_idx = -1;
137 for (i=0; i<dev_cnt; ++i) {
138 pjmedia_aud_dev_info info;
139
140 status = f->op->get_dev_info(f, i, &info);
141 if (status != PJ_SUCCESS) {
142 f->op->destroy(f);
143 return status;
144 }
145
146 if (drv->name[0]=='\0') {
147 /* Set driver name */
148 pj_ansi_strncpy(drv->name, info.driver, sizeof(drv->name));
149 drv->name[sizeof(drv->name)-1] = '\0';
150 }
151
152 if (drv->play_dev_idx < 0 && info.output_count) {
153 /* Set default playback device */
154 drv->play_dev_idx = i;
155 }
156 if (drv->rec_dev_idx < 0 && info.input_count) {
157 /* Set default capture device */
158 drv->rec_dev_idx = i;
159 }
160 if (drv->dev_idx < 0 && info.input_count &&
161 info.output_count)
162 {
163 /* Set default capture and playback device */
164 drv->dev_idx = i;
165 }
166
167 if (drv->play_dev_idx >= 0 && drv->rec_dev_idx >= 0 &&
168 drv->dev_idx >= 0)
169 {
170 /* Done. */
171 break;
172 }
173 }
174
175 /* Register the factory */
176 drv->f = f;
177 drv->f->sys.drv_idx = drv_idx;
178 drv->start_idx = aud_subsys.dev_cnt;
179 drv->dev_cnt = dev_cnt;
180
181 /* Register devices to global list */
182 for (i=0; i<dev_cnt; ++i) {
183 aud_subsys.dev_list[aud_subsys.dev_cnt++] = MAKE_DEV_ID(drv_idx, i);
184 }
185
186 return PJ_SUCCESS;
187}
188
189/* Internal: deinit driver */
190static void deinit_driver(unsigned drv_idx)
191{
192 struct driver *drv = &aud_subsys.drv[drv_idx];
193
194 if (drv->f) {
195 drv->f->op->destroy(drv->f);
196 drv->f = NULL;
197 }
198
199 drv->dev_cnt = 0;
200 drv->play_dev_idx = drv->rec_dev_idx = drv->dev_idx = -1;
201}
Benny Prijono2cd64f82009-02-17 19:57:48 +0000202
203/* API: Initialize the audio subsystem. */
204PJ_DEF(pj_status_t) pjmedia_aud_subsys_init(pj_pool_factory *pf)
205{
206 unsigned i;
207 pj_status_t status = PJ_ENOMEM;
208
Benny Prijono555139d2009-02-19 12:08:19 +0000209 /* Allow init() to be called multiple times as long as there is matching
210 * number of shutdown().
211 */
212 if (aud_subsys.init_count++ != 0) {
213 return PJ_SUCCESS;
214 }
215
Benny Prijonoe3ebd552009-02-18 20:14:15 +0000216 aud_subsys.pf = pf;
Benny Prijono10454dc2009-02-21 14:21:59 +0000217 aud_subsys.drv_cnt = 0;
218 aud_subsys.dev_cnt = 0;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000219
Benny Prijono10454dc2009-02-21 14:21:59 +0000220 /* Register creation functions */
221 aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_pa_factory;
222 aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_wmme_factory;
Benny Prijonoe3ebd552009-02-18 20:14:15 +0000223
Benny Prijono10454dc2009-02-21 14:21:59 +0000224 /* Initialize each factory and build the device ID list */
225 for (i=0; i<aud_subsys.drv_cnt; ++i) {
Benny Prijono96e74f32009-02-22 12:00:12 +0000226 status = init_driver(i);
Benny Prijono2cd64f82009-02-17 19:57:48 +0000227 if (status != PJ_SUCCESS) {
Benny Prijono96e74f32009-02-22 12:00:12 +0000228 deinit_driver(i);
Benny Prijonoe3ebd552009-02-18 20:14:15 +0000229 continue;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000230 }
Benny Prijono2cd64f82009-02-17 19:57:48 +0000231 }
232
Benny Prijono96e74f32009-02-22 12:00:12 +0000233 return aud_subsys.dev_cnt ? PJ_SUCCESS : status;
Benny Prijonoe3ebd552009-02-18 20:14:15 +0000234}
235
236/* API: get the pool factory registered to the audio subsystem. */
237PJ_DEF(pj_pool_factory*) pjmedia_aud_subsys_get_pool_factory(void)
238{
239 return aud_subsys.pf;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000240}
241
242/* API: Shutdown the audio subsystem. */
243PJ_DEF(pj_status_t) pjmedia_aud_subsys_shutdown(void)
244{
245 unsigned i;
246
Benny Prijono555139d2009-02-19 12:08:19 +0000247 /* Allow shutdown() to be called multiple times as long as there is matching
248 * number of init().
249 */
250 if (aud_subsys.init_count == 0) {
251 return PJ_SUCCESS;
252 }
253 --aud_subsys.init_count;
254
Benny Prijono10454dc2009-02-21 14:21:59 +0000255 for (i=0; i<aud_subsys.drv_cnt; ++i) {
Benny Prijono96e74f32009-02-22 12:00:12 +0000256 deinit_driver(i);
Benny Prijono2cd64f82009-02-17 19:57:48 +0000257 }
258
Benny Prijono96e74f32009-02-22 12:00:12 +0000259 aud_subsys.pf = NULL;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000260 return PJ_SUCCESS;
261}
262
Benny Prijono10454dc2009-02-21 14:21:59 +0000263/* API: get capability name/info */
264PJ_DEF(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
265 const char **p_desc)
266{
267 char *desc;
268 unsigned i;
269
270 if (p_desc==NULL) p_desc = &desc;
271
272 for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {
273 if ((1 << i)==cap)
274 break;
275 }
276
277 if (i==32) {
278 *p_desc = "??";
279 return "??";
280 }
281
282 *p_desc = cap_infos[i].info;
283 return cap_infos[i].name;
284}
285
Benny Prijono2cd64f82009-02-17 19:57:48 +0000286/* API: Get the number of sound devices installed in the system. */
287PJ_DEF(unsigned) pjmedia_aud_dev_count(void)
288{
Benny Prijono10454dc2009-02-21 14:21:59 +0000289 return aud_subsys.dev_cnt;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000290}
291
Benny Prijono96e74f32009-02-22 12:00:12 +0000292/* Internal: convert local index to global device index */
293static pj_status_t make_global_index(unsigned drv_idx,
294 pjmedia_aud_dev_index *id)
295{
296 if (*id < 0) {
297 return PJ_SUCCESS;
298 }
299
300 /* Check that factory still exists */
301 PJ_ASSERT_RETURN(aud_subsys.drv[drv_idx].f, PJ_EBUG);
302
303 /* Check that device index is valid */
304 PJ_ASSERT_RETURN(*id>=0 && *id<(int)aud_subsys.drv[drv_idx].dev_cnt,
305 PJ_EBUG);
306
307 *id += aud_subsys.drv[drv_idx].start_idx;
308 return PJ_SUCCESS;
309}
310
Benny Prijono10454dc2009-02-21 14:21:59 +0000311/* Internal: lookup device id */
312static pj_status_t lookup_dev(pjmedia_aud_dev_index id,
313 pjmedia_aud_dev_factory **p_f,
314 unsigned *p_local_index)
Benny Prijono2cd64f82009-02-17 19:57:48 +0000315{
Benny Prijono10454dc2009-02-21 14:21:59 +0000316 int f_id, index;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000317
Benny Prijono96e74f32009-02-22 12:00:12 +0000318 if (id < 0) {
319 unsigned i;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000320
Benny Prijono96e74f32009-02-22 12:00:12 +0000321 if (id == PJMEDIA_AUD_INVALID_DEV)
322 return PJMEDIA_EAUD_INVDEV;
323
324 for (i=0; i<aud_subsys.drv_cnt; ++i) {
325 struct driver *drv = &aud_subsys.drv[i];
326 if (drv->dev_idx >= 0) {
327 id = drv->dev_idx;
328 make_global_index(i, &id);
329 break;
330 } else if (id==PJMEDIA_AUD_DEFAULT_CAPTURE_DEV &&
331 drv->rec_dev_idx >= 0)
332 {
333 id = drv->rec_dev_idx;
334 make_global_index(i, &id);
335 break;
336 } else if (id==PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV &&
337 drv->play_dev_idx >= 0)
338 {
339 id = drv->play_dev_idx;
340 make_global_index(i, &id);
341 break;
342 }
343 }
344
345 if (id < 0) {
346 return PJMEDIA_EAUD_NODEFDEV;
347 }
348 }
Benny Prijono2cd64f82009-02-17 19:57:48 +0000349
Benny Prijono10454dc2009-02-21 14:21:59 +0000350 f_id = GET_FID(aud_subsys.dev_list[id]);
351 index = GET_INDEX(aud_subsys.dev_list[id]);
Benny Prijono2cd64f82009-02-17 19:57:48 +0000352
Benny Prijono10454dc2009-02-21 14:21:59 +0000353 if (f_id < 0 || f_id >= (int)aud_subsys.drv_cnt)
354 return PJMEDIA_EAUD_INVDEV;
355
356 if (index < 0 || index >= (int)aud_subsys.drv[f_id].dev_cnt)
357 return PJMEDIA_EAUD_INVDEV;
358
359 *p_f = aud_subsys.drv[f_id].f;
360 *p_local_index = (unsigned)index;
361
362 return PJ_SUCCESS;
363
Benny Prijono2cd64f82009-02-17 19:57:48 +0000364}
365
Benny Prijono2cd64f82009-02-17 19:57:48 +0000366/* API: Get device information. */
Benny Prijono10454dc2009-02-21 14:21:59 +0000367PJ_DEF(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_index id,
Benny Prijono2cd64f82009-02-17 19:57:48 +0000368 pjmedia_aud_dev_info *info)
369{
Benny Prijonoe3ebd552009-02-18 20:14:15 +0000370 pjmedia_aud_dev_factory *f;
Benny Prijono10454dc2009-02-21 14:21:59 +0000371 unsigned index;
372 pj_status_t status;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000373
Benny Prijono96e74f32009-02-22 12:00:12 +0000374 PJ_ASSERT_RETURN(info && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);
375 PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
Benny Prijono598b01d2009-02-18 13:55:03 +0000376
Benny Prijono10454dc2009-02-21 14:21:59 +0000377 status = lookup_dev(id, &f, &index);
378 if (status != PJ_SUCCESS)
379 return status;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000380
Benny Prijonoe3ebd552009-02-18 20:14:15 +0000381 return f->op->get_dev_info(f, index, info);
Benny Prijono2cd64f82009-02-17 19:57:48 +0000382}
383
Benny Prijono10454dc2009-02-21 14:21:59 +0000384/* API: find device */
385PJ_DEF(pj_status_t) pjmedia_aud_dev_lookup( const char *drv_name,
386 const char *dev_name,
387 pjmedia_aud_dev_index *id)
388{
389 pjmedia_aud_dev_factory *f = NULL;
Benny Prijono96e74f32009-02-22 12:00:12 +0000390 unsigned drv_idx, dev_idx;
Benny Prijono10454dc2009-02-21 14:21:59 +0000391
392 PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);
Benny Prijono96e74f32009-02-22 12:00:12 +0000393 PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
Benny Prijono10454dc2009-02-21 14:21:59 +0000394
Benny Prijono96e74f32009-02-22 12:00:12 +0000395 for (drv_idx=0; drv_idx<aud_subsys.drv_cnt; ++drv_idx) {
396 if (!pj_ansi_stricmp(drv_name, aud_subsys.drv[drv_idx].name)) {
397 f = aud_subsys.drv[drv_idx].f;
Benny Prijono10454dc2009-02-21 14:21:59 +0000398 break;
399 }
400 }
401
402 if (!f)
403 return PJ_ENOTFOUND;
404
Benny Prijono96e74f32009-02-22 12:00:12 +0000405 for (dev_idx=0; dev_idx<aud_subsys.drv[drv_idx].dev_cnt; ++dev_idx) {
Benny Prijono10454dc2009-02-21 14:21:59 +0000406 pjmedia_aud_dev_info info;
407 pj_status_t status;
408
Benny Prijono96e74f32009-02-22 12:00:12 +0000409 status = f->op->get_dev_info(f, dev_idx, &info);
Benny Prijono10454dc2009-02-21 14:21:59 +0000410 if (status != PJ_SUCCESS)
411 return status;
412
413 if (!pj_ansi_stricmp(dev_name, info.name))
414 break;
415 }
416
Benny Prijono96e74f32009-02-22 12:00:12 +0000417 if (dev_idx==aud_subsys.drv[drv_idx].dev_cnt)
Benny Prijono10454dc2009-02-21 14:21:59 +0000418 return PJ_ENOTFOUND;
419
Benny Prijono96e74f32009-02-22 12:00:12 +0000420 *id = dev_idx;
421 make_global_index(drv_idx, id);
Benny Prijono10454dc2009-02-21 14:21:59 +0000422
423 return PJ_SUCCESS;
424}
425
Benny Prijono2cd64f82009-02-17 19:57:48 +0000426/* API: Initialize the audio device parameters with default values for the
427 * specified device.
428 */
Benny Prijono10454dc2009-02-21 14:21:59 +0000429PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
430 pjmedia_aud_param *param)
Benny Prijono2cd64f82009-02-17 19:57:48 +0000431{
Benny Prijonoe3ebd552009-02-18 20:14:15 +0000432 pjmedia_aud_dev_factory *f;
Benny Prijono10454dc2009-02-21 14:21:59 +0000433 unsigned index;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000434 pj_status_t status;
435
Benny Prijono96e74f32009-02-22 12:00:12 +0000436 PJ_ASSERT_RETURN(param && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);
437 PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
Benny Prijono598b01d2009-02-18 13:55:03 +0000438
Benny Prijono10454dc2009-02-21 14:21:59 +0000439 status = lookup_dev(id, &f, &index);
440 if (status != PJ_SUCCESS)
441 return status;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000442
Benny Prijonoe3ebd552009-02-18 20:14:15 +0000443 status = f->op->default_param(f, index, param);
Benny Prijono2cd64f82009-02-17 19:57:48 +0000444 if (status != PJ_SUCCESS)
445 return status;
446
447 /* Normalize device IDs */
Benny Prijono96e74f32009-02-22 12:00:12 +0000448 make_global_index(f->sys.drv_idx, &param->rec_id);
449 make_global_index(f->sys.drv_idx, &param->play_id);
Benny Prijono2cd64f82009-02-17 19:57:48 +0000450
451 return PJ_SUCCESS;
452}
453
454/* API: Open audio stream object using the specified parameters. */
Benny Prijono10454dc2009-02-21 14:21:59 +0000455PJ_DEF(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_param *prm,
Benny Prijono2cd64f82009-02-17 19:57:48 +0000456 pjmedia_aud_rec_cb rec_cb,
457 pjmedia_aud_play_cb play_cb,
458 void *user_data,
459 pjmedia_aud_stream **p_aud_strm)
460{
Benny Prijono10454dc2009-02-21 14:21:59 +0000461 pjmedia_aud_dev_factory *rec_f=NULL, *play_f=NULL, *f=NULL;
462 pjmedia_aud_param param;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000463 pj_status_t status;
464
Benny Prijono10454dc2009-02-21 14:21:59 +0000465 PJ_ASSERT_RETURN(prm && prm->dir && p_aud_strm, PJ_EINVAL);
Benny Prijono96e74f32009-02-22 12:00:12 +0000466 PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
Benny Prijono10454dc2009-02-21 14:21:59 +0000467
Benny Prijono2cd64f82009-02-17 19:57:48 +0000468 /* Must make copy of param because we're changing device ID */
Benny Prijono10454dc2009-02-21 14:21:59 +0000469 pj_memcpy(&param, prm, sizeof(param));
Benny Prijono2cd64f82009-02-17 19:57:48 +0000470
Benny Prijono10454dc2009-02-21 14:21:59 +0000471 /* Normalize rec_id */
472 if (param.dir & PJMEDIA_DIR_CAPTURE) {
473 unsigned index;
474
Benny Prijono96e74f32009-02-22 12:00:12 +0000475 if (param.rec_id < 0)
476 param.rec_id = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV;
477
Benny Prijono10454dc2009-02-21 14:21:59 +0000478 status = lookup_dev(param.rec_id, &rec_f, &index);
479 if (status != PJ_SUCCESS)
480 return status;
481
482 param.rec_id = index;
483 f = rec_f;
484 }
485
486 /* Normalize play_id */
487 if (param.dir & PJMEDIA_DIR_PLAYBACK) {
488 unsigned index;
489
Benny Prijono96e74f32009-02-22 12:00:12 +0000490 if (param.play_id < 0)
491 param.play_id = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
492
Benny Prijono10454dc2009-02-21 14:21:59 +0000493 status = lookup_dev(param.play_id, &play_f, &index);
494 if (status != PJ_SUCCESS)
495 return status;
496
497 param.play_id = index;
498 f = play_f;
499
500 /* For now, rec_id and play_id must belong to the same factory */
Benny Prijono96e74f32009-02-22 12:00:12 +0000501 PJ_ASSERT_RETURN(rec_f == play_f, PJMEDIA_EAUD_INVDEV);
Benny Prijono10454dc2009-02-21 14:21:59 +0000502 }
503
Benny Prijono2cd64f82009-02-17 19:57:48 +0000504
Benny Prijono10454dc2009-02-21 14:21:59 +0000505 /* Create the stream */
Benny Prijonoe3ebd552009-02-18 20:14:15 +0000506 status = f->op->create_stream(f, &param, rec_cb, play_cb,
507 user_data, p_aud_strm);
Benny Prijono2cd64f82009-02-17 19:57:48 +0000508 if (status != PJ_SUCCESS)
509 return status;
510
Benny Prijono10454dc2009-02-21 14:21:59 +0000511 /* Assign factory id to the stream */
Benny Prijono96e74f32009-02-22 12:00:12 +0000512 (*p_aud_strm)->sys.drv_idx = f->sys.drv_idx;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000513 return PJ_SUCCESS;
514}
515
516/* API: Get the running parameters for the specified audio stream. */
517PJ_DEF(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,
Benny Prijono10454dc2009-02-21 14:21:59 +0000518 pjmedia_aud_param *param)
Benny Prijono2cd64f82009-02-17 19:57:48 +0000519{
520 pj_status_t status;
521
Benny Prijono96e74f32009-02-22 12:00:12 +0000522 PJ_ASSERT_RETURN(strm && param, PJ_EINVAL);
523 PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
524
Benny Prijono2cd64f82009-02-17 19:57:48 +0000525 status = strm->op->get_param(strm, param);
526 if (status != PJ_SUCCESS)
527 return status;
528
529 /* Normalize device id's */
Benny Prijono96e74f32009-02-22 12:00:12 +0000530 make_global_index(strm->sys.drv_idx, &param->rec_id);
531 make_global_index(strm->sys.drv_idx, &param->play_id);
Benny Prijono2cd64f82009-02-17 19:57:48 +0000532
533 return PJ_SUCCESS;
534}
535
536/* API: Get the value of a specific capability of the audio stream. */
537PJ_DEF(pj_status_t) pjmedia_aud_stream_get_cap(pjmedia_aud_stream *strm,
538 pjmedia_aud_dev_cap cap,
539 void *value)
540{
541 return strm->op->get_cap(strm, cap, value);
542}
543
544/* API: Set the value of a specific capability of the audio stream. */
545PJ_DEF(pj_status_t) pjmedia_aud_stream_set_cap(pjmedia_aud_stream *strm,
546 pjmedia_aud_dev_cap cap,
547 const void *value)
548{
549 return strm->op->set_cap(strm, cap, value);
550}
551
552/* API: Start the stream. */
553PJ_DEF(pj_status_t) pjmedia_aud_stream_start(pjmedia_aud_stream *strm)
554{
555 return strm->op->start(strm);
556}
557
558/* API: Stop the stream. */
559PJ_DEF(pj_status_t) pjmedia_aud_stream_stop(pjmedia_aud_stream *strm)
560{
561 return strm->op->stop(strm);
562}
563
564/* API: Destroy the stream. */
565PJ_DEF(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm)
566{
567 return strm->op->destroy(strm);
568}
569
570