~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjmedia/src/pjmedia-audiodev/audiodev.c

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: audiodev.c 4150 2012-06-01 04:29:56Z ming $ */
2
 
/* 
3
 
 * Copyright (C) 2008-2011 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/assert.h>
22
 
#include <pj/errno.h>
23
 
#include <pj/log.h>
24
 
#include <pj/pool.h>
25
 
#include <pj/string.h>
26
 
 
27
 
#define THIS_FILE   "audiodev.c"
28
 
 
29
 
#define DEFINE_CAP(name, info)  {name, info}
30
 
 
31
 
/* Capability names */
32
 
static struct cap_info
33
 
{
34
 
    const char *name;
35
 
    const char *info;
36
 
} cap_infos[] = 
37
 
{
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")
52
 
};
53
 
 
54
 
 
55
 
/*
56
 
 * The device index seen by application and driver is different. 
57
 
 *
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
60
 
 * factory only.
61
 
 */
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
66
 
 
67
 
 
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);
71
 
#endif
72
 
 
73
 
#if PJMEDIA_AUDIO_DEV_HAS_COREAUDIO
74
 
pjmedia_aud_dev_factory* pjmedia_coreaudio_factory(pj_pool_factory *pf);
75
 
#endif
76
 
 
77
 
#if PJMEDIA_AUDIO_DEV_HAS_ALSA
78
 
pjmedia_aud_dev_factory* pjmedia_alsa_factory(pj_pool_factory *pf);
79
 
#endif
80
 
 
81
 
#if PJMEDIA_AUDIO_DEV_HAS_BB10
82
 
pjmedia_aud_dev_factory* pjmedia_bb10_factory(pj_pool_factory *pf);
83
 
#endif
84
 
 
85
 
#if PJMEDIA_AUDIO_DEV_HAS_WMME
86
 
pjmedia_aud_dev_factory* pjmedia_wmme_factory(pj_pool_factory *pf);
87
 
#endif
88
 
 
89
 
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_VAS
90
 
pjmedia_aud_dev_factory* pjmedia_symb_vas_factory(pj_pool_factory *pf);
91
 
#endif
92
 
 
93
 
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_APS
94
 
pjmedia_aud_dev_factory* pjmedia_aps_factory(pj_pool_factory *pf);
95
 
#endif
96
 
 
97
 
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA
98
 
pjmedia_aud_dev_factory* pjmedia_symb_mda_factory(pj_pool_factory *pf);
99
 
#endif
100
 
 
101
 
#if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO
102
 
pjmedia_aud_dev_factory* pjmedia_null_audio_factory(pj_pool_factory *pf);
103
 
#endif
104
 
 
105
 
#define MAX_DRIVERS     16
106
 
#define MAX_DEVS        64
107
 
 
108
 
 
109
 
/* driver structure */
110
 
struct driver
111
 
{
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.                  */
122
 
};
123
 
 
124
 
/* The audio subsystem */
125
 
static struct aud_subsys
126
 
{
127
 
    unsigned         init_count;        /* How many times init() is called  */
128
 
    pj_pool_factory *pf;                /* The pool factory.                */
129
 
 
130
 
    unsigned         drv_cnt;           /* Number of drivers.               */
131
 
    struct driver    drv[MAX_DRIVERS];  /* Array of drivers.                */
132
 
 
133
 
    unsigned         dev_cnt;           /* Total number of devices.         */
134
 
    pj_uint32_t      dev_list[MAX_DEVS];/* Array of device IDs.             */
135
 
 
136
 
} aud_subsys;
137
 
 
138
 
/* API: get capability name/info */
139
 
PJ_DEF(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
140
 
                                             const char **p_desc)
141
 
{
142
 
    const char *desc;
143
 
    unsigned i;
144
 
 
145
 
    if (p_desc==NULL) p_desc = &desc;
146
 
 
147
 
    for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {
148
 
        if ((1 << i)==cap)
149
 
            break;
150
 
    }
151
 
 
152
 
    if (i==PJ_ARRAY_SIZE(cap_infos)) {
153
 
        *p_desc = "??";
154
 
        return "??";
155
 
    }
156
 
 
157
 
    *p_desc = cap_infos[i].info;
158
 
    return cap_infos[i].name;
159
 
}
160
 
 
161
 
static pj_status_t get_cap_pointer(const pjmedia_aud_param *param,
162
 
                                   pjmedia_aud_dev_cap cap,
163
 
                                   void **ptr,
164
 
                                   unsigned *size)
