~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: bb10_dev.c 4151 2012-06-01 04:49:57Z ming $ */
2
 
/*
3
 
 * Copyright (C) 2008-2012 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
 
 
20
 
/*
21
 
 * This is the implementation of BlackBerry 10 (BB10) audio device.
22
 
 * Original code was kindly donated by Truphone Ltd. (http://www.truphone.com)
23
 
 * The key methods here are bb10_capture_open, bb10_play_open together
24
 
 * with the capture and play threads ca_thread_func and pb_thread_func
25
 
 */
26
 
 
27
 
#include <pjmedia_audiodev.h>
28
 
#include <pj/assert.h>
29
 
#include <pj/log.h>
30
 
#include <pj/os.h>
31
 
#include <pj/pool.h>
32
 
#include <pjmedia/errno.h>
33
 
 
34
 
#if defined(PJMEDIA_AUDIO_DEV_HAS_BB10) && PJMEDIA_AUDIO_DEV_HAS_BB10 != 0
35
 
 
36
 
#include <sys/time.h>
37
 
#include <sys/types.h>
38
 
#include <unistd.h>
39
 
#include <sys/select.h>
40
 
#include <pthread.h>
41
 
#include <errno.h>
42
 
#include <sys/asoundlib.h>
43
 
 
44
 
 
45
 
#define THIS_FILE                       "bb10_dev.c"
46
 
#define BB10_DEVICE_NAME                "plughw:%d,%d"
47
 
/* Double these for 16khz sampling */
48
 
#define PREFERRED_FRAME_SIZE 320
49
 
#define VOIP_SAMPLE_RATE 8000
50
 
 
51
 
/* Set to 1 to enable tracing */
52
 
#if 1
53
 
#    define TRACE_(expr)                PJ_LOG(4,expr)
54
 
#else
55
 
#    define TRACE_(expr)
56
 
#endif
57
 
 
58
 
/*
59
 
 * Factory prototypes
60
 
 */
61
 
static pj_status_t bb10_factory_init(pjmedia_aud_dev_factory *f);
62
 
static pj_status_t bb10_factory_destroy(pjmedia_aud_dev_factory *f);
63
 
static pj_status_t bb10_factory_refresh(pjmedia_aud_dev_factory *f);
64
 
static unsigned    bb10_factory_get_dev_count(pjmedia_aud_dev_factory *f);
65
 
static pj_status_t bb10_factory_get_dev_info(pjmedia_aud_dev_factory *f,
66
 
                                             unsigned index,
67
 
                                             pjmedia_aud_dev_info *info);
68
 
static pj_status_t bb10_factory_default_param(pjmedia_aud_dev_factory *f,
69
 
                                              unsigned index,
70
 
                                              pjmedia_aud_param *param);
71
 
static pj_status_t bb10_factory_create_stream(pjmedia_aud_dev_factory *f,
72
 
                                              const pjmedia_aud_param *param,
73
 
                                              pjmedia_aud_rec_cb rec_cb,
74
 
                                              pjmedia_aud_play_cb play_cb,
75
 
                                              void *user_data,
76
 
                                              pjmedia_aud_stream **p_strm);
77
 
 
78
 
/*
79
 
 * Stream prototypes
80
 
 */
81
 
static pj_status_t bb10_stream_get_param(pjmedia_aud_stream *strm,
82
 
                                         pjmedia_aud_param *param);
83
 
static pj_status_t bb10_stream_get_cap(pjmedia_aud_stream *strm,
84
 
                                       pjmedia_aud_dev_cap cap,
85
 
                                       void *value);
86
 
static pj_status_t bb10_stream_set_cap(pjmedia_aud_stream *strm,
87
 
                                       pjmedia_aud_dev_cap cap,
88
 
                                       const void *value);
89
 
static pj_status_t bb10_stream_start(pjmedia_aud_stream *strm);
90
 
static pj_status_t bb10_stream_stop(pjmedia_aud_stream *strm);
91
 
static pj_status_t bb10_stream_destroy(pjmedia_aud_stream *strm);
92
 
 
93
 
 
94
 
struct bb10_factory
95
 
{
96
 
    pjmedia_aud_dev_factory      base;
97
 
    pj_pool_factory             *pf;
98
 
    pj_pool_t                   *pool;
99
 
    pj_pool_t                   *base_pool;
100
 
    unsigned                     dev_cnt;
101
 
    pjmedia_aud_dev_info         devs[1];
102
 
};
103
 
 
104
 
struct bb10_stream
105
 
{
106
 
    pjmedia_aud_stream   base;
107
 
 
108
 
    /* Common */
109
 
    pj_pool_t           *pool;
110
 
    struct bb10_factory *af;
111
 
    void                *user_data;
112
 
    pjmedia_aud_param    param;         /* Running parameter            */
113
 
    int                  rec_id;        /* Capture device id            */
114
 
    int                  quit;
115
 
 
116
 
    /* Playback */
117
 
    snd_pcm_t           *pb_pcm;
118
 
    snd_mixer_t         *pb_mixer;
119
 
    unsigned long        pb_frames;     /* samples_per_frame            */
120
 
    pjmedia_aud_play_cb  pb_cb;
121
 
    unsigned             pb_buf_size;
122
 
    char                *pb_buf;
123
 
    pj_thread_t         *pb_thread;
124
 
 
125
 
    /* Capture */
126
 
    snd_pcm_t           *ca_pcm;
127
 
    snd_mixer_t         *ca_mixer;
128
 
    unsigned long        ca_frames;     /* samples_per_frame            */
129
 
    pjmedia_aud_rec_cb   ca_cb;
130
 
    unsigned             ca_buf_size;
131
 
    char                *ca_buf;
132
 
    pj_thread_t         *ca_thread;
133
 
};
134
 
 
135
 
