blob: 01f10516eaf4383bd9e9766696436af92af678b0 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 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 pj_status_t null_factory_refresh(pjmedia_aud_dev_factory *f);
63static unsigned null_factory_get_dev_count(pjmedia_aud_dev_factory *f);
64static pj_status_t null_factory_get_dev_info(pjmedia_aud_dev_factory *f,
65 unsigned index,
66 pjmedia_aud_dev_info *info);
67static pj_status_t null_factory_default_param(pjmedia_aud_dev_factory *f,
68 unsigned index,
69 pjmedia_aud_param *param);
70static pj_status_t null_factory_create_stream(pjmedia_aud_dev_factory *f,
71 const pjmedia_aud_param *param,
72 pjmedia_aud_rec_cb rec_cb,
73 pjmedia_aud_play_cb play_cb,
74 void *user_data,
75 pjmedia_aud_stream **p_aud_strm);
76
77static pj_status_t null_stream_get_param(pjmedia_aud_stream *strm,
78 pjmedia_aud_param *param);
79static pj_status_t null_stream_get_cap(pjmedia_aud_stream *strm,
80 pjmedia_aud_dev_cap cap,
81 void *value);
82static pj_status_t null_stream_set_cap(pjmedia_aud_stream *strm,
83 pjmedia_aud_dev_cap cap,
84 const void *value);
85static pj_status_t null_stream_start(pjmedia_aud_stream *strm);
86static pj_status_t null_stream_stop(pjmedia_aud_stream *strm);
87static pj_status_t null_stream_destroy(pjmedia_aud_stream *strm);
88
89/* Operations */
90static pjmedia_aud_dev_factory_op factory_op =
91{
92 &null_factory_init,
93 &null_factory_destroy,
94 &null_factory_get_dev_count,
95 &null_factory_get_dev_info,
96 &null_factory_default_param,
97 &null_factory_create_stream,
98 &null_factory_refresh
99};
100
101static pjmedia_aud_stream_op stream_op =
102{
103 &null_stream_get_param,
104 &null_stream_get_cap,
105 &null_stream_set_cap,
106 &null_stream_start,
107 &null_stream_stop,
108 &null_stream_destroy
109};
110
111
112/****************************************************************************
113 * Factory operations
114 */
115/*
116 * Init null_audio audio driver.
117 */
118pjmedia_aud_dev_factory* pjmedia_null_audio_factory(pj_pool_factory *pf)
119{
120 struct null_audio_factory *f;
121 pj_pool_t *pool;
122
123 pool = pj_pool_create(pf, "null audio", 1000, 1000, NULL);
124 f = PJ_POOL_ZALLOC_T(pool, struct null_audio_factory);
125 f->pf = pf;
126 f->pool = pool;
127 f->base.op = &factory_op;
128
129 return &f->base;
130}
131
132
133/* API: init factory */
134static pj_status_t null_factory_init(pjmedia_aud_dev_factory *f)
135{
136 struct null_audio_factory *nf = (struct null_audio_factory*)f;
137 struct null_audio_dev_info *ndi;
138
139 /* Initialize input and output devices here */
140 nf->dev_count = 1;
141 nf->dev_info = (struct null_audio_dev_info*)
142 pj_pool_calloc(nf->pool, nf->dev_count,
143 sizeof(struct null_audio_dev_info));
144 ndi = &nf->dev_info[0];
145 pj_bzero(ndi, sizeof(*ndi));
146 strcpy(ndi->info.name, "null device");
147 strcpy(ndi->info.driver, "null");
148 ndi->info.input_count = 1;
149 ndi->info.output_count = 1;
150 ndi->info.default_samples_per_sec = 16000;
151 /* Set the device capabilities here */
152 ndi->info.caps = 0;
153
154 PJ_LOG(4, (THIS_FILE, "null audio initialized"));
155
156 return PJ_SUCCESS;
157}
158
159/* API: destroy factory */
160static pj_status_t null_factory_destroy(pjmedia_aud_dev_factory *f)
161{
162 struct null_audio_factory *nf = (struct null_audio_factory*)f;
163 pj_pool_t *pool = nf->pool;
164
165 nf->pool = NULL;
166 pj_pool_release(pool);
167
168 return PJ_SUCCESS;
169}
170
171/* API: refresh the list of devices */
172static pj_status_t null_factory_refresh(pjmedia_aud_dev_factory *f)
173{
174 PJ_UNUSED_ARG(f);
175 return PJ_SUCCESS;
176}
177
178/* API: get number of devices */
179static unsigned null_factory_get_dev_count(pjmedia_aud_dev_factory *f)
180{
181 struct null_audio_factory *nf = (struct null_audio_factory*)f;
182 return nf->dev_count;
183}
184
185/* API: get device info */
186static pj_status_t null_factory_get_dev_info(pjmedia_aud_dev_factory *f,
187 unsigned index,
188 pjmedia_aud_dev_info *info)
189{
190 struct null_audio_factory *nf = (struct null_audio_factory*)f;
191
192 PJ_ASSERT_RETURN(index < nf->dev_count, PJMEDIA_EAUD_INVDEV);
193
194 pj_memcpy(info, &nf->dev_info[index].info, sizeof(*info));
195
196 return PJ_SUCCESS;
197}
198
199/* API: create default device parameter */
200static pj_status_t null_factory_default_param(pjmedia_aud_dev_factory *f,
201 unsigned index,
202 pjmedia_aud_param *param)
203{
204 struct null_audio_factory *nf = (struct null_audio_factory*)f;
205 struct null_audio_dev_info *di = &nf->dev_info[index];
206
207 PJ_ASSERT_RETURN(index < nf->dev_count, PJMEDIA_EAUD_INVDEV);
208
209 pj_bzero(param, sizeof(*param));
210 if (di->info.input_count && di->info.output_count) {
211 param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
212 param->rec_id = index;
213 param->play_id = index;
214 } else if (di->info.input_count) {
215 param->dir = PJMEDIA_DIR_CAPTURE;
216 param->rec_id = index;
217 param->play_id = PJMEDIA_AUD_INVALID_DEV;
218 } else if (di->info.output_count) {
219 param->dir = PJMEDIA_DIR_PLAYBACK;
220 param->play_id = index;
221 param->rec_id = PJMEDIA_AUD_INVALID_DEV;
222 } else {
223 return PJMEDIA_EAUD_INVDEV;
224 }
225
226 /* Set the mandatory settings here */
227 /* The values here are just some examples */
228 param->clock_rate = di->info.default_samples_per_sec;
229 param->channel_count = 1;
230 param->samples_per_frame = di->info.default_samples_per_sec * 20 / 1000;
231 param->bits_per_sample = 16;
232
233 /* Set the device capabilities here */
234 param->flags = 0;
235
236 return PJ_SUCCESS;
237}
238
239/* API: create stream */
240static pj_status_t null_factory_create_stream(pjmedia_aud_dev_factory *f,
241 const pjmedia_aud_param *param,
242 pjmedia_aud_rec_cb rec_cb,
243 pjmedia_aud_play_cb play_cb,
244 void *user_data,
245 pjmedia_aud_stream **p_aud_strm)
246{
247 struct null_audio_factory *nf = (struct null_audio_factory*)f;
248 pj_pool_t *pool;
249 struct null_audio_stream *strm;
250
251 /* Create and Initialize stream descriptor */
252 pool = pj_pool_create(nf->pf, "null_audio-dev", 1000, 1000, NULL);
253 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
254
255 strm = PJ_POOL_ZALLOC_T(pool, struct null_audio_stream);
256 pj_memcpy(&strm->param, param, sizeof(*param));
257 strm->pool = pool;
258 strm->rec_cb = rec_cb;
259 strm->play_cb = play_cb;
260 strm->user_data = user_data;
261
262 /* Create player stream here */
263 if (param->dir & PJMEDIA_DIR_PLAYBACK) {
264 }
265
266 /* Create capture stream here */
267 if (param->dir & PJMEDIA_DIR_CAPTURE) {
268 }
269
270 /* Apply the remaining settings */
271 /* Below is an example if you want to set the output volume */
272 if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
273 null_stream_set_cap(&strm->base,
274 PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
275 &param->output_vol);
276 }
277
278 /* Done */
279 strm->base.op = &stream_op;
280 *p_aud_strm = &strm->base;
281
282 return PJ_SUCCESS;
283}
284
285/* API: Get stream info. */
286static pj_status_t null_stream_get_param(pjmedia_aud_stream *s,
287 pjmedia_aud_param *pi)
288{
289 struct null_audio_stream *strm = (struct null_audio_stream*)s;
290
291 PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
292
293 pj_memcpy(pi, &strm->param, sizeof(*pi));
294
295 /* Example: Update the volume setting */
296 if (null_stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
297 &pi->output_vol) == PJ_SUCCESS)
298 {
299 pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
300 }
301
302 return PJ_SUCCESS;
303}
304
305/* API: get capability */
306static pj_status_t null_stream_get_cap(pjmedia_aud_stream *s,
307 pjmedia_aud_dev_cap cap,
308 void *pval)
309{
310 struct null_audio_stream *strm = (struct null_audio_stream*)s;
311
312 PJ_UNUSED_ARG(strm);
313
314 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
315
316 /* Example: Get the output's volume setting */
317 if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING)
318 {
319 /* Output volume setting */
320 *(unsigned*)pval = 0; // retrieve output device's volume here
321 return PJ_SUCCESS;
322 } else {
323 return PJMEDIA_EAUD_INVCAP;
324 }
325}
326
327/* API: set capability */
328static pj_status_t null_stream_set_cap(pjmedia_aud_stream *s,
329 pjmedia_aud_dev_cap cap,
330 const void *pval)
331{
332 struct null_audio_stream *strm = (struct null_audio_stream*)s;
333
334 PJ_UNUSED_ARG(strm);
335
336 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
337
338 /* Example */
339 if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING)
340 {
341 /* Output volume setting */
342 // set output's volume level here
343 return PJ_SUCCESS;
344 }
345
346 return PJMEDIA_EAUD_INVCAP;
347}
348
349/* API: Start stream. */
350static pj_status_t null_stream_start(pjmedia_aud_stream *strm)
351{
352 struct null_audio_stream *stream = (struct null_audio_stream*)strm;
353
354 PJ_UNUSED_ARG(stream);
355
356 PJ_LOG(4, (THIS_FILE, "Starting null audio stream"));
357
358 return PJ_SUCCESS;
359}
360
361/* API: Stop stream. */
362static pj_status_t null_stream_stop(pjmedia_aud_stream *strm)
363{
364 struct null_audio_stream *stream = (struct null_audio_stream*)strm;
365
366 PJ_UNUSED_ARG(stream);
367
368 PJ_LOG(4, (THIS_FILE, "Stopping null audio stream"));
369
370 return PJ_SUCCESS;
371}
372
373
374/* API: Destroy stream. */
375static pj_status_t null_stream_destroy(pjmedia_aud_stream *strm)
376{
377 struct null_audio_stream *stream = (struct null_audio_stream*)strm;
378
379 PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
380
381 null_stream_stop(strm);
382
383 pj_pool_release(stream->pool);
384
385 return PJ_SUCCESS;
386}
387
388#endif /* PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO */