blob: 2ef65380e534601c1a929cbcc1d986960244a16f [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $Id$ */
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/conference.h>
21#include <pjmedia/alaw_ulaw.h>
22#include <pjmedia/delaybuf.h>
23#include <pjmedia/errno.h>
24#include <pjmedia/port.h>
25#include <pjmedia/resample.h>
26#include <pjmedia/silencedet.h>
27#include <pjmedia/sound_port.h>
28#include <pjmedia/stereo.h>
29#include <pj/array.h>
30#include <pj/assert.h>
31#include <pj/log.h>
32#include <pj/pool.h>
33#include <pj/string.h>
34
35#if !defined(PJMEDIA_CONF_USE_SWITCH_BOARD) || PJMEDIA_CONF_USE_SWITCH_BOARD==0
36
37/* CONF_DEBUG enables detailed operation of the conference bridge.
38 * Beware that it prints large amounts of logs (several lines per frame).
39 */
40//#define CONF_DEBUG
41#ifdef CONF_DEBUG
42# include <stdio.h>
43# define TRACE_(x) PJ_LOG(5,x)
44#else
45# define TRACE_(x)
46#endif
47
48
49/* REC_FILE macro enables recording of the samples written to the sound
50 * device. The file contains RAW PCM data with no header, and has the
51 * same settings (clock rate etc) as the conference bridge.
52 * This should only be enabled when debugging audio quality *only*.
53 */
54//#define REC_FILE "confrec.pcm"
55#ifdef REC_FILE
56static FILE *fhnd_rec;
57#endif
58
59
60#define THIS_FILE "conference.c"
61
62#define RX_BUF_COUNT PJMEDIA_SOUND_BUFFER_COUNT
63
64#define BYTES_PER_SAMPLE 2
65
66#define SIGNATURE PJMEDIA_CONF_BRIDGE_SIGNATURE
67#define SIGNATURE_PORT PJMEDIA_SIG_PORT_CONF_PASV
68/* Normal level is hardcodec to 128 in all over places */
69#define NORMAL_LEVEL 128
70#define SLOT_TYPE unsigned
71#define INVALID_SLOT ((SLOT_TYPE)-1)
72
73
74/* These are settings to control the adaptivity of changes in the
75 * signal level of the ports, so that sudden change in signal level
76 * in the port does not cause misaligned signal (which causes noise).
77 */
78#define ATTACK_A (conf->clock_rate / conf->samples_per_frame)
79#define ATTACK_B 1
80#define DECAY_A 0
81#define DECAY_B 1
82
83#define SIMPLE_AGC(last, target) \
84 if (target >= last) \
85 target = (ATTACK_A*(last+1)+ATTACK_B*target)/(ATTACK_A+ATTACK_B); \
86 else \
87 target = (DECAY_A*last+DECAY_B*target)/(DECAY_A+DECAY_B)
88
89#define MAX_LEVEL (32767)
90#define MIN_LEVEL (-32768)
91
92#define IS_OVERFLOW(s) ((s > MAX_LEVEL) || (s < MIN_LEVEL))
93
94
95/*
96 * DON'T GET CONFUSED WITH TX/RX!!
97 *
98 * TX and RX directions are always viewed from the conference bridge's point
99 * of view, and NOT from the port's point of view. So TX means the bridge
100 * is transmitting to the port, RX means the bridge is receiving from the
101 * port.
102 */
103
104
105/**
106 * This is a port connected to conference bridge.
107 */
108struct conf_port
109{
110 pj_str_t name; /**< Port name. */
111 pjmedia_port *port; /**< get_frame() and put_frame() */
112 pjmedia_port_op rx_setting; /**< Can we receive from this port */
113 pjmedia_port_op tx_setting; /**< Can we transmit to this port */
114 unsigned listener_cnt; /**< Number of listeners. */
115 SLOT_TYPE *listener_slots;/**< Array of listeners. */
116 unsigned transmitter_cnt;/**<Number of transmitters. */
117
118 /* Shortcut for port info. */
119 unsigned clock_rate; /**< Port's clock rate. */
120 unsigned samples_per_frame; /**< Port's samples per frame. */
121 unsigned channel_count; /**< Port's channel count. */
122
123 /* Calculated signal levels: */
124 unsigned tx_level; /**< Last tx level to this port. */
125 unsigned rx_level; /**< Last rx level from this port. */
126
127 /* The normalized signal level adjustment.
128 * A value of 128 (NORMAL_LEVEL) means there's no adjustment.
129 */
130 unsigned tx_adj_level; /**< Adjustment for TX. */
131 unsigned rx_adj_level; /**< Adjustment for RX. */
132
133 /* Resample, for converting clock rate, if they're different. */
134 pjmedia_resample *rx_resample;
135 pjmedia_resample *tx_resample;
136
137 /* RX buffer is temporary buffer to be used when there is mismatch
138 * between port's sample rate or ptime with conference's sample rate
139 * or ptime. The buffer is used for sampling rate conversion AND/OR to
140 * buffer the samples until there are enough samples to fulfill a
141 * complete frame to be processed by the bridge.
142 *
143 * When both sample rate AND ptime of the port match the conference
144 * settings, this buffer will not be created.
145 *
146 * This buffer contains samples at port's clock rate.
147 * The size of this buffer is the sum between port's samples per frame
148 * and bridge's samples per frame.
149 */
150 pj_int16_t *rx_buf; /**< The RX buffer. */
151 unsigned rx_buf_cap; /**< Max size, in samples */
152 unsigned rx_buf_count; /**< # of samples in the buf. */
153
154 /* Mix buf is a temporary buffer used to mix all signal received
155 * by this port from all other ports. The mixed signal will be
156 * automatically adjusted to the appropriate level whenever
157 * there is possibility of clipping.
158 *
159 * This buffer contains samples at bridge's clock rate.
160 * The size of this buffer is equal to samples per frame of the bridge.
161 */
162
163 int mix_adj; /**< Adjustment level for mix_buf. */
164 int last_mix_adj; /**< Last adjustment level. */
165 pj_int32_t *mix_buf; /**< Total sum of signal. */
166
167 /* Tx buffer is a temporary buffer to be used when there's mismatch
168 * between port's clock rate or ptime with conference's sample rate
169 * or ptime. This buffer is used as the source of the sampling rate
170 * conversion AND/OR to buffer the samples until there are enough
171 * samples to fulfill a complete frame to be transmitted to the port.
172 *
173 * When both sample rate and ptime of the port match the bridge's
174 * settings, this buffer will not be created.
175 *
176 * This buffer contains samples at port's clock rate.
177 * The size of this buffer is the sum between port's samples per frame
178 * and bridge's samples per frame.
179 */
180 pj_int16_t *tx_buf; /**< Tx buffer. */
181 unsigned tx_buf_cap; /**< Max size, in samples. */
182 unsigned tx_buf_count; /**< # of samples in the buffer. */
183
184 /* When the port is not receiving signal from any other ports (e.g. when
185 * no other ports is transmitting to this port), the bridge periodically
186 * transmit NULL frame to the port to keep the port "alive" (for example,
187 * a stream port needs this heart-beat to periodically transmit silence
188 * frame to keep NAT binding alive).
189 *
190 * This NULL frame should be sent to the port at the port's ptime rate.
191 * So if the port's ptime is greater than the bridge's ptime, the bridge
192 * needs to delay the NULL frame until it's the right time to do so.
193 *
194 * This variable keeps track of how many pending NULL samples are being
195 * "held" for this port. Once this value reaches samples_per_frame
196 * value of the port, a NULL frame is sent. The samples value on this
197 * variable is clocked at the port's clock rate.
198 */
199 unsigned tx_heart_beat;
200
201 /* Delay buffer is a special buffer for sound device port (port 0, master
202 * port) and other passive ports (sound device port is also passive port).
203 *
204 * We need the delay buffer because we can not expect the mic and speaker
205 * thread to run equally after one another. In most systems, each thread
206 * will run multiple times before the other thread gains execution time.
207 * For example, in my system, mic thread is called three times, then
208 * speaker thread is called three times, and so on. This we call burst.
209 *
210 * There is also possibility of drift, unbalanced rate between put_frame
211 * and get_frame operation, in passive ports. If drift happens, snd_buf
212 * needs to be expanded or shrinked.
213 *
214 * Burst and drift are handled by delay buffer.
215 */
216 pjmedia_delay_buf *delay_buf;
217};
218
219
220/*
221 * Conference bridge.
222 */
223struct pjmedia_conf
224{
225 unsigned options; /**< Bitmask options. */
226 unsigned max_ports; /**< Maximum ports. */
227 unsigned port_cnt; /**< Current number of ports. */
228 unsigned connect_cnt; /**< Total number of connections */
229 pjmedia_snd_port *snd_dev_port; /**< Sound device port. */
230 pjmedia_port *master_port; /**< Port zero's port. */
231 char master_name_buf[80]; /**< Port0 name buffer. */
232 pj_mutex_t *mutex; /**< Conference mutex. */
233 struct conf_port **ports; /**< Array of ports. */
234 unsigned clock_rate; /**< Sampling rate. */
235 unsigned channel_count;/**< Number of channels (1=mono). */
236 unsigned samples_per_frame; /**< Samples per frame. */
237 unsigned bits_per_sample; /**< Bits per sample. */
238};
239
240
241/* Prototypes */
242static pj_status_t put_frame(pjmedia_port *this_port,
243 pjmedia_frame *frame);
244static pj_status_t get_frame(pjmedia_port *this_port,
245 pjmedia_frame *frame);
246static pj_status_t get_frame_pasv(pjmedia_port *this_port,
247 pjmedia_frame *frame);
248static pj_status_t destroy_port(pjmedia_port *this_port);
249static pj_status_t destroy_port_pasv(pjmedia_port *this_port);
250
251
252/*
253 * Create port.
254 */
255static pj_status_t create_conf_port( pj_pool_t *pool,
256 pjmedia_conf *conf,
257 pjmedia_port *port,
258 const pj_str_t *name,
259 struct conf_port **p_conf_port)
260{
261 struct conf_port *conf_port;
262 pj_status_t status;
263
264 /* Create port. */
265 conf_port = PJ_POOL_ZALLOC_T(pool, struct conf_port);
266 PJ_ASSERT_RETURN(conf_port, PJ_ENOMEM);
267
268 /* Set name */
269 pj_strdup_with_null(pool, &conf_port->name, name);
270
271 /* Default has tx and rx enabled. */
272 conf_port->rx_setting = PJMEDIA_PORT_ENABLE;
273 conf_port->tx_setting = PJMEDIA_PORT_ENABLE;
274
275 /* Default level adjustment is 128 (which means no adjustment) */
276 conf_port->tx_adj_level = NORMAL_LEVEL;
277 conf_port->rx_adj_level = NORMAL_LEVEL;
278
279 /* Create transmit flag array */
280 conf_port->listener_slots = (SLOT_TYPE*)
281 pj_pool_zalloc(pool,
282 conf->max_ports * sizeof(SLOT_TYPE));
283 PJ_ASSERT_RETURN(conf_port->listener_slots, PJ_ENOMEM);
284
285 /* Save some port's infos, for convenience. */
286 if (port) {
287 pjmedia_audio_format_detail *afd;
288
289 afd = pjmedia_format_get_audio_format_detail(&port->info.fmt, 1);
290 conf_port->port = port;
291 conf_port->clock_rate = afd->clock_rate;
292 conf_port->samples_per_frame = PJMEDIA_AFD_SPF(afd);
293 conf_port->channel_count = afd->channel_count;
294 } else {
295 conf_port->port = NULL;
296 conf_port->clock_rate = conf->clock_rate;
297 conf_port->samples_per_frame = conf->samples_per_frame;
298 conf_port->channel_count = conf->channel_count;
299 }
300
301 /* If port's clock rate is different than conference's clock rate,
302 * create a resample sessions.
303 */
304 if (conf_port->clock_rate != conf->clock_rate) {
305
306 pj_bool_t high_quality;
307 pj_bool_t large_filter;
308
309 high_quality = ((conf->options & PJMEDIA_CONF_USE_LINEAR)==0);
310 large_filter = ((conf->options & PJMEDIA_CONF_SMALL_FILTER)==0);
311
312 /* Create resample for rx buffer. */
313 status = pjmedia_resample_create( pool,
314 high_quality,
315 large_filter,
316 conf->channel_count,
317 conf_port->clock_rate,/* Rate in */
318 conf->clock_rate, /* Rate out */
319 conf->samples_per_frame *
320 conf_port->clock_rate /
321 conf->clock_rate,
322 &conf_port->rx_resample);
323 if (status != PJ_SUCCESS)
324 return status;
325
326
327 /* Create resample for tx buffer. */
328 status = pjmedia_resample_create(pool,
329 high_quality,
330 large_filter,
331 conf->channel_count,
332 conf->clock_rate, /* Rate in */
333 conf_port->clock_rate, /* Rate out */
334 conf->samples_per_frame,
335 &conf_port->tx_resample);
336 if (status != PJ_SUCCESS)
337 return status;
338 }
339
340 /*
341 * Initialize rx and tx buffer, only when port's samples per frame or
342 * port's clock rate or channel number is different then the conference
343 * bridge settings.
344 */
345 if (conf_port->clock_rate != conf->clock_rate ||
346 conf_port->channel_count != conf->channel_count ||
347 conf_port->samples_per_frame != conf->samples_per_frame)
348 {
349 unsigned port_ptime, conf_ptime, buff_ptime;
350
351 port_ptime = conf_port->samples_per_frame / conf_port->channel_count *
352 1000 / conf_port->clock_rate;
353 conf_ptime = conf->samples_per_frame / conf->channel_count *
354 1000 / conf->clock_rate;
355
356 /* Calculate the size (in ptime) for the port buffer according to
357 * this formula:
358 * - if either ptime is an exact multiple of the other, then use
359 * the larger ptime (e.g. 20ms and 40ms, use 40ms).
360 * - if not, then the ptime is sum of both ptimes (e.g. 20ms
361 * and 30ms, use 50ms)
362 */
363 if (port_ptime > conf_ptime) {
364 buff_ptime = port_ptime;
365 if (port_ptime % conf_ptime)
366 buff_ptime += conf_ptime;
367 } else {
368 buff_ptime = conf_ptime;
369 if (conf_ptime % port_ptime)
370 buff_ptime += port_ptime;
371 }
372
373 /* Create RX buffer. */
374 //conf_port->rx_buf_cap = (unsigned)(conf_port->samples_per_frame +
375 // conf->samples_per_frame *
376 // conf_port->clock_rate * 1.0 /
377 // conf->clock_rate + 0.5);
378 conf_port->rx_buf_cap = conf_port->clock_rate * buff_ptime / 1000;
379 if (conf_port->channel_count > conf->channel_count)
380 conf_port->rx_buf_cap *= conf_port->channel_count;
381 else
382 conf_port->rx_buf_cap *= conf->channel_count;
383
384 conf_port->rx_buf_count = 0;
385 conf_port->rx_buf = (pj_int16_t*)
386 pj_pool_alloc(pool, conf_port->rx_buf_cap *
387 sizeof(conf_port->rx_buf[0]));
388 PJ_ASSERT_RETURN(conf_port->rx_buf, PJ_ENOMEM);
389
390 /* Create TX buffer. */
391 conf_port->tx_buf_cap = conf_port->rx_buf_cap;
392 conf_port->tx_buf_count = 0;
393 conf_port->tx_buf = (pj_int16_t*)
394 pj_pool_alloc(pool, conf_port->tx_buf_cap *
395 sizeof(conf_port->tx_buf[0]));
396 PJ_ASSERT_RETURN(conf_port->tx_buf, PJ_ENOMEM);
397 }
398
399
400 /* Create mix buffer. */
401 conf_port->mix_buf = (pj_int32_t*)
402 pj_pool_zalloc(pool, conf->samples_per_frame *
403 sizeof(conf_port->mix_buf[0]));
404 PJ_ASSERT_RETURN(conf_port->mix_buf, PJ_ENOMEM);
405 conf_port->last_mix_adj = NORMAL_LEVEL;
406
407
408 /* Done */
409 *p_conf_port = conf_port;
410 return PJ_SUCCESS;
411}
412
413
414/*
415 * Add passive port.
416 */
417static pj_status_t create_pasv_port( pjmedia_conf *conf,
418 pj_pool_t *pool,
419 const pj_str_t *name,
420 pjmedia_port *port,
421 struct conf_port **p_conf_port)
422{
423 struct conf_port *conf_port;
424 pj_status_t status;
425 unsigned ptime;
426
427 /* Create port */
428 status = create_conf_port(pool, conf, port, name, &conf_port);
429 if (status != PJ_SUCCESS)
430 return status;
431
432 /* Passive port has delay buf. */
433 ptime = conf->samples_per_frame * 1000 / conf->clock_rate /
434 conf->channel_count;
435 status = pjmedia_delay_buf_create(pool, name->ptr,
436 conf->clock_rate,
437 conf->samples_per_frame,
438 conf->channel_count,
439 RX_BUF_COUNT * ptime, /* max delay */
440 0, /* options */
441 &conf_port->delay_buf);
442 if (status != PJ_SUCCESS)
443 return status;
444
445 *p_conf_port = conf_port;
446
447 return PJ_SUCCESS;
448}
449
450
451/*
452 * Create port zero for the sound device.
453 */
454static pj_status_t create_sound_port( pj_pool_t *pool,
455 pjmedia_conf *conf )
456{
457 struct conf_port *conf_port;
458 pj_str_t name = { "Master/sound", 12 };
459 pj_status_t status;
460
461
462 status = create_pasv_port(conf, pool, &name, NULL, &conf_port);
463 if (status != PJ_SUCCESS)
464 return status;
465
466
467 /* Create sound device port: */
468
469 if ((conf->options & PJMEDIA_CONF_NO_DEVICE) == 0) {
470 pjmedia_aud_stream *strm;
471 pjmedia_aud_param param;
472
473 /*
474 * If capture is disabled then create player only port.
475 * Otherwise create bidirectional sound device port.
476 */
477 if (conf->options & PJMEDIA_CONF_NO_MIC) {
478 status = pjmedia_snd_port_create_player(pool, -1, conf->clock_rate,
479 conf->channel_count,
480 conf->samples_per_frame,
481 conf->bits_per_sample,
482 0, /* options */
483 &conf->snd_dev_port);
484
485 } else {
486 status = pjmedia_snd_port_create( pool, -1, -1, conf->clock_rate,
487 conf->channel_count,
488 conf->samples_per_frame,
489 conf->bits_per_sample,
490 0, /* Options */
491 &conf->snd_dev_port);
492
493 }
494
495 if (status != PJ_SUCCESS)
496 return status;
497
498 strm = pjmedia_snd_port_get_snd_stream(conf->snd_dev_port);
499 status = pjmedia_aud_stream_get_param(strm, &param);
500 if (status == PJ_SUCCESS) {
501 pjmedia_aud_dev_info snd_dev_info;
502 if (conf->options & PJMEDIA_CONF_NO_MIC)
503 pjmedia_aud_dev_get_info(param.play_id, &snd_dev_info);
504 else
505 pjmedia_aud_dev_get_info(param.rec_id, &snd_dev_info);
506 pj_strdup2_with_null(pool, &conf_port->name, snd_dev_info.name);
507 }
508
509 PJ_LOG(5,(THIS_FILE, "Sound device successfully created for port 0"));
510 }
511
512
513 /* Add the port to the bridge */
514 conf->ports[0] = conf_port;
515 conf->port_cnt++;
516
517 return PJ_SUCCESS;
518}
519
520/*
521 * Create conference bridge.
522 */
523PJ_DEF(pj_status_t) pjmedia_conf_create( pj_pool_t *pool,
524 unsigned max_ports,
525 unsigned clock_rate,
526 unsigned channel_count,
527 unsigned samples_per_frame,
528 unsigned bits_per_sample,
529 unsigned options,
530 pjmedia_conf **p_conf )
531{
532 pjmedia_conf *conf;
533 const pj_str_t name = { "Conf", 4 };
534 pj_status_t status;
535
536 /* Can only accept 16bits per sample, for now.. */
537 PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);
538
539 PJ_LOG(5,(THIS_FILE, "Creating conference bridge with %d ports",
540 max_ports));
541
542 /* Create and init conf structure. */
543 conf = PJ_POOL_ZALLOC_T(pool, pjmedia_conf);
544 PJ_ASSERT_RETURN(conf, PJ_ENOMEM);
545
546 conf->ports = (struct conf_port**)
547 pj_pool_zalloc(pool, max_ports*sizeof(void*));
548 PJ_ASSERT_RETURN(conf->ports, PJ_ENOMEM);
549
550 conf->options = options;
551 conf->max_ports = max_ports;
552 conf->clock_rate = clock_rate;
553 conf->channel_count = channel_count;
554 conf->samples_per_frame = samples_per_frame;
555 conf->bits_per_sample = bits_per_sample;
556
557
558 /* Create and initialize the master port interface. */
559 conf->master_port = PJ_POOL_ZALLOC_T(pool, pjmedia_port);
560 PJ_ASSERT_RETURN(conf->master_port, PJ_ENOMEM);
561
562 pjmedia_port_info_init(&conf->master_port->info, &name, SIGNATURE,
563 clock_rate, channel_count, bits_per_sample,
564 samples_per_frame);
565
566 conf->master_port->port_data.pdata = conf;
567 conf->master_port->port_data.ldata = 0;
568
569 conf->master_port->get_frame = &get_frame;
570 conf->master_port->put_frame = &put_frame;
571 conf->master_port->on_destroy = &destroy_port;
572
573
574 /* Create port zero for sound device. */
575 status = create_sound_port(pool, conf);
576 if (status != PJ_SUCCESS) {
577 pjmedia_conf_destroy(conf);
578 return status;
579 }
580
581 /* Create mutex. */
582 status = pj_mutex_create_recursive(pool, "conf", &conf->mutex);
583 if (status != PJ_SUCCESS) {
584 pjmedia_conf_destroy(conf);
585 return status;
586 }
587
588 /* If sound device was created, connect sound device to the
589 * master port.
590 */
591 if (conf->snd_dev_port) {
592 status = pjmedia_snd_port_connect( conf->snd_dev_port,
593 conf->master_port );
594 if (status != PJ_SUCCESS) {
595 pjmedia_conf_destroy(conf);
596 return status;
597 }
598 }
599
600
601 /* Done */
602
603 *p_conf = conf;
604
605 return PJ_SUCCESS;
606}
607
608
609/*
610 * Pause sound device.
611 */
612static pj_status_t pause_sound( pjmedia_conf *conf )
613{
614 /* Do nothing. */
615 PJ_UNUSED_ARG(conf);
616 return PJ_SUCCESS;
617}
618
619/*
620 * Resume sound device.
621 */
622static pj_status_t resume_sound( pjmedia_conf *conf )
623{
624 /* Do nothing. */
625 PJ_UNUSED_ARG(conf);
626 return PJ_SUCCESS;
627}
628
629
630/**
631 * Destroy conference bridge.
632 */
633PJ_DEF(pj_status_t) pjmedia_conf_destroy( pjmedia_conf *conf )
634{
635 unsigned i, ci;
636
637 PJ_ASSERT_RETURN(conf != NULL, PJ_EINVAL);
638
639 /* Destroy sound device port. */
640 if (conf->snd_dev_port) {
641 pjmedia_snd_port_destroy(conf->snd_dev_port);
642 conf->snd_dev_port = NULL;
643 }
644
645 /* Destroy delay buf of all (passive) ports. */
646 for (i=0, ci=0; i<conf->max_ports && ci<conf->port_cnt; ++i) {
647 struct conf_port *cport;
648
649 cport = conf->ports[i];
650 if (!cport)
651 continue;
652
653 ++ci;
654 if (cport->delay_buf) {
655 pjmedia_delay_buf_destroy(cport->delay_buf);
656 cport->delay_buf = NULL;
657 }
658 }
659
660 /* Destroy mutex */
661 if (conf->mutex)
662 pj_mutex_destroy(conf->mutex);
663
664 return PJ_SUCCESS;
665}
666
667
668/*
669 * Destroy the master port (will destroy the conference)
670 */
671static pj_status_t destroy_port(pjmedia_port *this_port)
672{
673 pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata;
674 return pjmedia_conf_destroy(conf);
675}
676
677static pj_status_t destroy_port_pasv(pjmedia_port *this_port) {
678 pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata;
679 struct conf_port *port = conf->ports[this_port->port_data.ldata];
680 pj_status_t status;
681
682 status = pjmedia_delay_buf_destroy(port->delay_buf);
683 if (status == PJ_SUCCESS)
684 port->delay_buf = NULL;
685
686 return status;
687}
688
689/*
690 * Get port zero interface.
691 */
692PJ_DEF(pjmedia_port*) pjmedia_conf_get_master_port(pjmedia_conf *conf)
693{
694 /* Sanity check. */
695 PJ_ASSERT_RETURN(conf != NULL, NULL);
696
697 /* Can only return port interface when PJMEDIA_CONF_NO_DEVICE was
698 * present in the option.
699 */
700 PJ_ASSERT_RETURN((conf->options & PJMEDIA_CONF_NO_DEVICE) != 0, NULL);
701
702 return conf->master_port;
703}
704
705
706/*
707 * Set master port name.
708 */
709PJ_DEF(pj_status_t) pjmedia_conf_set_port0_name(pjmedia_conf *conf,
710 const pj_str_t *name)
711{
712 pj_size_t len;
713
714 /* Sanity check. */
715 PJ_ASSERT_RETURN(conf != NULL && name != NULL, PJ_EINVAL);
716
717 len = name->slen;
718 if (len > sizeof(conf->master_name_buf))
719 len = sizeof(conf->master_name_buf);
720
721 if (len > 0) pj_memcpy(conf->master_name_buf, name->ptr, len);
722
723 conf->ports[0]->name.ptr = conf->master_name_buf;
724 conf->ports[0]->name.slen = len;
725
726 if (conf->master_port)
727 conf->master_port->info.name = conf->ports[0]->name;
728
729 return PJ_SUCCESS;
730}
731
732/*
733 * Add stream port to the conference bridge.
734 */
735PJ_DEF(pj_status_t) pjmedia_conf_add_port( pjmedia_conf *conf,
736 pj_pool_t *pool,
737 pjmedia_port *strm_port,
738 const pj_str_t *port_name,
739 unsigned *p_port )
740{
741 struct conf_port *conf_port;
742 unsigned index;
743 pj_status_t status;
744
745 PJ_ASSERT_RETURN(conf && pool && strm_port, PJ_EINVAL);
746
747 /* If port_name is not specified, use the port's name */
748 if (!port_name)
749 port_name = &strm_port->info.name;
750
751 /* For this version of PJMEDIA, channel(s) number MUST be:
752 * - same between port & conference bridge.
753 * - monochannel on port or conference bridge.
754 */
755 if (PJMEDIA_PIA_CCNT(&strm_port->info) != conf->channel_count &&
756 (PJMEDIA_PIA_CCNT(&strm_port->info) != 1 &&
757 conf->channel_count != 1))
758 {
759 pj_assert(!"Number of channels mismatch");
760 return PJMEDIA_ENCCHANNEL;
761 }
762
763 pj_mutex_lock(conf->mutex);
764
765 if (conf->port_cnt >= conf->max_ports) {
766 pj_assert(!"Too many ports");
767 pj_mutex_unlock(conf->mutex);
768 return PJ_ETOOMANY;
769 }
770
771 /* Find empty port in the conference bridge. */
772 for (index=0; index < conf->max_ports; ++index) {
773 if (conf->ports[index] == NULL)
774 break;
775 }
776
777 pj_assert(index != conf->max_ports);
778
779 /* Create conf port structure. */
780 status = create_conf_port(pool, conf, strm_port, port_name, &conf_port);
781 if (status != PJ_SUCCESS) {
782 pj_mutex_unlock(conf->mutex);
783 return status;
784 }
785
786 /* Put the port. */
787 conf->ports[index] = conf_port;
788 conf->port_cnt++;
789
790 /* Done. */
791 if (p_port) {
792 *p_port = index;
793 }
794
795 pj_mutex_unlock(conf->mutex);
796
797 return PJ_SUCCESS;
798}
799
800
801/*
802 * Add passive port.
803 */
804PJ_DEF(pj_status_t) pjmedia_conf_add_passive_port( pjmedia_conf *conf,
805 pj_pool_t *pool,
806 const pj_str_t *name,
807 unsigned clock_rate,
808 unsigned channel_count,
809 unsigned samples_per_frame,
810 unsigned bits_per_sample,
811 unsigned options,
812 unsigned *p_slot,
813 pjmedia_port **p_port )
814{
815 struct conf_port *conf_port;
816 pjmedia_port *port;
817 unsigned index;
818 pj_str_t tmp;
819 pj_status_t status;
820
821 PJ_LOG(1, (THIS_FILE, "This API has been deprecated since 1.3 and will "
822 "be removed in the future release!"));
823
824 PJ_ASSERT_RETURN(conf && pool, PJ_EINVAL);
825
826 /* For this version of PJMEDIA, channel(s) number MUST be:
827 * - same between port & conference bridge.
828 * - monochannel on port or conference bridge.
829 */
830 if (channel_count != conf->channel_count &&
831 (channel_count != 1 && conf->channel_count != 1))
832 {
833 pj_assert(!"Number of channels mismatch");
834 return PJMEDIA_ENCCHANNEL;
835 }
836
837 /* For this version, options must be zero */
838 PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
839 PJ_UNUSED_ARG(options);
840
841 pj_mutex_lock(conf->mutex);
842
843 if (conf->port_cnt >= conf->max_ports) {
844 pj_assert(!"Too many ports");
845 pj_mutex_unlock(conf->mutex);
846 return PJ_ETOOMANY;
847 }
848
849 /* Find empty port in the conference bridge. */
850 for (index=0; index < conf->max_ports; ++index) {
851 if (conf->ports[index] == NULL)
852 break;
853 }
854
855 pj_assert(index != conf->max_ports);
856
857 if (name == NULL) {
858 name = &tmp;
859
860 tmp.ptr = (char*) pj_pool_alloc(pool, 32);
861 tmp.slen = pj_ansi_snprintf(tmp.ptr, 32, "ConfPort#%d", index);
862 }
863
864 /* Create and initialize the media port structure. */
865 port = PJ_POOL_ZALLOC_T(pool, pjmedia_port);
866 PJ_ASSERT_RETURN(port, PJ_ENOMEM);
867
868 pjmedia_port_info_init(&port->info, name, SIGNATURE_PORT,
869 clock_rate, channel_count, bits_per_sample,
870 samples_per_frame);
871
872 port->port_data.pdata = conf;
873 port->port_data.ldata = index;
874
875 port->get_frame = &get_frame_pasv;
876 port->put_frame = &put_frame;
877 port->on_destroy = &destroy_port_pasv;
878
879
880 /* Create conf port structure. */
881 status = create_pasv_port(conf, pool, name, port, &conf_port);
882 if (status != PJ_SUCCESS) {
883 pj_mutex_unlock(conf->mutex);
884 return status;
885 }
886
887
888 /* Put the port. */
889 conf->ports[index] = conf_port;
890 conf->port_cnt++;
891
892 /* Done. */
893 if (p_slot)
894 *p_slot = index;
895 if (p_port)
896 *p_port = port;
897
898 pj_mutex_unlock(conf->mutex);
899
900 return PJ_SUCCESS;
901}
902
903
904
905/*
906 * Change TX and RX settings for the port.
907 */
908PJ_DEF(pj_status_t) pjmedia_conf_configure_port( pjmedia_conf *conf,
909 unsigned slot,
910 pjmedia_port_op tx,
911 pjmedia_port_op rx)
912{
913 struct conf_port *conf_port;
914
915 /* Check arguments */
916 PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);
917
918 pj_mutex_lock(conf->mutex);
919
920 /* Port must be valid. */
921 conf_port = conf->ports[slot];
922 if (conf_port == NULL) {
923 pj_mutex_unlock(conf->mutex);
924 return PJ_EINVAL;
925 }
926
927 conf_port = conf->ports[slot];
928
929 if (tx != PJMEDIA_PORT_NO_CHANGE)
930 conf_port->tx_setting = tx;
931
932 if (rx != PJMEDIA_PORT_NO_CHANGE)
933 conf_port->rx_setting = rx;
934
935 pj_mutex_unlock(conf->mutex);
936
937 return PJ_SUCCESS;
938}
939
940
941/*
942 * Connect port.
943 */
944PJ_DEF(pj_status_t) pjmedia_conf_connect_port( pjmedia_conf *conf,
945 unsigned src_slot,
946 unsigned sink_slot,
947 int level )
948{
949 struct conf_port *src_port, *dst_port;
950 pj_bool_t start_sound = PJ_FALSE;
951 unsigned i;
952
953 /* Check arguments */
954 PJ_ASSERT_RETURN(conf && src_slot<conf->max_ports &&
955 sink_slot<conf->max_ports, PJ_EINVAL);
956
957 /* For now, level MUST be zero. */
958 PJ_ASSERT_RETURN(level == 0, PJ_EINVAL);
959
960 pj_mutex_lock(conf->mutex);
961
962 /* Ports must be valid. */
963 src_port = conf->ports[src_slot];
964 dst_port = conf->ports[sink_slot];
965 if (!src_port || !dst_port) {
966 pj_mutex_unlock(conf->mutex);
967 return PJ_EINVAL;
968 }
969
970 /* Check if connection has been made */
971 for (i=0; i<src_port->listener_cnt; ++i) {
972 if (src_port->listener_slots[i] == sink_slot)
973 break;
974 }
975
976 if (i == src_port->listener_cnt) {
977 src_port->listener_slots[src_port->listener_cnt] = sink_slot;
978 ++conf->connect_cnt;
979 ++src_port->listener_cnt;
980 ++dst_port->transmitter_cnt;
981
982 if (conf->connect_cnt == 1)
983 start_sound = 1;
984
985 PJ_LOG(4,(THIS_FILE,"Port %d (%.*s) transmitting to port %d (%.*s)",
986 src_slot,
987 (int)src_port->name.slen,
988 src_port->name.ptr,
989 sink_slot,
990 (int)dst_port->name.slen,
991 dst_port->name.ptr));
992 }
993
994 pj_mutex_unlock(conf->mutex);
995
996 /* Sound device must be started without mutex, otherwise the
997 * sound thread will deadlock (?)
998 */
999 if (start_sound)
1000 resume_sound(conf);
1001
1002 return PJ_SUCCESS;
1003}
1004
1005
1006/*
1007 * Disconnect port
1008 */
1009PJ_DEF(pj_status_t) pjmedia_conf_disconnect_port( pjmedia_conf *conf,
1010 unsigned src_slot,
1011 unsigned sink_slot )
1012{
1013 struct conf_port *src_port, *dst_port;
1014 unsigned i;
1015
1016 /* Check arguments */
1017 PJ_ASSERT_RETURN(conf && src_slot<conf->max_ports &&
1018 sink_slot<conf->max_ports, PJ_EINVAL);
1019
1020 pj_mutex_lock(conf->mutex);
1021
1022 /* Ports must be valid. */
1023 src_port = conf->ports[src_slot];
1024 dst_port = conf->ports[sink_slot];
1025 if (!src_port || !dst_port) {
1026 pj_mutex_unlock(conf->mutex);
1027 return PJ_EINVAL;
1028 }
1029
1030 /* Check if connection has been made */
1031 for (i=0; i<src_port->listener_cnt; ++i) {
1032 if (src_port->listener_slots[i] == sink_slot)
1033 break;
1034 }
1035
1036 if (i != src_port->listener_cnt) {
1037 pj_assert(src_port->listener_cnt > 0 &&
1038 src_port->listener_cnt < conf->max_ports);
1039 pj_assert(dst_port->transmitter_cnt > 0 &&
1040 dst_port->transmitter_cnt < conf->max_ports);
1041 pj_array_erase(src_port->listener_slots, sizeof(SLOT_TYPE),
1042 src_port->listener_cnt, i);
1043 --conf->connect_cnt;
1044 --src_port->listener_cnt;
1045 --dst_port->transmitter_cnt;
1046
1047 PJ_LOG(4,(THIS_FILE,
1048 "Port %d (%.*s) stop transmitting to port %d (%.*s)",
1049 src_slot,
1050 (int)src_port->name.slen,
1051 src_port->name.ptr,
1052 sink_slot,
1053 (int)dst_port->name.slen,
1054 dst_port->name.ptr));
1055
1056 /* if source port is passive port and has no listener, reset delaybuf */
1057 if (src_port->delay_buf && src_port->listener_cnt == 0)
1058 pjmedia_delay_buf_reset(src_port->delay_buf);
1059 }
1060
1061 pj_mutex_unlock(conf->mutex);
1062
1063 if (conf->connect_cnt == 0) {
1064 pause_sound(conf);
1065 }
1066
1067 return PJ_SUCCESS;
1068}
1069
1070/*
1071 * Get number of ports currently registered to the conference bridge.
1072 */
1073PJ_DEF(unsigned) pjmedia_conf_get_port_count(pjmedia_conf *conf)
1074{
1075 return conf->port_cnt;
1076}
1077
1078/*
1079 * Get total number of ports connections currently set up in the bridge.
1080 */
1081PJ_DEF(unsigned) pjmedia_conf_get_connect_count(pjmedia_conf *conf)
1082{
1083 return conf->connect_cnt;
1084}
1085
1086
1087/*
1088 * Remove the specified port.
1089 */
1090PJ_DEF(pj_status_t) pjmedia_conf_remove_port( pjmedia_conf *conf,
1091 unsigned port )
1092{
1093 struct conf_port *conf_port;
1094 unsigned i;
1095
1096 /* Check arguments */
1097 PJ_ASSERT_RETURN(conf && port < conf->max_ports, PJ_EINVAL);
1098
1099 /* Suspend the sound devices.
1100 * Don't want to remove port while port is being accessed by sound
1101 * device's threads!
1102 */
1103
1104 pj_mutex_lock(conf->mutex);
1105
1106 /* Port must be valid. */
1107 conf_port = conf->ports[port];
1108 if (conf_port == NULL) {
1109 pj_mutex_unlock(conf->mutex);
1110 return PJ_EINVAL;
1111 }
1112
1113 conf_port->tx_setting = PJMEDIA_PORT_DISABLE;
1114 conf_port->rx_setting = PJMEDIA_PORT_DISABLE;
1115
1116 /* Remove this port from transmit array of other ports. */
1117 for (i=0; i<conf->max_ports; ++i) {
1118 unsigned j;
1119 struct conf_port *src_port;
1120
1121 src_port = conf->ports[i];
1122
1123 if (!src_port)
1124 continue;
1125
1126 if (src_port->listener_cnt == 0)
1127 continue;
1128
1129 for (j=0; j<src_port->listener_cnt; ++j) {
1130 if (src_port->listener_slots[j] == port) {
1131 pj_array_erase(src_port->listener_slots, sizeof(SLOT_TYPE),
1132 src_port->listener_cnt, j);
1133 pj_assert(conf->connect_cnt > 0);
1134 --conf->connect_cnt;
1135 --src_port->listener_cnt;
1136 break;
1137 }
1138 }
1139 }
1140
1141 /* Update transmitter_cnt of ports we're transmitting to */
1142 while (conf_port->listener_cnt) {
1143 unsigned dst_slot;
1144 struct conf_port *dst_port;
1145
1146 dst_slot = conf_port->listener_slots[conf_port->listener_cnt-1];
1147 dst_port = conf->ports[dst_slot];
1148 --dst_port->transmitter_cnt;
1149 --conf_port->listener_cnt;
1150 pj_assert(conf->connect_cnt > 0);
1151 --conf->connect_cnt;
1152 }
1153
1154 /* Destroy pjmedia port if this conf port is passive port,
1155 * i.e: has delay buf.
1156 */
1157 if (conf_port->delay_buf) {
1158 pjmedia_port_destroy(conf_port->port);
1159 conf_port->port = NULL;
1160 }
1161
1162 /* Remove the port. */
1163 conf->ports[port] = NULL;
1164 --conf->port_cnt;
1165
1166 pj_mutex_unlock(conf->mutex);
1167
1168
1169 /* Stop sound if there's no connection. */
1170 if (conf->connect_cnt == 0) {
1171 pause_sound(conf);
1172 }
1173
1174 return PJ_SUCCESS;
1175}
1176
1177
1178/*
1179 * Enum ports.
1180 */
1181PJ_DEF(pj_status_t) pjmedia_conf_enum_ports( pjmedia_conf *conf,
1182 unsigned ports[],
1183 unsigned *p_count )
1184{
1185 unsigned i, count=0;
1186
1187 PJ_ASSERT_RETURN(conf && p_count && ports, PJ_EINVAL);
1188
1189 /* Lock mutex */
1190 pj_mutex_lock(conf->mutex);
1191
1192 for (i=0; i<conf->max_ports && count<*p_count; ++i) {
1193 if (!conf->ports[i])
1194 continue;
1195
1196 ports[count++] = i;
1197 }
1198
1199 /* Unlock mutex */
1200 pj_mutex_unlock(conf->mutex);
1201
1202 *p_count = count;
1203 return PJ_SUCCESS;
1204}
1205
1206/*
1207 * Get port info
1208 */
1209PJ_DEF(pj_status_t) pjmedia_conf_get_port_info( pjmedia_conf *conf,
1210 unsigned slot,
1211 pjmedia_conf_port_info *info)
1212{
1213 struct conf_port *conf_port;
1214
1215 /* Check arguments */
1216 PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);
1217
1218 /* Lock mutex */
1219 pj_mutex_lock(conf->mutex);
1220
1221 /* Port must be valid. */
1222 conf_port = conf->ports[slot];
1223 if (conf_port == NULL) {
1224 pj_mutex_unlock(conf->mutex);
1225 return PJ_EINVAL;
1226 }
1227
1228 info->slot = slot;
1229 info->name = conf_port->name;
1230 info->tx_setting = conf_port->tx_setting;
1231 info->rx_setting = conf_port->rx_setting;
1232 info->listener_cnt = conf_port->listener_cnt;
1233 info->listener_slots = conf_port->listener_slots;
1234 info->transmitter_cnt = conf_port->transmitter_cnt;
1235 info->clock_rate = conf_port->clock_rate;
1236 info->channel_count = conf_port->channel_count;
1237 info->samples_per_frame = conf_port->samples_per_frame;
1238 info->bits_per_sample = conf->bits_per_sample;
1239 info->tx_adj_level = conf_port->tx_adj_level - NORMAL_LEVEL;
1240 info->rx_adj_level = conf_port->rx_adj_level - NORMAL_LEVEL;
1241
1242 /* Unlock mutex */
1243 pj_mutex_unlock(conf->mutex);
1244
1245 return PJ_SUCCESS;
1246}
1247
1248
1249PJ_DEF(pj_status_t) pjmedia_conf_get_ports_info(pjmedia_conf *conf,
1250 unsigned *size,
1251 pjmedia_conf_port_info info[])
1252{
1253 unsigned i, count=0;
1254
1255 PJ_ASSERT_RETURN(conf && size && info, PJ_EINVAL);
1256
1257 /* Lock mutex */
1258 pj_mutex_lock(conf->mutex);
1259
1260 for (i=0; i<conf->max_ports && count<*size; ++i) {
1261 if (!conf->ports[i])
1262 continue;
1263
1264 pjmedia_conf_get_port_info(conf, i, &info[count]);
1265 ++count;
1266 }
1267
1268 /* Unlock mutex */
1269 pj_mutex_unlock(conf->mutex);
1270
1271 *size = count;
1272 return PJ_SUCCESS;
1273}
1274
1275
1276/*
1277 * Get signal level.
1278 */
1279PJ_DEF(pj_status_t) pjmedia_conf_get_signal_level( pjmedia_conf *conf,
1280 unsigned slot,
1281 unsigned *tx_level,
1282 unsigned *rx_level)
1283{
1284 struct conf_port *conf_port;
1285
1286 /* Check arguments */
1287 PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);
1288
1289 /* Lock mutex */
1290 pj_mutex_lock(conf->mutex);
1291
1292 /* Port must be valid. */
1293 conf_port = conf->ports[slot];
1294 if (conf_port == NULL) {
1295 pj_mutex_unlock(conf->mutex);
1296 return PJ_EINVAL;
1297 }
1298
1299 if (tx_level != NULL) {
1300 *tx_level = conf_port->tx_level;
1301 }
1302
1303 if (rx_level != NULL)
1304 *rx_level = conf_port->rx_level;
1305
1306 /* Unlock mutex */
1307 pj_mutex_unlock(conf->mutex);
1308
1309 return PJ_SUCCESS;
1310}
1311
1312
1313/*
1314 * Adjust RX level of individual port.
1315 */
1316PJ_DEF(pj_status_t) pjmedia_conf_adjust_rx_level( pjmedia_conf *conf,
1317 unsigned slot,
1318 int adj_level )
1319{
1320 struct conf_port *conf_port;
1321
1322 /* Check arguments */
1323 PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);
1324
1325 /* Value must be from -128 to +127 */
1326 /* Disabled, you can put more than +127, at your own risk:
1327 PJ_ASSERT_RETURN(adj_level >= -128 && adj_level <= 127, PJ_EINVAL);
1328 */
1329 PJ_ASSERT_RETURN(adj_level >= -128, PJ_EINVAL);
1330
1331 /* Lock mutex */
1332 pj_mutex_lock(conf->mutex);
1333
1334 /* Port must be valid. */
1335 conf_port = conf->ports[slot];
1336 if (conf_port == NULL) {
1337 pj_mutex_unlock(conf->mutex);
1338 return PJ_EINVAL;
1339 }
1340
1341 /* Set normalized adjustment level. */
1342 conf_port->rx_adj_level = adj_level + NORMAL_LEVEL;
1343
1344 /* Unlock mutex */
1345 pj_mutex_unlock(conf->mutex);
1346
1347 return PJ_SUCCESS;
1348}
1349
1350
1351/*
1352 * Adjust TX level of individual port.
1353 */
1354PJ_DEF(pj_status_t) pjmedia_conf_adjust_tx_level( pjmedia_conf *conf,
1355 unsigned slot,
1356 int adj_level )
1357{
1358 struct conf_port *conf_port;
1359
1360 /* Check arguments */
1361 PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);
1362
1363 /* Value must be from -128 to +127 */
1364 /* Disabled, you can put more than +127,, at your own risk:
1365 PJ_ASSERT_RETURN(adj_level >= -128 && adj_level <= 127, PJ_EINVAL);
1366 */
1367 PJ_ASSERT_RETURN(adj_level >= -128, PJ_EINVAL);
1368
1369 /* Lock mutex */
1370 pj_mutex_lock(conf->mutex);
1371
1372 /* Port must be valid. */
1373 conf_port = conf->ports[slot];
1374 if (conf_port == NULL) {
1375 pj_mutex_unlock(conf->mutex);
1376 return PJ_EINVAL;
1377 }
1378
1379 /* Set normalized adjustment level. */
1380 conf_port->tx_adj_level = adj_level + NORMAL_LEVEL;
1381
1382 /* Unlock mutex */
1383 pj_mutex_unlock(conf->mutex);
1384
1385 return PJ_SUCCESS;
1386}
1387
1388
1389/*
1390 * Read from port.
1391 */
1392static pj_status_t read_port( pjmedia_conf *conf,
1393 struct conf_port *cport, pj_int16_t *frame,
1394 pj_size_t count, pjmedia_frame_type *type )
1395{
1396
1397 pj_assert(count == conf->samples_per_frame);
1398
1399 TRACE_((THIS_FILE, "read_port %.*s: count=%d",
1400 (int)cport->name.slen, cport->name.ptr,
1401 count));
1402
1403 /*
1404 * If port's samples per frame and sampling rate and channel count
1405 * matche conference bridge's settings, get the frame directly from
1406 * the port.
1407 */
1408 if (cport->rx_buf_cap == 0) {
1409 pjmedia_frame f;
1410 pj_status_t status;
1411
1412 f.buf = frame;
1413 f.size = count * BYTES_PER_SAMPLE;
1414
1415 TRACE_((THIS_FILE, " get_frame %.*s: count=%d",
1416 (int)cport->name.slen, cport->name.ptr,
1417 count));
1418
1419 status = pjmedia_port_get_frame(cport->port, &f);
1420
1421 *type = f.type;
1422
1423 return status;
1424
1425 } else {
1426 unsigned samples_req;
1427
1428 /* Initialize frame type */
1429 if (cport->rx_buf_count == 0) {
1430 *type = PJMEDIA_FRAME_TYPE_NONE;
1431 } else {
1432 /* we got some samples in the buffer */
1433 *type = PJMEDIA_FRAME_TYPE_AUDIO;
1434 }
1435
1436 /*
1437 * If we don't have enough samples in rx_buf, read from the port
1438 * first. Remember that rx_buf may be in different clock rate and
1439 * channel count!
1440 */
1441
1442 samples_req = (unsigned) (count * 1.0 *
1443 cport->clock_rate / conf->clock_rate + 0.5);
1444
1445 while (cport->rx_buf_count < samples_req) {
1446
1447 pjmedia_frame f;
1448 pj_status_t status;
1449
1450 f.buf = cport->rx_buf + cport->rx_buf_count;
1451 f.size = cport->samples_per_frame * BYTES_PER_SAMPLE;
1452
1453 TRACE_((THIS_FILE, " get_frame, count=%d",
1454 cport->samples_per_frame));
1455
1456 status = pjmedia_port_get_frame(cport->port, &f);
1457
1458 if (status != PJ_SUCCESS) {
1459 /* Fatal error! */
1460 return status;
1461 }
1462
1463 if (f.type != PJMEDIA_FRAME_TYPE_AUDIO) {
1464 TRACE_((THIS_FILE, " get_frame returned non-audio"));
1465 pjmedia_zero_samples( cport->rx_buf + cport->rx_buf_count,
1466 cport->samples_per_frame);
1467 } else {
1468 /* We've got at least one frame */
1469 *type = PJMEDIA_FRAME_TYPE_AUDIO;
1470 }
1471
1472 /* Adjust channels */
1473 if (cport->channel_count != conf->channel_count) {
1474 if (cport->channel_count == 1) {
1475 pjmedia_convert_channel_1ton((pj_int16_t*)f.buf,
1476 (const pj_int16_t*)f.buf,
1477 conf->channel_count,
1478 cport->samples_per_frame,
1479 0);
1480 cport->rx_buf_count += (cport->samples_per_frame *
1481 conf->channel_count);
1482 } else { /* conf->channel_count == 1 */
1483 pjmedia_convert_channel_nto1((pj_int16_t*)f.buf,
1484 (const pj_int16_t*)f.buf,
1485 cport->channel_count,
1486 cport->samples_per_frame,
1487 PJMEDIA_STEREO_MIX, 0);
1488 cport->rx_buf_count += (cport->samples_per_frame /
1489 cport->channel_count);
1490 }
1491 } else {
1492 cport->rx_buf_count += cport->samples_per_frame;
1493 }
1494
1495 TRACE_((THIS_FILE, " rx buffer size is now %d",
1496 cport->rx_buf_count));
1497
1498 pj_assert(cport->rx_buf_count <= cport->rx_buf_cap);
1499 }
1500
1501 /*
1502 * If port's clock_rate is different, resample.
1503 * Otherwise just copy.
1504 */
1505 if (cport->clock_rate != conf->clock_rate) {
1506
1507 unsigned src_count;
1508
1509 TRACE_((THIS_FILE, " resample, input count=%d",
1510 pjmedia_resample_get_input_size(cport->rx_resample)));
1511
1512 pjmedia_resample_run( cport->rx_resample,cport->rx_buf, frame);
1513
1514 src_count = (unsigned)(count * 1.0 * cport->clock_rate /
1515 conf->clock_rate + 0.5);
1516 cport->rx_buf_count -= src_count;
1517 if (cport->rx_buf_count) {
1518 pjmedia_move_samples(cport->rx_buf, cport->rx_buf+src_count,
1519 cport->rx_buf_count);
1520 }
1521
1522 TRACE_((THIS_FILE, " rx buffer size is now %d",
1523 cport->rx_buf_count));
1524
1525 } else {
1526
1527 pjmedia_copy_samples(frame, cport->rx_buf, (unsigned)count);
1528 cport->rx_buf_count -= (unsigned)count;
1529 if (cport->rx_buf_count) {
1530 pjmedia_move_samples(cport->rx_buf, cport->rx_buf+count,
1531 cport->rx_buf_count);
1532 }
1533 }
1534 }
1535
1536 return PJ_SUCCESS;
1537}
1538
1539
1540/*
1541 * Write the mixed signal to the port.
1542 */
1543static pj_status_t write_port(pjmedia_conf *conf, struct conf_port *cport,
1544 const pj_timestamp *timestamp,
1545 pjmedia_frame_type *frm_type)
1546{
1547 pj_int16_t *buf;
1548 unsigned j, ts;
1549 pj_status_t status;
1550 pj_int32_t adj_level;
1551 pj_int32_t tx_level;
1552 unsigned dst_count;
1553
1554 *frm_type = PJMEDIA_FRAME_TYPE_AUDIO;
1555
1556 /* If port is muted or nobody is transmitting to this port,
1557 * transmit NULL frame.
1558 */
1559 if (cport->tx_setting == PJMEDIA_PORT_MUTE || cport->transmitter_cnt==0) {
1560
1561 pjmedia_frame frame;
1562
1563 /* Clear left-over samples in tx_buffer, if any, so that it won't
1564 * be transmitted next time we have audio signal.
1565 */
1566 cport->tx_buf_count = 0;
1567
1568 /* Add sample counts to heart-beat samples */
1569 cport->tx_heart_beat += conf->samples_per_frame * cport->clock_rate /
1570 conf->clock_rate *
1571 cport->channel_count / conf->channel_count;
1572
1573 /* Set frame timestamp */
1574 frame.timestamp.u64 = timestamp->u64 * cport->clock_rate /
1575 conf->clock_rate;
1576 frame.type = PJMEDIA_FRAME_TYPE_NONE;
1577 frame.buf = NULL;
1578 frame.size = 0;
1579
1580 /* Transmit heart-beat frames (may transmit more than one NULL frame
1581 * if port's ptime is less than bridge's ptime.
1582 */
1583 if (cport->port && cport->port->put_frame) {
1584 while (cport->tx_heart_beat >= cport->samples_per_frame) {
1585
1586 pjmedia_port_put_frame(cport->port, &frame);
1587
1588 cport->tx_heart_beat -= cport->samples_per_frame;
1589 frame.timestamp.u64 += cport->samples_per_frame;
1590 }
1591 }
1592
1593 cport->tx_level = 0;
1594 *frm_type = PJMEDIA_FRAME_TYPE_NONE;
1595 return PJ_SUCCESS;
1596
1597 } else if (cport->tx_setting != PJMEDIA_PORT_ENABLE) {
1598 cport->tx_level = 0;
1599 *frm_type = PJMEDIA_FRAME_TYPE_NONE;
1600 return PJ_SUCCESS;
1601 }
1602
1603 /* Reset heart-beat sample count */
1604 cport->tx_heart_beat = 0;
1605
1606 buf = (pj_int16_t*) cport->mix_buf;
1607
1608 /* If there are sources in the mix buffer, convert the mixed samples
1609 * from 32bit to 16bit in the mixed samples itself. This is possible
1610 * because mixed sample is 32bit.
1611 *
1612 * In addition to this process, if we need to change the level of
1613 * TX signal, we adjust is here too.
1614 */
1615
1616 /* Calculate signal level and adjust the signal when needed.
1617 * Two adjustments performed at once:
1618 * 1. user setting adjustment (tx_adj_level).
1619 * 2. automatic adjustment of overflowed mixed buffer (mix_adj).
1620 */
1621
1622 /* Apply simple AGC to the mix_adj, the automatic adjust, to avoid
1623 * dramatic change in the level thus causing noise because the signal
1624 * is now not aligned with the signal from the previous frame.
1625 */
1626 SIMPLE_AGC(cport->last_mix_adj, cport->mix_adj);
1627 cport->last_mix_adj = cport->mix_adj;
1628
1629 /* adj_level = cport->tx_adj_level * cport->mix_adj / NORMAL_LEVEL;*/
1630 adj_level = cport->tx_adj_level * cport->mix_adj;
1631 adj_level >>= 7;
1632
1633 tx_level = 0;
1634
1635 if (adj_level != NORMAL_LEVEL) {
1636 for (j=0; j<conf->samples_per_frame; ++j) {
1637 pj_int32_t itemp = cport->mix_buf[j];
1638
1639 /* Adjust the level */
1640 /*itemp = itemp * adj_level / NORMAL_LEVEL;*/
1641 itemp = (itemp * adj_level) >> 7;
1642
1643 /* Clip the signal if it's too loud */
1644 if (itemp > MAX_LEVEL) itemp = MAX_LEVEL;
1645 else if (itemp < MIN_LEVEL) itemp = MIN_LEVEL;
1646
1647 /* Put back in the buffer. */
1648 buf[j] = (pj_int16_t) itemp;
1649
1650 tx_level += (buf[j]>=0? buf[j] : -buf[j]);
1651 }
1652 } else {
1653 for (j=0; j<conf->samples_per_frame; ++j) {
1654 buf[j] = (pj_int16_t) cport->mix_buf[j];
1655 tx_level += (buf[j]>=0? buf[j] : -buf[j]);
1656 }
1657 }
1658
1659 tx_level /= conf->samples_per_frame;
1660
1661 /* Convert level to 8bit complement ulaw */
1662 tx_level = pjmedia_linear2ulaw(tx_level) ^ 0xff;
1663
1664 cport->tx_level = tx_level;
1665
1666 /* If port has the same clock_rate and samples_per_frame and
1667 * number of channels as the conference bridge, transmit the
1668 * frame as is.
1669 */
1670 if (cport->clock_rate == conf->clock_rate &&
1671 cport->samples_per_frame == conf->samples_per_frame &&
1672 cport->channel_count == conf->channel_count)
1673 {
1674 if (cport->port != NULL) {
1675 pjmedia_frame frame;
1676
1677 frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
1678 frame.buf = buf;
1679 frame.size = conf->samples_per_frame * BYTES_PER_SAMPLE;
1680 /* No need to adjust timestamp, port has the same
1681 * clock rate as conference bridge
1682 */
1683 frame.timestamp = *timestamp;
1684
1685 TRACE_((THIS_FILE, "put_frame %.*s, count=%d",
1686 (int)cport->name.slen, cport->name.ptr,
1687 frame.size / BYTES_PER_SAMPLE));
1688
1689 return pjmedia_port_put_frame(cport->port, &frame);
1690 } else
1691 return PJ_SUCCESS;
1692 }
1693
1694 /* If it has different clock_rate, must resample. */
1695 if (cport->clock_rate != conf->clock_rate) {
1696 pjmedia_resample_run( cport->tx_resample, buf,
1697 cport->tx_buf + cport->tx_buf_count );
1698 dst_count = (unsigned)(conf->samples_per_frame * 1.0 *
1699 cport->clock_rate / conf->clock_rate + 0.5);
1700 } else {
1701 /* Same clock rate.
1702 * Just copy the samples to tx_buffer.
1703 */
1704 pjmedia_copy_samples( cport->tx_buf + cport->tx_buf_count,
1705 buf, conf->samples_per_frame );
1706 dst_count = conf->samples_per_frame;
1707 }
1708
1709 /* Adjust channels */
1710 if (cport->channel_count != conf->channel_count) {
1711 pj_int16_t *tx_buf = cport->tx_buf + cport->tx_buf_count;
1712 if (conf->channel_count == 1) {
1713 pjmedia_convert_channel_1ton(tx_buf, tx_buf,
1714 cport->channel_count,
1715 dst_count, 0);
1716 dst_count *= cport->channel_count;
1717 } else { /* cport->channel_count == 1 */
1718 pjmedia_convert_channel_nto1(tx_buf, tx_buf,
1719 conf->channel_count,
1720 dst_count, PJMEDIA_STEREO_MIX, 0);
1721 dst_count /= conf->channel_count;
1722 }
1723 }
1724
1725 cport->tx_buf_count += dst_count;
1726
1727 pj_assert(cport->tx_buf_count <= cport->tx_buf_cap);
1728
1729 /* Transmit while we have enough frame in the tx_buf. */
1730 status = PJ_SUCCESS;
1731 ts = 0;
1732 while (cport->tx_buf_count >= cport->samples_per_frame &&
1733 status == PJ_SUCCESS)
1734 {
1735
1736 TRACE_((THIS_FILE, "write_port %.*s: count=%d",
1737 (int)cport->name.slen, cport->name.ptr,
1738 cport->samples_per_frame));
1739
1740 if (cport->port) {
1741 pjmedia_frame frame;
1742
1743 frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
1744 frame.buf = cport->tx_buf;
1745 frame.size = cport->samples_per_frame * BYTES_PER_SAMPLE;
1746 /* Adjust timestamp as port may have different clock rate
1747 * than the bridge.
1748 */
1749 frame.timestamp.u64 = timestamp->u64 * cport->clock_rate /
1750 conf->clock_rate;
1751
1752 /* Add timestamp for individual frame */
1753 frame.timestamp.u64 += ts;
1754 ts += cport->samples_per_frame;
1755
1756 TRACE_((THIS_FILE, "put_frame %.*s, count=%d",
1757 (int)cport->name.slen, cport->name.ptr,
1758 frame.size / BYTES_PER_SAMPLE));
1759
1760 status = pjmedia_port_put_frame(cport->port, &frame);
1761
1762 } else
1763 status = PJ_SUCCESS;
1764
1765 cport->tx_buf_count -= cport->samples_per_frame;
1766 if (cport->tx_buf_count) {
1767 pjmedia_move_samples(cport->tx_buf,
1768 cport->tx_buf + cport->samples_per_frame,
1769 cport->tx_buf_count);
1770 }
1771
1772 TRACE_((THIS_FILE, " tx_buf count now is %d",
1773 cport->tx_buf_count));
1774 }
1775
1776 return status;
1777}
1778
1779
1780/*
1781 * Player callback.
1782 */
1783static pj_status_t get_frame(pjmedia_port *this_port,
1784 pjmedia_frame *frame)
1785{
1786 pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata;
1787 pjmedia_frame_type speaker_frame_type = PJMEDIA_FRAME_TYPE_NONE;
1788 unsigned ci, cj, i, j;
1789 pj_int16_t *p_in;
1790
1791 TRACE_((THIS_FILE, "- clock -"));
1792
1793 /* Check that correct size is specified. */
1794 pj_assert(frame->size == conf->samples_per_frame *
1795 conf->bits_per_sample / 8);
1796
1797 /* Must lock mutex */
1798 pj_mutex_lock(conf->mutex);
1799
1800 /* Reset port source count. We will only reset port's mix
1801 * buffer when we have someone transmitting to it.
1802 */
1803 for (i=0, ci=0; i<conf->max_ports && ci < conf->port_cnt; ++i) {
1804 struct conf_port *conf_port = conf->ports[i];
1805
1806 /* Skip empty port. */
1807 if (!conf_port)
1808 continue;
1809
1810 /* Var "ci" is to count how many ports have been visited so far. */
1811 ++ci;
1812
1813 /* Reset buffer (only necessary if the port has transmitter) and
1814 * reset auto adjustment level for mixed signal.
1815 */
1816 conf_port->mix_adj = NORMAL_LEVEL;
1817 if (conf_port->transmitter_cnt) {
1818 pj_bzero(conf_port->mix_buf,
1819 conf->samples_per_frame*sizeof(conf_port->mix_buf[0]));
1820 }
1821 }
1822
1823 /* Get frames from all ports, and "mix" the signal
1824 * to mix_buf of all listeners of the port.
1825 */
1826 for (i=0, ci=0; i < conf->max_ports && ci < conf->port_cnt; ++i) {
1827 struct conf_port *conf_port = conf->ports[i];
1828 pj_int32_t level = 0;
1829
1830 /* Skip empty port. */
1831 if (!conf_port)
1832 continue;
1833
1834 /* Var "ci" is to count how many ports have been visited so far. */
1835 ++ci;
1836
1837 /* Skip if we're not allowed to receive from this port. */
1838 if (conf_port->rx_setting == PJMEDIA_PORT_DISABLE) {
1839 conf_port->rx_level = 0;
1840 continue;
1841 }
1842
1843 /* Also skip if this port doesn't have listeners. */
1844 if (conf_port->listener_cnt == 0) {
1845 conf_port->rx_level = 0;
1846 continue;
1847 }
1848
1849 /* Get frame from this port.
1850 * For passive ports, get the frame from the delay_buf.
1851 * For other ports, get the frame from the port.
1852 */
1853 if (conf_port->delay_buf != NULL) {
1854 pj_status_t status;
1855
1856 status = pjmedia_delay_buf_get(conf_port->delay_buf,
1857 (pj_int16_t*)frame->buf);
1858 if (status != PJ_SUCCESS)
1859 continue;
1860
1861 } else {
1862
1863 pj_status_t status;
1864 pjmedia_frame_type frame_type;
1865
1866 status = read_port(conf, conf_port, (pj_int16_t*)frame->buf,
1867 conf->samples_per_frame, &frame_type);
1868
1869 if (status != PJ_SUCCESS) {
1870 /* bennylp: why do we need this????
1871 * Also see comments on similar issue with write_port().
1872 PJ_LOG(4,(THIS_FILE, "Port %.*s get_frame() returned %d. "
1873 "Port is now disabled",
1874 (int)conf_port->name.slen,
1875 conf_port->name.ptr,
1876 status));
1877 conf_port->rx_setting = PJMEDIA_PORT_DISABLE;
1878 */
1879 continue;
1880 }
1881
1882 /* Check that the port is not removed when we call get_frame() */
1883 if (conf->ports[i] == NULL)
1884 continue;
1885
1886 /* Ignore if we didn't get any frame */
1887 if (frame_type != PJMEDIA_FRAME_TYPE_AUDIO)
1888 continue;
1889 }
1890
1891 p_in = (pj_int16_t*) frame->buf;
1892
1893 /* Adjust the RX level from this port
1894 * and calculate the average level at the same time.
1895 */
1896 if (conf_port->rx_adj_level != NORMAL_LEVEL) {
1897 for (j=0; j<conf->samples_per_frame; ++j) {
1898 /* For the level adjustment, we need to store the sample to
1899 * a temporary 32bit integer value to avoid overflowing the
1900 * 16bit sample storage.
1901 */
1902 pj_int32_t itemp;
1903
1904 itemp = p_in[j];
1905 /*itemp = itemp * adj / NORMAL_LEVEL;*/
1906 /* bad code (signed/unsigned badness):
1907 * itemp = (itemp * conf_port->rx_adj_level) >> 7;
1908 */
1909 itemp *= conf_port->rx_adj_level;
1910 itemp >>= 7;
1911
1912 /* Clip the signal if it's too loud */
1913 if (itemp > MAX_LEVEL) itemp = MAX_LEVEL;
1914 else if (itemp < MIN_LEVEL) itemp = MIN_LEVEL;
1915
1916 p_in[j] = (pj_int16_t) itemp;
1917 level += (p_in[j]>=0? p_in[j] : -p_in[j]);
1918 }
1919 } else {
1920 for (j=0; j<conf->samples_per_frame; ++j) {
1921 level += (p_in[j]>=0? p_in[j] : -p_in[j]);
1922 }
1923 }
1924
1925 level /= conf->samples_per_frame;
1926
1927 /* Convert level to 8bit complement ulaw */
1928 level = pjmedia_linear2ulaw(level) ^ 0xff;
1929
1930 /* Put this level to port's last RX level. */
1931 conf_port->rx_level = level;
1932
1933 // Ticket #671: Skipping very low audio signal may cause noise
1934 // to be generated in the remote end by some hardphones.
1935 /* Skip processing frame if level is zero */
1936 //if (level == 0)
1937 // continue;
1938
1939 /* Add the signal to all listeners. */
1940 for (cj=0; cj < conf_port->listener_cnt; ++cj)
1941 {
1942 struct conf_port *listener;
1943 pj_int32_t *mix_buf;
1944 unsigned k;
1945
1946 listener = conf->ports[conf_port->listener_slots[cj]];
1947
1948 /* Skip if this listener doesn't want to receive audio */
1949 if (listener->tx_setting != PJMEDIA_PORT_ENABLE)
1950 continue;
1951
1952 mix_buf = listener->mix_buf;
1953
1954 if (listener->transmitter_cnt > 1) {
1955 /* Mixing signals,
1956 * and calculate appropriate level adjustment if there is
1957 * any overflowed level in the mixed signal.
1958 */
1959 for (k=0; k < conf->samples_per_frame; ++k) {
1960 mix_buf[k] += p_in[k];
1961 /* Check if normalization adjustment needed. */
1962 if (IS_OVERFLOW(mix_buf[k])) {
1963 /* NORMAL_LEVEL * MAX_LEVEL / mix_buf[k]; */
1964 int tmp_adj = (MAX_LEVEL<<7) / mix_buf[k];
1965 if (tmp_adj<0) tmp_adj = -tmp_adj;
1966
1967 if (tmp_adj<listener->mix_adj)
1968 listener->mix_adj = tmp_adj;
1969
1970 } /* if any overflow in the mixed signals */
1971 } /* loop mixing signals */
1972 } else {
1973 /* Only 1 transmitter:
1974 * just copy the samples to the mix buffer
1975 * no mixing and level adjustment needed
1976 */
1977 for (k=0; k<conf->samples_per_frame; ++k) {
1978 mix_buf[k] = p_in[k];
1979 }
1980 }
1981 } /* loop the listeners of conf port */
1982 } /* loop of all conf ports */
1983
1984 /* Time for all ports to transmit whetever they have in their
1985 * buffer.
1986 */
1987 for (i=0, ci=0; i<conf->max_ports && ci<conf->port_cnt; ++i) {
1988 struct conf_port *conf_port = conf->ports[i];
1989 pjmedia_frame_type frm_type;
1990 pj_status_t status;
1991
1992 if (!conf_port)
1993 continue;
1994
1995 /* Var "ci" is to count how many ports have been visited. */
1996 ++ci;
1997
1998 status = write_port( conf, conf_port, &frame->timestamp,
1999 &frm_type);
2000 if (status != PJ_SUCCESS) {
2001 /* bennylp: why do we need this????
2002 One thing for sure, put_frame()/write_port() may return
2003 non-successfull status on Win32 if there's temporary glitch
2004 on network interface, so disabling the port here does not
2005 sound like a good idea.
2006
2007 PJ_LOG(4,(THIS_FILE, "Port %.*s put_frame() returned %d. "
2008 "Port is now disabled",
2009 (int)conf_port->name.slen,
2010 conf_port->name.ptr,
2011 status));
2012 conf_port->tx_setting = PJMEDIA_PORT_DISABLE;
2013 */
2014 continue;
2015 }
2016
2017 /* Set the type of frame to be returned to sound playback
2018 * device.
2019 */
2020 if (i == 0)
2021 speaker_frame_type = frm_type;
2022 }
2023
2024 /* Return sound playback frame. */
2025 if (conf->ports[0]->tx_level) {
2026 TRACE_((THIS_FILE, "write to audio, count=%d",
2027 conf->samples_per_frame));
2028 pjmedia_copy_samples( (pj_int16_t*)frame->buf,
2029 (const pj_int16_t*)conf->ports[0]->mix_buf,
2030 conf->samples_per_frame);
2031 } else {
2032 /* Force frame type NONE */
2033 speaker_frame_type = PJMEDIA_FRAME_TYPE_NONE;
2034 }
2035
2036 /* MUST set frame type */
2037 frame->type = speaker_frame_type;
2038
2039 pj_mutex_unlock(conf->mutex);
2040
2041#ifdef REC_FILE
2042 if (fhnd_rec == NULL)
2043 fhnd_rec = fopen(REC_FILE, "wb");
2044 if (fhnd_rec)
2045 fwrite(frame->buf, frame->size, 1, fhnd_rec);
2046#endif
2047
2048 return PJ_SUCCESS;
2049}
2050
2051
2052/*
2053 * get_frame() for passive port
2054 */
2055static pj_status_t get_frame_pasv(pjmedia_port *this_port,
2056 pjmedia_frame *frame)
2057{
2058 pj_assert(0);
2059 PJ_UNUSED_ARG(this_port);
2060 PJ_UNUSED_ARG(frame);
2061 return -1;
2062}
2063
2064
2065/*
2066 * Recorder (or passive port) callback.
2067 */
2068static pj_status_t put_frame(pjmedia_port *this_port,
2069 pjmedia_frame *frame)
2070{
2071 pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata;
2072 struct conf_port *port = conf->ports[this_port->port_data.ldata];
2073 pj_status_t status;
2074
2075 /* Check for correct size. */
2076 PJ_ASSERT_RETURN( frame->size == conf->samples_per_frame *
2077 conf->bits_per_sample / 8,
2078 PJMEDIA_ENCSAMPLESPFRAME);
2079
2080 /* Check existance of delay_buf instance */
2081 PJ_ASSERT_RETURN( port->delay_buf, PJ_EBUG );
2082
2083 /* Skip if this port is muted/disabled. */
2084 if (port->rx_setting != PJMEDIA_PORT_ENABLE) {
2085 return PJ_SUCCESS;
2086 }
2087
2088 /* Skip if no port is listening to the microphone */
2089 if (port->listener_cnt == 0) {
2090 return PJ_SUCCESS;
2091 }
2092
2093 status = pjmedia_delay_buf_put(port->delay_buf, (pj_int16_t*)frame->buf);
2094
2095 return status;
2096}
2097
2098#endif