static pjmedia_aud_dev_factory_op bb10_factory_op =
136
 
{
137
 
    &bb10_factory_init,
138
 
    &bb10_factory_destroy,
139
 
    &bb10_factory_get_dev_count,
140
 
    &bb10_factory_get_dev_info,
141
 
    &bb10_factory_default_param,
142
 
    &bb10_factory_create_stream,
143
 
    &bb10_factory_refresh
144
 
};
145
 
 
146
 
static pjmedia_aud_stream_op bb10_stream_op =
147
 
{
148
 
    &bb10_stream_get_param,
149
 
    &bb10_stream_get_cap,
150
 
    &bb10_stream_set_cap,
151
 
    &bb10_stream_start,
152
 
    &bb10_stream_stop,
153
 
    &bb10_stream_destroy
154
 
};
155
 
 
156
 
/*
157
 
 * BB10 - tests loads the audio units and sets up the driver structure
158
 
 */
159
 
static pj_status_t bb10_add_dev (struct bb10_factory *af)
160
 
{
161
 
    pjmedia_aud_dev_info *adi;
162
 
    int pb_result, ca_result;
163
 
    int card = -1;
164
 
    int dev = 0;
165
 
    snd_pcm_t *pcm_handle;
166
 
 
167
 
    if (af->dev_cnt >= PJ_ARRAY_SIZE(af->devs))
168
 
        return PJ_ETOOMANY;
169
 
 
170
 
    adi = &af->devs[af->dev_cnt];
171
 
 
172
 
    TRACE_((THIS_FILE, "bb10_add_dev Enter"));
173
 
 
174
 
    if ((pb_result = snd_pcm_open_preferred (&pcm_handle, &card, &dev,
175
 
                                             SND_PCM_OPEN_PLAYBACK)) >= 0)
176
 
    {
177
 
        TRACE_((THIS_FILE, "Try to open the device for playback - success"));
178
 
        snd_pcm_close (pcm_handle);
179
 
    } else {
180
 
        TRACE_((THIS_FILE, "Try to open the device for playback - failure"));
181
 
    }
182
 
 
183
 
    if ((ca_result = snd_pcm_open_preferred (&pcm_handle, &card, &dev,
184
 
                                             SND_PCM_OPEN_CAPTURE)) >=0)
185
 
    {
186
 
        TRACE_((THIS_FILE, "Try to open the device for capture - success"));
187
 
        snd_pcm_close (pcm_handle);
188
 
    } else {
189
 
        TRACE_((THIS_FILE, "Try to open the device for capture - failure"));
190
 
    }
191
 
 
192
 
    if (pb_result < 0 && ca_result < 0) {
193
 
        TRACE_((THIS_FILE, "Unable to open sound device", "preferred"));
194
 
        return PJMEDIA_EAUD_NODEV;
195
 
    }
196
 
 
197
 
    /* Reset device info */
198
 
    pj_bzero(adi, sizeof(*adi));
199
 
 
200
 
    /* Set device name */
201
 
    strcpy(adi->name, "preferred");
202
 
 
203
 
    /* Check the number of playback channels */
204
 
    adi->output_count = (pb_result >= 0) ? 1 : 0;
205
 
 
206
 
    /* Check the number of capture channels */
207
 
    adi->input_count = (ca_result >= 0) ? 1 : 0;
208
 
 
209
 
    /* Set the default sample rate */
210
 
    adi->default_samples_per_sec = 8000;
211
 
 
212
 
    /* Driver name */
213
 
    strcpy(adi->driver, "BB10");
214
 
 
215
 
    ++af->dev_cnt;
216
 
 
217
 
    PJ_LOG (4,(THIS_FILE, "Added sound device %s", adi->name));
218
 
 
219
 
    return PJ_SUCCESS;
220
 
}
221
 
 
222
 
/* Create BB10 audio driver. */
223
 
pjmedia_aud_dev_factory* pjmedia_bb10_factory(pj_pool_factory *pf)
224
 
{
225
 
    struct bb10_factory *af;
226
 
    pj_pool_t *pool;
227
 
 
228
 
    pool = pj_pool_create(pf, "bb10_aud_base", 256, 256, NULL);
229
 
    af = PJ_POOL_ZALLOC_T(pool, struct bb10_factory);
230
 
    af->pf = pf;
231
 
    af->base_pool = pool;
232
 
    af->base.op = &bb10_factory_op;
233
 
 
234
 
    return &af->base;
235
 
}
236
 
 
237
 
 
238
 
/* API: init factory */
239
 
static pj_status_t bb10_factory_init(pjmedia_aud_dev_factory *f)
240
 
{
241
 
    pj_status_t status;
242
 
 
243
 
    status = bb10_factory_refresh(f);
244
 
    if (status != PJ_SUCCESS)
245
 
        return status;
246
 
 
247
 
    PJ_LOG(4,(THIS_FILE, "BB10 initialized"));
248
 
    return PJ_SUCCESS;
249
 
}
250
 
 
251
 
 
252
 
/* API: destroy factory */
253
 
static pj_status_t bb10_factory_destroy(pjmedia_aud_dev_factory *f)
254
 
