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

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.2.1/pjmedia/src/pjmedia/conf_switch.c

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: conf_switch.c 4443 2013-03-20 06:56:19Z nanang $ */
 
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/errno.h>
 
23
#include <pjmedia/port.h>
 
24
#include <pjmedia/silencedet.h>
 
25
#include <pjmedia/sound_port.h>
 
26
#include <pj/array.h>
 
27
#include <pj/assert.h>
 
28
#include <pj/log.h>
 
29
#include <pj/math.h>
 
30
#include <pj/pool.h>
 
31
#include <pj/string.h>
 
32
 
 
33
#if defined(PJMEDIA_CONF_USE_SWITCH_BOARD) && PJMEDIA_CONF_USE_SWITCH_BOARD!=0
 
34
 
 
35
/* CONF_DEBUG enables detailed operation of the conference bridge.
 
36
 * Beware that it prints large amounts of logs (several lines per frame).
 
37
 */
 
38
//#define CONF_DEBUG
 
39
#ifdef CONF_DEBUG
 
40
#   include <stdio.h>
 
41
#   define TRACE_(x)   PJ_LOG(5,x)
 
42
#else
 
43
#   define TRACE_(x)
 
44
#endif
 
45
 
 
46
#define THIS_FILE           "conf_switch.c"
 
47
 
 
48
#define SIGNATURE           PJMEDIA_CONF_SWITCH_SIGNATURE
 
49
#define SIGNATURE_PORT      PJMEDIA_PORT_SIGNATURE('S', 'W', 'T', 'P')
 
50
#define NORMAL_LEVEL        128
 
51
#define SLOT_TYPE           unsigned
 
52
#define INVALID_SLOT        ((SLOT_TYPE)-1)
 
53
#define BUFFER_SIZE         PJMEDIA_CONF_SWITCH_BOARD_BUF_SIZE
 
54
#define MAX_LEVEL           (32767)
 
55
#define MIN_LEVEL           (-32768)
 
56
 
 
57
/*
 
58
 * DON'T GET CONFUSED WITH TX/RX!!
 
59
 *
 
60
 * TX and RX directions are always viewed from the conference bridge's point
 
61
 * of view, and NOT from the port's point of view. So TX means the bridge
 
62
 * is transmitting to the port, RX means the bridge is receiving from the
 
63
 * port.
 
64
 */
 
65
 
 
66
 
 
67
/**
 
68
 * This is a port connected to conference bridge.
 
69
 */
 
70
struct conf_port
 
71
{
 
72
    SLOT_TYPE            slot;          /**< Array of listeners.            */
 
73
    pj_str_t             name;          /**< Port name.                     */
 
74
    pjmedia_port        *port;          /**< get_frame() and put_frame()    */
 
75
    pjmedia_port_op      rx_setting;    /**< Can we receive from this port  */
 
76
    pjmedia_port_op      tx_setting;    /**< Can we transmit to this port   */
 
77
    unsigned             listener_cnt;  /**< Number of listeners.           */
 
78
    SLOT_TYPE           *listener_slots;/**< Array of listeners.            */
 
79
    unsigned             transmitter_cnt;/**<Number of transmitters.        */
 
80
 
 
81
    /* Shortcut for port info. */
 
82
    pjmedia_port_info   *info;
 
83
    unsigned             samples_per_frame;
 
84
 
 
85
    /* Calculated signal levels: */
 
86
    unsigned             tx_level;      /**< Last tx level to this port.    */
 
87
    unsigned             rx_level;      /**< Last rx level from this port.  */
 
88
 
 
89
    /* The normalized signal level adjustment.
 
90
     * A value of 128 (NORMAL_LEVEL) means there's no adjustment.
 
91
     */
 
92
    unsigned             tx_adj_level;  /**< Adjustment for TX.             */
 
93
    unsigned             rx_adj_level;  /**< Adjustment for RX.             */
 
94
 
 
95
    pj_timestamp         ts_clock;
 
96
    pj_timestamp         ts_rx;
 
97
    pj_timestamp         ts_tx;
 
98
 
 
99
    /* Tx buffer is a temporary buffer to be used when there's mismatch 
 
100
     * between port's ptime with conference's ptime. This buffer is used as 
 
101
     * the source to buffer the samples until there are enough samples to 
 
102
     * fulfill a complete frame to be transmitted to the port.
 
103
     */
 
104
    pj_uint8_t           tx_buf[BUFFER_SIZE]; /**< Tx buffer.               */
 
105
};
 
106
 
 
107
 
 
108
/*
 
109
 * Conference bridge.
 
110
 */
 
111
struct pjmedia_conf
 
112
{
 
113
    unsigned              options;      /**< Bitmask options.               */
 
114
    unsigned              max_ports;    /**< Maximum ports.                 */
 
115
    unsigned              port_cnt;     /**< Current number of ports.       */
 
116
    unsigned              connect_cnt;  /**< Total number of connections    */
 
117
    pjmedia_port         *master_port;  /**< Port zero's port.              */
 
118
    char                  master_name_buf[80]; /**< Port0 name buffer.      */
 
119
    pj_mutex_t           *mutex;        /**< Conference mutex.              */
 
120
    struct conf_port    **ports;        /**< Array of ports.                */
 
121
    pj_uint8_t            buf[BUFFER_SIZE];     /**< Common buffer.         */
 
122
};
 
123
 
 
124
 
 
125
/* Prototypes */
 
126
static pj_status_t put_frame(pjmedia_port *this_port, 
 
127
                             pjmedia_frame *frame);
 
128
static pj_status_t get_frame(pjmedia_port *this_port, 
 
129
                             pjmedia_frame *frame);
 
130
static pj_status_t destroy_port(pjmedia_port *this_port);
 
131
 
 
132
 
 
133
/*
 
134
 * Create port.
 
135
 */
 
136
static pj_status_t create_conf_port( pj_pool_t *pool,
 
137
                                     pjmedia_conf *conf,
 
138
                                     pjmedia_port *port,
 
139
                                     const pj_str_t *name,
 
140
                                     struct conf_port **p_conf_port)
 
141
{
 
142
    struct conf_port *conf_port;
 
143
    pjmedia_frame *f;
 
144
 
 
145
    PJ_ASSERT_RETURN(pool && conf && port && name && p_conf_port, PJ_EINVAL);
 
146
 
 
147
    /* Check port's buffer size */
 
148
    if (port->info.fmt.id == PJMEDIA_FORMAT_PCM &&
 
149
        PJMEDIA_PIA_SPF(&port->info)*2 > BUFFER_SIZE - sizeof(pjmedia_frame))
 
150
    {
 
151
        pj_assert(!"Too small buffer size for audio switchboard. "
 
152
                   "Try increase PJMEDIA_CONF_SWITCH_BOARD_BUF_SIZE");
 
153
        return PJ_ETOOSMALL;
 
154
    }
 
155
 
 
156
    /* Create port. */
 
157
    conf_port = PJ_POOL_ZALLOC_T(pool, struct conf_port);
 
158
 
 
159
    /* Set name */
 
160
    pj_strdup_with_null(pool, &conf_port->name, name);
 
161
 
 
162
    /* Default has tx and rx enabled. */
 
163
    conf_port->rx_setting = PJMEDIA_PORT_ENABLE;
 
164
    conf_port->tx_setting = PJMEDIA_PORT_ENABLE;
 
165
 
 
166
    /* Default level adjustment is 128 (which means no adjustment) */
 
167
    conf_port->tx_adj_level = NORMAL_LEVEL;
 
168
    conf_port->rx_adj_level = NORMAL_LEVEL;
 
169
 
 
170
    /* Create transmit flag array */
 
171
    conf_port->listener_slots = (SLOT_TYPE*)
 
172
                                pj_pool_zalloc(pool, 
 
173
                                          conf->max_ports * sizeof(SLOT_TYPE));
 
174
    PJ_ASSERT_RETURN(conf_port->listener_slots, PJ_ENOMEM);
 
175
 
 
176
    /* Save some port's infos, for convenience. */
 
177
    conf_port->port = port;
 
178
    conf_port->info = &port->info;
 
179
    conf_port->samples_per_frame = PJMEDIA_PIA_SPF(&port->info);
 
180
 
 
181
    /* Init pjmedia_frame structure in the TX buffer. */
 
182
    f = (pjmedia_frame*)conf_port->tx_buf;
 
183
    f->buf = conf_port->tx_buf + sizeof(pjmedia_frame);
 
184
 
 
185
    /* Done */
 
186
    *p_conf_port = conf_port;
 
187
    return PJ_SUCCESS;
 
188
}
 
189
 
 
190
/*
 
191
 * Create port zero for the sound device.
 
192
 */
 
193
static pj_status_t create_sound_port( pj_pool_t *pool,
 
194
                                      pjmedia_conf *conf )
 