165
 
{
166
 
#define FIELD_INFO(name)    *ptr = (void*)&param->name; \
167
 
                            *size = sizeof(param->name)
168
 
 
169
 
    switch (cap) {
170
 
    case PJMEDIA_AUD_DEV_CAP_EXT_FORMAT:
171
 
        FIELD_INFO(ext_fmt);
172
 
        break;
173
 
    case PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY:
174
 
        FIELD_INFO(input_latency_ms);
175
 
        break;
176
 
    case PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY:
177
 
        FIELD_INFO(output_latency_ms);
178
 
        break;
179
 
    case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
180
 
        FIELD_INFO(input_vol);
181
 
        break;
182
 
    case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
183
 
        FIELD_INFO(output_vol);
184
 
        break;
185
 
    case PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE:
186
 
        FIELD_INFO(input_route);
187
 
        break;
188
 
    case PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE:
189
 
        FIELD_INFO(output_route);
190
 
        break;
191
 
    case PJMEDIA_AUD_DEV_CAP_EC:
192
 
        FIELD_INFO(ec_enabled);
193
 
        break;
194
 
    case PJMEDIA_AUD_DEV_CAP_EC_TAIL:
195
 
        FIELD_INFO(ec_tail_ms);
196
 
        break;
197
 
    /* vad is no longer in "fmt" in 2.0.
198
 
    case PJMEDIA_AUD_DEV_CAP_VAD:
199
 
        FIELD_INFO(ext_fmt.vad);
200
 
        break;
201
 
    */
202
 
    case PJMEDIA_AUD_DEV_CAP_CNG:
203
 
        FIELD_INFO(cng_enabled);
204
 
        break;
205
 
    case PJMEDIA_AUD_DEV_CAP_PLC:
206
 
        FIELD_INFO(plc_enabled);
207
 
        break;
208
 
    default:
209
 
        return PJMEDIA_EAUD_INVCAP;
210
 
    }
211
 
 
212
 
#undef FIELD_INFO
213
 
 
214
 
    return PJ_SUCCESS;
215
 
}
216
 
 
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,
220
 
                                               const void *pval)
221
 
{
222
 
    void *cap_ptr;
223
 
    unsigned cap_size;
224
 
    pj_status_t status;
225
 
 
226
 
    status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
227
 
    if (status != PJ_SUCCESS)
228
 
        return status;
229
 
 
230
 
    pj_memcpy(cap_ptr, pval, cap_size);
231
 
    param->flags |= cap;
232
 
 
233
 
    return PJ_SUCCESS;
234
 
}
235
 
 
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,
239
 
                                               void *pval)
240
 
{
241
 
    void *cap_ptr;
242
 
    unsigned cap_size;
243
 
    pj_status_t status;
244
 
 
245
 
    status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
246
 
    if (status != PJ_SUCCESS)
247
 
        return status;
248
 
 
249
 
    if ((param->flags & cap) == 0) {
250
 
        pj_bzero(cap_ptr, cap_size);
251
 
        return PJMEDIA_EAUD_INVCAP;
252
 
    }
253
 
 
254
 
    pj_memcpy(pval, cap_ptr, cap_size);
255
 
    return PJ_SUCCESS;
256
 
}
257
 
 
258
 
/* Internal: init driver */
259
 
static pj_status_t init_driver(unsigned drv_idx, pj_bool_t refresh)
260
 
{
261
 
    struct driver *drv = &aud_subsys.drv[drv_idx];
262
 
    pjmedia_aud_dev_factory *f;
263
 
    unsigned i, dev_cnt;
264
 
    pj_status_t status;
265
 
 
266
 
    if (!refresh) {
267
 
        /* Create the factory */
268
 
        f = (*drv->create)(aud_subsys.pf);
269
 
        if (!f)
270
 
            return PJ_EUNKNOWN;
271
 
 
272
 
        /* Call factory->init() */
273
 
        status = f->op->init(f);
274
 
        if (status != PJ_SUCCESS) {
275
 
            f->op->destroy(f);
276
 
            return status;
277
 
        }
278
 
    } else {
279
 
        f = drv->f;
280
 
    }
281
 
 
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;
289
 
    }
290
 
 
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
294
 
     *
295
 
    if (dev_cnt == 0) {
296
 
        f->op->destroy(f);
297
 
        return PJMEDIA_EAUD_NODEV;
298
 
    }
299
 
    */
300
 
 
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;
305
 
 
306
 
        status = f->op->get_dev_info(f, i, &info);