{
255
 
    struct bb10_factory *af = (struct bb10_factory*)f;
256
 
 
257
 
    if (af->pool) {
258
 
        TRACE_((THIS_FILE, "bb10_factory_destroy() - 1"));
259
 
        pj_pool_release(af->pool);
260
 
    }
261
 
 
262
 
    if (af->base_pool) {
263
 
        pj_pool_t *pool = af->base_pool;
264
 
        af->base_pool = NULL;
265
 
        TRACE_((THIS_FILE, "bb10_factory_destroy() - 2"));
266
 
        pj_pool_release(pool);
267
 
    }
268
 
 
269
 
    return PJ_SUCCESS;
270
 
}
271
 
 
272
 
 
273
 
/* API: refresh the device list */
274
 
static pj_status_t bb10_factory_refresh(pjmedia_aud_dev_factory *f)
275
 
{
276
 
    struct bb10_factory *af = (struct bb10_factory*)f;
277
 
    int err;
278
 
 
279
 
    TRACE_((THIS_FILE, "bb10_factory_refresh()"));
280
 
 
281
 
    if (af->pool != NULL) {
282
 
        pj_pool_release(af->pool);
283
 
        af->pool = NULL;
284
 
    }
285
 
 
286
 
    af->pool = pj_pool_create(af->pf, "bb10_aud", 256, 256, NULL);
287
 
    af->dev_cnt = 0;
288
 
 
289
 
    err = bb10_add_dev(af);
290
 
 
291
 
    PJ_LOG(4,(THIS_FILE, "BB10 driver found %d devices", af->dev_cnt));
292
 
 
293
 
    return err;
294
 
}
295
 
 
296
 
 
297
 
/* API: get device count */
298
 
static unsigned  bb10_factory_get_dev_count(pjmedia_aud_dev_factory *f)
299
 
{
300
 
    struct bb10_factory *af = (struct bb10_factory*)f;
301
 
    return af->dev_cnt;
302
 
}
303
 
 
304
 
 
305
 
/* API: get device info */
306
 
static pj_status_t bb10_factory_get_dev_info(pjmedia_aud_dev_factory *f,
307
 
                                             unsigned index,
308
 
                                             pjmedia_aud_dev_info *info)
309
 
{
310
 
    struct bb10_factory *af = (struct bb10_factory*)f;
311
 
 
312
 
    PJ_ASSERT_RETURN(index>=0 && index<af->dev_cnt, PJ_EINVAL);
313
 
 
314
 
    pj_memcpy(info, &af->devs[index], sizeof(*info));
315
 
    info->caps = PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY |
316
 
                 PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
317
 
 
318
 
    return PJ_SUCCESS;
319
 
}
320
 
 
321
 
/* API: create default parameter */
322
 
static pj_status_t bb10_factory_default_param(pjmedia_aud_dev_factory *f,
323
 
                                              unsigned index,
324
 
                                              pjmedia_aud_param *param)
325
 
{
326
 
    struct bb10_factory *af = (struct bb10_factory*)f;
327
 
    pjmedia_aud_dev_info *adi;
328
 
 
329
 
    PJ_ASSERT_RETURN(index>=0 && index<af->dev_cnt, PJ_EINVAL);
330
 
 
331
 
    adi = &af->devs[index];
332
 
 
333
 
    pj_bzero(param, sizeof(*param));
334
 
    if (adi->input_count && adi->output_count) {
335
 
        param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
336
 
        param->rec_id = index;
337
 
        param->play_id = index;
338
 
    } else if (adi->input_count) {
339
 
        param->dir = PJMEDIA_DIR_CAPTURE;
340
 
        param->rec_id = index;
341
 
        param->play_id = PJMEDIA_AUD_INVALID_DEV;
342
 
    } else if (adi->output_count) {
343
 
        param->dir = PJMEDIA_DIR_PLAYBACK;
344
 
        param->play_id = index;
345
 
        param->rec_id = PJMEDIA_AUD_INVALID_DEV;
346
 
    } else {
347
 
        return PJMEDIA_EAUD_INVDEV;
348
 
    }
349
 
 
350
 
    param->clock_rate = adi->default_samples_per_sec;
351
 
    param->channel_count = 1;
352
 
    param->samples_per_frame = adi->default_samples_per_sec * 20 / 1000;
353
 
    param->bits_per_sample = 16;
354
 
    param->flags = adi->caps;
355
 
    param->input_latency_ms = PJMEDIA_SND_DEFAULT_REC_LATENCY;
356
 
    param->output_latency_ms = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
357
 
 
358
 
    TRACE_((THIS_FILE, "bb10_factory_default_param clock = %d flags = %d"
359
 
                       " spf = %d", param->clock_rate, param->flags,
360
 
                       param->samples_per_frame));
361
 
 
362
 
    return PJ_SUCCESS;
363
 
}
364
 
 
365
 
 
366
 
static void close_play_pcm(struct bb10_stream *stream)
367
 
{
368
 
    if (stream != NULL && stream->pb_pcm != NULL) {
369
 
        snd_pcm_close(stream->pb_pcm);
370
 
        stream->pb_pcm = NULL;
371
 
    }
372
 
}
373
 
 
374
 
static void close_play_mixer(struct bb10_stream *stream)
375
 
{
376
 
    if (stream != NULL && stream->pb_mixer != NULL) {
377
 
        snd_mixer_close(stream->pb_mixer);
378
 
        stream->pb_mixer = NULL;
379
 
    }
380
 
}
381
 
 
382
 