195
{
 
196
    struct conf_port *conf_port;
 
197
    pj_str_t name = { "Master/sound", 12 };
 
198
    pj_status_t status;
 
199
 
 
200
    status = create_conf_port(pool, conf, conf->master_port, &name, &conf_port);
 
201
    if (status != PJ_SUCCESS)
 
202
        return status;
 
203
 
 
204
     /* Add the port to the bridge */
 
205
    conf_port->slot = 0;
 
206
    conf->ports[0] = conf_port;
 
207
    conf->port_cnt++;
 
208
 
 
209
    PJ_LOG(5,(THIS_FILE, "Sound device successfully created for port 0"));
 
210
    return PJ_SUCCESS;
 
211
}
 
212
 
 
213
/*
 
214
 * Create conference bridge.
 
215
 */
 
216
PJ_DEF(pj_status_t) pjmedia_conf_create( pj_pool_t *pool,
 
217
                                         unsigned max_ports,
 
218
                                         unsigned clock_rate,
 
219
                                         unsigned channel_count,
 
220
                                         unsigned samples_per_frame,
 
221
                                         unsigned bits_per_sample,
 
222
                                         unsigned options,
 
223
                                         pjmedia_conf **p_conf )
 
224
{
 
225
    pjmedia_conf *conf;
 
226
    const pj_str_t name = { "Conf", 4 };
 
227
    pj_status_t status;
 
228
 
 
229
    /* Can only accept 16bits per sample, for now.. */
 
230
    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);
 
231
 
 
232
    PJ_LOG(5,(THIS_FILE, "Creating conference bridge with %d ports",
 
233
              max_ports));
 
234
 
 
235
    /* Create and init conf structure. */
 
236
    conf = PJ_POOL_ZALLOC_T(pool, pjmedia_conf);
 
237
    PJ_ASSERT_RETURN(conf, PJ_ENOMEM);
 
238
 
 
239
    conf->ports = (struct conf_port**) 
 
240
                  pj_pool_zalloc(pool, max_ports*sizeof(void*));
 
241
    PJ_ASSERT_RETURN(conf->ports, PJ_ENOMEM);
 
242
 
 
243
    conf->options = options;
 
244
    conf->max_ports = max_ports;
 
245
    
 
246
    /* Create and initialize the master port interface. */
 
247
    conf->master_port = PJ_POOL_ZALLOC_T(pool, pjmedia_port);
 
248
    PJ_ASSERT_RETURN(conf->master_port, PJ_ENOMEM);
 
249
    
 
250
    pjmedia_port_info_init(&conf->master_port->info, &name, SIGNATURE,
 
251
                           clock_rate, channel_count, bits_per_sample,
 
252
                           samples_per_frame);
 
253
 
 
254
    conf->master_port->port_data.pdata = conf;
 
255
    conf->master_port->port_data.ldata = 0;
 
256
 
 
257
    conf->master_port->get_frame = &get_frame;
 
258
    conf->master_port->put_frame = &put_frame;
 
259
    conf->master_port->on_destroy = &destroy_port;
 
260
 
 
261
 
 
262
    /* Create port zero for sound device. */
 
263
    status = create_sound_port(pool, conf);
 
264
    if (status != PJ_SUCCESS)
 
265
        return status;
 
266
 
 
267
    /* Create mutex. */
 
268
    status = pj_mutex_create_recursive(pool, "conf", &conf->mutex);
 
269
    if (status != PJ_SUCCESS)
 
270
        return status;
 
271
 
 
272
    /* Done */
 
273
 
 
274
    *p_conf = conf;
 
275
 
 
276
    return PJ_SUCCESS;
 
277
}
 
278
 
 
279
 
 
280
/*
 
281
 * Pause sound device.
 
282
 */
 
283
static pj_status_t pause_sound( pjmedia_conf *conf )
 
284
{
 
285
    /* Do nothing. */
 
286
    PJ_UNUSED_ARG(conf);
 
287
    return PJ_SUCCESS;
 
288
}
 
289
 
 
290
/*
 
291
 * Resume sound device.
 
292
 */
 
293
static pj_status_t resume_sound( pjmedia_conf *conf )
 
294
{
 
295
    /* Do nothing. */
 
296
    PJ_UNUSED_ARG(conf);
 
297
    return PJ_SUCCESS;
 
298
}
 
299
 
 
300
 
 
301
/**
 
302
 * Destroy conference bridge.
 
303
 */
 
304
PJ_DEF(pj_status_t) pjmedia_conf_destroy( pjmedia_conf *conf )
 
305
{
 
306
    PJ_ASSERT_RETURN(conf != NULL, PJ_EINVAL);
 
307
 
 
308
    /* Destroy mutex */
 
309
    pj_mutex_destroy(conf->mutex);
 
310
 
 
311
    return PJ_SUCCESS;
 
312
}
 
313
 
 
314
 
 
315
/*
 
316
 * Destroy the master port (will destroy the conference)
 
317
 */
 
318
static pj_status_t destroy_port(pjmedia_port *this_port)
 
319
{
 
320
    pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata;
 
321
    return pjmedia_conf_destroy(conf);
 
322
}
 
323
 
 
324
/*
 
325
 * Get port zero interface.
 
326
 */
 
327
PJ_DEF(pjmedia_port*) pjmedia_conf_get_master_port(pjmedia_conf *conf)
 
328
{
 
329
    /* Sanity check. */
 
330
    PJ_ASSERT_RETURN(conf != NULL, NULL);
 
331
 
 
332
    /* Can only return port interface when PJMEDIA_CONF_NO_DEVICE was
 
333
     * present in the option.
 
334
     */
 
335
    PJ_ASSERT_RETURN((conf->options & PJMEDIA_CONF_NO_DEVICE) != 0, NULL);
 
336
    
 
337
    return conf->master_port;
 
338
}
 
339
 
 
340
 
 
341
/*
 
342
 * Set master port name.
 
343
 */
 
344
PJ_DEF(pj_status_t) pjmedia_conf_set_port0_name(pjmedia_conf *conf,
 
345
                                                const pj_str_t *name)
 
346
{
 
347
    unsigned len;
 
348
 
 
349
    /* Sanity check. */
 
350
    PJ_ASSERT_RETURN(conf != NULL && name != NULL, PJ_EINVAL);
 
351
 
 
352
    len = name->slen;
 
353
    if (len > sizeof(conf->master_name_buf))
 
354
        len = sizeof(conf->master_name_buf);
 
355
    
 
356
    if (len > 0) pj_memcpy(conf->master_name_buf, name->ptr, len);
 
357
 
 
358
    conf->ports[0]->name.ptr = conf->master_name_buf;
 
359
    conf->ports[0]->name.slen = len;
 
360
 
 
361
    conf->master_port->info.name = conf->ports[0]->name;
 
362
 
 
363
    return PJ_SUCCESS;
 
364
}
 
365
 
 
366
/*
 
367
 * Add stream port to the conference bridge.
 
368
 */
 
369
PJ_DEF(pj_status_t) pjmedia_conf_add_port( pjmedia_conf *conf,
 
370
                                           pj_pool_t *pool,
 
371
                                           pjmedia_port *strm_port,
 
372
                                           const pj_str_t *port_name,
 
373
                                           unsigned *p_port )
 
374
{
 
375
    struct conf_port *conf_port;
 
376
    unsigned index;
 
377
    pj_status_t status;
 
378
 
 
379
    PJ_ASSERT_RETURN(conf && pool && strm_port, PJ_EINVAL);
 
380
    /*
 
381
    PJ_ASSERT_RETURN(conf->clock_rate == strm_port->info.clock_rate, 
 
382
                     PJMEDIA_ENCCLOCKRATE);
 
383
    PJ_ASSERT_RETURN(conf->channel_count == strm_port->info.channel_count, 
 
384
                     PJMEDIA_ENCCHANNEL);
 
385
    PJ_ASSERT_RETURN(conf->bits_per_sample == strm_port->info.bits_per_sample,
 
386
                     PJMEDIA_ENCBITS);
 
387
    */
 
388
 
 
389
    /* Port's samples per frame should be equal to or multiplication of 
 
390
     * conference's samples per frame.
 
391
     */
 
392
    /*
 
393
    Not sure if this is needed!
 
394
    PJ_ASSERT_RETURN((conf->samples_per_frame %
 
395
                     strm_port->info.samples_per_frame==0) ||
 
396
                     (strm_port->info.samples_per_frame %
 
397
                     conf->samples_per_frame==0),
 
398
                     PJMEDIA_ENCSAMPLESPFRAME);
 
399
    */
 
400
 
 
401
    /* If port_name is not specified, use the port's name */
 
402
    if (!port_name)
 
403
        port_name = &strm_port->info.name;
 
404
 
 
405
    pj_mutex_lock(conf->mutex);
 
406
 
 
407
    if (conf->port_cnt >= conf->max_ports) {
 
408
        pj_assert(!"Too many ports");
 
409
        pj_mutex_unlock(conf->mutex);
 
410
        return PJ_ETOOMANY;
 
411
    }
 
412
 
 
413
    /* Find empty port in the conference bridge. */
 
414
    for (index=0; index < conf->max_ports; ++index) {
 
415
        if (conf->ports[index] == NULL)
 
416
            break;
 
417
    }
 
418
 
 
419
    pj_assert(index != conf->max_ports);
 
420
 
 
421
    /* Create conf port structure. */
 
422
    status = create_conf_port(pool, conf, strm_port, port_name, &conf_port);
 
423
    if (status != PJ_SUCCESS) {
 
424
        pj_mutex_unlock(conf->mutex);
 
425
        return status;
 
426
    }
 
427
 
 
428
    /* Put the port. */
 
429
    conf_port->slot = index;
 
430
    conf->ports[index] = conf_port;
 
431
    conf->port_cnt++;
 
432
 
 
433
    /* Done. */
 
434
    if (p_port) {
 
435
        *p_port = index;
 
436
    }
 
437
 
 
438
    pj_mutex_unlock(conf->mutex);
 
439
 
 
440
    return PJ_SUCCESS;
 
441
}
 