307
 
        if (status != PJ_SUCCESS) {
308
 
            f->op->destroy(f);
309
 
            return status;
310
 
        }
311
 
 
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';
316
 
        }
317
 
 
318
 
        if (drv->play_dev_idx < 0 && info.output_count) {
319
 
            /* Set default playback device */
320
 
            drv->play_dev_idx = i;
321
 
        }
322
 
        if (drv->rec_dev_idx < 0 && info.input_count) {
323
 
            /* Set default capture device */
324
 
            drv->rec_dev_idx = i;
325
 
        }
326
 
        if (drv->dev_idx < 0 && info.input_count &&
327
 
            info.output_count)
328
 
        {
329
 
            /* Set default capture and playback device */
330
 
            drv->dev_idx = i;
331
 
        }
332
 
 
333
 
        if (drv->play_dev_idx >= 0 && drv->rec_dev_idx >= 0 && 
334
 
            drv->dev_idx >= 0) 
335
 
        {
336
 
            /* Done. */
337
 
            break;
338
 
        }
339
 
    }
340
 
 
341
 
    /* Register the factory */
342
 
    drv->f = f;
343
 
    drv->f->sys.drv_idx = drv_idx;
344
 
    drv->start_idx = aud_subsys.dev_cnt;
345
 
    drv->dev_cnt = dev_cnt;
346
 
 
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);
350
 
    }
351
 
 
352
 
    return PJ_SUCCESS;
353
 
}
354
 
 
355
 
/* Internal: deinit driver */
356
 
static void deinit_driver(unsigned drv_idx)
357
 
{
358
 
    struct driver *drv = &aud_subsys.drv[drv_idx];
359
 
 
360
 
    if (drv->f) {
361
 
        drv->f->op->destroy(drv->f);
362
 
        drv->f = NULL;
363
 
    }
364
 
 
365
 
    drv->dev_cnt = 0;
366
 
    drv->play_dev_idx = drv->rec_dev_idx = drv->dev_idx = -1;
367
 
}
368
 
 
369
 
/* API: Initialize the audio subsystem. */
370
 
PJ_DEF(pj_status_t) pjmedia_aud_subsys_init(pj_pool_factory *pf)
371
 
{
372
 
    unsigned i;
373
 
    pj_status_t status;
374
 
 
375
 
    /* Allow init() to be called multiple times as long as there is matching
376
 
     * number of shutdown().
377
 
     */
378
 
    if (aud_subsys.init_count++ != 0) {
379
 
        return PJ_SUCCESS;
380
 
    }
381
 
 
382
 
    /* Register error subsystem */
383
 
    status = pj_register_strerror(PJMEDIA_AUDIODEV_ERRNO_START, 
384
 
                                  PJ_ERRNO_SPACE_SIZE, 
385
 
                                  &pjmedia_audiodev_strerror);
386
 
    pj_assert(status == PJ_SUCCESS);
387
 
 
388
 
    /* Init */
389
 
    aud_subsys.pf = pf;
390
 
    aud_subsys.drv_cnt = 0;
391
 
    aud_subsys.dev_cnt = 0;
392
 
 
393
 
    /* Register creation functions */
394
 
#if PJMEDIA_AUDIO_DEV_HAS_BB10
395
 
    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_bb10_factory;
396
 
#endif
397
 
#if PJMEDIA_AUDIO_DEV_HAS_ALSA
398
 
    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_alsa_factory;
399
 
#endif
400
 
#if PJMEDIA_AUDIO_DEV_HAS_COREAUDIO
401
 
    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_coreaudio_factory;
402
 
#endif
403
 
#if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
404
 
    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_pa_factory;
405
 
#endif
406
 
#if PJMEDIA_AUDIO_DEV_HAS_WMME
407
 
    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_wmme_factory;
408
 
#endif
409
 
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_VAS
410
 
    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_symb_vas_factory;
411
 
#endif
412
 
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_APS
413
 
    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_aps_factory;
414
 
#endif
415
 
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA
416
 
    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_symb_mda_factory;
417
 
#endif
418
 
#if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO
419
 
    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_null_audio_factory;
420
 
#endif
421
 
 
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) {
426
 
            deinit_driver(i);
427
 
            continue;
428
 
        }
429
 
    }
430
 
 
431
 
    return aud_subsys.dev_cnt ? PJ_SUCCESS : status;
432
 
}
433
 
 
434
 
/* API: register an audio device factory to the audio subsystem. */
435
 
PJ_DEF(pj_status_t)
436
 
