blob: feb96d227db49b4410e9810bc0c5de330d1fff64 [file] [log] [blame]
Sauw Ming60a0c9b2010-02-19 09:57:48 +00001/* $Id$ */
2/*
3 * Copyright (C) 2008-2010 Teluu Inc. (http://www.teluu.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pjmedia-audiodev/audiodev_imp.h>
20#include <pj/assert.h>
21#include <pj/log.h>
22#include <pj/os.h>
23
24#if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO
25
26#define THIS_FILE "null_dev.c"
27
28/* null_audio device info */
29struct null_audio_dev_info
30{
31 pjmedia_aud_dev_info info;
32 unsigned dev_id;
33};
34
35/* null_audio factory */
36struct null_audio_factory
37{
38 pjmedia_aud_dev_factory base;
39 pj_pool_t *pool;
40 pj_pool_factory *pf;
41
42 unsigned dev_count;
43 struct null_audio_dev_info *dev_info;
44};
45
46/* Sound stream. */
47struct null_audio_stream
48{
49 pjmedia_aud_stream base; /**< Base stream */
50 pjmedia_aud_param param; /**< Settings */
51 pj_pool_t *pool; /**< Memory pool. */
52
53 pjmedia_aud_rec_cb rec_cb; /**< Capture callback. */
54 pjmedia_aud_play_cb play_cb; /**< Playback callback. */
55 void *user_data; /**< Application data. */
56};
57
58
59/* Prototypes */
60static pj_status_t null_factory_init(pjmedia_aud_dev_factory *f);
61static pj_status_t null_factory_destroy(pjmedia_aud_dev_factory *f);
62static unsigned null_factory_get_dev_count(pjmedia_aud_dev_factory *f);
63static pj_status_t null_factory_get_dev_info(pjmedia_aud_dev_factory *f,
64 unsigned index,
65 pjmedia_aud_dev_info *info);
66static pj_status_t null_factory_default_param(pjmedia_aud_dev_factory *f,
67 unsigned index,
68 pjmedia_aud_param *param);
69static pj_status_t null_factory_create_stream(pjmedia_aud_dev_factory *f,
70 const pjmedia_aud_param *param,
71 pjmedia_aud_rec_cb rec_cb,
72 pjmedia_aud_play_cb play_cb,
73 void *user_data,
74 pjmedia_aud_stream **p_aud_strm);
75
76static pj_status_t null_stream_get_param(pjmedia_aud_stream *strm,
77 pjmedia_aud_param *param);
78static pj_status_t null_stream_get_cap(pjmedia_aud_stream *strm,
79 pjmedia_aud_dev_cap cap,
80 void *value);
81static pj_status_t null_stream_set_cap(pjmedia_aud_stream *strm,
82 pjmedia_aud_dev_cap cap,
83 const void *value);
84static pj_status_t null_stream_start(pjmedia_aud_stream *strm);
85static pj_status_t null_stream_stop(pjmedia_aud_stream *strm);
86static pj_status_t null_stream_destroy(pjmedia_aud_stream *strm);
87
88/* Operations */
89static pjmedia_aud_dev_factory_op factory_op =
90{
91 &null_factory_init,
92 &null_factory_destroy,
93 &null_factory_get_dev_count,
94 &null_factory_get_dev_info,
95 &null_factory_default_param,
96 &null_factory_create_stream
97};
98
99static pjmedia_aud_stream_op stream_op =
100{
101 &null_stream_get_param,
102 &null_stream_get_cap,
103 &null_stream_set_cap,
104 &null_stream_start,
105 &null_stream_stop,
106 &null_stream_destroy
107};
108
109
110/****************************************************************************
111 * Factory operations
112 */
113/*
114 * Init null_audio audio driver.
115 */
116pjmedia_aud_dev_factory* pjmedia_null_audio_factory(pj_pool_factory *pf)
117{
118 struct null_audio_factory *f;
119 pj_pool_t *pool;
120
121 pool = pj_pool_create(pf, "null audio", 1000, 1000, NULL);
122 f = PJ_POOL_ZALLOC_T(pool, struct null_audio_factory);
123 f->pf = pf;
124 f->pool = pool;
125 f->base.op = &factory_op;
126
127 return &f->base;
128}
129
130
131/* API: init factory */
132static pj_status_t null_factory_init(pjmedia_aud_dev_factory *f)
133{
134 struct null_audio_factory *nf = (struct null_audio_factory*)f;
135 struct null_audio_dev_info *ndi;
136
137 /* Initialize input and output devices here */
138 nf->dev_count = 1;
139 nf->dev_info = (struct null_audio_dev_info*)
140 pj_pool_calloc(nf->pool, nf->dev_count,
141 sizeof(struct null_audio_dev_info));
142 ndi = &nf->dev_info[0];
143 pj_bzero(ndi, sizeof(*ndi));
144 strcpy(ndi->info.name, "null device");
145 strcpy(ndi->info.driver, "null");
146 ndi->info.input_count = 1;
147 ndi->info.output_count = 1;
148 ndi->info.default_samples_per_sec = 16000;
149 /* Set the device capabilities here */
150 ndi->info.caps = 0;
151
152 PJ_LOG(4, (THIS_FILE, "null audio initialized"));
153
154 return PJ_SUCCESS;
155}
156
157/* API: destroy factory */
158static pj_status_t null_factory_destroy(pjmedia_aud_dev_factory *f)
159{
160 struct null_audio_factory *nf = (struct null_audio_factory*)f;
161 pj_pool_t *pool = nf->pool;
162
163 nf->pool = NULL;
164 pj_pool_release(pool);
165
166 return PJ_SUCCESS;
167}
168
169/* API: get number of devices */
170static unsigned null_factory_get_dev_count(pjmedia_aud_dev_factory *f)
171{
172 struct null_audio_factory *nf = (struct null_audio_factory*)f;
173 return nf->dev_count;
174}
175
176/* API: get device info */
177static pj_status_t null_factory_get_dev_info(pjmedia_aud_dev_factory *f,
178 unsigned index,
179 pjmedia_aud_dev_info *info)
180{
181 struct null_audio_factory *nf = (struct null_audio_factory*)f;
182
183 PJ_ASSERT_RETURN(index < nf->dev_count, PJMEDIA_EAUD_INVDEV);
184
185 pj_memcpy(info, &nf->dev_info[index].info, sizeof(*info));
186
187 return PJ_SUCCESS;
188}
189
190/* API: create default device parameter */
191static pj_status_t null_factory_default_param(pjmedia_aud_dev_factory *f,
192 unsigned index,
193 pjmedia_aud_param *param)
194{
195 struct null_audio_factory *nf = (struct null_audio_factory*)f;
196 struct null_audio_dev_info *di = &nf->dev_info[index];
197
198 PJ_ASSERT_RETURN(index < nf->dev_count, PJMEDIA_EAUD_INVDEV);
199
200 pj_bzero(param, sizeof(*param));
201 if (di->info.input_count && di->info.output_count) {
202 param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
203 param->rec_id = index;
204 param->play_id = index;
205 } else if (di->info.input_count) {
206 param->dir = PJMEDIA_DIR_CAPTURE;
207 param->rec_id = index;
208 param->play_id = PJMEDIA_AUD_INVALID_DEV;
209 } else if (di->info.output_count) {
210 param->dir = PJMEDIA_DIR_PLAYBACK;
211 param->play_id = index;
212 param->rec_id = PJMEDIA_AUD_INVALID_DEV;
213 } else {
214 return PJMEDIA_EAUD_INVDEV;
215 }
216
217 /* Set the mandatory settings here */
218 /* The values here are just some examples */
219 param->clock_rate = di->info.default_samples_per_sec;
220 param->channel_count = 1;
221 param->samples_per_frame = di->info.default_samples_per_sec * 20 / 1000;
222 param->bits_per_sample = 16;
223
224 /* Set the device capabilities here */
225 param->flags = 0;
226
227 return PJ_SUCCESS;
228}
229
230/* API: create stream */
231static pj_status_t null_factory_create_stream(pjmedia_aud_dev_factory *f,
232 const pjmedia_aud_param *param,
233 pjmedia_aud_rec_cb rec_cb,
234 pjmedia_aud_play_cb play_cb,
235 void *user_data,
236 pjmedia_aud_stream **p_aud_strm)
237{
238 struct null_audio_factory *nf = (struct null_audio_factory*)f;
239 pj_pool_t *pool;
240 struct null_audio_stream *strm;
241
242 /* Create and Initialize stream descriptor */
243 pool = pj_pool_create(nf->pf, "null_audio-dev", 1000, 1000, NULL);
244 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
245
246 strm = PJ_POOL_ZALLOC_T(pool, struct null_audio_stream);
247 pj_memcpy(&strm->param, param, sizeof(*param));
248 strm->pool = pool;
249 strm->rec_cb = rec_cb;
250 strm->play_cb = play_cb;
251 strm->user_data = user_data;
252
253 /* Create player stream here */
254 if (param->dir & PJMEDIA_DIR_PLAYBACK) {
255 }
256
257 /* Create capture stream here */
258 if (param->dir & PJMEDIA_DIR_CAPTURE) {
259 }
260
261 /* Apply the remaining settings */
262 /* Below is an example if you want to set the output volume */
263 if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
264 null_stream_set_cap(&strm->base,
265 PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
266 &param->output_vol);
267 }
268
269 /* Done */
270 strm->base.op = &stream_op;
271 *p_aud_strm = &strm->base;
272
273 return PJ_SUCCESS;
274}
275
276/* API: Get stream info. */
277static pj_status_t null_stream_get_param(pjmedia_aud_stream *s,
278 pjmedia_aud_param *pi)
279{
280 struct null_audio_stream *strm = (struct null_audio_stream*)s;
281
282 PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
283
284 pj_memcpy(pi, &strm->param, sizeof(*pi));
285
286 /* Example: Update the volume setting */
287 if (null_stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
288 &pi->output_vol) == PJ_SUCCESS)
289 {
290 pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
291 }
292
293 return PJ_SUCCESS;
294}
295
296/* API: get capability */
297static pj_status_t null_stream_get_cap(pjmedia_aud_stream *s,
298 pjmedia_aud_dev_cap cap,
299 void *pval)
300{
301 struct null_audio_stream *strm = (struct null_audio_stream*)s;
302
303 PJ_UNUSED_ARG(strm);
304
305 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
306
307 /* Example: Get the output's volume setting */
308 if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING)
309 {
310 /* Output volume setting */
311 *(unsigned*)pval = 0; // retrieve output device's volume here
312 return PJ_SUCCESS;
313 } else {
314 return PJMEDIA_EAUD_INVCAP;
315 }
316}
317
318/* API: set capability */
319static pj_status_t null_stream_set_cap(pjmedia_aud_stream *s,
320 pjmedia_aud_dev_cap cap,
321 const void *pval)
322{
323 struct null_audio_stream *strm = (struct null_audio_stream*)s;
324
325 PJ_UNUSED_ARG(strm);
326
327 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
328
329 /* Example */
330 if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING)
331 {
332 /* Output volume setting */
333 // set output's volume level here
334 return PJ_SUCCESS;
335 }
336
337 return PJMEDIA_EAUD_INVCAP;
338}
339
340/* API: Start stream. */
341static pj_status_t null_stream_start(pjmedia_aud_stream *strm)
342{
343 struct null_audio_stream *stream = (struct null_audio_stream*)strm;
344
345 PJ_UNUSED_ARG(stream);
346
347 PJ_LOG(4, (THIS_FILE, "Starting null audio stream"));
348
349 return PJ_SUCCESS;
350}
351
352/* API: Stop stream. */
353static pj_status_t null_stream_stop(pjmedia_aud_stream *strm)
354{
355 struct null_audio_stream *stream = (struct null_audio_stream*)strm;
356
357 PJ_UNUSED_ARG(stream);
358
359 PJ_LOG(4, (THIS_FILE, "Stopping null audio stream"));
360
361 return PJ_SUCCESS;
362}
363
364
365/* API: Destroy stream. */
366static pj_status_t null_stream_destroy(pjmedia_aud_stream *strm)
367{
368 struct null_audio_stream *stream = (struct null_audio_stream*)strm;
369
370 PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
371
372 null_stream_stop(strm);
373
374 pj_pool_release(stream->pool);
375
376 return PJ_SUCCESS;
377}
378
379#endif /* PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO */