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

« back to all changes in this revision

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