static void flush_play(struct bb10_stream *stream)
383
 
{
384
 
    if (stream != NULL && stream->pb_pcm != NULL) {
385
 
        snd_pcm_plugin_flush (stream->pb_pcm, SND_PCM_CHANNEL_PLAYBACK);
386
 
    }
387
 
}
388
 
 
389
 
static void close_capture_pcm(struct bb10_stream *stream)
390
 
{
391
 
    if (stream != NULL && stream->ca_pcm != NULL) {
392
 
        snd_pcm_close(stream->ca_pcm);
393
 
        stream->ca_pcm = NULL;
394
 
    }
395
 
}
396
 
 
397
 
static void close_capture_mixer(struct bb10_stream *stream)
398
 
{
399
 
    if (stream != NULL && stream->ca_mixer != NULL) {
400
 
        snd_mixer_close(stream->ca_mixer);
401
 
        stream->ca_mixer = NULL;
402
 
    }
403
 
}
404
 
 
405
 
static void flush_capture(struct bb10_stream *stream)
406
 
{
407
 
    if (stream != NULL && stream->ca_pcm != NULL) {
408
 
        snd_pcm_plugin_flush (stream->ca_pcm, SND_PCM_CHANNEL_CAPTURE);
409
 
    }
410
 
}
411
 
 
412
 
 
413
 
/**
414
 
 * Play audio received from PJMEDIA
415
 
 */
416
 
static int pb_thread_func (void *arg)
417
 
{
418
 
    struct bb10_stream* stream = (struct bb10_stream *) arg;
419
 
    /* Handle from bb10_open_playback */
420
 
    /* Will be 640 */
421
 
    int size                    = stream->pb_buf_size;
422
 
    /* 160 frames for 20ms */
423
 
    unsigned long nframes       = stream->pb_frames;
424
 
    void *user_data             = stream->user_data;
425
 
    char *buf                   = stream->pb_buf;
426
 
    pj_timestamp tstamp;
427
 
    int result = 0;
428
 
 
429
 
    pj_bzero (buf, size);
430
 
    tstamp.u64 = 0;
431
 
 
432
 
    TRACE_((THIS_FILE, "pb_thread_func: size = %d ", size));
433
 
 
434
 
    /* Do the final initialization now the thread has started. */
435
 
    if ((result = snd_pcm_plugin_prepare(stream->pb_pcm,
436
 
                                         SND_PCM_CHANNEL_PLAYBACK)) < 0)
437
 
    {
438
 
        close_play_mixer(stream);
439
 
        close_play_pcm(stream);
440
 
        TRACE_((THIS_FILE, "pb_thread_func failed prepare = %d", result));
441
 
        return PJ_SUCCESS;
442
 
    }
443
 
 
444
 
    while (!stream->quit) {
445
 
        pjmedia_frame frame;
446
 
 
447
 
        frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
448
 
        /* pointer to buffer filled by PJMEDIA */
449
 
        frame.buf = buf;
450
 
        frame.size = size;
451
 
        frame.timestamp.u64 = tstamp.u64;
452
 
        frame.bit_info = 0;
453
 
 
454
 
        result = stream->pb_cb (user_data, &frame);
455
 
        if (result != PJ_SUCCESS || stream->quit)
456
 
            break;
457
 
 
458
 
        if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
459
 
            pj_bzero (buf, size);
460
 
 
461
 
        /* Write 640 to play unit */
462
 
        result = snd_pcm_plugin_write(stream->pb_pcm,buf,size);
463
 
        if (result != size) {
464
 
            TRACE_((THIS_FILE, "pb_thread_func failed write = %d", result));
465
 
        }
466
 
 
467
 
        tstamp.u64 += nframes;
468
 
    }
469
 
 
470
 
    flush_play(stream);
471
 
    close_play_mixer(stream);
472
 
    close_play_pcm(stream);
473
 
    TRACE_((THIS_FILE, "pb_thread_func: Stopped"));
474
 
 
475
 
    return PJ_SUCCESS;
476
 
}
477
 
 
478
 
 
479
 
 
480
 
static int ca_thread_func (void *arg)
481
 
