blob: b3af9e9dac4687201664ece6455561011dfdd2ae [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>
22
Benny Prijono598b01d2009-02-18 13:55:03 +000023/*
24 * The Device ID seen by application and driver is different.
25 *
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.
31 */
Benny Prijono2cd64f82009-02-17 19:57:48 +000032#define MAKE_DEV_ID(f_id, index) (((f_id & 0xFFFF) << 16) & (index & 0xFFFF))
33#define GET_INDEX(dev_id) ((dev_id) & 0xFFFF)
34#define GET_FID(dev_id) ((dev_id) >> 16)
Benny Prijono598b01d2009-02-18 13:55:03 +000035#define DEFAULT_DEV_ID 0
Benny Prijono2cd64f82009-02-17 19:57:48 +000036
37
Benny Prijono598b01d2009-02-18 13:55:03 +000038/* extern functions to create factories */
Benny Prijono2cd64f82009-02-17 19:57:48 +000039pjmedia_aud_dev_factory* pjmedia_pa_factory(pj_pool_factory *pf);
Benny Prijono598b01d2009-02-18 13:55:03 +000040pjmedia_aud_dev_factory* pjmedia_wmme_factory(pj_pool_factory *pf);
41
Benny Prijono2cd64f82009-02-17 19:57:48 +000042
43/* Array of factories */
44static struct factory
45{
46 pjmedia_aud_dev_factory* (*create)(pj_pool_factory*);
47 pjmedia_aud_dev_factory *f;
48
49} factories[] =
50{
Benny Prijono598b01d2009-02-18 13:55:03 +000051 /* WMME */
52 {
53 &pjmedia_wmme_factory
54 },
55 /* PortAudio: */
Benny Prijono2cd64f82009-02-17 19:57:48 +000056 {
57 &pjmedia_pa_factory
Benny Prijono598b01d2009-02-18 13:55:03 +000058 },
Benny Prijono2cd64f82009-02-17 19:57:48 +000059};
60static unsigned factory_cnt;
61
62
63/* API: Initialize the audio subsystem. */
64PJ_DEF(pj_status_t) pjmedia_aud_subsys_init(pj_pool_factory *pf)
65{
66 unsigned i;
67 pj_status_t status = PJ_ENOMEM;
68
69 factory_cnt = 0;
70
71 for (i=0; i<PJ_ARRAY_SIZE(factories); ++i) {
72 factories[i].f = (*factories[i].create)(pf);
73 if (!factories[i].f)
74 continue;
75
76 status = factories[i].f->op->init(factories[i].f);
77 if (status != PJ_SUCCESS) {
78 factories[i].f->op->destroy(factories[i].f);
79 factories[i].f = NULL;
80 }
81
82 factories[i].f->internal.id = i;
83 ++factory_cnt;
84 }
85
86 return factory_cnt ? PJ_SUCCESS : status;
87}
88
89/* API: Shutdown the audio subsystem. */
90PJ_DEF(pj_status_t) pjmedia_aud_subsys_shutdown(void)
91{
92 unsigned i;
93
94 for (i=0; i<PJ_ARRAY_SIZE(factories); ++i) {
95 if (!factories[i].f)
96 continue;
97
98 factories[i].f->op->destroy(factories[i].f);
99 factories[i].f = NULL;
100 }
101
102 return PJ_SUCCESS;
103}
104
105/* API: Get the number of sound devices installed in the system. */
106PJ_DEF(unsigned) pjmedia_aud_dev_count(void)
107{
108 unsigned i, count = 0;
109
110 for (i=0; i<PJ_ARRAY_SIZE(factories); ++i) {
111 if (!factories[i].f)
112 continue;
113
114 count += factories[i].f->op->get_dev_count(factories[i].f);
115 }
116
117 return count;
118}
119
120/* API: Enumerate device ID's. */
121PJ_DEF(unsigned) pjmedia_aud_dev_enum(unsigned max_count,
122 pjmedia_aud_dev_id ids[])
123{
124 unsigned i, count = 0;
125
126 for (i=0; i<PJ_ARRAY_SIZE(factories) && count < max_count; ++i) {
127 unsigned j, fcount;
128
129 if (!factories[i].f)
130 continue;
131
132 fcount = factories[i].f->op->get_dev_count(factories[i].f);
133 for (j=0; j<fcount && count<max_count; ++j) {
134 ids[count++] = MAKE_DEV_ID(i, j);
135 }
136 }
137
138 return count;
139}
140
141
142/* API: Get device information. */
143PJ_DEF(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_id id,
144 pjmedia_aud_dev_info *info)
145{
146 int f_id, index;
147
Benny Prijono598b01d2009-02-18 13:55:03 +0000148 if (id == PJMEDIA_AUD_DEV_DEFAULT_ID)
149 id = DEFAULT_DEV_ID;
150
Benny Prijono2cd64f82009-02-17 19:57:48 +0000151 f_id = GET_FID(id);
152 index = GET_INDEX(id);
153
154 if (f_id < 0 || f_id >= PJ_ARRAY_SIZE(factories))
155 return PJMEDIA_EAUD_INVDEV;
156
157 if (factories[f_id].f == NULL)
158 return PJMEDIA_EAUD_INVDEV;
159
160 return factories[f_id].f->op->get_dev_info(factories[f_id].f,
161 index, info);
162}
163
164/* API: Initialize the audio device parameters with default values for the
165 * specified device.
166 */
167PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_id id,
168 pjmedia_aud_dev_param *param)
169{
170 int f_id, index;
171 pj_status_t status;
172
Benny Prijono598b01d2009-02-18 13:55:03 +0000173 if (id == PJMEDIA_AUD_DEV_DEFAULT_ID)
174 id = DEFAULT_DEV_ID;
175
Benny Prijono2cd64f82009-02-17 19:57:48 +0000176 f_id = GET_FID(id);
177 index = GET_INDEX(id);
178
179 if (f_id < 0 || f_id >= PJ_ARRAY_SIZE(factories))
180 return PJMEDIA_EAUD_INVDEV;
181
182 if (factories[f_id].f == NULL)
183 return PJMEDIA_EAUD_INVDEV;
184
185 status = factories[f_id].f->op->default_param(factories[f_id].f,
186 index, param);
187 if (status != PJ_SUCCESS)
188 return status;
189
190 /* Normalize device IDs */
191 if (param->rec_id != PJMEDIA_AUD_DEV_DEFAULT_ID)
192 param->rec_id = MAKE_DEV_ID(f_id, param->rec_id);
193 if (param->play_id != PJMEDIA_AUD_DEV_DEFAULT_ID)
194 param->play_id = MAKE_DEV_ID(f_id, param->play_id);
195
196 return PJ_SUCCESS;
197}
198
199/* API: Open audio stream object using the specified parameters. */
200PJ_DEF(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_dev_param *p,
201 pjmedia_aud_rec_cb rec_cb,
202 pjmedia_aud_play_cb play_cb,
203 void *user_data,
204 pjmedia_aud_stream **p_aud_strm)
205{
206 pjmedia_aud_dev_param param;
207 int f_id;
208 pj_status_t status;
209
210 /* Must make copy of param because we're changing device ID */
211 pj_memcpy(&param, p, sizeof(param));
212
213 /* Set default device */
Benny Prijono598b01d2009-02-18 13:55:03 +0000214 if (param.rec_id == PJMEDIA_AUD_DEV_DEFAULT_ID)
215 param.rec_id = DEFAULT_DEV_ID;
216 if (param.play_id == PJMEDIA_AUD_DEV_DEFAULT_ID)
217 param.play_id = DEFAULT_DEV_ID;
Benny Prijono2cd64f82009-02-17 19:57:48 +0000218
219 if (param.dir & PJMEDIA_DIR_CAPTURE)
220 f_id = GET_FID(param.rec_id);
221 else
222 f_id = GET_FID(param.play_id);
223
224 if (f_id < 0 || f_id >= PJ_ARRAY_SIZE(factories))
225 return PJMEDIA_EAUD_INVDEV;
226
227 /* Normalize device id's */
228 param.rec_id = GET_INDEX(param.rec_id);
229 param.play_id = GET_INDEX(param.play_id);
230
231 if (factories[f_id].f == NULL)
232 return PJMEDIA_EAUD_INVDEV;
233
234 status = factories[f_id].f->op->create_stream(factories[f_id].f,
235 &param, rec_cb, play_cb,
236 user_data, p_aud_strm);
237 if (status != PJ_SUCCESS)
238 return status;
239
240 (*p_aud_strm)->factory = factories[f_id].f;
241 return PJ_SUCCESS;
242}
243
244/* API: Get the running parameters for the specified audio stream. */
245PJ_DEF(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,
246 pjmedia_aud_dev_param *param)
247{
248 pj_status_t status;
249
250 status = strm->op->get_param(strm, param);
251 if (status != PJ_SUCCESS)
252 return status;
253
254 /* Normalize device id's */
255 if (param->rec_id != PJMEDIA_AUD_DEV_DEFAULT_ID)
256 param->rec_id = MAKE_DEV_ID(strm->factory->internal.id, param->rec_id);
257 if (param->play_id != PJMEDIA_AUD_DEV_DEFAULT_ID)
258 param->play_id = MAKE_DEV_ID(strm->factory->internal.id, param->play_id);
259
260 return PJ_SUCCESS;
261}
262
263/* API: Get the value of a specific capability of the audio stream. */
264PJ_DEF(pj_status_t) pjmedia_aud_stream_get_cap(pjmedia_aud_stream *strm,
265 pjmedia_aud_dev_cap cap,
266 void *value)
267{
268 return strm->op->get_cap(strm, cap, value);
269}
270
271/* API: Set the value of a specific capability of the audio stream. */
272PJ_DEF(pj_status_t) pjmedia_aud_stream_set_cap(pjmedia_aud_stream *strm,
273 pjmedia_aud_dev_cap cap,
274 const void *value)
275{
276 return strm->op->set_cap(strm, cap, value);
277}
278
279/* API: Start the stream. */
280PJ_DEF(pj_status_t) pjmedia_aud_stream_start(pjmedia_aud_stream *strm)
281{
282 return strm->op->start(strm);
283}
284
285/* API: Stop the stream. */
286PJ_DEF(pj_status_t) pjmedia_aud_stream_stop(pjmedia_aud_stream *strm)
287{
288 return strm->op->stop(strm);
289}
290
291/* API: Destroy the stream. */
292PJ_DEF(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm)
293{
294 return strm->op->destroy(strm);
295}
296
297