442
 
 
443
 
 
444
/*
 
445
 * Add passive port.
 
446
 */
 
447
PJ_DEF(pj_status_t) pjmedia_conf_add_passive_port( pjmedia_conf *conf,
 
448
                                                   pj_pool_t *pool,
 
449
                                                   const pj_str_t *name,
 
450
                                                   unsigned clock_rate,
 
451
                                                   unsigned channel_count,
 
452
                                                   unsigned samples_per_frame,
 
453
                                                   unsigned bits_per_sample,
 
454
                                                   unsigned options,
 
455
                                                   unsigned *p_slot,
 
456
                                                   pjmedia_port **p_port )
 
457
{
 
458
    PJ_UNUSED_ARG(conf);
 
459
    PJ_UNUSED_ARG(pool);
 
460
    PJ_UNUSED_ARG(name);
 
461
    PJ_UNUSED_ARG(clock_rate);
 
462
    PJ_UNUSED_ARG(channel_count);
 
463
    PJ_UNUSED_ARG(samples_per_frame);
 
464
    PJ_UNUSED_ARG(bits_per_sample);
 
465
    PJ_UNUSED_ARG(options);
 
466
    PJ_UNUSED_ARG(p_slot);
 
467
    PJ_UNUSED_ARG(p_port);
 
468
 
 
469
    return PJ_ENOTSUP;
 
470
}
 
471
 
 
472
 
 
473
 
 
474
/*
 
475
 * Change TX and RX settings for the port.
 
476
 */
 
477
PJ_DEF(pj_status_t) pjmedia_conf_configure_port( pjmedia_conf *conf,
 
478
                                                  unsigned slot,
 
479
                                                  pjmedia_port_op tx,
 
480
                                                  pjmedia_port_op rx)
 
481
{
 
482
    struct conf_port *conf_port;
 
483
 
 
484
    /* Check arguments */
 
485
    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);
 
486
 
 
487
    pj_mutex_lock(conf->mutex);
 
488
 
 
489
    /* Port must be valid. */
 
490
    conf_port = conf->ports[slot];
 
491
    if (conf_port == NULL) {
 
492
        pj_mutex_unlock(conf->mutex);
 
493
        return PJ_EINVAL;
 
494
    }
 
495
 
 
496
    if (tx != PJMEDIA_PORT_NO_CHANGE)
 
497
        conf_port->tx_setting = tx;
 
498
 
 
499
    if (rx != PJMEDIA_PORT_NO_CHANGE)
 
500
        conf_port->rx_setting = rx;
 
501
 
 
502
    pj_mutex_unlock(conf->mutex);
 
503
 
 
504
    return PJ_SUCCESS;
 
505
}
 
506
 
 
507
 
 
508
/*
 
509
 * Connect port.
 
510
 */
 
511
PJ_DEF(pj_status_t) pjmedia_conf_connect_port( pjmedia_conf *conf,
 
512
                                               unsigned src_slot,
 
513
                                               unsigned sink_slot,
 
514
                                               int level )
 
515
{
 
516
    struct conf_port *src_port, *dst_port;
 
517
    pj_bool_t start_sound = PJ_FALSE;
 
518
    pjmedia_audio_format_detail *src_afd, *dst_afd;
 
519
    unsigned i;
 
520
 
 
521
    /* Check arguments */
 
522
    PJ_ASSERT_RETURN(conf && src_slot<conf->max_ports && 
 
523
                     sink_slot<conf->max_ports, PJ_EINVAL);
 
524
 
 
525
    /* For now, level MUST be zero. */
 
526
    PJ_ASSERT_RETURN(level == 0, PJ_EINVAL);
 
527
 
 
528
    pj_mutex_lock(conf->mutex);
 
529
 
 
530
    /* Ports must be valid. */
 
531
    src_port = conf->ports[src_slot];
 
532
    dst_port = conf->ports[sink_slot];
 
533
    if (!src_port || !dst_port) {
 
534
        pj_mutex_unlock(conf->mutex);
 
535
        return PJ_EINVAL;
 
536
    }
 
537
 
 
538
    src_afd = pjmedia_format_get_audio_format_detail(&src_port->info->fmt, 1);
 
539
    dst_afd = pjmedia_format_get_audio_format_detail(&dst_port->info->fmt, 1);
 
540
 
 
541
    /* Format must match. */
 
542
    if (src_port->info->fmt.id != dst_port->info->fmt.id ||
 
543
        src_afd->avg_bps != dst_afd->avg_bps)
 
544
    {
 
545
        pj_mutex_unlock(conf->mutex);
 
546
        return PJMEDIA_ENOTCOMPATIBLE;
 
547
    }
 
548
 
 
549
    /* Clock rate must match. */
 
550
    if (src_afd->clock_rate != dst_afd->clock_rate) {
 
551
        pj_mutex_unlock(conf->mutex);
 
552
        return PJMEDIA_ENCCLOCKRATE;
 
553
    }
 
554
 
 
555
    /* Channel count must match. */
 
556
    if (src_afd->channel_count != dst_afd->channel_count) {
 
557
        pj_mutex_unlock(conf->mutex);
 
558
        return PJMEDIA_ENCCHANNEL;
 
559
    }
 
560
 
 
561
    /* Source and sink ptime must be equal or a multiplication factor. */
 
562
    if ((src_afd->frame_time_usec % dst_afd->frame_time_usec != 0) &&
 
563
        (dst_afd->frame_time_usec % src_afd->frame_time_usec != 0))
 
564
    {
 
565
        pj_mutex_unlock(conf->mutex);
 
566
        return PJMEDIA_ENCSAMPLESPFRAME;
 
567
    }
 
568
    
 
569
    /* If sink is currently listening to other ports, it needs to be released
 
570
     * first before the new connection made.
 
571
     */ 
 
572
    if (dst_port->transmitter_cnt > 0) {
 
573
        unsigned j;
 
574
        pj_bool_t transmitter_found = PJ_FALSE;
 
575
 
 
576
        pj_assert(dst_port->transmitter_cnt == 1);
 
577
        for (j=0; j<conf->max_ports && !transmitter_found; ++j) {
 
578
            if (conf->ports[j]) {
 
579
                unsigned k;
 
580
 
 
581
                for (k=0; k < conf->ports[j]->listener_cnt; ++k) {
 
582
                    if (conf->ports[j]->listener_slots[k] == sink_slot) {
 
583
                        PJ_LOG(2,(THIS_FILE, "Connection [%d->%d] is "
 
584
                                  "disconnected for new connection [%d->%d]",
 
585
                                  j, sink_slot, src_slot, sink_slot));
 
586
                        pjmedia_conf_disconnect_port(conf, j, sink_slot);
 
587
                        transmitter_found = PJ_TRUE;
 
588
                        break;
 
589
                    }
 
590
                }
 
591
            }
 
592
        }
 
593
        pj_assert(dst_port->transmitter_cnt == 0);
 
594
    }
 
595
 
 
596
    /* Check if connection has been made */
 
597
    for (i=0; i<src_port->listener_cnt; ++i) {
 
598
        if (src_port->listener_slots[i] == sink_slot)
 
599
            break;
 
600
    }
 
601
 
 
602
    /* Update master port info shortcut, note that application may update
 
603
     * the master port info when the audio device needs to be reopened with
 
604
     * a new format to match to ports connection format.
 
605
     */
 
606
    conf->ports[0]->samples_per_frame = PJMEDIA_PIA_SPF(conf->ports[0]->info);
 
607
 
 
608
    if (i == src_port->listener_cnt) {
 
609
        src_port->listener_slots[src_port->listener_cnt] = sink_slot;
 
610
        ++conf->connect_cnt;
 
611
        ++src_port->listener_cnt;
 
612
        ++dst_port->transmitter_cnt;
 
613
 
 
614
        if (conf->connect_cnt == 1)
 
615
            start_sound = 1;
 
616
 
 
617
        PJ_LOG(4,(THIS_FILE,"Port %d (%.*s) transmitting to port %d (%.*s)",
 
618
                  src_slot,
 
619
                  (int)src_port->name.slen,
 
620
                  src_port->name.ptr,
 
621
                  sink_slot,
 
622
                  (int)dst_port->name.slen,
 
623
                  dst_port->name.ptr));
 
624
    }
 
625
 
 
626
    pj_mutex_unlock(conf->mutex);
 
627
 
 
628
    /* Sound device must be started without mutex, otherwise the
 
629
     * sound thread will deadlock (?)
 
630
     */
 
631
    if (start_sound)
 
632
        resume_sound(conf);
 
633
 
 
634
    return PJ_SUCCESS;
 
635
}
 
636
 
 
637
 
 
638
/*
 
639
 * Disconnect port
 
640
 */
 
641
PJ_DEF(pj_status_t) pjmedia_conf_disconnect_port( pjmedia_conf *conf,
 
642
                                                  unsigned src_slot,
 
643
                                                  unsigned sink_slot )
 
644
{
 
645
    struct conf_port *src_port, *dst_port;
 
646
    unsigned i;
 
647
 
 
648
    /* Check arguments */
 
649
    PJ_ASSERT_RETURN(conf && src_slot<conf->max_ports && 
 
650
                     sink_slot<conf->max_ports, PJ_EINVAL);
 
651
 
 
652
    pj_mutex_lock(conf->mutex);
 
653
 
 
654
    /* Ports must be valid. */
 
655
    src_port = conf->ports[src_slot];
 
656
    dst_port = conf->ports[sink_slot];
 
657
    if (!src_port || !dst_port) {
 
658
        pj_mutex_unlock(conf->mutex);
 
659
        return PJ_EINVAL;
 
660
    }
 
661
 
 
662
    /* Check if connection has been made */
 
663
    for (i=0; i<src_port->listener_cnt; ++i) {
 
664
        if (src_port->listener_slots[i] == sink_slot)
 
665
            break;
 
666
    }
 
667
 
 
668
    if (i != src_port->listener_cnt) {
 
669
        pjmedia_frame_ext *f;
 
670
 
 
671
        pj_assert(src_port->listener_cnt > 0 && 
 
672
                  src_port->listener_cnt < conf->max_ports);
 
673
        pj_assert(dst_port->transmitter_cnt > 0 && 
 
674
                  dst_port->transmitter_cnt < conf->max_ports);
 
675
        pj_array_erase(src_port->listener_slots, sizeof(SLOT_TYPE), 
 
676
                       src_port->listener_cnt, i);
 
677
        --conf->connect_cnt;
 
678
        --src_port->listener_cnt;
 
679
        --dst_port->transmitter_cnt;
 
680
        
 
681
        /* Cleanup listener TX buffer. */
 
682
        f = (pjmedia_frame_ext*)dst_port->tx_buf;
 
683
        f->base.type = PJMEDIA_FRAME_TYPE_NONE;
 
684
        f->base.size = 0;
 
685
        f->samples_cnt = 0;
 
686
        f->subframe_cnt = 0;
 
687
 
 
688
        PJ_LOG(4,(THIS_FILE,
 
689
                  "Port %d (%.*s) stop transmitting to port %d (%.*s)",
 
690
                  src_slot,
 
691
                  (int)src_port->name.slen,
 
692
                  src_port->name.ptr,
 
693
                  sink_slot,
 
694
                  (int)dst_port->name.slen,
 
695
                  dst_port->name.ptr));
 
696
    }
 
697
 
 
698
    pj_mutex_unlock(conf->mutex);
 
699
 
 
700
    if (conf->connect_cnt == 0) {
 
701
        pause_sound(conf);
 
702
    }
 
703
 
 
704
    return PJ_SUCCESS;
 
705
}
 
706
 
 
707
/*
 
708
 * Get number of ports currently registered to the conference bridge.
 
709
 */
 
710
PJ_DEF(unsigned) pjmedia_conf_get_port_count(pjmedia_conf *conf)
 
711
{
 
712
    return conf->port_cnt;
 
713
}
 
714
 
 
715
/*
 
716
 * Get total number of ports connections currently set up in the bridge.
 
717
 */
 
718
PJ_DEF(unsigned) pjmedia_conf_get_connect_count(pjmedia_conf *conf)
 
719
{
 
720
    return conf->connect_cnt;
 
721
}
 
722
 
 
723
 
 
724
/*
 
725
 * Remove the specified port.
 
726
 */
 
727
PJ_DEF(pj_status_t) pjmedia_conf_remove_port( pjmedia_conf *conf,
 
728
                                              unsigned port )
 
729
{
 
730
    struct conf_port *conf_port;
 
731
    unsigned i;
 
732
 
 
733
    /* Check arguments */
 
734
    PJ_ASSERT_RETURN(conf && port < conf->max_ports, PJ_EINVAL);
 
735
 
 
736
    /* Suspend the sound devices.
 
737
     * Don't want to remove port while port is being accessed by sound
 
738
     * device's threads!
 
739
     */
 
740
 
 
741
    pj_mutex_lock(conf->mutex);
 
742
 
 
743
    /* Port must be valid. */
 
744
    conf_port = conf->ports[port];
 
745
    if (conf_port == NULL) {
 
746
        pj_mutex_unlock(conf->mutex);
 
747
        return PJ_EINVAL;
 
748
    }
 
749
 
 
750
    conf_port->tx_setting = PJMEDIA_PORT_DISABLE;
 
751
    conf_port->rx_setting = PJMEDIA_PORT_DISABLE;
 
752
 
 
753
    /* Remove this port from transmit array of other ports. */
 
754
    for (i=0; i<conf->max_ports; ++i) {
 
755
        unsigned j;
 
756
        struct conf_port *src_port;
 
757
 
 
758
        src_port = conf->ports[i];
 
759
 
 
760
        if (!src_port)
 
761
            continue;
 
762
 
 
763
        if (src_port->listener_cnt == 0)
 
764
            continue;
 
765
 
 
766
        for (j=0; j<src_port->listener_cnt; ++j) {
 
767
            if (src_port->listener_slots[j] == port) {
 
768
                pj_array_erase(src_port->listener_slots, sizeof(SLOT_TYPE),
 
769
                               src_port->listener_cnt, j);
 
770
                pj_assert(conf->connect_cnt > 0);
 
771
                --conf->connect_cnt;
 
772
                --src_port->listener_cnt;
 
773
                break;
 
774
            }
 
775
        }
 
776
    }
 
777
 
 
778
    /* Update transmitter_cnt of ports we're transmitting to */
 
779
    while (conf_port->listener_cnt) {
 
780
        unsigned dst_slot;
 
781
        struct conf_port *dst_port;
 
782
        pjmedia_frame_ext *f;
 
783
 
 
784
        dst_slot = conf_port->listener_slots[conf_port->listener_cnt-1];
 
785
        dst_port = conf->ports[dst_slot];
 
786
        --dst_port->transmitter_cnt;
 
787
        --conf_port->listener_cnt;
 
788
        pj_assert(conf->connect_cnt > 0);
 
789
        --conf->connect_cnt;
 
790
 
 
791
        /* Cleanup & reinit listener TX buffer. */
 
792
        f = (pjmedia_frame_ext*)dst_port->tx_buf;
 
793
        f->base.type = PJMEDIA_FRAME_TYPE_NONE;
 
794
        f->base.size = 0;
 
795
        f->samples_cnt = 0;
 
796
        f->subframe_cnt = 0;
 
797
    }
 
798
 
 
799
    /* Remove the port. */
 
800
    conf->ports[port] = NULL;
 
801
    --conf->port_cnt;
 
802
 
 
803
    pj_mutex_unlock(conf->mutex);
 
804
 
 
805
 
 
806
    /* Stop sound if there's no connection. */
 
807
    if (conf->connect_cnt == 0) {
 
808
        pause_sound(conf);
 
809
    }
 
810
 
 
811
    return PJ_SUCCESS;
 
812
}
 
813
 
 
814
 
 
815
/*
 
816
 * Enum ports.
 
817
 */
 
818
PJ_DEF(pj_status_t) pjmedia_conf_enum_ports( pjmedia_conf *conf,
 
819
                                             unsigned ports[],
 
820
                                             unsigned *p_count )
 