{
482
 
    struct bb10_stream* stream = (struct bb10_stream *) arg;
483
 
    int size                   = stream->ca_buf_size;
484
 
    unsigned long nframes      = stream->ca_frames;
485
 
    void *user_data            = stream->user_data;
486
 
    /* Buffer to fill for PJMEDIA */
487
 
    char *buf                  = stream->ca_buf;
488
 
    pj_timestamp tstamp;
489
 
    int result;
490
 
    struct sched_param param;
491
 
    pthread_t *thid;
492
 
 
493
 
    TRACE_((THIS_FILE, "ca_thread_func: size = %d ", size));
494
 
 
495
 
    thid = (pthread_t*) pj_thread_get_os_handle (pj_thread_this());
496
 
    param.sched_priority = sched_get_priority_max (SCHED_RR);
497
 
 
498
 
    result = pthread_setschedparam (*thid, SCHED_RR, &param);
499
 
    if (result) {
500
 
        if (result == EPERM) {
501
 
            PJ_LOG (4,(THIS_FILE, "Unable to increase thread priority, "
502
 
                                  "root access needed."));
503
 
        } else {
504
 
            PJ_LOG (4,(THIS_FILE, "Unable to increase thread priority, "
505
 
                                  "error: %d", result));
506
 
        }
507
 
    }
508
 
 
509
 
    pj_bzero (buf, size);
510
 
    tstamp.u64 = 0;
511
 
 
512
 
    /* Final init now the thread has started */
513
 
    if ((result = snd_pcm_plugin_prepare (stream->ca_pcm,
514
 
                                          SND_PCM_CHANNEL_CAPTURE)) < 0)
515
 
    {
516
 
        close_capture_mixer(stream);
517
 
        close_capture_pcm(stream);
518
 
        TRACE_((THIS_FILE, "ca_thread_func failed prepare = %d", result));
519
 
        return PJ_SUCCESS;
520
 
    }
521
 
 
522
 
    while (!stream->quit) {
523
 
        pjmedia_frame frame;
524
 
 
525
 
        pj_bzero (buf, size);
526
 
 
527
 
        result = snd_pcm_plugin_read(stream->ca_pcm, buf,size);
528
 
        if (result == -EPIPE) {
529
 
            PJ_LOG (4,(THIS_FILE, "ca_thread_func: overrun!"));
530
 
            snd_pcm_plugin_prepare (stream->ca_pcm, SND_PCM_CHANNEL_CAPTURE);
531
 
            continue;
532
 
        } else if (result < 0) {
533
 
            PJ_LOG (4,(THIS_FILE, "ca_thread_func: error reading data!"));
534
 
        }
535
 
 
536
 
        if (stream->quit)
537
 
            break;
538
 
 
539
 
        frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
540
 
        frame.buf = (void *) buf;
541
 
        frame.size = size;
542
 
        frame.timestamp.u64 = tstamp.u64;
543
 
        frame.bit_info = 0;
544
 
 
545
 
        result = stream->ca_cb (user_data, &frame);
546
 
        if (result != PJ_SUCCESS || stream->quit)
547
 
            break;
548
 
 
549
 
        tstamp.u64 += nframes;
550
 
    }
551
 
 
552
 
    flush_capture(stream);
553
 
    close_capture_mixer(stream);
554
 
    close_capture_pcm(stream);
555
 
    TRACE_((THIS_FILE, "ca_thread_func: Stopped"));
556
 
 
557
 
    return PJ_SUCCESS;
558
 
}
559
 
 
560
 
 
561
 
static pj_status_t bb10_open_playback (struct bb10_stream *stream,
562
 
                                       const pjmedia_aud_param *param)
563
 
{
564
 
    int card = -1;
565
 
    int dev = 0;
566
 
    int ret = 0;
567
 
    snd_pcm_channel_info_t pi;
568
 
    snd_pcm_channel_setup_t setup;
569
 
    snd_mixer_group_t group;
570
 
    snd_pcm_channel_params_t pp;
571
 
    unsigned int rate;
572
 
    unsigned long tmp_buf_size;
573
 
 
574
 
    if (param->play_id < 0 || param->play_id >= stream->af->dev_cnt) {
575
 
        return PJMEDIA_EAUD_INVDEV;
576
 
    }
577
 
 
578
 
    if ((ret = snd_pcm_open_preferred (&stream->pb_pcm, &card, &dev,
579
 
                                       SND_PCM_OPEN_PLAYBACK)) < 0)
580
 
    {
581
 
        TRACE_((THIS_FILE, "snd_pcm_open_preferred ret = %d", ret));
582
 
        return PJMEDIA_EAUD_SYSERR;
583
 
    }
584
 
 
585
 
    /* TODO PJ_ZERO */
586
 
    memset (&pi, 0, sizeof (pi));
587
 
    pi.channel = SND_PCM_CHANNEL_PLAYBACK;
588
 
    if ((ret = snd_pcm_plugin_info (stream->pb_pcm, &pi)) < 0) {
589
 
        TRACE_((THIS_FILE, "snd_pcm_plugin_info ret = %d", ret));
590
 
        return PJMEDIA_EAUD_SYSERR;
591
 
    }
592
 
 
593
 
    memset (&pp, 0, sizeof (pp));
594
 
 
595
 
    /* Request VoIP compatible capabilities
596
 
     * On simulator frag_size is always negotiated to 170
597
 
     */
598
 
    pp.mode = SND_PCM_MODE_BLOCK;
599
 
    pp.channel = SND_PCM_CHANNEL_PLAYBACK;
600
 
    pp.start_mode = SND_PCM_START_DATA;
601
 
    pp.stop_mode = SND_PCM_STOP_ROLLOVER;
602
 
    /* HARD CODE for the time being PJMEDIA expects 640 for 16khz */
603
 
    pp.buf.block.frag_size = PREFERRED_FRAME_SIZE*2;
604
 
    /* Increasing this internal buffer count delays write failure in the loop */
605
 
    pp.buf.block.frags_max = 4;
606
 
    pp.buf.block.frags_min = 1;
607
 
    pp.format.interleave = 1;
608
 
    /* HARD CODE for the time being PJMEDIA expects 16khz */
609
 
    PJ_TODO(REMOVE_SAMPLE_RATE_HARD_CODE);
610
 
    pj_assert(param->clock_rate == VOIP_SAMPLE_RATE * 2);
611
 
    pp.format.rate = VOIP_SAMPLE_RATE*2;
612
 
    pp.format.voices = 1;
613
 
    pp.format.format = SND_PCM_SFMT_S16_LE;
614
 
 
615
 
    /* Make the calls as per the wave sample */
616
 
    if ((ret = snd_pcm_plugin_params (stream->pb_pcm, &pp)) < 0) {
617
 
        TRACE_((THIS_FILE, "snd_pcm_plugin_params ret = %d", ret));
618
 
        return PJMEDIA_EAUD_SYSERR;
619
 
    }
620
 
 
621
 
    memset (&setup, 0, sizeof (setup));
622
 
    memset (&group, 0, sizeof (group));
623
 
    setup.channel = SND_PCM_CHANNEL_PLAYBACK;
624
 
    setup.mixer_gid = &group.gid;
625
 
 
626
 
    if ((ret = snd_pcm_plugin_setup (stream->pb_pcm, &setup)) < 0) {
627
 
        TRACE_((THIS_FILE, "snd_pcm_plugin_setup ret = %d", ret));
628
 
        return PJMEDIA_EAUD_SYSERR;
629
 
    }
630
 
 
631
 
    if (group.gid.name[0] == 0) {
632
 
        return PJMEDIA_EAUD_SYSERR;
633
 
    }
634
 
 
635
 
    if ((ret = snd_mixer_open (&stream->pb_mixer, card,
636
 
                               setup.mixer_device)) < 0)
637
 
    {
638
 
        TRACE_((THIS_FILE, "snd_mixer_open ret = %d", ret));
639
 
        return PJMEDIA_EAUD_SYSERR;
640
 
    }
641
 
 
642
 
 
643
 
    rate = param->clock_rate;
644
 
    /* Set the sound device buffer size and latency */
645
 
    if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY) {
646
 
        tmp_buf_size = (rate / 1000) * param->output_latency_ms;
647
 
    } else {
648
 
        tmp_buf_size = (rate / 1000) * PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
649
 
    }
