blob: 676f4bb8c15172bad4c1c202a99f8154798ec9bd [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);
Benny Prijono32d267b2009-01-01 22:08:21 +0000108 if (fgets(buf, len, stdin) == NULL)
109 return PJ_FALSE;
Benny Prijonocbc1c472006-03-19 00:50:23 +0000110
111 /* Remove trailing newlines. */
112 for (p=buf; ; ++p) {
113 if (*p=='\r' || *p=='\n') *p='\0';
114 else if (!*p) break;
115 }
116
117 if (!*buf)
118 return PJ_FALSE;
119
120 return PJ_TRUE;
121}
122
123
124/*****************************************************************************
125 * main()
126 */
127int main(int argc, char *argv[])
128{
Benny Prijonobc797312006-03-24 20:44:27 +0000129 int dev_id = -1;
130 int clock_rate = CLOCK_RATE;
131 int channel_count = NCHANNELS;
132 int samples_per_frame = NSAMPLES;
133 int bits_per_sample = NBITS;
134
Benny Prijonocbc1c472006-03-19 00:50:23 +0000135 pj_caching_pool cp;
136 pjmedia_endpt *med_endpt;
137 pj_pool_t *pool;
138 pjmedia_conf *conf;
Benny Prijonocbc1c472006-03-19 00:50:23 +0000139
Benny Prijonoadb34652006-03-19 12:09:53 +0000140 int i, port_count, file_count;
Benny Prijonocbc1c472006-03-19 00:50:23 +0000141 pjmedia_port **file_port; /* Array of file ports */
Benny Prijonobc797312006-03-24 20:44:27 +0000142 pjmedia_port *rec_port = NULL; /* Wav writer port */
Benny Prijonocbc1c472006-03-19 00:50:23 +0000143
144 char tmp[10];
145 pj_status_t status;
146
147
Benny Prijonocbc1c472006-03-19 00:50:23 +0000148 /* Must init PJLIB first: */
149 status = pj_init();
150 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
151
Benny Prijonobc797312006-03-24 20:44:27 +0000152 /* Get command line options. */
153 if (get_snd_options(THIS_FILE, argc, argv, &dev_id, &clock_rate,
154 &channel_count, &samples_per_frame, &bits_per_sample))
155 {
156 usage();
157 return 1;
158 }
159
Benny Prijonocbc1c472006-03-19 00:50:23 +0000160 /* Must create a pool factory before we can allocate any memory. */
161 pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
162
163 /*
164 * Initialize media endpoint.
165 * This will implicitly initialize PJMEDIA too.
166 */
Benny Prijono275fd682006-03-22 11:59:11 +0000167 status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
Benny Prijonocbc1c472006-03-19 00:50:23 +0000168 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
169
170 /* Create memory pool to allocate memory */
171 pool = pj_pool_create( &cp.factory, /* pool factory */
172 "wav", /* pool name. */
173 4000, /* init size */
174 4000, /* increment size */
175 NULL /* callback on error */
176 );
177
178
Benny Prijonobc797312006-03-24 20:44:27 +0000179 file_count = argc - pj_optind;
180 port_count = file_count + 1 + RECORDER;
Benny Prijonoadb34652006-03-19 12:09:53 +0000181
Benny Prijonocbc1c472006-03-19 00:50:23 +0000182 /* Create the conference bridge.
183 * With default options (zero), the bridge will create an instance of
184 * sound capture and playback device and connect them to slot zero.
185 */
186 status = pjmedia_conf_create( pool, /* pool to use */
Benny Prijonoadb34652006-03-19 12:09:53 +0000187 port_count,/* number of ports */
Benny Prijonobc797312006-03-24 20:44:27 +0000188 clock_rate,
189 channel_count,
190 samples_per_frame,
191 bits_per_sample,
Benny Prijonocbc1c472006-03-19 00:50:23 +0000192 0, /* options */
193 &conf /* result */
194 );
195 if (status != PJ_SUCCESS) {
196 app_perror(THIS_FILE, "Unable to create conference bridge", status);
197 return 1;
198 }
199
Benny Prijonobc797312006-03-24 20:44:27 +0000200#if RECORDER
Benny Prijono15953012006-04-27 22:37:08 +0000201 status = pjmedia_wav_writer_port_create( pool, "confrecord.wav",
Benny Prijonobc797312006-03-24 20:44:27 +0000202 clock_rate, channel_count,
203 samples_per_frame,
Benny Prijono6fd4b8f2006-06-22 18:51:50 +0000204 bits_per_sample, 0, 0,
Benny Prijonobc797312006-03-24 20:44:27 +0000205 &rec_port);
206 if (status != PJ_SUCCESS) {
207 app_perror(THIS_FILE, "Unable to create WAV writer", status);
208 return 1;
209 }
210
211 pjmedia_conf_add_port(conf, pool, rec_port, NULL, NULL);
212#endif
213
Benny Prijonocbc1c472006-03-19 00:50:23 +0000214
Benny Prijonocbc1c472006-03-19 00:50:23 +0000215 /* Create file ports. */
Benny Prijonocbc1c472006-03-19 00:50:23 +0000216 file_port = pj_pool_alloc(pool, file_count * sizeof(pjmedia_port*));
217
218 for (i=0; i<file_count; ++i) {
219
220 /* Load the WAV file to file port. */
Benny Prijono15953012006-04-27 22:37:08 +0000221 status = pjmedia_wav_player_port_create(
Benny Prijonobc797312006-03-24 20:44:27 +0000222 pool, /* pool. */
223 argv[i+pj_optind], /* filename */
Benny Prijono15953012006-04-27 22:37:08 +0000224 0, /* use default ptime */
Benny Prijonobc797312006-03-24 20:44:27 +0000225 0, /* flags */
226 0, /* buf size */
Benny Prijonobc797312006-03-24 20:44:27 +0000227 &file_port[i] /* result */
228 );
Benny Prijonocbc1c472006-03-19 00:50:23 +0000229 if (status != PJ_SUCCESS) {
230 char title[80];
Benny Prijonobc797312006-03-24 20:44:27 +0000231 pj_ansi_sprintf(title, "Unable to use %s", argv[i+pj_optind]);
Benny Prijonocbc1c472006-03-19 00:50:23 +0000232 app_perror(THIS_FILE, title, status);
233 usage();
234 return 1;
235 }
236
237 /* Add the file port to conference bridge */
238 status = pjmedia_conf_add_port( conf, /* The bridge */
239 pool, /* pool */
240 file_port[i], /* port to connect */
241 NULL, /* Use port's name */
Benny Prijonobc797312006-03-24 20:44:27 +0000242 NULL /* ptr for slot # */
Benny Prijonocbc1c472006-03-19 00:50:23 +0000243 );
244 if (status != PJ_SUCCESS) {
245 app_perror(THIS_FILE, "Unable to add conference port", status);
246 return 1;
247 }
248 }
249
250
251 /*
252 * All ports are set up in the conference bridge.
253 * But at this point, no media will be flowing since no ports are
254 * "connected". User must connect the port manually.
255 */
256
257
Benny Prijonobc797312006-03-24 20:44:27 +0000258 /* Dump memory usage */
259 dump_pool_usage(THIS_FILE, &cp);
260
Benny Prijonocbc1c472006-03-19 00:50:23 +0000261 /* Sleep to allow log messages to flush */
262 pj_thread_sleep(100);
263
264
265 /*
266 * UI Menu:
267 */
268 for (;;) {
269 char tmp1[10];
270 char tmp2[10];
271 char *err;
Benny Prijono32d267b2009-01-01 22:08:21 +0000272 int src, dst, level, dur;
Benny Prijonocbc1c472006-03-19 00:50:23 +0000273
274 puts("");
275 conf_list(conf, 0);
276 puts("");
277 puts("Menu:");
278 puts(" s Show ports details");
279 puts(" c Connect one port to another");
280 puts(" d Disconnect port connection");
281 puts(" t Adjust signal level transmitted (tx) to a port");
282 puts(" r Adjust signal level received (rx) from a port");
283 puts(" v Display VU meter for a particular port");
284 puts(" q Quit");
285 puts("");
286
287 printf("Enter selection: "); fflush(stdout);
288
Benny Prijono32d267b2009-01-01 22:08:21 +0000289 if (fgets(tmp, sizeof(tmp), stdin) == NULL)
290 break;
Benny Prijonocbc1c472006-03-19 00:50:23 +0000291
292 switch (tmp[0]) {
293 case 's':
294 puts("");
295 conf_list(conf, 1);
296 break;
297
298 case 'c':
299 puts("");
300 puts("Connect source port to destination port");
Benny Prijonoadb34652006-03-19 12:09:53 +0000301 if (!input("Enter source port number", tmp1, sizeof(tmp1)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000302 continue;
303 src = strtol(tmp1, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000304 if (*err || src < 0 || src >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000305 puts("Invalid slot number");
306 continue;
307 }
308
Benny Prijonoadb34652006-03-19 12:09:53 +0000309 if (!input("Enter destination port number", tmp2, sizeof(tmp2)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000310 continue;
311 dst = strtol(tmp2, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000312 if (*err || dst < 0 || dst >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000313 puts("Invalid slot number");
314 continue;
315 }
316
317 status = pjmedia_conf_connect_port(conf, src, dst, 0);
318 if (status != PJ_SUCCESS)
319 app_perror(THIS_FILE, "Error connecting port", status);
320
321 break;
322
323 case 'd':
324 puts("");
325 puts("Disconnect port connection");
Benny Prijonoadb34652006-03-19 12:09:53 +0000326 if (!input("Enter source port number", tmp1, sizeof(tmp1)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000327 continue;
328 src = strtol(tmp1, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000329 if (*err || src < 0 || src >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000330 puts("Invalid slot number");
331 continue;
332 }
333
Benny Prijonoadb34652006-03-19 12:09:53 +0000334 if (!input("Enter destination port number", tmp2, sizeof(tmp2)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000335 continue;
336 dst = strtol(tmp2, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000337 if (*err || dst < 0 || dst >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000338 puts("Invalid slot number");
339 continue;
340 }
341
342 status = pjmedia_conf_disconnect_port(conf, src, dst);
343 if (status != PJ_SUCCESS)
344 app_perror(THIS_FILE, "Error connecting port", status);
345
346
347 break;
348
349 case 't':
350 puts("");
351 puts("Adjust transmit level of a port");
Benny Prijonoadb34652006-03-19 12:09:53 +0000352 if (!input("Enter port number", tmp1, sizeof(tmp1)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000353 continue;
354 src = strtol(tmp1, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000355 if (*err || src < 0 || src >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000356 puts("Invalid slot number");
357 continue;
358 }
359
Benny Prijono0eef2c72007-02-17 19:38:21 +0000360 if (!input("Enter level (-128 to >127, 0 for normal)",
Benny Prijonocbc1c472006-03-19 00:50:23 +0000361 tmp2, sizeof(tmp2)) )
362 continue;
363 level = strtol(tmp2, &err, 10);
Benny Prijono0eef2c72007-02-17 19:38:21 +0000364 if (*err || level < -128) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000365 puts("Invalid level");
366 continue;
367 }
368
369 status = pjmedia_conf_adjust_tx_level( conf, src, level);
370 if (status != PJ_SUCCESS)
371 app_perror(THIS_FILE, "Error adjusting level", status);
372 break;
373
374
375 case 'r':
376 puts("");
377 puts("Adjust receive level of a port");
Benny Prijonoadb34652006-03-19 12:09:53 +0000378 if (!input("Enter port number", tmp1, sizeof(tmp1)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000379 continue;
380 src = strtol(tmp1, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000381 if (*err || src < 0 || src >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000382 puts("Invalid slot number");
383 continue;
384 }
385
Benny Prijono0eef2c72007-02-17 19:38:21 +0000386 if (!input("Enter level (-128 to >127, 0 for normal)",
Benny Prijonocbc1c472006-03-19 00:50:23 +0000387 tmp2, sizeof(tmp2)) )
388 continue;
389 level = strtol(tmp2, &err, 10);
Benny Prijono0eef2c72007-02-17 19:38:21 +0000390 if (*err || level < -128) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000391 puts("Invalid level");
392 continue;
393 }
394
395 status = pjmedia_conf_adjust_rx_level( conf, src, level);
396 if (status != PJ_SUCCESS)
397 app_perror(THIS_FILE, "Error adjusting level", status);
398 break;
399
400 case 'v':
401 puts("");
402 puts("Display VU meter");
Benny Prijonoadb34652006-03-19 12:09:53 +0000403 if (!input("Enter port number to monitor", tmp1, sizeof(tmp1)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000404 continue;
405 src = strtol(tmp1, &err, 10);
Benny Prijonoadb34652006-03-19 12:09:53 +0000406 if (*err || src < 0 || src >= port_count) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000407 puts("Invalid slot number");
408 continue;
409 }
410
Benny Prijonoadb34652006-03-19 12:09:53 +0000411 if (!input("Enter r for rx level or t for tx level", tmp2, sizeof(tmp2)))
Benny Prijonocbc1c472006-03-19 00:50:23 +0000412 continue;
413 if (tmp2[0] != 'r' && tmp2[0] != 't') {
414 puts("Invalid option");
415 continue;
416 }
417
Benny Prijonoadb34652006-03-19 12:09:53 +0000418 if (!input("Duration to monitor (in seconds)", tmp1, sizeof(tmp1)) )
Benny Prijonocbc1c472006-03-19 00:50:23 +0000419 continue;
Benny Prijono32d267b2009-01-01 22:08:21 +0000420 dur = strtol(tmp1, &err, 10);
Benny Prijonocbc1c472006-03-19 00:50:23 +0000421 if (*err) {
422 puts("Invalid duration number");
423 continue;
424 }
425
Benny Prijono32d267b2009-01-01 22:08:21 +0000426 monitor_level(conf, src, tmp2[0], dur);
Benny Prijonocbc1c472006-03-19 00:50:23 +0000427 break;
428
429 case 'q':
430 goto on_quit;
431
432 default:
433 printf("Invalid input character '%c'\n", tmp[0]);
434 break;
435 }
436 }
437
438on_quit:
439
440 /* Start deinitialization: */
441
442 /* Destroy conference bridge */
443 status = pjmedia_conf_destroy( conf );
444 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
445
446
447 /* Destroy file ports */
448 for (i=0; i<file_count; ++i) {
449 status = pjmedia_port_destroy( file_port[i]);
450 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
451 }
452
Benny Prijonobc797312006-03-24 20:44:27 +0000453 /* Destroy recorder port */
454 if (rec_port)
455 pjmedia_port_destroy(rec_port);
456
Benny Prijonocbc1c472006-03-19 00:50:23 +0000457 /* Release application pool */
458 pj_pool_release( pool );
459
460 /* Destroy media endpoint. */
461 pjmedia_endpt_destroy( med_endpt );
462
463 /* Destroy pool factory */
464 pj_caching_pool_destroy( &cp );
465
Benny Prijonoaf1bb1e2006-11-21 12:39:31 +0000466 /* Shutdown PJLIB */
467 pj_shutdown();
Benny Prijonocbc1c472006-03-19 00:50:23 +0000468
469 /* Done. */
470 return 0;
471}
472
473
474/*
475 * List the ports in conference bridge
476 */
477static void conf_list(pjmedia_conf *conf, int detail)
478{
479 enum { MAX_PORTS = 32 };
480 unsigned i, count;
481 pjmedia_conf_port_info info[MAX_PORTS];
482
483 printf("Conference ports:\n");
484
485 count = PJ_ARRAY_SIZE(info);
486 pjmedia_conf_get_ports_info(conf, &count, info);
487
488 for (i=0; i<count; ++i) {
489 char txlist[4*MAX_PORTS];
490 unsigned j;
491 pjmedia_conf_port_info *port_info = &info[i];
492
493 txlist[0] = '\0';
Benny Prijonoc78c3a32006-06-16 15:54:43 +0000494 for (j=0; j<port_info->listener_cnt; ++j) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000495 char s[10];
Benny Prijonoc78c3a32006-06-16 15:54:43 +0000496 pj_ansi_sprintf(s, "#%d ", port_info->listener_slots[j]);
497 pj_ansi_strcat(txlist, s);
498
Benny Prijonocbc1c472006-03-19 00:50:23 +0000499 }
500
501 if (txlist[0] == '\0') {
502 txlist[0] = '-';
503 txlist[1] = '\0';
504 }
505
506 if (!detail) {
507 printf("Port #%02d %-25.*s transmitting to: %s\n",
508 port_info->slot,
509 (int)port_info->name.slen,
510 port_info->name.ptr,
511 txlist);
512 } else {
513 unsigned tx_level, rx_level;
514
515 pjmedia_conf_get_signal_level(conf, port_info->slot,
516 &tx_level, &rx_level);
517
518 printf("Port #%02d:\n"
519 " Name : %.*s\n"
520 " Sampling rate : %d Hz\n"
Benny Prijonobc797312006-03-24 20:44:27 +0000521 " Samples per frame : %d\n"
Benny Prijonocbc1c472006-03-19 00:50:23 +0000522 " Frame time : %d ms\n"
523 " Signal level adjustment : tx=%d, rx=%d\n"
524 " Current signal level : tx=%u, rx=%u\n"
525 " Transmitting to ports : %s\n\n",
526 port_info->slot,
527 (int)port_info->name.slen,
528 port_info->name.ptr,
529 port_info->clock_rate,
Benny Prijonobc797312006-03-24 20:44:27 +0000530 port_info->samples_per_frame,
Benny Prijonocbc1c472006-03-19 00:50:23 +0000531 port_info->samples_per_frame*1000/port_info->clock_rate,
532 port_info->tx_adj_level,
533 port_info->rx_adj_level,
534 tx_level,
535 rx_level,
536 txlist);
537 }
538
539 }
540 puts("");
541}
542
543
544/*
545 * Display VU meter
546 */
547static void monitor_level(pjmedia_conf *conf, int slot, int dir, int dur)
548{
Benny Prijonoadb34652006-03-19 12:09:53 +0000549 enum { SLEEP = 20, SAMP_CNT = 2};
Benny Prijonocbc1c472006-03-19 00:50:23 +0000550 pj_status_t status;
Benny Prijonoadb34652006-03-19 12:09:53 +0000551 int i, total_count;
552 unsigned level, samp_cnt;
553
Benny Prijonocbc1c472006-03-19 00:50:23 +0000554
555 puts("");
556 printf("Displaying VU meter for port %d for about %d seconds\n",
557 slot, dur);
558
Benny Prijonoadb34652006-03-19 12:09:53 +0000559 total_count = dur * 1000 / SLEEP;
Benny Prijonocbc1c472006-03-19 00:50:23 +0000560
Benny Prijonoadb34652006-03-19 12:09:53 +0000561 level = 0;
562 samp_cnt = 0;
563
564 for (i=0; i<total_count; ++i) {
Benny Prijonocbc1c472006-03-19 00:50:23 +0000565 unsigned tx_level, rx_level;
Benny Prijonoadb34652006-03-19 12:09:53 +0000566 int j, length;
Benny Prijonocbc1c472006-03-19 00:50:23 +0000567 char meter[21];
568
Benny Prijonoadb34652006-03-19 12:09:53 +0000569 /* Poll the volume every 20 msec */
Benny Prijonocbc1c472006-03-19 00:50:23 +0000570 status = pjmedia_conf_get_signal_level(conf, slot,
571 &tx_level, &rx_level);
572 if (status != PJ_SUCCESS) {
573 app_perror(THIS_FILE, "Unable to read level", status);
574 return;
575 }
576
Benny Prijonoadb34652006-03-19 12:09:53 +0000577 level += (dir=='r' ? rx_level : tx_level);
578 ++samp_cnt;
579
580 /* Accumulate until we have enough samples */
581 if (samp_cnt < SAMP_CNT) {
582 pj_thread_sleep(SLEEP);
583 continue;
584 }
585
586 /* Get average */
587 level = level / samp_cnt;
588
589 /* Draw bar */
590 length = 20 * level / 255;
591 for (j=0; j<length; ++j)
Benny Prijonocbc1c472006-03-19 00:50:23 +0000592 meter[j] = '#';
593 for (; j<20; ++j)
594 meter[j] = ' ';
595 meter[20] = '\0';
596
Benny Prijonoadb34652006-03-19 12:09:53 +0000597 printf("Port #%02d %cx level: [%s] %d \r",
598 slot, dir, meter, level);
599
600 /* Next.. */
601 samp_cnt = 0;
602 level = 0;
Benny Prijonocbc1c472006-03-19 00:50:23 +0000603
604 pj_thread_sleep(SLEEP);
605 }
606
607 puts("");
608}
609