pjmedia_aud_register_factory(pjmedia_aud_dev_factory_create_func_ptr adf)
437
 
{
438
 
    pj_status_t status;
439
 
 
440
 
    if (aud_subsys.init_count == 0)
441
 
        return PJMEDIA_EAUD_INIT;
442
 
 
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++;
447
 
    } else {
448
 
        deinit_driver(aud_subsys.drv_cnt);
449
 
    }
450
 
 
451
 
    return status;
452
 
}
453
 
 
454
 
/* API: unregister an audio device factory from the audio subsystem. */
455
 
PJ_DEF(pj_status_t)
456
 
pjmedia_aud_unregister_factory(pjmedia_aud_dev_factory_create_func_ptr adf)
457
 
{
458
 
    unsigned i, j;
459
 
 
460
 
    if (aud_subsys.init_count == 0)
461
 
        return PJMEDIA_EAUD_INIT;
462
 
 
463
 
    for (i=0; i<aud_subsys.drv_cnt; ++i) {
464
 
        struct driver *drv = &aud_subsys.drv[i];
465
 
 
466
 
        if (drv->create == adf) {
467
 
            for (j = drv->start_idx; j < drv->start_idx + drv->dev_cnt; j++)
468
 
            {
469
 
                aud_subsys.dev_list[j] = (pj_uint32_t)PJMEDIA_AUD_INVALID_DEV;
470
 
            }
471
 
 
472
 
            deinit_driver(i);
473
 
            pj_bzero(drv, sizeof(*drv));
474
 
            return PJ_SUCCESS;
475
 
        }
476
 
    }
477
 
 
478
 
    return PJMEDIA_EAUD_ERR;
479
 
}
480
 
 
481
 
/* API: get the pool factory registered to the audio subsystem. */
482
 
PJ_DEF(pj_pool_factory*) pjmedia_aud_subsys_get_pool_factory(void)
483
 
{
484
 
    return aud_subsys.pf;
485
 
}
486
 
 
487
 
/* API: Shutdown the audio subsystem. */
488
 
PJ_DEF(pj_status_t) pjmedia_aud_subsys_shutdown(void)
489
 
{
490
 
    unsigned i;
491
 
 
492
 
    /* Allow shutdown() to be called multiple times as long as there is matching
493
 
     * number of init().
494
 
     */
495
 
    if (aud_subsys.init_count == 0) {
496
 
        return PJ_SUCCESS;
497
 
    }
498
 
    --aud_subsys.init_count;
499
 
 
500
 
    if (aud_subsys.init_count == 0) {
501
 
        for (i=0; i<aud_subsys.drv_cnt; ++i) {
502
 
            deinit_driver(i);
503
 
        }
504
 
 
505
 
        aud_subsys.pf = NULL;
506
 
    }
507
 
    return PJ_SUCCESS;
508
 
}
509
 
 
510
 
/* API: Refresh the list of sound devices installed in the system. */
511
 
PJ_DEF(pj_status_t) pjmedia_aud_dev_refresh(void)
512
 
{
513
 
    unsigned i;
514
 
    
515
 
    aud_subsys.dev_cnt = 0;
516
 
    for (i=0; i<aud_subsys.drv_cnt; ++i) {
517
 
        struct driver *drv = &aud_subsys.drv[i];
518
 
        
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));
524
 
            }
525
 
        }
526
 
        init_driver(i, PJ_TRUE);
527
 
    }
528
 
    return PJ_SUCCESS;
529
 
}
530
 
 
531
 
/* API: Get the number of sound devices installed in the system. */
532
 
PJ_DEF(unsigned) pjmedia_aud_dev_count(void)
533
 
{
534
 
    return aud_subsys.dev_cnt;
535
 
}
536
 
 
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)
540
 
{
541
 
    if (*id < 0) {
542
 
        return PJ_SUCCESS;
543
 
    }
544
 
 
545
 
    /* Check that factory still exists */
546
 
    PJ_ASSERT_RETURN(aud_subsys.drv[drv_idx].f, PJ_EBUG);
547
 
 
548
 
    /* Check that device index is valid */
549
 
    PJ_ASSERT_RETURN(*id>=0 && *id<(int)aud_subsys.drv[drv_idx].dev_cnt, 
550
 
                     PJ_EBUG);
551
 
 
552
 
    *id += aud_subsys.drv[drv_idx].start_idx;
553
 
    return PJ_SUCCESS;
554
 
}
555
 
 
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)
560
 