650
 
    /* Set period size to samples_per_frame frames. */
651
 
    stream->pb_frames = param->samples_per_frame;
652
 
    stream->param.output_latency_ms = tmp_buf_size / (rate / 1000);
653
 
 
654
 
    /* Set our buffer */
655
 
    stream->pb_buf_size = stream->pb_frames * param->channel_count *
656
 
                          (param->bits_per_sample/8);
657
 
    stream->pb_buf = (char *) pj_pool_alloc(stream->pool, stream->pb_buf_size);
658
 
 
659
 
    TRACE_((THIS_FILE, "bb10_open_playback: pb_frames = %d clock = %d",
660
 
                       stream->pb_frames, param->clock_rate));
661
 
 
662
 
    return PJ_SUCCESS;
663
 
}
664
 
 
665
 
static pj_status_t bb10_open_capture (struct bb10_stream *stream,
666
 
                                      const pjmedia_aud_param *param)
667
 
{
668
 
    int ret = 0;
669
 
    unsigned int rate;
670
 
    unsigned long tmp_buf_size;
671
 
    int card = -1;
672
 
    int dev = 0;
673
 
    int frame_size;
674
 
    snd_pcm_channel_info_t pi;
675
 
    snd_mixer_group_t group;
676
 
    snd_pcm_channel_params_t pp;
677
 
    snd_pcm_channel_setup_t setup;
678
 
 
679
 
    if (param->rec_id < 0 || param->rec_id >= stream->af->dev_cnt)
680
 
        return PJMEDIA_EAUD_INVDEV;
681
 
 
682
 
    /* BB10 Audio init here (not prepare) */
683
 
    if ((ret = snd_pcm_open_preferred (&stream->ca_pcm, &card, &dev,
684
 
                                       SND_PCM_OPEN_CAPTURE)) < 0)
685
 
    {
686
 
        TRACE_((THIS_FILE, "snd_pcm_open_preferred ret = %d", ret));
687
 
        return PJMEDIA_EAUD_SYSERR;
688
 
    }
689
 
 
690
 
    /* sample reads the capabilities of the capture */
691
 
    memset (&pi, 0, sizeof (pi));
692
 
    pi.channel = SND_PCM_CHANNEL_CAPTURE;
693
 
    if ((ret = snd_pcm_plugin_info (stream->ca_pcm, &pi)) < 0) {
694
 
        TRACE_((THIS_FILE, "snd_pcm_plugin_info ret = %d", ret));
695
 
        return PJMEDIA_EAUD_SYSERR;
696
 
    }
697
 
 
698
 
    /* Request the VoIP parameters
699
 
     * These parameters are different to waverec sample
700
 
     */
701
 
    memset (&pp, 0, sizeof (pp));
702
 
    /* Blocking read */
703
 
    pp.mode = SND_PCM_MODE_BLOCK;
704
 
    pp.channel = SND_PCM_CHANNEL_CAPTURE;
705
 
    pp.start_mode = SND_PCM_START_DATA;
706
 
    /* Auto-recover from errors */
707
 
    pp.stop_mode = SND_PCM_STOP_ROLLOVER;
708
 
    /* HARD CODE for the time being PJMEDIA expects 640 for 16khz */
709
 
    pp.buf.block.frag_size = PREFERRED_FRAME_SIZE*2;
710
 
    /* Not applicable for capture hence -1 */
711
 
    pp.buf.block.frags_max = -1;
712
 
    pp.buf.block.frags_min = 1;
713
 
    pp.format.interleave = 1;
714
 
    /* HARD CODE for the time being PJMEDIA expects 16khz */
715
 
    PJ_TODO(REMOVE_SAMPLE_RATE_HARD_CODE);
716
 
    pj_assert(param->clock_rate == VOIP_SAMPLE_RATE * 2);
717
 
    pp.format.rate = VOIP_SAMPLE_RATE*2;
718
 
    pp.format.voices = 1;
719
 
    pp.format.format = SND_PCM_SFMT_S16_LE;
720
 
 
721
 
    /* make the request */
722
 
    if ((ret = snd_pcm_plugin_params (stream->ca_pcm, &pp)) < 0) {
723
 
        TRACE_((THIS_FILE, "snd_pcm_plugin_params ret = %d", ret));
724
 
        return PJMEDIA_EAUD_SYSERR;
725
 
    }
726
 
 
727
 
    /* Again based on the sample */
728
 
    memset (&setup, 0, sizeof (setup));
729
 
    memset (&group, 0, sizeof (group));
730
 
    setup.channel = SND_PCM_CHANNEL_CAPTURE;
731
 
    setup.mixer_gid = &group.gid;
732
 
    if ((ret = snd_pcm_plugin_setup (stream->ca_pcm, &setup)) < 0) {
733
 
        TRACE_((THIS_FILE, "snd_pcm_plugin_setup ret = %d", ret));
734
 
        return PJMEDIA_EAUD_SYSERR;
735
 
    }
736
 
 
737
 
    frame_size = setup.buf.block.frag_size;
738
 
 
739
 
    if (group.gid.name[0] == 0) {
740
 
    } else {
741
 
    }
742
 
 
743
 
    if ((ret = snd_mixer_open (&stream->ca_mixer, card,
744
 
                               setup.mixer_device)) < 0)
745
 
    {
746
 
        TRACE_((THIS_FILE,"snd_mixer_open ret = %d",ret));
747
 
        return PJMEDIA_EAUD_SYSERR;
748
 
    }
749
 
 
750
 
    /* frag_size should be 160 */
751
 
    frame_size = setup.buf.block.frag_size;
752
 
 
753
 
    /* END BB10 init */
754
 
 
755
 
    /* Set clock rate */
756
 
    rate = param->clock_rate;
757
 
    stream->ca_frames = (unsigned long) param->samples_per_frame /
758
 
                        param->channel_count;
759
 
 
760
 
    /* Set the sound device buffer size and latency */
761
 
    if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY) {
762
 
        tmp_buf_size = (rate / 1000) * param->input_latency_ms;
763
 
    } else {
764
 
        tmp_buf_size = (rate / 1000) * PJMEDIA_SND_DEFAULT_REC_LATENCY;
765
 
    }
