blob: feb6aa1198779e009ec67b52252ce4a8ac130d16 [file] [log] [blame]
Benny Prijonocbc1c472006-03-19 00:50:23 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
Benny Prijono32177c02008-06-20 22:44:47 +00004 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonocbc1c472006-03-19 00:50:23 +00005 *
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
21#include <pjmedia.h>
Benny Prijonobc797312006-03-24 20:44:27 +000022#include <pjlib-util.h> /* pj_getopt */
23#include <pjlib.h>
24
25#include <stdlib.h> /* atoi() */
26#include <stdio.h>
27
28#include "util.h"
29
Benny Prijono1ec70b32006-06-20 15:39:07 +000030/**
31 * \page page_pjmedia_samples_confsample_c Samples: Using Conference Bridge
32 *
33 * Sample to mix multiple files in the conference bridge and play the
34 * result to sound device.
35 *
36 * This file is pjsip-apps/src/samples/confsample.c
37 *
38 * \includelineno confsample.c
39 */
40
41
Benny Prijonobc797312006-03-24 20:44:27 +000042/* For logging purpose. */
43#define THIS_FILE "confsample.c"
44
45
46/* Shall we put recorder in the conference */
47#define RECORDER 1
48
Benny Prijonocbc1c472006-03-19 00:50:23 +000049
Benny Prijonofa137ca2006-03-20 17:42:37 +000050static const char *desc =
51 " FILE: \n"
52 " \n"
53 " confsample.c \n"
54 " \n"
55 " PURPOSE: \n"
56 " \n"
57 " Demonstrate how to use conference bridge. \n"
58 " \n"
59 " USAGE: \n"
60 " \n"
Benny Prijonobc797312006-03-24 20:44:27 +000061 " confsample [options] [file1.wav] [file2.wav] ... \n"
Benny Prijonofa137ca2006-03-20 17:42:37 +000062 " \n"
Benny Prijonobc797312006-03-24 20:44:27 +000063 " options: \n"
64 SND_USAGE
65 " \n"
Benny Prijonofa137ca2006-03-20 17:42:37 +000066 " fileN.wav are optional WAV files to be connected to the conference \n"
67 " bridge. The WAV files MUST have single channel (mono) and 16 bit PCM \n"
68 " samples. It can have arbitrary sampling rate. \n"
69 " \n"
70 " DESCRIPTION: \n"
71 " \n"
72 " Here we create a conference bridge, with at least one port (port zero \n"
73 " is always created for the sound device). \n"
74 " \n"
75 " If WAV files are specified, the WAV file player ports will be connected \n"
76 " to slot starting from number one in the bridge. The WAV files can have \n"
77 " arbitrary sampling rate; the bridge will convert it to its clock rate. \n"
Benny Prijonobc797312006-03-24 20:44:27 +000078 " However, the files MUST have a single audio channel only (i.e. mono). \n";
Benny Prijonocbc1c472006-03-19 00:50:23 +000079
Benny Prijonofa137ca2006-03-20 17:42:37 +000080
81
Benny Prijonocbc1c472006-03-19 00:50:23 +000082/*
83 * Prototypes:
84 */
85
86/* List the ports in the conference bridge */
87static void conf_list(pjmedia_conf *conf, pj_bool_t detail);
88
89/* Display VU meter */
90static void monitor_level(pjmedia_conf *conf, int slot, int dir, int dur);
91
92
Benny Prijonocbc1c472006-03-19 00:50:23 +000093/* Show usage */
94static void usage(void)
95{
96 puts("");
Benny Prijono84827832006-03-23 13:15:59 +000097 puts(desc);
Benny Prijonocbc1c472006-03-19 00:50:23 +000098}
99
100
101
102/* Input simple string */
Benny Prijonoadb34652006-03-19 12:09:53 +0000103static pj_bool_t input(const char *title, char *buf, pj_size_t len)
Benny Prijonocbc1c472006-03-19 00:50:23 +0000104{
105 char *p;
106
107 printf("%s (empty to cancel): ", title); fflush(stdout);
108 fgets(buf, len, stdin);
109
110 /* Remove trailing newlines. */
111 for (p=buf; ; ++p) {
112 if (*p=='\r' || *p=='\n') *p='\0';
113 else if (!*p) break;
114 }
115
116 if (!*buf)
117 return PJ_FALSE;
118
119 return PJ_TRUE;
120}
121
122
123/*****************************************************************************
124 * main()
125 */
126int main(int argc, char *argv[])
127{
Benny Prijonobc797312006-03-24 20:44:27 +0000128 int dev_id = -1;
129 int clock_rate = CLOCK_RATE;
130 int channel_count = NCHANNELS;
131 int samples_per_frame = NSAMPLES;
132 int bits_per_sample = NBITS;
133
Benny Prijonocbc1c472006-03-19 00:50:23 +0000134 pj_caching_pool cp;
135 pjmedia_endpt *med_endpt;
136 pj_pool_t *pool;
137 pjmedia_conf *conf;
Benny Prijonocbc1c472006-03-19 00:50:23 +0000138
Benny Prijonoadb34652006-03-19 12:09:53 +0000139 int i, port_count, file_count;
Benny Prijonocbc1c472006-03-19 00:50:23 +0000140 pjmedia_port **file_port; /* Array of file ports */
Benny Prijonobc797312006-03-24 20:44:27 +0000141 pjmedia_port *rec_port = NULL; /* Wav writer port */
Benny Prijonocbc1c472006-03-19 00:50:23 +0000142
143 char tmp[10];
144 pj_status_t status;
145
146
Benny Prijonocbc1c472006-03-19 00:50:23 +0000147 /* Must init PJLIB first: */
148 status = pj_init();
149 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
150
Benny Prijonobc797312006-03-24 20:44:27 +0000151 /* Get command line options. */
152 if (get_snd_options(THIS_FILE, argc, argv, &dev_id, &clock_rate,
153 &channel_count, &samples_per_frame, &bits_per_sample))
154 {
155 usage();
156 return 1;
157 }
158
Benny Prijonocbc1c472006-03-19 00:50:23 +0000159 /* Must create a pool factory before we can allocate any memory. */
160 pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
161
162 /*
163 * Initialize media endpoint.
164 * This will implicitly initialize PJMEDIA too.
165 */
Benny Prijono275fd682006-03-22 11:59:11 +0000166 status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
Benny Prijonocbc1c472006-03-19 00:50:23 +0000167 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
168
169 /* Create memory pool to allocate memory */
170 pool = pj_pool_create( &cp.factory, /* pool factory */
171 "wav", /* pool name. */
172 4000, /* init size */
173 4000, /* increment size */
174 NULL /* callback on error */
175 );
176
177
Benny Prijonobc797312006-03-24 20:44:27 +0000178 file_count = argc - pj_optind;
179 port_count = file_count + 1 + RECORDER;
Benny Prijonoadb34652006-03-19 12:09:53 +0000180
Benny Prijonocbc1c472006-03-19 00:50:23 +0000181 /* Create the conference bridge.
182 * With default options (zero), the bridge will create an instance of
183 * sound capture and playback device and connect them to slot zero.
184 */
185 status = pjmedia_conf_create( pool, /* pool to use */
Benny Prijonoadb34652006-03-19 12:09:53 +0000186 port_count,/* number of ports */
Benny Prijonobc797312006-03-24 20:44:27 +0000187 clock_rate,
188 channel_count,
189 samples_per_frame,
190 bits_per_sample,
Benny Prijonocbc1c472006-03-19 00:50:23 +0000191 0, /* options */
192 &conf /* result */
193 );
194 if (status != PJ_SUCCESS) {
195 app_perror(THIS_FILE, "Unable to create conference bridge", status);
196 return 1;
197 }
198
Benny Prijonobc797312006-03-24 20:44:27 +0000199#if RECORDER
Benny Prijono15953012006-04-27 22:37:08 +0000200 status = pjmedia_wav_writer_port_create( pool, "confrecord.wav",
Benny Prijonobc797312006-03-24 20:44:27 +0000201 clock_rate, channel_count,
202 samples_per_frame,
Benny Prijono6fd4b8f2006-06-22 18:51:50 +0000203 bits_per_sample, 0, 0,
Benny Prijonobc797312006-03-24 20:44:27 +0000204 &rec_port);
205 if (status != PJ_SUCCESS) {
206 app_perror(THIS_FILE, "Unable to create WAV writer", status);
207 return 1;
208 }
209
210 pjmedia_conf_add_port(conf, pool, rec_port, NULL, NULL);
211#endif
212
Benny Prijonocbc1c472006-03-19 00:50:23 +0000213
Benny Prijonocbc1c472006-03-19 00:50:23 +0000214 /* Create file ports. */
Benny Prijonocbc1c472006-03-19 00:50:23 +0000215 file_port = pj_pool_alloc(pool, file_count * sizeof(pjmedia_port*));
216
217 for (i=0; i<file_count; ++i) {
218
219 /* Load the WAV file to file port. */
Benny Prijono15953012006-04-27 22:37:08 +0000220 status = pjmedia_wav_player_port_create(
Benny Prijonobc797312006-03-24 20:44:27 +0000221 pool, /* pool. */
222 argv[i+pj_optind], /* filename */
Benny Prijono15953012006-04-27 22:37:08 +0000223 0, /* use default ptime */
Benny Prijonobc797312006-03-24 20:44:27 +0000224 0, /* flags */
225 0, /* buf size */
Benny Prijonobc797312006-03-24 20:44:27 +0000226 &file_port[i] /* result */
227 );
Benny Prijonocbc1c472006-03-19 00:50:23 +0000228 if (status != PJ_SUCCESS) {
229 char title[80];
Benny Prijonobc797312006-03-24 20:44:27 +0000230 pj_ansi_sprintf(title, "Unable to use %s", argv[i+pj_optind]);
Benny Prijonocbc1c472006-03-19 00:50:23 +0000231 app_perror(THIS_FILE, title, status);
232 usage();
233 return 1;
234 }
235
236 /* Add the file port to conference bridge */
237 status = pjmedia_conf_add_port( conf, /* The bridge */
238 pool, /* pool */
239 file_port[i], /* port to connect */
240 NULL, /* Use port's name */
Benny Prijonobc797312006-03-24 20:44:27 +0000241 NULL /* ptr for slot # */
Benny Prijonocbc1c472006-03-19 00:50:23 +0000242 );
243 if (status != PJ_SUCCESS) {
244 app_perror(THIS_FILE, "Unable to add conference port", status);
245 return 1;
246 }
247 }
248
249
250 /*
251 * All ports are set up in the conference bridge.
252 * But at this point, no media will be flowing since no ports are
253 * "connected". User must connect the port manually.
254 */
255
256
Benny Prijonobc797312006-03-24 20:44:27 +0000257 /* Dump memory usage */
258 dump_pool_usage(THIS_FILE, &cp);
259
Benny Prijonocbc1c472006-03-19 00:50:23 +0000260 /* Sleep to allow log messages to flush */
261 pj_thread_sleep(100);
262
263
264 /*
265 * UI Menu:
266 */
267 for (;;) {
268 char tmp1[10];
269 char tmp2[10];
270 char *err;
271 int src, dst, level;
272
273 puts("");
274 conf_list(conf, 0);
275 puts("");
276 puts("Menu:");
277 puts(" s Show ports details");
278 puts(" c Connect one port to another");
279 puts(" d Disconnect port connection");
280 puts(" t Adjust signal level transmitted (tx) to a port");
281 puts(" r Adjust signal level received (rx) from a port");
282 puts(" v Display VU meter for a particular port");
283 puts(" q Quit");
284 puts("");
285
286 printf("Enter selection: "); fflush(stdout);
287
288 fgets(tmp, sizeof(tmp), stdin);
289
290 switch (tmp[0]) {
291 case 's':
292 puts("");
293 conf_list(conf, 1);
294 break;
295
296 case 'c':
297 puts("");
298 puts("Connect source port to destination port");
Benny Prijonoadb34652006-03-19 12:09:53 +0000299 if (!input("Enter source port number", tmp1, sizeof(tmp1)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000300 continue;
301 src = strtol(tmp1, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000302 if (*err || src < 0 || src >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000303 puts("Invalid slot number");
304 continue;
305 }
306
Benny Prijonoadb34652006-03-19 12:09:53 +0000307 if (!input("Enter destination port number", tmp2, sizeof(tmp2)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000308 continue;
309 dst = strtol(tmp2, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000310 if (*err || dst < 0 || dst >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000311 puts("Invalid slot number");
312 continue;
313 }
314
315 status = pjmedia_conf_connect_port(conf, src, dst, 0);
316 if (status != PJ_SUCCESS)
317 app_perror(THIS_FILE, "Error connecting port", status);
318
319 break;
320
321 case 'd':
322 puts("");
323 puts("Disconnect port connection");
Benny Prijonoadb34652006-03-19 12:09:53 +0000324 if (!input("Enter source port number", tmp1, sizeof(tmp1)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000325 continue;
326 src = strtol(tmp1, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000327 if (*err || src < 0 || src >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000328 puts("Invalid slot number");
329 continue;
330 }
331
Benny Prijonoadb34652006-03-19 12:09:53 +0000332 if (!input("Enter destination port number", tmp2, sizeof(tmp2)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000333 continue;
334 dst = strtol(tmp2, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000335 if (*err || dst < 0 || dst >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000336 puts("Invalid slot number");
337 continue;
338 }
339
340 status = pjmedia_conf_disconnect_port(conf, src, dst);
341 if (status != PJ_SUCCESS)
342 app_perror(THIS_FILE, "Error connecting port", status);
343
344
345 break;
346
347 case 't':
348 puts("");
349 puts("Adjust transmit level of a port");
Benny Prijonoadb34652006-03-19 12:09:53 +0000350 if (!input("Enter port number", tmp1, sizeof(tmp1)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000351 continue;
352 src = strtol(tmp1, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000353 if (*err || src < 0 || src >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000354 puts("Invalid slot number");
355 continue;
356 }
357
Benny Prijono0eef2c72007-02-17 19:38:21 +0000358 if (!input("Enter level (-128 to >127, 0 for normal)",
Benny Prijonocbc1c472006-03-19 00:50:23 +0000359 tmp2, sizeof(tmp2)) )
360 continue;
361 level = strtol(tmp2, &err, 10);
Benny Prijono0eef2c72007-02-17 19:38:21 +0000362 if (*err || level < -128) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000363 puts("Invalid level");
364 continue;
365 }
366
367 status = pjmedia_conf_adjust_tx_level( conf, src, level);
368 if (status != PJ_SUCCESS)
369 app_perror(THIS_FILE, "Error adjusting level", status);
370 break;
371
372
373 case 'r':
374 puts("");
375 puts("Adjust receive level of a port");
Benny Prijonoadb34652006-03-19 12:09:53 +0000376 if (!input("Enter port number", tmp1, sizeof(tmp1)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000377 continue;
378 src = strtol(tmp1, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000379 if (*err || src < 0 || src >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000380 puts("Invalid slot number");
381 continue;
382 }
383
Benny Prijono0eef2c72007-02-17 19:38:21 +0000384 if (!input("Enter level (-128 to >127, 0 for normal)",
Benny Prijonocbc1c472006-03-19 00:50:23 +0000385 tmp2, sizeof(tmp2)) )
386 continue;
387 level = strtol(tmp2, &err, 10);
Benny Prijono0eef2c72007-02-17 19:38:21 +0000388 if (*err || level < -128) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000389 puts("Invalid level");
390 continue;
391 }
392
393 status = pjmedia_conf_adjust_rx_level( conf, src, level);
394 if (status != PJ_SUCCESS)
395 app_perror(THIS_FILE, "Error adjusting level", status);
396 break;
397
398 case 'v':
399 puts("");
400 puts("Display VU meter");
Benny Prijonoadb34652006-03-19 12:09:53 +0000401 if (!input("Enter port number to monitor", tmp1, sizeof(tmp1)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000402 continue;
403 src = strtol(tmp1, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000404 if (*err || src < 0 || src >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000405 puts("Invalid slot number");
406 continue;
407 }
408
Benny Prijonoadb34652006-03-19 12:09:53 +0000409 if (!input("Enter r for rx level or t for tx level", tmp2, sizeof(tmp2)))
Benny Prijonocbc1c472006-03-19 00:50:23 +0000410 continue;
411 if (tmp2[0] != 'r' && tmp2[0] != 't') {
412 puts("Invalid option");
413 continue;
414 }
415
Benny Prijonoadb34652006-03-19 12:09:53 +0000416 if (!input("Duration to monitor (in seconds)", tmp1, sizeof(tmp1)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000417 continue;
418 strtol(tmp1, &err, 10);
419 if (*err) {
420 puts("Invalid duration number");
421 continue;
422 }
423
424 monitor_level(conf, src, tmp2[0], strtol(tmp1, &err, 10));
425 break;
426
427 case 'q':
428 goto on_quit;
429
430 default:
431 printf("Invalid input character '%c'\n", tmp[0]);
432 break;
433 }
434 }
435
436on_quit:
437
438 /* Start deinitialization: */
439
440 /* Destroy conference bridge */
441 status = pjmedia_conf_destroy( conf );
442 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
443
444
445 /* Destroy file ports */
446 for (i=0; i<file_count; ++i) {
447 status = pjmedia_port_destroy( file_port[i]);
448 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
449 }
450
Benny Prijonobc797312006-03-24 20:44:27 +0000451 /* Destroy recorder port */
452 if (rec_port)
453 pjmedia_port_destroy(rec_port);
454
Benny Prijonocbc1c472006-03-19 00:50:23 +0000455 /* Release application pool */
456 pj_pool_release( pool );
457
458 /* Destroy media endpoint. */
459 pjmedia_endpt_destroy( med_endpt );
460
461 /* Destroy pool factory */
462 pj_caching_pool_destroy( &cp );
463
Benny Prijonoaf1bb1e2006-11-21 12:39:31 +0000464 /* Shutdown PJLIB */
465 pj_shutdown();
Benny Prijonocbc1c472006-03-19 00:50:23 +0000466
467 /* Done. */
468 return 0;
469}
470
471
472/*
473 * List the ports in conference bridge
474 */
475static void conf_list(pjmedia_conf *conf, int detail)
476{
477 enum { MAX_PORTS = 32 };
478 unsigned i, count;
479 pjmedia_conf_port_info info[MAX_PORTS];
480
481 printf("Conference ports:\n");
482
483 count = PJ_ARRAY_SIZE(info);
484 pjmedia_conf_get_ports_info(conf, &count, info);
485
486 for (i=0; i<count; ++i) {
487 char txlist[4*MAX_PORTS];
488 unsigned j;
489 pjmedia_conf_port_info *port_info = &info[i];
490
491 txlist[0] = '\0';
Benny Prijonoc78c3a32006-06-16 15:54:43 +0000492 for (j=0; j<port_info->listener_cnt; ++j) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000493 char s[10];
Benny Prijonoc78c3a32006-06-16 15:54:43 +0000494 pj_ansi_sprintf(s, "#%d ", port_info->listener_slots[j]);
495 pj_ansi_strcat(txlist, s);
496
Benny Prijonocbc1c472006-03-19 00:50:23 +0000497 }
498
499 if (txlist[0] == '\0') {
500 txlist[0] = '-';
501 txlist[1] = '\0';
502 }
503
504 if (!detail) {
505 printf("Port #%02d %-25.*s transmitting to: %s\n",
506 port_info->slot,
507 (int)port_info->name.slen,
508 port_info->name.ptr,
509 txlist);
510 } else {
511 unsigned tx_level, rx_level;
512
513 pjmedia_conf_get_signal_level(conf, port_info->slot,
514 &tx_level, &rx_level);
515
516 printf("Port #%02d:\n"
517 " Name : %.*s\n"
518 " Sampling rate : %d Hz\n"
Benny Prijonobc797312006-03-24 20:44:27 +0000519 " Samples per frame : %d\n"
Benny Prijonocbc1c472006-03-19 00:50:23 +0000520 " Frame time : %d ms\n"
521 " Signal level adjustment : tx=%d, rx=%d\n"
522 " Current signal level : tx=%u, rx=%u\n"
523 " Transmitting to ports : %s\n\n",
524 port_info->slot,
525 (int)port_info->name.slen,
526 port_info->name.ptr,
527 port_info->clock_rate,
Benny Prijonobc797312006-03-24 20:44:27 +0000528 port_info->samples_per_frame,
Benny Prijonocbc1c472006-03-19 00:50:23 +0000529 port_info->samples_per_frame*1000/port_info->clock_rate,
530 port_info->tx_adj_level,
531 port_info->rx_adj_level,
532 tx_level,
533 rx_level,
534 txlist);
535 }
536
537 }
538 puts("");
539}
540
541
542/*
543 * Display VU meter
544 */
545static void monitor_level(pjmedia_conf *conf, int slot, int dir, int dur)
546{
Benny Prijonoadb34652006-03-19 12:09:53 +0000547 enum { SLEEP = 20, SAMP_CNT = 2};
Benny Prijonocbc1c472006-03-19 00:50:23 +0000548 pj_status_t status;
Benny Prijonoadb34652006-03-19 12:09:53 +0000549 int i, total_count;
550 unsigned level, samp_cnt;
551
Benny Prijonocbc1c472006-03-19 00:50:23 +0000552
553 puts("");
554 printf("Displaying VU meter for port %d for about %d seconds\n",
555 slot, dur);
556
Benny Prijonoadb34652006-03-19 12:09:53 +0000557 total_count = dur * 1000 / SLEEP;
Benny Prijonocbc1c472006-03-19 00:50:23 +0000558
Benny Prijonoadb34652006-03-19 12:09:53 +0000559 level = 0;
560 samp_cnt = 0;
561
562 for (i=0; i<total_count; ++i) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000563 unsigned tx_level, rx_level;
Benny Prijonoadb34652006-03-19 12:09:53 +0000564 int j, length;
Benny Prijonocbc1c472006-03-19 00:50:23 +0000565 char meter[21];
566
Benny Prijonoadb34652006-03-19 12:09:53 +0000567 /* Poll the volume every 20 msec */
Benny Prijonocbc1c472006-03-19 00:50:23 +0000568 status = pjmedia_conf_get_signal_level(conf, slot,
569 &tx_level, &rx_level);
570 if (status != PJ_SUCCESS) {
571 app_perror(THIS_FILE, "Unable to read level", status);
572 return;
573 }
574
Benny Prijonoadb34652006-03-19 12:09:53 +0000575 level += (dir=='r' ? rx_level : tx_level);
576 ++samp_cnt;
577
578 /* Accumulate until we have enough samples */
579 if (samp_cnt < SAMP_CNT) {
580 pj_thread_sleep(SLEEP);
581 continue;
582 }
583
584 /* Get average */
585 level = level / samp_cnt;
586
587 /* Draw bar */
588 length = 20 * level / 255;
589 for (j=0; j<length; ++j)
Benny Prijonocbc1c472006-03-19 00:50:23 +0000590 meter[j] = '#';
591 for (; j<20; ++j)
592 meter[j] = ' ';
593 meter[20] = '\0';
594
Benny Prijonoadb34652006-03-19 12:09:53 +0000595 printf("Port #%02d %cx level: [%s] %d \r",
596 slot, dir, meter, level);
597
598 /* Next.. */
599 samp_cnt = 0;
600 level = 0;
Benny Prijonocbc1c472006-03-19 00:50:23 +0000601
602 pj_thread_sleep(SLEEP);
603 }
604
605 puts("");
606}
607