{
561
 
    int f_id, index;
562
 
 
563
 
    if (id < 0) {
564
 
        unsigned i;
565
 
 
566
 
        if (id == PJMEDIA_AUD_INVALID_DEV)
567
 
            return PJMEDIA_EAUD_INVDEV;
568
 
 
569
 
        for (i=0; i<aud_subsys.drv_cnt; ++i) {
570
 
            struct driver *drv = &aud_subsys.drv[i];
571
 
            if (drv->dev_idx >= 0) {
572
 
                id = drv->dev_idx;
573
 
                make_global_index(i, &id);
574
 
                break;
575
 
            } else if (id==PJMEDIA_AUD_DEFAULT_CAPTURE_DEV && 
576
 
                drv->rec_dev_idx >= 0) 
577
 
            {
578
 
                id = drv->rec_dev_idx;
579
 
                make_global_index(i, &id);
580
 
                break;
581
 
            } else if (id==PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV && 
582
 
                drv->play_dev_idx >= 0) 
583
 
            {
584
 
                id = drv->play_dev_idx;
585
 
                make_global_index(i, &id);
586
 
                break;
587
 
            }
588
 
        }
589
 
 
590
 
        if (id < 0) {
591
 
            return PJMEDIA_EAUD_NODEFDEV;
592
 
        }
593
 
    }
594
 
 
595
 
    f_id = GET_FID(aud_subsys.dev_list[id]);
596
 
    index = GET_INDEX(aud_subsys.dev_list[id]);
597
 
 
598
 
    if (f_id < 0 || f_id >= (int)aud_subsys.drv_cnt)
599
 
        return PJMEDIA_EAUD_INVDEV;
600
 
 
601
 
    if (index < 0 || index >= (int)aud_subsys.drv[f_id].dev_cnt)
602
 
        return PJMEDIA_EAUD_INVDEV;
603
 
 
604
 
    *p_f = aud_subsys.drv[f_id].f;
605
 
    *p_local_index = (unsigned)index;
606
 
 
607
 
    return PJ_SUCCESS;
608
 
 
609
 
}
610
 
 
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)
614
 
{
615
 
    pjmedia_aud_dev_factory *f;
616
 
    unsigned index;
617
 
    pj_status_t status;
618
 
 
619
 
    PJ_ASSERT_RETURN(info && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);
620
 
    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
621
 
 
622
 
    status = lookup_dev(id, &f, &index);
623
 
    if (status != PJ_SUCCESS)
624
 
        return status;
625
 
 
626
 
    return f->op->get_dev_info(f, index, info);
627
 
}
628
 
 
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)
633
 
{
634
 
    pjmedia_aud_dev_factory *f = NULL;
635
 
    unsigned drv_idx, dev_idx;
636
 
 
637
 
    PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);
638
 
    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
639
 
 
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;
643
 
            break;
644
 
        }
645
 
    }
646
 
 
647
 
    if (!f)
648
 
        return PJ_ENOTFOUND;
649
 
 
650
 
    for (dev_idx=0; dev_idx<aud_subsys.drv[drv_idx].dev_cnt; ++dev_idx) {
651
 
        pjmedia_aud_dev_info info;
652
 
        pj_status_t status;
653
 
 
654
 
        status = f->op->get_dev_info(f, dev_idx, &info);
655
 
        if (status != PJ_SUCCESS)
656
 
            return status;
657
 
 
658
 
        if (!pj_ansi_stricmp(dev_name, info.name))
659
 
            break;
660
 
    }
661
 
 
662
 
    if (dev_idx==aud_subsys.drv[drv_idx].dev_cnt)
663
 
        return PJ_ENOTFOUND;
664
 
 
665
 
    *id = dev_idx;
666
 
    make_global_index(drv_idx, id);
667
 
 
668
 
    return PJ_SUCCESS;
669
 
}
670
 
 
671
 
/* API: Initialize the audio device parameters with default values for the
672
 
 * specified device.
673
 
 */
674
 
PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
675
 
                                                  pjmedia_aud_param *param)
676
 
{
677
 
    pjmedia_aud_dev_factory *f;
678
 
    unsigned index;
679
 
    pj_status_t status;
680
 
 
681
 
    PJ_ASSERT_RETURN(param && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);
682
 
    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
683
 
 
684
 
    status = lookup_dev(id, &f, &index);
685
 
    if (status != PJ_SUCCESS)
686
 
        return status;
687
 
 
688
 
    status = f->op->default_param(f, index, param);
689
 
    if (status != PJ_SUCCESS)
690
 
        return status;
691
 
 
692
 
    /* Normalize device IDs */
693
 
    make_global_index(f->sys.drv_idx, &param->rec_id);
694
 
    make_global_index(f->sys.drv_idx, &param->play_id);
695
 
 
696
 
    return PJ_SUCCESS;
697
 
}
698
 
 
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,
703
 
                                              void *user_data,