766
 
 
767
 
    stream->param.input_latency_ms = tmp_buf_size / (rate / 1000);
768
 
 
769
 
    /* Set our buffer */
770
 
    stream->ca_buf_size = stream->ca_frames * param->channel_count *
771
 
                          (param->bits_per_sample/8);
772
 
    stream->ca_buf = (char *)pj_pool_alloc (stream->pool, stream->ca_buf_size);
773
 
 
774
 
    TRACE_((THIS_FILE, "bb10_open_capture: ca_frames = %d clock = %d",
775
 
                       stream->ca_frames, param->clock_rate));
776
 
 
777
 
    return PJ_SUCCESS;
778
 
}
779
 
 
780
 
 
781
 
/* API: create stream */
782
 
static pj_status_t bb10_factory_create_stream(pjmedia_aud_dev_factory *f,
783
 
                                              const pjmedia_aud_param *param,
784
 
                                              pjmedia_aud_rec_cb rec_cb,
785
 
                                              pjmedia_aud_play_cb play_cb,
786
 
                                              void *user_data,
787
 
                                              pjmedia_aud_stream **p_strm)
788
 
{
789
 
    struct bb10_factory *af = (struct bb10_factory*)f;
790
 
    pj_status_t status;
791
 
    pj_pool_t* pool;
792
 
    struct bb10_stream* stream;
793
 
 
794
 
    pool = pj_pool_create (af->pf, "bb10%p", 1024, 1024, NULL);
795
 
    if (!pool)
796
 
        return PJ_ENOMEM;
797
 
 
798
 
    /* Allocate and initialize comon stream data */
799
 
    stream = PJ_POOL_ZALLOC_T (pool, struct bb10_stream);
800
 
    stream->base.op   = &bb10_stream_op;
801
 
    stream->pool      = pool;
802
 
    stream->af        = af;
803
 
    stream->user_data = user_data;
804
 
    stream->pb_cb     = play_cb;
805
 
    stream->ca_cb     = rec_cb;
806
 
    stream->quit      = 0;
807
 
    pj_memcpy(&stream->param, param, sizeof(*param));
808
 
 
809
 
    /* Init playback */
810
 
    if (param->dir & PJMEDIA_DIR_PLAYBACK) {
811
 
        status = bb10_open_playback (stream, param);
812
 
        if (status != PJ_SUCCESS) {
813
 
            pj_pool_release (pool);
814
 
            return status;
815
 
        }
816
 
    }
817
 
 
818
 
    /* Init capture */
819
 
    if (param->dir & PJMEDIA_DIR_CAPTURE) {
820
 
        status = bb10_open_capture (stream, param);
821
 
        if (status != PJ_SUCCESS) {
822
 
            if (param->dir & PJMEDIA_DIR_PLAYBACK) {
823
 
                close_play_mixer(stream);
824
 
                close_play_pcm(stream);
825
 
            }
826
 
            pj_pool_release (pool);
827
 
            return status;
828
 
        }
829
 
    }
830
 
 
831
 
    *p_strm = &stream->base;
832
 
    return PJ_SUCCESS;
833
 
}
834
 
 
835
 
 
836
 