821
{
 
822
    unsigned i, count=0;
 
823
 
 
824
    PJ_ASSERT_RETURN(conf && p_count && ports, PJ_EINVAL);
 
825
 
 
826
    /* Lock mutex */
 
827
    pj_mutex_lock(conf->mutex);
 
828
 
 
829
    for (i=0; i<conf->max_ports && count<*p_count; ++i) {
 
830
        if (!conf->ports[i])
 
831
            continue;
 
832
 
 
833
        ports[count++] = i;
 
834
    }
 
835
 
 
836
    /* Unlock mutex */
 
837
    pj_mutex_unlock(conf->mutex);
 
838
 
 
839
    *p_count = count;
 
840
    return PJ_SUCCESS;
 
841
}
 
842
 
 
843
/*
 
844
 * Get port info
 
845
 */
 
846
PJ_DEF(pj_status_t) pjmedia_conf_get_port_info( pjmedia_conf *conf,
 
847
                                                unsigned slot,
 
848
                                                pjmedia_conf_port_info *info)
 
849
{
 
850
    struct conf_port *conf_port;
 
851
    const pjmedia_audio_format_detail *afd;
 
852
 
 
853
    /* Check arguments */
 
854
    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);
 
855
 
 
856
    /* Lock mutex */
 
857
    pj_mutex_lock(conf->mutex);
 
858
 
 
859
    /* Port must be valid. */
 
860
    conf_port = conf->ports[slot];
 
861
    if (conf_port == NULL) {
 
862
        pj_mutex_unlock(conf->mutex);
 
863
        return PJ_EINVAL;
 
864
    }
 
865
 
 
866
    afd = pjmedia_format_get_audio_format_detail(&conf_port->info->fmt, 1);
 
867
 
 
868
    pj_bzero(info, sizeof(pjmedia_conf_port_info));
 
869
 
 
870
    info->slot = slot;
 
871
    info->name = conf_port->name;
 
872
    info->tx_setting = conf_port->tx_setting;
 
873
    info->rx_setting = conf_port->rx_setting;
 
874
    info->listener_cnt = conf_port->listener_cnt;
 
875
    info->listener_slots = conf_port->listener_slots;
 
876
    info->transmitter_cnt = conf_port->transmitter_cnt;
 
877
    info->clock_rate = afd->clock_rate;
 
878
    info->channel_count = afd->channel_count;
 
879
    info->samples_per_frame = conf_port->samples_per_frame;
 
880
    info->bits_per_sample = afd->bits_per_sample;
 
881
    info->format = conf_port->port->info.fmt;
 
882
    info->tx_adj_level = conf_port->tx_adj_level - NORMAL_LEVEL;
 
883
    info->rx_adj_level = conf_port->rx_adj_level - NORMAL_LEVEL;
 
884
 
 
885
    /* Unlock mutex */
 
886
    pj_mutex_unlock(conf->mutex);
 
887
 
 
888
    return PJ_SUCCESS;
 
889
}
 
890
 
 
891
 
 
892
PJ_DEF(pj_status_t) pjmedia_conf_get_ports_info(pjmedia_conf *conf,
 
893
                                                unsigned *size,
 
894
                                                pjmedia_conf_port_info info[])
 
895
{
 
896
    unsigned i, count=0;
 
897
 
 
898
    PJ_ASSERT_RETURN(conf && size && info, PJ_EINVAL);
 
899
 
 
900
    /* Lock mutex */
 
901
    pj_mutex_lock(conf->mutex);
 
902
 
 
903
    for (i=0; i<conf->max_ports && count<*size; ++i) {
 
904
        if (!conf->ports[i])
 
905
            continue;
 
906
 
 
907
        pjmedia_conf_get_port_info(conf, i, &info[count]);
 
908
        ++count;
 
909
    }
 
910
 
 
911
    /* Unlock mutex */
 
912
    pj_mutex_unlock(conf->mutex);
 
913
 
 
914
    *size = count;
 
915
    return PJ_SUCCESS;
 
916
}
 
917
 
 
918
 
 
919
/*
 
920
 * Get signal level.
 
921
 */
 
922
PJ_DEF(pj_status_t) pjmedia_conf_get_signal_level( pjmedia_conf *conf,
 
923
                                                   unsigned slot,
 
924
                                                   unsigned *tx_level,
 
925
                                                   unsigned *rx_level)
 
926
{
 
927
    struct conf_port *conf_port;
 
928
 
 
929
    /* Check arguments */
 
930
    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);
 
931
 
 
932
    /* Lock mutex */
 
933
    pj_mutex_lock(conf->mutex);
 
934
 
 
935
    /* Port must be valid. */
 
936
    conf_port = conf->ports[slot];
 
937
    if (conf_port == NULL) {
 
938
        pj_mutex_unlock(conf->mutex);
 
939
        return PJ_EINVAL;
 
940
    }
 
941
 
 
942
    if (tx_level != NULL) {
 
943
        *tx_level = conf_port->tx_level;
 
944
    }
 
945
 
 
946
    if (rx_level != NULL) 
 
947
        *rx_level = conf_port->rx_level;
 
948
 
 
949
    /* Unlock mutex */
 
950
    pj_mutex_unlock(conf->mutex);
 
951
 
 
952
    return PJ_SUCCESS;
 
953
}
 
954
 
 
955
 
 
956
/*
 
957
 * Adjust RX level of individual port.
 
958
 */
 
959
PJ_DEF(pj_status_t) pjmedia_conf_adjust_rx_level( pjmedia_conf *conf,
 
960
                                                  unsigned slot,
 
961
                                                  int adj_level )
 
962
{
 
963
    struct conf_port *conf_port;
 
964
 
 
965
    /* Check arguments */
 
966
    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);
 
967
 
 
968
    /* Value must be from -128 to +127 */
 
969
    /* Disabled, you can put more than +127, at your own risk: 
 
970
     PJ_ASSERT_RETURN(adj_level >= -128 && adj_level <= 127, PJ_EINVAL);
 
971
     */
 
972
    PJ_ASSERT_RETURN(adj_level >= -128, PJ_EINVAL);
 
973
 
 
974
    /* Lock mutex */
 
975
    pj_mutex_lock(conf->mutex);
 
976
 
 
977
    /* Port must be valid. */
 
978
    conf_port = conf->ports[slot];
 
979
    if (conf_port == NULL) {
 
980
        pj_mutex_unlock(conf->mutex);
 
981
        return PJ_EINVAL;
 
982
    }
 
983
 
 
984
    /* Level adjustment is applicable only for ports that work with raw PCM. */
 
985
    PJ_ASSERT_RETURN(conf_port->info->fmt.id == PJMEDIA_FORMAT_L16,
 
986
                     PJ_EIGNORED);
 
987
 
 
988
    /* Set normalized adjustment level. */
 
989
    conf_port->rx_adj_level = adj_level + NORMAL_LEVEL;
 
990
 
 
991
    /* Unlock mutex */
 
992
    pj_mutex_unlock(conf->mutex);
 
993
 
 
994
    return PJ_SUCCESS;
 
995
}
 
996
 
 
997
 
 
998
/*
 
999
 * Adjust TX level of individual port.
 
1000
 */
 
1001
PJ_DEF(pj_status_t) pjmedia_conf_adjust_tx_level( pjmedia_conf *conf,
 
1002
                                                  unsigned slot,
 
1003
                                                  int adj_level )
 
1004
{
 
1005
    struct conf_port *conf_port;
 
1006
 
 
1007
    /* Check arguments */
 
1008
    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);
 
1009
 
 
1010
    /* Value must be from -128 to +127 */
 
1011
    /* Disabled, you can put more than +127,, at your own risk:
 
1012
     PJ_ASSERT_RETURN(adj_level >= -128 && adj_level <= 127, PJ_EINVAL);
 
1013
     */
 
1014
    PJ_ASSERT_RETURN(adj_level >= -128, PJ_EINVAL);
 
1015
 
 
1016
    /* Lock mutex */
 
1017
    pj_mutex_lock(conf->mutex);
 
1018
 
 
1019
    /* Port must be valid. */
 
1020
    conf_port = conf->ports[slot];
 
1021
    if (conf_port == NULL) {
 
1022
        pj_mutex_unlock(conf->mutex);
 
1023
        return PJ_EINVAL;
 
1024
    }
 
1025
 
 
1026
    /* Level adjustment is applicable only for ports that work with raw PCM. */
 
1027
    PJ_ASSERT_RETURN(conf_port->info->fmt.id == PJMEDIA_FORMAT_L16,
 
1028
                     PJ_EIGNORED);
 
1029
 
 
1030
    /* Set normalized adjustment level. */
 
1031
    conf_port->tx_adj_level = adj_level + NORMAL_LEVEL;
 
1032
 
 
1033
    /* Unlock mutex */
 
1034
    pj_mutex_unlock(conf->mutex);
 
1035
 
 
1036
    return PJ_SUCCESS;
 
1037
}
 
1038
 
 
1039
/* Deliver frm_src to a listener port, eventually call  port's put_frame() 
 
1040
 * when samples count in the frm_dst are equal to port's samples_per_frame.
 
1041
 */
 
