1
/* $Id: sound_port.c 4079 2012-04-24 10:26:07Z ming $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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.
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.
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
20
#include <pjmedia/sound_port.h>
21
#include <pjmedia/alaw_ulaw.h>
22
#include <pjmedia/delaybuf.h>
23
#include <pjmedia/echo.h>
24
#include <pjmedia/errno.h>
25
#include <pj/assert.h>
28
#include <pj/string.h> /* pj_memset() */
30
#define AEC_TAIL 128 /* default AEC length in ms */
31
#define AEC_SUSPEND_LIMIT 5 /* seconds of no activity */
33
#define THIS_FILE "sound_port.c"
35
//#define TEST_OVERFLOW_UNDERFLOW
37
struct pjmedia_snd_port
42
pjmedia_aud_param aud_param;
43
pjmedia_aud_stream *aud_stream;
48
unsigned channel_count;
49
unsigned samples_per_frame;
50
unsigned bits_per_sample;
52
unsigned prm_ec_options;
55
pjmedia_echo_state *ec_state;
58
pj_bool_t ec_suspended;
59
unsigned ec_suspend_count;
60
unsigned ec_suspend_limit;
64
* The callback called by sound player when it needs more samples to be
67
static pj_status_t play_cb(void *user_data, pjmedia_frame *frame)
69
pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
71
const unsigned required_size = frame->size;
74
port = snd_port->port;
78
status = pjmedia_port_get_frame(port, frame);
79
if (status != PJ_SUCCESS)
82
if (frame->type != PJMEDIA_FRAME_TYPE_AUDIO)
85
/* Must supply the required samples */
86
pj_assert(frame->size == required_size);
88
if (snd_port->ec_state) {
89
if (snd_port->ec_suspended) {
90
snd_port->ec_suspended = PJ_FALSE;
91
//pjmedia_echo_state_reset(snd_port->ec_state);
92
PJ_LOG(4,(THIS_FILE, "EC activated"));
94
snd_port->ec_suspend_count = 0;
95
pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf);
102
frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
103
frame->size = required_size;
104
pj_bzero(frame->buf, frame->size);
106
if (snd_port->ec_state && !snd_port->ec_suspended) {
107
++snd_port->ec_suspend_count;
108
if (snd_port->ec_suspend_count > snd_port->ec_suspend_limit) {
109
snd_port->ec_suspended = PJ_TRUE;
110
PJ_LOG(4,(THIS_FILE, "EC suspended because of inactivity"));
112
if (snd_port->ec_state) {
113
/* To maintain correct delay in EC */
114
pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf);
123
* The callback called by sound recorder when it has finished capturing a
126
static pj_status_t rec_cb(void *user_data, pjmedia_frame *frame)
128
pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
131
port = snd_port->port;
136
if (snd_port->ec_state && !snd_port->ec_suspended) {
137
pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) frame->buf, 0);
140
pjmedia_port_put_frame(port, frame);
146
* The callback called by sound player when it needs more samples to be
147
* played. This version is for non-PCM data.
149
static pj_status_t play_cb_ext(void *user_data, pjmedia_frame *frame)
151
pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
152
pjmedia_port *port = snd_port->port;
155
frame->type = PJMEDIA_FRAME_TYPE_NONE;
159
pjmedia_port_get_frame(port, frame);
166
* The callback called by sound recorder when it has finished capturing a
167
* frame. This version is for non-PCM data.
169
static pj_status_t rec_cb_ext(void *user_data, pjmedia_frame *frame)
171
pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
174
port = snd_port->port;
178
pjmedia_port_put_frame(port, frame);
183
/* Initialize with default values (zero) */
184
PJ_DEF(void) pjmedia_snd_port_param_default(pjmedia_snd_port_param *prm)
186
pj_bzero(prm, sizeof(*prm));
190
* Start the sound stream.
191
* This may be called even when the sound stream has already been started.
193
static pj_status_t start_sound_device( pj_pool_t *pool,
194
pjmedia_snd_port *snd_port )
196
pjmedia_aud_rec_cb snd_rec_cb;
197
pjmedia_aud_play_cb snd_play_cb;
198
pjmedia_aud_param param_copy;
201
/* Check if sound has been started. */
202
if (snd_port->aud_stream != NULL)
205
PJ_ASSERT_RETURN(snd_port->dir == PJMEDIA_DIR_CAPTURE ||
206
snd_port->dir == PJMEDIA_DIR_PLAYBACK ||
207
snd_port->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK,
210
/* Get device caps */
211
if (snd_port->aud_param.dir & PJMEDIA_DIR_CAPTURE) {
212
pjmedia_aud_dev_info dev_info;
214
status = pjmedia_aud_dev_get_info(snd_port->aud_param.rec_id,
216
if (status != PJ_SUCCESS)
219
snd_port->aud_caps = dev_info.caps;
221
snd_port->aud_caps = 0;
224
/* Process EC settings */
225
pj_memcpy(¶m_copy, &snd_port->aud_param, sizeof(param_copy));
226
if (param_copy.flags & PJMEDIA_AUD_DEV_CAP_EC) {
228
if ((snd_port->prm_ec_options & PJMEDIA_ECHO_USE_SW_ECHO) == 0 &&
229
snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)
231
/* Device supports EC */
234
/* Application wants to use software EC or device
235
* doesn't support EC, remove EC settings from
238
param_copy.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC |
239
PJMEDIA_AUD_DEV_CAP_EC_TAIL);
243
/* Use different callback if format is not PCM */
244
if (snd_port->aud_param.ext_fmt.id == PJMEDIA_FORMAT_L16) {
245
snd_rec_cb = &rec_cb;
246
snd_play_cb = &play_cb;
248
snd_rec_cb = &rec_cb_ext;
249
snd_play_cb = &play_cb_ext;
252
/* Open the device */
253
status = pjmedia_aud_stream_create(¶m_copy,
257
&snd_port->aud_stream);
259
if (status != PJ_SUCCESS)
262
/* Inactivity limit before EC is suspended. */
263
snd_port->ec_suspend_limit = AEC_SUSPEND_LIMIT *
264
(snd_port->clock_rate /
265
snd_port->samples_per_frame);
267
/* Create software EC if parameter specifies EC and
268
* (app specifically requests software EC or device
269
* doesn't support EC). Only do this if the format is PCM!
271
if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC) &&
272
((snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)==0 ||
273
(snd_port->prm_ec_options & PJMEDIA_ECHO_USE_SW_ECHO) != 0) &&
274
param_copy.ext_fmt.id == PJMEDIA_FORMAT_PCM)
276
if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) {
277
snd_port->aud_param.flags |= PJMEDIA_AUD_DEV_CAP_EC_TAIL;
278
snd_port->aud_param.ec_tail_ms = AEC_TAIL;
279
PJ_LOG(4,(THIS_FILE, "AEC tail is set to default %u ms",
280
snd_port->aud_param.ec_tail_ms));
283
status = pjmedia_snd_port_set_ec(snd_port, pool,
284
snd_port->aud_param.ec_tail_ms,
285
snd_port->prm_ec_options);
286
if (status != PJ_SUCCESS) {
287
pjmedia_aud_stream_destroy(snd_port->aud_stream);
288
snd_port->aud_stream = NULL;
293
/* Start sound stream. */
294
if (!(snd_port->options & PJMEDIA_SND_PORT_NO_AUTO_START)) {
295
status = pjmedia_aud_stream_start(snd_port->aud_stream);
297
if (status != PJ_SUCCESS) {
298
pjmedia_aud_stream_destroy(snd_port->aud_stream);
299
snd_port->aud_stream = NULL;
308
* Stop the sound device.
309
* This may be called even when there's no sound device in the port.
311
static pj_status_t stop_sound_device( pjmedia_snd_port *snd_port )
313
/* Check if we have sound stream device. */
314
if (snd_port->aud_stream) {
315
pjmedia_aud_stream_stop(snd_port->aud_stream);
316
pjmedia_aud_stream_destroy(snd_port->aud_stream);
317
snd_port->aud_stream = NULL;
321
if (snd_port->ec_state) {
322
pjmedia_echo_destroy(snd_port->ec_state);
323
snd_port->ec_state = NULL;
331
* Create bidirectional port.
333
PJ_DEF(pj_status_t) pjmedia_snd_port_create( pj_pool_t *pool,
337
unsigned channel_count,
338
unsigned samples_per_frame,
339
unsigned bits_per_sample,
341
pjmedia_snd_port **p_port)
343
pjmedia_snd_port_param param;
346
pjmedia_snd_port_param_default(¶m);
348
status = pjmedia_aud_dev_default_param(rec_id, ¶m.base);
349
if (status != PJ_SUCCESS)
352
param.base.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
353
param.base.rec_id = rec_id;
354
param.base.play_id = play_id;
355
param.base.clock_rate = clock_rate;
356
param.base.channel_count = channel_count;
357
param.base.samples_per_frame = samples_per_frame;
358
param.base.bits_per_sample = bits_per_sample;
359
param.options = options;
360
param.ec_options = 0;
362
return pjmedia_snd_port_create2(pool, ¶m, p_port);
366
* Create sound recorder AEC.
368
PJ_DEF(pj_status_t) pjmedia_snd_port_create_rec( pj_pool_t *pool,
371
unsigned channel_count,
372
unsigned samples_per_frame,
373
unsigned bits_per_sample,
375
pjmedia_snd_port **p_port)
377
pjmedia_snd_port_param param;
380
pjmedia_snd_port_param_default(¶m);
382
status = pjmedia_aud_dev_default_param(dev_id, ¶m.base);
383
if (status != PJ_SUCCESS)
386
param.base.dir = PJMEDIA_DIR_CAPTURE;
387
param.base.rec_id = dev_id;
388
param.base.clock_rate = clock_rate;
389
param.base.channel_count = channel_count;
390
param.base.samples_per_frame = samples_per_frame;
391
param.base.bits_per_sample = bits_per_sample;
392
param.options = options;
393
param.ec_options = 0;
395
return pjmedia_snd_port_create2(pool, ¶m, p_port);
400
* Create sound player port.
402
PJ_DEF(pj_status_t) pjmedia_snd_port_create_player( pj_pool_t *pool,
405
unsigned channel_count,
406
unsigned samples_per_frame,
407
unsigned bits_per_sample,
409
pjmedia_snd_port **p_port)
411
pjmedia_snd_port_param param;
414
pjmedia_snd_port_param_default(¶m);
416
status = pjmedia_aud_dev_default_param(dev_id, ¶m.base);
417
if (status != PJ_SUCCESS)
420
param.base.dir = PJMEDIA_DIR_PLAYBACK;
421
param.base.play_id = dev_id;
422
param.base.clock_rate = clock_rate;
423
param.base.channel_count = channel_count;
424
param.base.samples_per_frame = samples_per_frame;
425
param.base.bits_per_sample = bits_per_sample;
426
param.options = options;
427
param.ec_options = 0;
429
return pjmedia_snd_port_create2(pool, ¶m, p_port);
436
PJ_DEF(pj_status_t) pjmedia_snd_port_create2(pj_pool_t *pool,
437
const pjmedia_snd_port_param *prm,
438
pjmedia_snd_port **p_port)
440
pjmedia_snd_port *snd_port;
443
PJ_ASSERT_RETURN(pool && prm && p_port, PJ_EINVAL);
445
snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port);
446
PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM);
448
snd_port->dir = prm->base.dir;
449
snd_port->rec_id = prm->base.rec_id;
450
snd_port->play_id = prm->base.play_id;
451
snd_port->clock_rate = prm->base.clock_rate;
452
snd_port->channel_count = prm->base.channel_count;
453
snd_port->samples_per_frame = prm->base.samples_per_frame;
454
snd_port->bits_per_sample = prm->base.bits_per_sample;
455
pj_memcpy(&snd_port->aud_param, &prm->base, sizeof(snd_port->aud_param));
456
snd_port->options = prm->options;
457
snd_port->prm_ec_options = prm->ec_options;
459
/* Start sound device immediately.
460
* If there's no port connected, the sound callback will return
463
status = start_sound_device( pool, snd_port );
464
if (status != PJ_SUCCESS) {
465
pjmedia_snd_port_destroy(snd_port);
475
* Destroy port (also destroys the sound device).
477
PJ_DEF(pj_status_t) pjmedia_snd_port_destroy(pjmedia_snd_port *snd_port)
479
PJ_ASSERT_RETURN(snd_port, PJ_EINVAL);
481
return stop_sound_device(snd_port);
486
* Retrieve the sound stream associated by this sound device port.
488
PJ_DEF(pjmedia_aud_stream*) pjmedia_snd_port_get_snd_stream(
489
pjmedia_snd_port *snd_port)
491
PJ_ASSERT_RETURN(snd_port, NULL);
492
return snd_port->aud_stream;
497
* Change EC settings.
499
PJ_DEF(pj_status_t) pjmedia_snd_port_set_ec( pjmedia_snd_port *snd_port,
504
pjmedia_aud_param prm;
507
/* Sound must be opened in full-duplex mode */
508
PJ_ASSERT_RETURN(snd_port &&
509
snd_port->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK,
512
/* Determine whether we use device or software EC */
513
if ((snd_port->prm_ec_options & PJMEDIA_ECHO_USE_SW_ECHO) == 0 &&
514
snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)
516
/* We use device EC */
517
pj_bool_t ec_enabled;
519
/* Query EC status */
520
status = pjmedia_aud_stream_get_cap(snd_port->aud_stream,
521
PJMEDIA_AUD_DEV_CAP_EC,
523
if (status != PJ_SUCCESS)
527
/* Change EC setting */
530
/* Enable EC first */
531
pj_bool_t value = PJ_TRUE;
532
status = pjmedia_aud_stream_set_cap(snd_port->aud_stream,
533
PJMEDIA_AUD_DEV_CAP_EC,
535
if (status != PJ_SUCCESS)
539
if ((snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) {
540
/* Device does not support setting EC tail */
541
return PJMEDIA_EAUD_INVCAP;
544
return pjmedia_aud_stream_set_cap(snd_port->aud_stream,
545
PJMEDIA_AUD_DEV_CAP_EC_TAIL,
548
} else if (ec_enabled) {
550
pj_bool_t value = PJ_FALSE;
551
return pjmedia_aud_stream_set_cap(snd_port->aud_stream,
552
PJMEDIA_AUD_DEV_CAP_EC,
555
/* Request to disable EC but EC has been disabled */
561
/* We use software EC */
563
/* Check if there is change in parameters */
564
if (tail_ms==snd_port->ec_tail_len && options==snd_port->ec_options) {
565
PJ_LOG(5,(THIS_FILE, "pjmedia_snd_port_set_ec() ignored, no "
566
"change in settings"));
570
status = pjmedia_aud_stream_get_param(snd_port->aud_stream, &prm);
571
if (status != PJ_SUCCESS)
574
/* Audio stream must be in PCM format */
575
PJ_ASSERT_RETURN(prm.ext_fmt.id == PJMEDIA_FORMAT_PCM,
579
if (snd_port->ec_state) {
580
pjmedia_echo_destroy(snd_port->ec_state);
581
snd_port->ec_state = NULL;
587
//No need to add input latency in the latency calculation,
588
//since actual input latency should be zero.
589
//delay_ms = (si.rec_latency + si.play_latency) * 1000 /
590
// snd_port->clock_rate;
591
/* Set EC latency to 3/4 of output latency to reduce the
592
* possibility of missing/late reference frame.
594
delay_ms = prm.output_latency_ms * 3/4;
595
status = pjmedia_echo_create2(pool, snd_port->clock_rate,
596
snd_port->channel_count,
597
snd_port->samples_per_frame,
599
options, &snd_port->ec_state);
600
if (status != PJ_SUCCESS)
601
snd_port->ec_state = NULL;
603
snd_port->ec_suspended = PJ_FALSE;
605
PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the "
610
snd_port->ec_options = options;
611
snd_port->ec_tail_len = tail_ms;
618
/* Get AEC tail length */
619
PJ_DEF(pj_status_t) pjmedia_snd_port_get_ec_tail( pjmedia_snd_port *snd_port,
622
PJ_ASSERT_RETURN(snd_port && p_length, PJ_EINVAL);
624
/* Determine whether we use device or software EC */
625
if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) {
626
/* We use device EC */
627
pj_bool_t ec_enabled;
630
/* Query EC status */
631
status = pjmedia_aud_stream_get_cap(snd_port->aud_stream,
632
PJMEDIA_AUD_DEV_CAP_EC,
634
if (status != PJ_SUCCESS)
639
} else if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC_TAIL) {
640
/* Get device EC tail */
641
status = pjmedia_aud_stream_get_cap(snd_port->aud_stream,
642
PJMEDIA_AUD_DEV_CAP_EC_TAIL,
644
if (status != PJ_SUCCESS)
647
/* Just use default */
648
*p_length = AEC_TAIL;
652
/* We use software EC */
653
*p_length = snd_port->ec_state ? snd_port->ec_tail_len : 0;
662
PJ_DEF(pj_status_t) pjmedia_snd_port_connect( pjmedia_snd_port *snd_port,
665
pjmedia_port_info *pinfo;
667
PJ_ASSERT_RETURN(snd_port && port, PJ_EINVAL);
669
/* Check that port has the same configuration as the sound device
673
if (pinfo->clock_rate != snd_port->clock_rate)
674
return PJMEDIA_ENCCLOCKRATE;
676
if (pinfo->samples_per_frame != snd_port->samples_per_frame)
677
return PJMEDIA_ENCSAMPLESPFRAME;
679
if (pinfo->channel_count != snd_port->channel_count)
680
return PJMEDIA_ENCCHANNEL;
682
if (pinfo->bits_per_sample != snd_port->bits_per_sample)
683
return PJMEDIA_ENCBITS;
686
snd_port->port = port;
692
* Get the connected port.
694
PJ_DEF(pjmedia_port*) pjmedia_snd_port_get_port(pjmedia_snd_port *snd_port)
696
PJ_ASSERT_RETURN(snd_port, NULL);
697
return snd_port->port;
704
PJ_DEF(pj_status_t) pjmedia_snd_port_disconnect(pjmedia_snd_port *snd_port)
706
PJ_ASSERT_RETURN(snd_port, PJ_EINVAL);
708
snd_port->port = NULL;