/* API: get running parameter */
837
 
static pj_status_t bb10_stream_get_param(pjmedia_aud_stream *s,
838
 
                                         pjmedia_aud_param *pi)
839
 
{
840
 
    struct bb10_stream *stream = (struct bb10_stream*)s;
841
 
 
842
 
    PJ_ASSERT_RETURN(s && pi, PJ_EINVAL);
843
 
 
844
 
    pj_memcpy(pi, &stream->param, sizeof(*pi));
845
 
 
846
 
    return PJ_SUCCESS;
847
 
}
848
 
 
849
 
 
850
 
/* API: get capability */
851
 
static pj_status_t bb10_stream_get_cap(pjmedia_aud_stream *s,
852
 
                                       pjmedia_aud_dev_cap cap,
853
 
                                       void *pval)
854
 
{
855
 
    struct bb10_stream *stream = (struct bb10_stream*)s;
856
 
 
857
 
    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
858
 
 
859
 
    if (cap==PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY &&
860
 
        (stream->param.dir & PJMEDIA_DIR_CAPTURE))
861
 
    {
862
 
        /* Recording latency */
863
 
        *(unsigned*)pval = stream->param.input_latency_ms;
864
 
        return PJ_SUCCESS;
865
 
    } else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY &&
866
 
               (stream->param.dir & PJMEDIA_DIR_PLAYBACK))
867
 
    {
868
 
        /* Playback latency */
869
 
        *(unsigned*)pval = stream->param.output_latency_ms;
870
 
        return PJ_SUCCESS;
871
 
    } else {
872
 
        return PJMEDIA_EAUD_INVCAP;
873
 
    }
874
 
}
875
 
 
876
 
 
877
 
/* API: set capability */
878
 
static pj_status_t bb10_stream_set_cap(pjmedia_aud_stream *strm,
879
 
                                       pjmedia_aud_dev_cap cap,
880
 
                                       const void *value)
881
 
{
882
 
    PJ_UNUSED_ARG(strm);
883
 
    PJ_UNUSED_ARG(cap);
884
 
    PJ_UNUSED_ARG(value);
885
 
 
886
 
    return PJMEDIA_EAUD_INVCAP;
887
 
}
888
 
 
889
 
 
890
 
/* API: start stream */
891
 
static pj_status_t bb10_stream_start (pjmedia_aud_stream *s)
892
 
{
893
 
    struct bb10_stream *stream = (struct bb10_stream*)s;
894
 
    pj_status_t status = PJ_SUCCESS;
895
 
 
896
 
    stream->quit = 0;
897
 
    if (stream->param.dir & PJMEDIA_DIR_PLAYBACK) {
898
 
        status = pj_thread_create (stream->pool,
899
 
                                   "bb10sound_playback",
900
 
                                   pb_thread_func,
901
 
                                   stream,
902
 
                                   0,
903
 
                                   0,
904
 
                                   &stream->pb_thread);
905
 
        if (status != PJ_SUCCESS)
906
 
            return status;
907
 
    }
908
 
 
909
 
    if (stream->param.dir & PJMEDIA_DIR_CAPTURE) {
910
 
        status = pj_thread_create (stream->pool,
911
 
                                   "bb10sound_playback",
912
 
                                   ca_thread_func,
913
 
                                   stream,
914
 
                                   0,
915
 
                                   0,
916
 
                                   &stream->ca_thread);
917
 
        if (status != PJ_SUCCESS) {
918
 
            stream->quit = PJ_TRUE;
919
 
            pj_thread_join(stream->pb_thread);
920
 
            pj_thread_destroy(stream->pb_thread);
921
 
            stream->pb_thread = NULL;
922
 
        }
923
 
    }
924
 
 
925
 
    return status;
926
 
}
927
 
 
928
 
 
929
 
/* API: stop stream */
930
 
static pj_status_t bb10_stream_stop (pjmedia_aud_stream *s)
931
 
{
932
 
    struct bb10_stream *stream = (struct bb10_stream*)s;
933
 
 
934
 
    stream->quit = 1;
935
 
    TRACE_((THIS_FILE,"bb10_stream_stop()"));
936
 
 
937
 
    if (stream->pb_thread) {
938
 
        pj_thread_join (stream->pb_thread);
939
 
        pj_thread_destroy(stream->pb_thread);
940
 
        stream->pb_thread = NULL;
941
 
    }
942
 
 
943
 
    if (stream->ca_thread) {
944
 
        pj_thread_join (stream->ca_thread);
945
 
        pj_thread_destroy(stream->ca_thread);
946
 
        stream->ca_thread = NULL;
947
 
    }
948
 
 
949
 
    return PJ_SUCCESS;
950
 
}
951
 
 
952
 
static pj_status_t bb10_stream_destroy (pjmedia_aud_stream *s)
953
 
{
954
 
    struct bb10_stream *stream = (struct bb10_stream*)s;
955
 
 
956
 
    TRACE_((THIS_FILE,"bb10_stream_destroy()"));
957
 
 
958
 
    bb10_stream_stop (s);
959
 
 
960
 
    pj_pool_release (stream->pool);
961
 
 
962
 
    return PJ_SUCCESS;
963
 
}
964
 
 
965
 
#endif  /* PJMEDIA_AUDIO_DEV_HAS_BB10 */