704
 
                                              pjmedia_aud_stream **p_aud_strm)
705
 
{
706
 
    pjmedia_aud_dev_factory *rec_f=NULL, *play_f=NULL, *f=NULL;
707
 
    pjmedia_aud_param param;
708
 
    pj_status_t status;
709
 
 
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,
715
 
                     PJ_EINVAL);
716
 
 
717
 
    /* Must make copy of param because we're changing device ID */
718
 
    pj_memcpy(&param, prm, sizeof(param));
719
 
 
720
 
    /* Normalize rec_id */
721
 
    if (param.dir & PJMEDIA_DIR_CAPTURE) {
722
 
        unsigned index;
723
 
 
724
 
        if (param.rec_id < 0)
725
 
            param.rec_id = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV;
726
 
 
727
 
        status = lookup_dev(param.rec_id, &rec_f, &index);
728
 
        if (status != PJ_SUCCESS)
729
 
            return status;
730
 
 
731
 
        param.rec_id = index;
732
 
        f = rec_f;
733
 
    }
734
 
 
735
 
    /* Normalize play_id */
736
 
    if (param.dir & PJMEDIA_DIR_PLAYBACK) {
737
 
        unsigned index;
738
 
 
739
 
        if (param.play_id < 0)
740
 
            param.play_id = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
741
 
 
742
 
        status = lookup_dev(param.play_id, &play_f, &index);
743
 
        if (status != PJ_SUCCESS)
744
 
            return status;
745
 
 
746
 
        param.play_id = index;
747
 
        f = play_f;
748
 
    }
749
 
 
750
 
    PJ_ASSERT_RETURN(f != NULL, PJ_EBUG);
751
 
 
752
 
    /* For now, rec_id and play_id must belong to the same factory */
753
 
    PJ_ASSERT_RETURN((param.dir != PJMEDIA_DIR_CAPTURE_PLAYBACK) || 
754
 
                     (rec_f == play_f),
755
 
                     PJMEDIA_EAUD_INVDEV);
756
 
 
757
 
    /* Create the stream */
758
 
    status = f->op->create_stream(f, &param, rec_cb, play_cb,
759
 
                                  user_data, p_aud_strm);
760
 
    if (status != PJ_SUCCESS)
761
 
        return status;
762
 
 
763
 
    /* Assign factory id to the stream */
764
 
    (*p_aud_strm)->sys.drv_idx = f->sys.drv_idx;
765
 
    return PJ_SUCCESS;
766
 
}
767
 
 
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)
771
 
{
772
 
    pj_status_t status;
773
 
 
774
 
    PJ_ASSERT_RETURN(strm && param, PJ_EINVAL);
775
 
    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
776
 
 
777
 
    status = strm->op->get_param(strm, param);
778
 
    if (status != PJ_SUCCESS)
779
 
        return status;
780
 
 
781
 
    /* Normalize device id's */
782
 
    make_global_index(strm->sys.drv_idx, &param->rec_id);
783
 
    make_global_index(strm->sys.drv_idx, &param->play_id);
784
 
 
785
 
    return PJ_SUCCESS;
786
 
}
787
 
 
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,
791
 
                                               void *value)
792
 
{
793
 
    return strm->op->get_cap(strm, cap, value);
794
 
}
795
 
 
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,
799
 
                                               const void *value)
800
 
{
801
 
    return strm->op->set_cap(strm, cap, value);
802
 
}
803
 
 
804
 
/* API: Start the stream. */
805
 
PJ_DEF(pj_status_t) pjmedia_aud_stream_start(pjmedia_aud_stream *strm)
806
 
{
807
 
    return strm->op->start(strm);
808
 
}
809
 
 
810
 
/* API: Stop the stream. */
811
 
PJ_DEF(pj_status_t) pjmedia_aud_stream_stop(pjmedia_aud_stream *strm)
812
 
{
813
 
    return strm->op->stop(strm);
814
 
}
815
 
 
816
 
/* API: Destroy the stream. */
817
 
PJ_DEF(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm)
818
 
{
819
 
    return strm->op->destroy(strm);
820
 
}
821
 
 
822