1042
static pj_status_t write_frame(struct conf_port *cport_dst,
 
1043
                               const pjmedia_frame *frm_src)
 
1044
{
 
1045
    pjmedia_frame *frm_dst = (pjmedia_frame*)cport_dst->tx_buf;
 
1046
    
 
1047
    PJ_TODO(MAKE_SURE_DEST_FRAME_HAS_ENOUGH_SPACE);
 
1048
 
 
1049
    frm_dst->type = frm_src->type;
 
1050
    frm_dst->timestamp = cport_dst->ts_tx;
 
1051
 
 
1052
    if (frm_src->type == PJMEDIA_FRAME_TYPE_EXTENDED) {
 
1053
 
 
1054
        pjmedia_frame_ext *f_src = (pjmedia_frame_ext*)frm_src;
 
1055
        pjmedia_frame_ext *f_dst = (pjmedia_frame_ext*)frm_dst;
 
1056
        unsigned i;
 
1057
 
 
1058
        for (i = 0; i < f_src->subframe_cnt; ++i) {
 
1059
            pjmedia_frame_ext_subframe *sf;
 
1060
            
 
1061
            /* Copy frame to listener's TX buffer. */
 
1062
            sf = pjmedia_frame_ext_get_subframe(f_src, i);
 
1063
            pjmedia_frame_ext_append_subframe(f_dst, sf->data, sf->bitlen, 
 
1064
                                              f_src->samples_cnt / 
 
1065
                                              f_src->subframe_cnt);
 
1066
 
 
1067
            /* Check if it's time to deliver the TX buffer to listener, 
 
1068
             * i.e: samples count in TX buffer equal to listener's
 
1069
             * samples per frame.
 
1070
             */
 
1071
            if (f_dst->samples_cnt >= cport_dst->samples_per_frame)
 
1072
            {
 
1073
                if (cport_dst->slot) {
 
1074
                    pjmedia_port_put_frame(cport_dst->port, 
 
1075
                                           (pjmedia_frame*)f_dst);
 
1076
 
 
1077
                    /* Reset TX buffer. */
 
1078
                    f_dst->subframe_cnt = 0;
 
1079
                    f_dst->samples_cnt = 0;
 
1080
                }
 
1081
 
 
1082
                /* Update TX timestamp. */
 
1083
                pj_add_timestamp32(&cport_dst->ts_tx,
 
1084
                                   cport_dst->samples_per_frame);
 
1085
            }
 
1086
        }
 
1087
 
 
1088
    } else if (frm_src->type == PJMEDIA_FRAME_TYPE_AUDIO) {
 
1089
 
 
1090
        pj_int16_t *f_start, *f_end;
 
1091
 
 
1092
        f_start = (pj_int16_t*)frm_src->buf;
 
1093
        f_end   = f_start + (frm_src->size >> 1);
 
1094
 
 
1095
        while (f_start < f_end) {
 
1096
            unsigned nsamples_to_copy, nsamples_req;
 
1097
 
 
1098
            /* Copy frame to listener's TX buffer.
 
1099
             * Note that if the destination is port 0, just copy the whole
 
1100
             * available samples.
 
1101
             */
 
1102
            nsamples_to_copy = f_end - f_start;
 
1103
            nsamples_req = cport_dst->samples_per_frame -
 
1104
                          (frm_dst->size>>1);
 
1105
            if (cport_dst->slot && nsamples_to_copy > nsamples_req)
 
1106
                nsamples_to_copy = nsamples_req;
 
1107
 
 
1108
            /* Adjust TX level. */
 
1109
            if (cport_dst->tx_adj_level != NORMAL_LEVEL) {
 
1110
                pj_int16_t *p, *p_end;
 
1111
 
 
1112
                p = f_start;
 
1113
                p_end = p + nsamples_to_copy;
 
1114
                while (p < p_end) {
 
1115
                    pj_int32_t itemp = *p;
 
1116
 
 
1117
                    /* Adjust the level */
 
1118
                    itemp = (itemp * cport_dst->tx_adj_level) >> 7;
 
1119
 
 
1120
                    /* Clip the signal if it's too loud */
 
1121
                    if (itemp > MAX_LEVEL) itemp = MAX_LEVEL;
 
1122
                    else if (itemp < MIN_LEVEL) itemp = MIN_LEVEL;
 
1123
 
 
1124
                    /* Put back in the buffer. */
 
1125
                    *p = (pj_int16_t)itemp;
 
1126
                    ++p;
 
1127
                }
 
1128
            }
 
1129
 
 
1130
            pjmedia_copy_samples((pj_int16_t*)frm_dst->buf + (frm_dst->size>>1),
 
1131
                                 f_start, 
 
1132
                                 nsamples_to_copy);
 
1133
            frm_dst->size += nsamples_to_copy << 1;
 
1134
            f_start += nsamples_to_copy;
 
1135
 
 
1136
            /* Check if it's time to deliver the TX buffer to listener, 
 
1137
             * i.e: samples count in TX buffer equal to listener's
 
1138
             * samples per frame. Note that for destination port 0 this
 
1139
             * function will just populate all samples in the TX buffer.
 
1140
             */
 
1141
            if (cport_dst->slot == 0) {
 
1142
                /* Update TX timestamp. */
 
1143
                pj_add_timestamp32(&cport_dst->ts_tx, nsamples_to_copy);
 
1144
            } else if ((frm_dst->size >> 1) == 
 
1145
                       cport_dst->samples_per_frame)
 
1146
            {
 
1147
                pjmedia_port_put_frame(cport_dst->port, frm_dst);
 
1148
 
 
1149
                /* Reset TX buffer. */
 
1150
                frm_dst->size = 0;
 
1151
 
 
1152
                /* Update TX timestamp. */
 
1153
                pj_add_timestamp32(&cport_dst->ts_tx, 
 
1154
                                   cport_dst->samples_per_frame);
 
1155
            }
 
1156
        }
 
1157
 
 
1158
    } else if (frm_src->type == PJMEDIA_FRAME_TYPE_NONE) {
 
1159
 
 
1160
        /* Check port format. */
 
1161
        if (cport_dst->port &&
 
1162
            cport_dst->port->info.fmt.id == PJMEDIA_FORMAT_L16)
 
1163
        {
 
1164
            /* When there is already some samples in listener's TX buffer, 
 
1165
             * pad the buffer with "zero samples".
 
1166
             */
 
1167
            if (frm_dst->size != 0) {
 
1168
                pjmedia_zero_samples((pj_int16_t*)frm_dst->buf,
 
1169
                                     cport_dst->samples_per_frame -
 
1170
                                     (frm_dst->size>>1));
 
1171
 
 
1172
                frm_dst->type = PJMEDIA_FRAME_TYPE_AUDIO;
 
1173
                frm_dst->size = cport_dst->samples_per_frame << 1;
 
1174
                if (cport_dst->slot) {
 
1175
                    pjmedia_port_put_frame(cport_dst->port, frm_dst);
 
1176
 
 
1177
                    /* Reset TX buffer. */
 
1178
                    frm_dst->size = 0;
 
1179
                }
 
1180
 
 
1181
                /* Update TX timestamp. */
 
1182
                pj_add_timestamp32(&cport_dst->ts_tx, 
 
1183
                                   cport_dst->samples_per_frame);
 
1184
            }
 
1185
        } else {
 
1186
            pjmedia_frame_ext *f_dst = (pjmedia_frame_ext*)frm_dst;
 
1187
 
 
1188
            if (f_dst->samples_cnt != 0) {
 
1189
                frm_dst->type = PJMEDIA_FRAME_TYPE_EXTENDED;
 
1190
                pjmedia_frame_ext_append_subframe(f_dst, NULL, 0, (pj_uint16_t)
 
1191
                    (cport_dst->samples_per_frame - f_dst->samples_cnt));
 
1192
                if (cport_dst->slot) {
 
1193
                    pjmedia_port_put_frame(cport_dst->port, frm_dst);
 
1194
 
 
1195
                    /* Reset TX buffer. */
 
1196
                    f_dst->subframe_cnt = 0;
 
1197
                    f_dst->samples_cnt = 0;
 
1198
                }
 
1199
 
 
1200
                /* Update TX timestamp. */
 
1201
                pj_add_timestamp32(&cport_dst->ts_tx, 
 
1202
                                   cport_dst->samples_per_frame);
 
1203
            }
 
1204
        }
 
1205
 
 
1206
        /* Synchronize clock. */
 
1207
        while (pj_cmp_timestamp(&cport_dst->ts_clock, 
 
1208
                                &cport_dst->ts_tx) > 0)
 
1209
        {
 
1210
            frm_dst->type = PJMEDIA_FRAME_TYPE_NONE;
 
1211
            frm_dst->timestamp = cport_dst->ts_tx;
 
1212
            if (cport_dst->slot)
 
1213
                pjmedia_port_put_frame(cport_dst->port, frm_dst);
 
1214
 
 
1215
            /* Update TX timestamp. */
 
1216
            pj_add_timestamp32(&cport_dst->ts_tx, cport_dst->samples_per_frame);
 
1217
        }
 
1218
    }
 
1219
 
 
1220
    return PJ_SUCCESS;
 
1221
}
 
1222
 
 
1223
/*
 
1224
 * Player callback.
 
1225
 */
 
1226
static pj_status_t get_frame(pjmedia_port *this_port, 
 
1227
                             pjmedia_frame *frame)
 
1228
{
 
1229
    pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata;
 
1230
    unsigned ci, i;
 
1231
    
 
1232
    /* Lock mutex */
 
1233
    pj_mutex_lock(conf->mutex);
 
1234
 
 
1235
    /* Call get_frame() from all ports (except port 0) that has 
 
1236
     * receiver and distribute the frame (put the frame to the destination 
 
1237
     * port's buffer to accommodate different ptime, and ultimately call 
 
1238
     * put_frame() of that port) to ports that are receiving from this port.
 
1239
     */
 
1240
    for (i=1, ci=1; i<conf->max_ports && ci<conf->port_cnt; ++i) {
 
1241
        struct conf_port *cport = conf->ports[i];
 
1242
        unsigned master_samples_per_frame;
 
1243
 
 
1244
        /* Skip empty port. */
 
1245
        if (!cport)
 
1246
            continue;
 
1247
 
 
1248
        /* Var "ci" is to count how many ports have been visited so far. */
 
1249
        ++ci;
 
1250
 
 
1251
        master_samples_per_frame = PJMEDIA_PIA_SPF(&conf->master_port->info);
 
1252
 
 
1253
        /* Update clock of the port. */
 
1254
        pj_add_timestamp32(&cport->ts_clock, master_samples_per_frame);
 
1255
 
 
1256
        /* Skip if we're not allowed to receive from this port or 
 
1257
         * the port doesn't have listeners.
 
1258
         */
 
1259
        if (cport->rx_setting == PJMEDIA_PORT_DISABLE || 
 
1260
            cport->listener_cnt == 0)
 
1261
        {
 
1262
            cport->rx_level = 0;
 
1263
            pj_add_timestamp32(&cport->ts_rx, master_samples_per_frame);
 
1264
            continue;
 
1265
        }
 
1266
 
 
1267
        /* Get frame from each port, put it to the listener TX buffer,
 
1268
         * and eventually call put_frame() of the listener. This loop 
 
1269
         * will also make sure the ptime between conf & port synchronized.
 
1270
         */
 
1271
        while (pj_cmp_timestamp(&cport->ts_clock, &cport->ts_rx) > 0) {
 
1272
            pjmedia_frame *f = (pjmedia_frame*)conf->buf;
 
1273
            pj_status_t status;
 
1274
            unsigned j;
 
1275
            pj_int32_t level = 0;
 
1276
 
 
1277
            pj_add_timestamp32(&cport->ts_rx, cport->samples_per_frame);
 
1278
            
 
1279
            f->buf = &conf->buf[sizeof(pjmedia_frame)];
 
1280
            f->size = cport->samples_per_frame<<1;
 
1281
 
 
1282
            /* Get frame from port. */
 
1283
            status = pjmedia_port_get_frame(cport->port, f);
 
1284
            if (status != PJ_SUCCESS)
 
1285
                continue;
 
1286
 
 
1287
            /* Calculate & adjust RX level. */
 
1288
            if (f->type == PJMEDIA_FRAME_TYPE_AUDIO) {
 
1289
                if (cport->rx_adj_level != NORMAL_LEVEL) {
 
1290
                    pj_int16_t *p = (pj_int16_t*)f->buf;
 
1291
                    pj_int16_t *end;
 
1292
 
 
1293
                    end = p + (f->size >> 1);
 
1294
                    while (p < end) {
 
1295
                        pj_int32_t itemp = *p;
 
1296
 
 
1297
                        /* Adjust the level */
 
1298
                        itemp = (itemp * cport->rx_adj_level) >> 7;
 
1299
 
 
1300
                        /* Clip the signal if it's too loud */
 
1301
                        if (itemp > MAX_LEVEL) itemp = MAX_LEVEL;
 
1302
                        else if (itemp < MIN_LEVEL) itemp = MIN_LEVEL;
 
1303
 
 
1304
                        level += PJ_ABS(itemp);
 
1305
 
 
1306
                        /* Put back in the buffer. */
 
1307
                        *p = (pj_int16_t)itemp;
 
1308
                        ++p;
 
1309
                    }
 
1310
                    level /= (f->size >> 1);
 
1311
                } else {
 
1312
                    level = pjmedia_calc_avg_signal((const pj_int16_t*)f->buf,
 
1313
                                                    f->size >> 1);
 
1314
                }
 
1315
            } else if (f->type == PJMEDIA_FRAME_TYPE_EXTENDED) {
 
1316
                /* For extended frame, level is unknown, so we just set 
 
1317
                 * it to NORMAL_LEVEL. 
 
1318
                 */
 
1319
                level = NORMAL_LEVEL;
 
1320
            }
 
1321
 
 
1322
            cport->rx_level = pjmedia_linear2ulaw(level) ^ 0xff;
 
1323
 
 
1324
            /* Put the frame to all listeners. */
 
1325
            for (j=0; j < cport->listener_cnt; ++j) 
 
1326
            {
 
1327
                struct conf_port *listener;
 
1328
 
 
1329
                listener = conf->ports[cport->listener_slots[j]];
 
1330
 
 
1331
                /* Skip if this listener doesn't want to receive audio */
 
1332
                if (listener->tx_setting == PJMEDIA_PORT_DISABLE) {
 
1333
                    pj_add_timestamp32(&listener->ts_tx, 
 
1334
                                       listener->samples_per_frame);
 
1335
                    listener->tx_level = 0;
 
1336
                    continue;
 
1337
                }
 
1338
            
 
1339
                status = write_frame(listener, f);
 
1340
                if (status != PJ_SUCCESS) {
 
1341
                    listener->tx_level = 0;
 
1342
                    continue;
 
1343
                }
 
1344
 
 
1345
                /* Set listener TX level based on transmitter RX level & 
 
1346
                 * listener TX level.
 
1347
                 */
 
1348
                listener->tx_level = (cport->rx_level * listener->tx_adj_level)
 
1349
                                     >> 8;
 
1350
            }
 
1351
        }
 
1352
    }
 
1353
 
 
1354
    /* Keep alive. Update TX timestamp and send frame type NONE to all 
 
1355
     * underflow ports at their own clock.
 
1356
     */
 
1357
    for (i=1, ci=1; i<conf->max_ports && ci<conf->port_cnt; ++i) {
 
1358
        struct conf_port *cport = conf->ports[i];
 
1359
 
 
1360
        /* Skip empty port. */
 
1361
        if (!cport)
 
1362
            continue;
 
1363
 
 
1364
        /* Var "ci" is to count how many ports have been visited so far. */
 
1365
        ++ci;
 
1366
 
 
1367
        if (cport->tx_setting==PJMEDIA_PORT_MUTE || cport->transmitter_cnt==0)
 
1368
        {
 
1369
            pjmedia_frame_ext *f;
 
1370
            
 
1371
            /* Clear left-over samples in tx_buffer, if any, so that it won't
 
1372
             * be transmitted next time we have audio signal.
 
1373
             */
 
1374
            f = (pjmedia_frame_ext*)cport->tx_buf;
 
1375
            f->base.type = PJMEDIA_FRAME_TYPE_NONE;
 
1376
            f->base.size = 0;
 
1377
            f->samples_cnt = 0;
 
1378
            f->subframe_cnt = 0;
 
1379
            
 
1380
            cport->tx_level = 0;
 
1381
 
 
1382
            while (pj_cmp_timestamp(&cport->ts_clock, &cport->ts_tx) > 0)
 
1383
            {
 
1384
                if (cport->tx_setting == PJMEDIA_PORT_ENABLE) {
 
1385
                    pjmedia_frame tmp_f;
 
1386
 
 
1387
                    tmp_f.timestamp = cport->ts_tx;
 
1388
                    tmp_f.type = PJMEDIA_FRAME_TYPE_NONE;
 
1389
                    tmp_f.buf = NULL;
 
1390
                    tmp_f.size = 0;
 
1391
 
 
1392
                    pjmedia_port_put_frame(cport->port, &tmp_f);
 
1393
                    pj_add_timestamp32(&cport->ts_tx, cport->samples_per_frame);
 
1394
                }
 
1395
            }
 
1396
        }
 
1397
    }
 
1398
 
 
1399
    /* Return sound playback frame. */
 
1400
    do {
 
1401
        struct conf_port *this_cport = conf->ports[this_port->port_data.ldata];
 
1402
        pjmedia_frame *f_src = (pjmedia_frame*) this_cport->tx_buf;
 
1403
 
 
1404
        frame->type = f_src->type;
 
1405
 
 
1406
        if (f_src->type == PJMEDIA_FRAME_TYPE_EXTENDED) {
 
1407
            pjmedia_frame_ext *f_src_ = (pjmedia_frame_ext*)f_src;
 
1408
            pjmedia_frame_ext *f_dst = (pjmedia_frame_ext*)frame;
 
1409
            pjmedia_frame_ext_subframe *sf;
 
1410
            unsigned samples_per_subframe;
 
1411
            
 
1412
            if (f_src_->samples_cnt < this_cport->samples_per_frame) {
 
1413
                f_dst->base.type = PJMEDIA_FRAME_TYPE_NONE;
 
1414
                f_dst->samples_cnt = 0;
 
1415
                f_dst->subframe_cnt = 0;
 
1416
                break;
 
1417
            }
 
1418
 
 
1419
            f_dst->samples_cnt = 0;
 
1420
            f_dst->subframe_cnt = 0;
 
1421
            i = 0;
 
1422
            samples_per_subframe = f_src_->samples_cnt / f_src_->subframe_cnt;
 
1423
 
 
1424
 
 
1425
            while (f_dst->samples_cnt < this_cport->samples_per_frame) {
 
1426
                sf = pjmedia_frame_ext_get_subframe(f_src_, i++);
 
1427
                pj_assert(sf);
 
1428
                pjmedia_frame_ext_append_subframe(f_dst, sf->data, sf->bitlen,
 
1429
                                                  samples_per_subframe);
 
1430
            }
 
1431
 
 
1432
            /* Shift left TX buffer. */
 
1433
            pjmedia_frame_ext_pop_subframes(f_src_, i);
 
1434
 
 
1435
        } else if (f_src->type == PJMEDIA_FRAME_TYPE_AUDIO) {
 
1436
            if ((f_src->size>>1) < this_cport->samples_per_frame) {
 
1437
                frame->type = PJMEDIA_FRAME_TYPE_NONE;
 
1438
                frame->size = 0;
 
1439
                break;
 
1440
            }
 
1441
 
 
1442
            pjmedia_copy_samples((pj_int16_t*)frame->buf, 
 
1443
                                 (pj_int16_t*)f_src->buf, 
 
1444
                                 this_cport->samples_per_frame);
 
1445
            frame->size = this_cport->samples_per_frame << 1;
 
1446
 
 
1447
            /* Shift left TX buffer. */
 
1448
            f_src->size -= frame->size;
 
1449
            if (f_src->size)
 
1450
                pjmedia_move_samples((pj_int16_t*)f_src->buf,
 
1451
                                     (pj_int16_t*)f_src->buf + 
 
1452
                                     this_cport->samples_per_frame,
 
1453
                                     f_src->size >> 1);
 
1454
        } else { /* PJMEDIA_FRAME_TYPE_NONE */
 
1455
            pjmedia_frame_ext *f_src_ = (pjmedia_frame_ext*)f_src;
 
1456
 
 
1457
            /* Reset source/TX buffer */
 
1458
            f_src_->base.size = 0;
 
1459
            f_src_->samples_cnt = 0;
 
1460
            f_src_->subframe_cnt = 0;
 
1461
        }
 
1462
    } while (0);
 
1463
 
 
1464
    /* Unlock mutex */
 
1465
    pj_mutex_unlock(conf->mutex);
 
1466
 
 
1467
    return PJ_SUCCESS;
 
1468
}
 
1469
 
 
1470
/*
 
1471
 * Recorder callback.
 
1472
 */
 
1473
static pj_status_t put_frame(pjmedia_port *this_port, 
 
1474
                             pjmedia_frame *f)
 
1475
{
 
1476
    pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata;
 
1477
    struct conf_port *cport;
 
1478
    unsigned j;
 
1479
    pj_int32_t level = 0;
 
1480
 
 
1481
    /* Lock mutex */
 
1482
    pj_mutex_lock(conf->mutex);
 
1483
 
 
1484
    /* Get conf port of this port */
 
1485
    cport = conf->ports[this_port->port_data.ldata];
 
1486
    if (cport == NULL) {
 
1487
        /* Unlock mutex */
 
1488
        pj_mutex_unlock(conf->mutex);
 
1489
        return PJ_SUCCESS;
 
1490
    }
 
1491
 
 
1492
    pj_add_timestamp32(&cport->ts_rx, cport->samples_per_frame);
 
1493
    
 
1494
    /* Skip if this port is muted/disabled. */
 
1495
    if (cport->rx_setting == PJMEDIA_PORT_DISABLE) {
 
1496
        cport->rx_level = 0;
 
1497
        /* Unlock mutex */
 
1498
        pj_mutex_unlock(conf->mutex);
 
1499
        return PJ_SUCCESS;
 
1500
    }
 
1501
 
 
1502
    /* Skip if no port is listening to the microphone */
 
1503
    if (cport->listener_cnt == 0) {
 
1504
        cport->rx_level = 0;
 
1505
        /* Unlock mutex */
 
1506
        pj_mutex_unlock(conf->mutex);
 
1507
        return PJ_SUCCESS;
 
1508
    }
 
1509
 
 
1510
    /* Calculate & adjust RX level. */
 
1511
    if (f->type == PJMEDIA_FRAME_TYPE_AUDIO) {
 
1512
        if (cport->rx_adj_level != NORMAL_LEVEL) {
 
1513
            pj_int16_t *p = (pj_int16_t*)f->buf;
 
1514
            pj_int16_t *end;
 
1515
 
 
1516
            end = p + (f->size >> 1);
 
1517
            while (p < end) {
 
1518
                pj_int32_t itemp = *p;
 
1519
 
 
1520
                /* Adjust the level */
 
1521
                itemp = (itemp * cport->rx_adj_level) >> 7;
 
1522
 
 
1523
                /* Clip the signal if it's too loud */
 
1524
                if (itemp > MAX_LEVEL) itemp = MAX_LEVEL;
 
1525
                else if (itemp < MIN_LEVEL) itemp = MIN_LEVEL;
 
1526
 
 
1527
                level += PJ_ABS(itemp);
 
1528
 
 
1529
                /* Put back in the buffer. */
 
1530
                *p = (pj_int16_t)itemp;
 
1531
                ++p;
 
1532
            }
 
1533
            level /= (f->size >> 1);
 
1534
        } else {
 
1535
            level = pjmedia_calc_avg_signal((const pj_int16_t*)f->buf,
 
1536
                                            f->size >> 1);
 
1537
        }
 
1538
    } else if (f->type == PJMEDIA_FRAME_TYPE_EXTENDED) {
 
1539
        /* For extended frame, level is unknown, so we just set 
 
1540
         * it to NORMAL_LEVEL. 
 
1541
         */
 
1542
        level = NORMAL_LEVEL;
 
1543
    }
 
1544
 
 
1545
    cport->rx_level = pjmedia_linear2ulaw(level) ^ 0xff;
 
1546
 
 
1547
    /* Put the frame to all listeners. */
 
1548
    for (j=0; j < cport->listener_cnt; ++j) 
 
1549
    {
 
1550
        struct conf_port *listener;
 
1551
        pj_status_t status;
 
1552
 
 
1553
        listener = conf->ports[cport->listener_slots[j]];
 
1554
 
 
1555
        /* Skip if this listener doesn't want to receive audio */
 
1556
        if (listener->tx_setting == PJMEDIA_PORT_DISABLE) {
 
1557
            pj_add_timestamp32(&listener->ts_tx, 
 
1558
                               listener->samples_per_frame);
 
1559
            listener->tx_level = 0;
 
1560
            continue;
 
1561
        }
 
1562
 
 
1563
        /* Skip loopback for now. */
 
1564
        if (listener == cport) {
 
1565
            pj_add_timestamp32(&listener->ts_tx, 
 
1566
                               listener->samples_per_frame);
 
1567
            listener->tx_level = 0;
 
1568
            continue;
 
1569
        }
 
1570
            
 
1571
        status = write_frame(listener, f);
 
1572
        if (status != PJ_SUCCESS) {
 
1573
            listener->tx_level = 0;
 
1574
            continue;
 
1575
        }
 
1576
 
 
1577
        /* Set listener TX level based on transmitter RX level & listener
 
1578
         * TX level.
 
1579
         */
 
1580
        listener->tx_level = (cport->rx_level * listener->tx_adj_level) >> 8;
 
1581
    }
 
1582
 
 
1583
    /* Unlock mutex */
 
1584
    pj_mutex_unlock(conf->mutex);
 
1585
 
 
1586
    return PJ_SUCCESS;
 
1587
}
 
1588
 
 
1589
#endif