diff options
author | Benny Prijono <bennylp@teluu.com> | 2006-03-24 20:44:27 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2006-03-24 20:44:27 +0000 |
commit | a82abf01b16983b97036a5e0e11e70d188970256 (patch) | |
tree | 91cbe4cc7412ac0fbf2338d47af42bfbca05152e /pjsip-apps/src/samples | |
parent | 4317d89db92d5d7766e5409cc3a9c1142796d1ed (diff) |
Added more samples: WAV recorder, resample, etc., and also moved some common functions to util.h
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@361 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip-apps/src/samples')
-rw-r--r-- | pjsip-apps/src/samples/confsample.c | 127 | ||||
-rw-r--r-- | pjsip-apps/src/samples/debug.c | 2 | ||||
-rw-r--r-- | pjsip-apps/src/samples/playfile.c | 48 | ||||
-rw-r--r-- | pjsip-apps/src/samples/recfile.c | 183 | ||||
-rw-r--r-- | pjsip-apps/src/samples/resampleplay.c | 227 | ||||
-rw-r--r-- | pjsip-apps/src/samples/simpleua.c | 35 | ||||
-rw-r--r-- | pjsip-apps/src/samples/util.h | 217 |
7 files changed, 633 insertions, 206 deletions
diff --git a/pjsip-apps/src/samples/confsample.c b/pjsip-apps/src/samples/confsample.c index bf786d65..843b99fa 100644 --- a/pjsip-apps/src/samples/confsample.c +++ b/pjsip-apps/src/samples/confsample.c @@ -18,6 +18,21 @@ */ #include <pjmedia.h> +#include <pjlib-util.h> /* pj_getopt */ +#include <pjlib.h> + +#include <stdlib.h> /* atoi() */ +#include <stdio.h> + +#include "util.h" + +/* For logging purpose. */ +#define THIS_FILE "confsample.c" + + +/* Shall we put recorder in the conference */ +#define RECORDER 1 + static const char *desc = " FILE: \n" @@ -30,9 +45,11 @@ static const char *desc = " \n" " USAGE: \n" " \n" - " confsample [file1.wav] [file2.wav] ... \n" + " confsample [options] [file1.wav] [file2.wav] ... \n" + " \n" + " options: \n" + SND_USAGE " \n" - " where: \n" " fileN.wav are optional WAV files to be connected to the conference \n" " bridge. The WAV files MUST have single channel (mono) and 16 bit PCM \n" " samples. It can have arbitrary sampling rate. \n" @@ -45,24 +62,9 @@ static const char *desc = " If WAV files are specified, the WAV file player ports will be connected \n" " to slot starting from number one in the bridge. The WAV files can have \n" " arbitrary sampling rate; the bridge will convert it to its clock rate. \n" - " However, the files MUST have a single audio channel only (i.e. mono). \n"; - -#include <pjmedia.h> -#include <pjlib.h> - -#include <stdlib.h> /* atoi() */ -#include <stdio.h> + " However, the files MUST have a single audio channel only (i.e. mono). \n"; -/* For logging purpose. */ -#define THIS_FILE "confsample.c" - -/* Constants */ -#define CLOCK_RATE 44100 -#define NSAMPLES (CLOCK_RATE * 20 / 1000) -#define NCHANNELS 1 -#define NBITS 16 - /* * Prototypes: @@ -75,19 +77,6 @@ static void conf_list(pjmedia_conf *conf, pj_bool_t detail); static void monitor_level(pjmedia_conf *conf, int slot, int dir, int dur); -/* Util to display the error message for the specified error code */ -static int app_perror( const char *sender, const char *title, - pj_status_t status) -{ - char errmsg[PJ_ERR_MSG_SIZE]; - - pj_strerror(status, errmsg, sizeof(errmsg)); - - printf("%s: %s [code=%d]\n", title, errmsg, status); - return 1; -} - - /* Show usage */ static void usage(void) { @@ -123,6 +112,12 @@ static pj_bool_t input(const char *title, char *buf, pj_size_t len) */ int main(int argc, char *argv[]) { + int dev_id = -1; + int clock_rate = CLOCK_RATE; + int channel_count = NCHANNELS; + int samples_per_frame = NSAMPLES; + int bits_per_sample = NBITS; + pj_caching_pool cp; pjmedia_endpt *med_endpt; pj_pool_t *pool; @@ -130,22 +125,24 @@ int main(int argc, char *argv[]) int i, port_count, file_count; pjmedia_port **file_port; /* Array of file ports */ + pjmedia_port *rec_port = NULL; /* Wav writer port */ char tmp[10]; pj_status_t status; - /* Just in case user needs help */ - if (argc > 1 && (*argv[1]=='-' || *argv[1]=='/' || *argv[1]=='?')) { - usage(); - return 1; - } - - /* Must init PJLIB first: */ status = pj_init(); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); + /* Get command line options. */ + if (get_snd_options(THIS_FILE, argc, argv, &dev_id, &clock_rate, + &channel_count, &samples_per_frame, &bits_per_sample)) + { + usage(); + return 1; + } + /* Must create a pool factory before we can allocate any memory. */ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); @@ -165,8 +162,8 @@ int main(int argc, char *argv[]) ); - file_count = argc-1; - port_count = file_count + 1; + file_count = argc - pj_optind; + port_count = file_count + 1 + RECORDER; /* Create the conference bridge. * With default options (zero), the bridge will create an instance of @@ -174,10 +171,10 @@ int main(int argc, char *argv[]) */ status = pjmedia_conf_create( pool, /* pool to use */ port_count,/* number of ports */ - CLOCK_RATE,/* sampling rate */ - NCHANNELS,/* # of channels. */ - NSAMPLES, /* samples per frame */ - NBITS, /* bits per sample */ + clock_rate, + channel_count, + samples_per_frame, + bits_per_sample, 0, /* options */ &conf /* result */ ); @@ -186,6 +183,20 @@ int main(int argc, char *argv[]) return 1; } +#if RECORDER + status = pjmedia_file_writer_port_create( pool, "confrecord.wav", + clock_rate, channel_count, + samples_per_frame, + bits_per_sample, 0, 0, NULL, + &rec_port); + if (status != PJ_SUCCESS) { + app_perror(THIS_FILE, "Unable to create WAV writer", status); + return 1; + } + + pjmedia_conf_add_port(conf, pool, rec_port, NULL, NULL); +#endif + /* Create file ports. */ file_port = pj_pool_alloc(pool, file_count * sizeof(pjmedia_port*)); @@ -193,16 +204,17 @@ int main(int argc, char *argv[]) for (i=0; i<file_count; ++i) { /* Load the WAV file to file port. */ - status = pjmedia_file_player_port_create( pool, /* pool. */ - argv[i+1],/* filename */ - 0, /* flags */ - 0, /* buf size */ - NULL, /* user data */ - &file_port[i] /* result */ - ); + status = pjmedia_file_player_port_create( + pool, /* pool. */ + argv[i+pj_optind], /* filename */ + 0, /* flags */ + 0, /* buf size */ + NULL, /* user data */ + &file_port[i] /* result */ + ); if (status != PJ_SUCCESS) { char title[80]; - pj_ansi_sprintf(title, "Unable to use %s", argv[i+1]); + pj_ansi_sprintf(title, "Unable to use %s", argv[i+pj_optind]); app_perror(THIS_FILE, title, status); usage(); return 1; @@ -213,7 +225,7 @@ int main(int argc, char *argv[]) pool, /* pool */ file_port[i], /* port to connect */ NULL, /* Use port's name */ - NULL /* ptr to receive slot # */ + NULL /* ptr for slot # */ ); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to add conference port", status); @@ -229,6 +241,9 @@ int main(int argc, char *argv[]) */ + /* Dump memory usage */ + dump_pool_usage(THIS_FILE, &cp); + /* Sleep to allow log messages to flush */ pj_thread_sleep(100); @@ -420,6 +435,10 @@ on_quit: PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); } + /* Destroy recorder port */ + if (rec_port) + pjmedia_port_destroy(rec_port); + /* Release application pool */ pj_pool_release( pool ); @@ -483,6 +502,7 @@ static void conf_list(pjmedia_conf *conf, int detail) printf("Port #%02d:\n" " Name : %.*s\n" " Sampling rate : %d Hz\n" + " Samples per frame : %d\n" " Frame time : %d ms\n" " Signal level adjustment : tx=%d, rx=%d\n" " Current signal level : tx=%u, rx=%u\n" @@ -491,6 +511,7 @@ static void conf_list(pjmedia_conf *conf, int detail) (int)port_info->name.slen, port_info->name.ptr, port_info->clock_rate, + port_info->samples_per_frame, port_info->samples_per_frame*1000/port_info->clock_rate, port_info->tx_adj_level, port_info->rx_adj_level, diff --git a/pjsip-apps/src/samples/debug.c b/pjsip-apps/src/samples/debug.c index a37114c0..7e295392 100644 --- a/pjsip-apps/src/samples/debug.c +++ b/pjsip-apps/src/samples/debug.c @@ -27,5 +27,5 @@ * E.g.: * #include "playfile.c" */ -#include "confsample.c" +#include "resampleplay.c" diff --git a/pjsip-apps/src/samples/playfile.c b/pjsip-apps/src/samples/playfile.c index a703bc57..215ff415 100644 --- a/pjsip-apps/src/samples/playfile.c +++ b/pjsip-apps/src/samples/playfile.c @@ -18,6 +18,13 @@ */ #include <pjmedia.h> +#include <pjlib-util.h> +#include <pjlib.h> +#include <stdio.h> +#include <stdlib.h> + +#include "util.h" + /* * playfile.c @@ -33,26 +40,26 @@ * */ -#include <pjmedia.h> -#include <pjlib.h> - -#include <stdio.h> /* For logging purpose. */ #define THIS_FILE "playfile.c" -/* Util to display the error message for the specified error code */ -static int app_perror( const char *sender, const char *title, - pj_status_t status) -{ - char errmsg[PJ_ERR_MSG_SIZE]; - - pj_strerror(status, errmsg, sizeof(errmsg)); - - printf("%s: %s [code=%d]\n", title, errmsg, status); - return 1; -} +static const char *desc = +" FILE \n" +" \n" +" playfile.c \n" +" \n" +" PURPOSE \n" +" \n" +" Demonstrate how to play a WAV file. \n" +" \n" +" USAGE \n" +" \n" +" playfile FILE.WAV \n" +" \n" +" The WAV file could have mono or stereo channels with arbitrary \n" +" sampling rate, but MUST contain uncompressed (i.e. 16bit) PCM. \n"; /* @@ -69,17 +76,6 @@ int main(int argc, char *argv[]) pj_status_t status; - /* Verify cmd line arguments. */ - if (argc != 2) { - puts(""); - puts("Usage: "); - puts(" playfile <wav-file>"); - puts(""); - puts("The WAV file could have mono or stereo channels with arbitrary"); - puts("sampling rate, but MUST contain uncompressed (i.e. 16bit) PCM."); - return 0; - } - /* Must init PJLIB first: */ status = pj_init(); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); diff --git a/pjsip-apps/src/samples/recfile.c b/pjsip-apps/src/samples/recfile.c new file mode 100644 index 00000000..3fd96125 --- /dev/null +++ b/pjsip-apps/src/samples/recfile.c @@ -0,0 +1,183 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include <pjmedia.h> +#include <pjlib.h> + +#include <stdio.h> + +/* For logging purpose. */ +#define THIS_FILE "recfile.c" + +/* Configs */ +#define CLOCK_RATE 44100 +#define SAMPLES_PER_FRAME (CLOCK_RATE * 20 / 1000) +#define NCHANNELS 2 +#define BITS_PER_SAMPLE 16 + + +static const char *desc = + " FILE \n" + " recfile.c \n" + " \n" + " PURPOSE: \n" + " Record microphone to WAVE file. \n" + " \n" + " USAGE: \n" + " recfile FILE.WAV \n" + ""; + + +/* Util to display the error message for the specified error code */ +static int app_perror( const char *sender, const char *title, + pj_status_t status) +{ + char errmsg[PJ_ERR_MSG_SIZE]; + + PJ_UNUSED_ARG(sender); + + pj_strerror(status, errmsg, sizeof(errmsg)); + + printf("%s: %s [code=%d]\n", title, errmsg, status); + return 1; +} + + +/* + * main() + */ +int main(int argc, char *argv[]) +{ + pj_caching_pool cp; + pjmedia_endpt *med_endpt; + pj_pool_t *pool; + pjmedia_port *file_port; + pjmedia_snd_port *snd_port; + char tmp[10]; + pj_status_t status; + + + /* Verify cmd line arguments. */ + if (argc != 2) { + puts(""); + puts(desc); + return 0; + } + + /* Must init PJLIB first: */ + status = pj_init(); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); + + /* Must create a pool factory before we can allocate any memory. */ + pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); + + /* + * Initialize media endpoint. + * This will implicitly initialize PJMEDIA too. + */ + status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); + + /* Create memory pool for our file player */ + pool = pj_pool_create( &cp.factory, /* pool factory */ + "app", /* pool name. */ + 4000, /* init size */ + 4000, /* increment size */ + NULL /* callback on error */ + ); + + /* Create WAVE file writer port. */ + status = pjmedia_file_writer_port_create( pool, argv[1], + CLOCK_RATE, + NCHANNELS, + SAMPLES_PER_FRAME, + BITS_PER_SAMPLE, + 0, 0, NULL, + &file_port); + if (status != PJ_SUCCESS) { + app_perror(THIS_FILE, "Unable to open WAV file for writing", status); + return 1; + } + + /* Create sound player port. */ + status = pjmedia_snd_port_create_rec( + pool, /* pool */ + -1, /* use default dev. */ + file_port->info.sample_rate, /* clock rate. */ + file_port->info.channel_count, /* # of channels. */ + file_port->info.samples_per_frame, /* samples per frame. */ + file_port->info.bits_per_sample, /* bits per sample. */ + 0, /* options */ + &snd_port /* returned port */ + ); + if (status != PJ_SUCCESS) { + app_perror(THIS_FILE, "Unable to open sound device", status); + return 1; + } + + /* Connect file port to the sound player. + * Stream playing will commence immediately. + */ + status = pjmedia_snd_port_connect( snd_port, file_port); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); + + + + /* + * Recording should be started now. + */ + + + /* Sleep to allow log messages to flush */ + pj_thread_sleep(10); + + + printf("Recodring %s..\n", argv[1]); + puts(""); + puts("Press <ENTER> to stop recording and quit"); + + fgets(tmp, sizeof(tmp), stdin); + + + /* Start deinitialization: */ + + /* Destroy sound device */ + status = pjmedia_snd_port_destroy( snd_port ); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); + + + /* Destroy file port */ + status = pjmedia_port_destroy( file_port ); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); + + + /* Release application pool */ + pj_pool_release( pool ); + + /* Destroy media endpoint. */ + pjmedia_endpt_destroy( med_endpt ); + + /* Destroy pool factory */ + pj_caching_pool_destroy( &cp ); + + + /* Done. */ + return 0; +} diff --git a/pjsip-apps/src/samples/resampleplay.c b/pjsip-apps/src/samples/resampleplay.c new file mode 100644 index 00000000..62b6761d --- /dev/null +++ b/pjsip-apps/src/samples/resampleplay.c @@ -0,0 +1,227 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjmedia.h> +#include <pjlib-util.h> +#include <pjlib.h> + +#include <stdio.h> +#include <stdlib.h> + +#include "util.h" + +/* For logging purpose. */ +#define THIS_FILE "resampleplay.c" + + +static const char *desc = +" FILE \n" +" \n" +" resampleplay.c \n" +" \n" +" PURPOSE \n" +" \n" +" Demonstrate how use resample port to play a WAV file to sound \n" +" device using different sampling rate. \n" +" \n" +" USAGE \n" +" \n" +" resampleplay [options] FILE.WAV \n" +" \n" +" where options: \n" +SND_USAGE +" \n" +" The WAV file could have mono or stereo channels with arbitrary \n" +" sampling rate, but MUST contain uncompressed (i.e. 16bit) PCM. \n"; + + +int main(int argc, char *argv[]) +{ + pj_caching_pool cp; + pjmedia_endpt *med_endpt; + pj_pool_t *pool; + pjmedia_port *file_port; + pjmedia_port *resample_port; + pjmedia_snd_port *snd_port; + char tmp[10]; + pj_status_t status; + + int dev_id = -1; + int sampling_rate = CLOCK_RATE; + int channel_count = NCHANNELS; + int samples_per_frame = NSAMPLES; + int bits_per_sample = NBITS; + //int ptime; + //int down_samples; + + /* Must init PJLIB first: */ + status = pj_init(); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); + + + /* Get options */ + if (get_snd_options(THIS_FILE, argc, argv, &dev_id, &sampling_rate, + &channel_count, &samples_per_frame, &bits_per_sample)) + { + puts(""); + puts(desc); + return 1; + } + + if (!argv[pj_optind]) { + puts("Error: no file is specified"); + puts(desc); + return 1; + } + + /* Must create a pool factory before we can allocate any memory. */ + pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); + + /* + * Initialize media endpoint. + * This will implicitly initialize PJMEDIA too. + */ + status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); + + /* Create memory pool for our file player */ + pool = pj_pool_create( &cp.factory, /* pool factory */ + "app", /* pool name. */ + 4000, /* init size */ + 4000, /* increment size */ + NULL /* callback on error */ + ); + + /* Create the file port. */ + status = pjmedia_file_player_port_create( pool, argv[pj_optind], 0, + 0, 0, &file_port); + if (status != PJ_SUCCESS) { + app_perror(THIS_FILE, "Unable to open file", status); + return 1; + } + + /* File must have same number of channels. */ + if (file_port->info.channel_count != (unsigned)channel_count) { + PJ_LOG(3,(THIS_FILE, "Error: file has different number of channels. " + "Perhaps you'd need -c option?")); + pjmedia_port_destroy(file_port); + return 1; + } + + /* Calculate number of samples per frame to be taken from file port */ + //ptime = samples_per_frame * 1000 / sampling_rate; + + /* Create the resample port. */ + status = pjmedia_resample_port_create( pool, 1, 1, + file_port->info.sample_rate, + sampling_rate, + channel_count, + (unsigned)( + samples_per_frame * 1.0 * + file_port->info.sample_rate / + sampling_rate), + &resample_port); + if (status != PJ_SUCCESS) { + app_perror(THIS_FILE, "Unable to create resample port", status); + return 1; + } + + /* Connect resample port to file port */ + status = pjmedia_port_connect( pool, resample_port, file_port); + if (status != PJ_SUCCESS) { + app_perror(THIS_FILE, "Error connecting ports", status); + return 1; + } + + /* Create sound player port. */ + status = pjmedia_snd_port_create( + pool, /* pool */ + dev_id, /* device */ + dev_id, /* device */ + sampling_rate, /* clock rate. */ + channel_count, /* # of channels. */ + samples_per_frame, /* samples per frame. */ + bits_per_sample, /* bits per sample. */ + 0, /* options */ + &snd_port /* returned port */ + ); + if (status != PJ_SUCCESS) { + app_perror(THIS_FILE, "Unable to open sound device", status); + return 1; + } + + /* Connect resample port to sound device */ + status = pjmedia_snd_port_connect( snd_port, resample_port); + if (status != PJ_SUCCESS) { + app_perror(THIS_FILE, "Error connecting sound ports", status); + return 1; + } + + + /* Dump memory usage */ + dump_pool_usage(THIS_FILE, &cp); + + /* + * File should be playing and looping now, using sound device's thread. + */ + + + /* Sleep to allow log messages to flush */ + pj_thread_sleep(100); + + + printf("Playing %s at sampling rate %d (original file sampling rate=%d)\n", + argv[pj_optind], sampling_rate, file_port->info.sample_rate); + puts(""); + puts("Press <ENTER> to stop playing and quit"); + + fgets(tmp, sizeof(tmp), stdin); + + + /* Start deinitialization: */ + + + /* Destroy sound device */ + status = pjmedia_snd_port_destroy( snd_port ); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); + + + /* Destroy resample port. + * This will destroy all downstream ports (e.g. the file port) + */ + status = pjmedia_port_destroy( resample_port ); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); + + + /* Release application pool */ + pj_pool_release( pool ); + + /* Destroy media endpoint. */ + pjmedia_endpt_destroy( med_endpt ); + + /* Destroy pool factory */ + pj_caching_pool_destroy( &cp ); + + + /* Done. */ + return 0; + +} + + + diff --git a/pjsip-apps/src/samples/simpleua.c b/pjsip-apps/src/samples/simpleua.c index bed26711..8079225d 100644 --- a/pjsip-apps/src/samples/simpleua.c +++ b/pjsip-apps/src/samples/simpleua.c @@ -61,6 +61,7 @@ /* For logging purpose. */ #define THIS_FILE "simpleua.c" +#include "util.h" /* * Static variables. @@ -124,20 +125,6 @@ static pjsip_module mod_simpleua = }; -/* - * Util to display the error message for the specified error code - */ -static int app_perror( const char *sender, const char *title, - pj_status_t status) -{ - char errmsg[PJ_ERR_MSG_SIZE]; - - pj_strerror(status, errmsg, sizeof(errmsg)); - - PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status)); - return 1; -} - /* * main() @@ -415,24 +402,8 @@ int main(int argc, char *argv[]) pjsip_endpt_handle_events(g_endpt, &timeout); } - /* On exit, dump memory usage: */ - { - pj_pool_t *p; - unsigned total_alloc = 0; - unsigned total_used = 0; - - /* Accumulate memory usage in active list. */ - p = cp.used_list.next; - while (p != (pj_pool_t*) &cp.used_list) { - total_alloc += pj_pool_get_capacity(p); - total_used += pj_pool_get_used_size(p); - p = p->next; - } - - printf("Total pool memory allocated=%d KB, used=%d KB\n", - total_alloc / 1000, - total_used / 1000); - } + /* On exit, dump current memory usage: */ + dump_pool_usage(THIS_FILE, &cp); return 0; } diff --git a/pjsip-apps/src/samples/util.h b/pjsip-apps/src/samples/util.h index fbe1e04f..784ba0f9 100644 --- a/pjsip-apps/src/samples/util.h +++ b/pjsip-apps/src/samples/util.h @@ -1,38 +1,6 @@ -/* Include all PJSIP core headers. */ -#include <pjsip.h> -/* Include all PJMEDIA headers. */ -#include <pjmedia.h> - -/* Include all PJMEDIA-CODEC headers. */ -#include <pjmedia-codec.h> - -/* Include all PJSIP-UA headers */ -#include <pjsip_ua.h> - -/* Include all PJSIP-SIMPLE headers */ -#include <pjsip_simple.h> - -/* Include all PJLIB-UTIL headers. */ -#include <pjlib-util.h> - -/* Include all PJLIB headers. */ -#include <pjlib.h> - - -/* Global endpoint instance. */ -static pjsip_endpoint *g_endpt; - -/* Global caching pool factory. */ -static pj_caching_pool cp; - -/* Global media endpoint. */ -static pjmedia_endpt *g_med_endpt; - -/* - * Show error. - */ +/* Util to display the error message for the specified error code */ static int app_perror( const char *sender, const char *title, pj_status_t status) { @@ -40,84 +8,145 @@ static int app_perror( const char *sender, const char *title, pj_strerror(status, errmsg, sizeof(errmsg)); - PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status)); + PJ_LOG(3,(sender, "%s: %s [code=%d]", title, errmsg, status)); return 1; } -/* - * Perform the very basic initialization: - * - init PJLIB. - * - init memory pool - * - create SIP endpoint instance. - */ -static pj_status_t util_init(void) -{ - pj_status_t status; - - /* Init PJLIB */ - status = pj_init(); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "pj_init() error", status); - return status; - } - /* Init PJLIB-UTIL: */ - status = pjlib_util_init(); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "pjlib_util_init() error", status); - return status; - } - /* Init memory pool: */ +/* Constants */ +#define CLOCK_RATE 44100 +#define NSAMPLES (CLOCK_RATE * 20 / 1000) +#define NCHANNELS 1 +#define NBITS 16 - /* Init caching pool. */ - pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); +/* + * Common sound options. + */ +#define SND_USAGE \ +" -d, --dev=NUM Sound device use device id NUM (default=-1) \n"\ +" -r, --rate=HZ Set clock rate in samples per sec (default=44100)\n"\ +" -c, --channel=NUM Set # of channels (default=1 for mono). \n"\ +" -f, --frame=NUM Set # of samples per frame (default equival 20ms)\n"\ +" -b, --bit=NUM Set # of bits per sample (default=16) \n" - /* Create global endpoint: */ +/* + * This utility function parses the command line and look for + * common sound options. + */ +static pj_status_t get_snd_options( const char *app_name, + int argc, + char *argv[], + int *dev_id, + int *clock_rate, + int *channel_count, + int *samples_per_frame, + int *bits_per_sample) +{ + struct pj_getopt_option long_options[] = { + { "dev", 1, 0, 'd' }, + { "rate", 1, 0, 'r' }, + { "channel", 1, 0, 'c' }, + { "frame", 1, 0, 'f' }, + { "bit", 1, 0, 'b' }, + { NULL, 0, 0, 0 }, + }; + int c; + int option_index; + long val; + char *err; + + *samples_per_frame = 0; + + pj_optind = 0; + while((c=pj_getopt_long(argc,argv, "d:r:c:f:b:", + long_options, &option_index))!=-1) { - const pj_str_t *hostname; - const char *endpt_name; - - /* Endpoint MUST be assigned a globally unique name. - * The name will be used as the hostname in Warning header. - */ - /* For this implementation, we'll use hostname for simplicity */ - hostname = pj_gethostname(); - endpt_name = hostname->ptr; + switch (c) { + case 'd': + /* device */ + val = strtol(pj_optarg, &err, 10); + if (*err) { + PJ_LOG(3,(app_name, "Error: invalid value for device id")); + return PJ_EINVAL; + } + *dev_id = val; + break; + + case 'r': + /* rate */ + val = strtol(pj_optarg, &err, 10); + if (*err) { + PJ_LOG(3,(app_name, "Error: invalid value for clock rate")); + return PJ_EINVAL; + } + *clock_rate = val; + break; + + case 'c': + /* channel count */ + val = strtol(pj_optarg, &err, 10); + if (*err) { + PJ_LOG(3,(app_name, "Error: invalid channel count")); + return PJ_EINVAL; + } + *channel_count = val; + break; + + case 'f': + /* frame count/samples per frame */ + val = strtol(pj_optarg, &err, 10); + if (*err) { + PJ_LOG(3,(app_name, "Error: invalid samples per frame")); + return PJ_EINVAL; + } + *samples_per_frame = val; + break; + + case 'b': + /* bit per sample */ + val = strtol(pj_optarg, &err, 10); + if (*err) { + PJ_LOG(3,(app_name, "Error: invalid samples bits per sample")); + return PJ_EINVAL; + } + *bits_per_sample = val; + break; + + default: + /* Unknown options */ + PJ_LOG(3,(app_name, "Error: unknown options '%c'", pj_optopt)); + return PJ_EINVAL; + } - /* Create the endpoint: */ + } - status = pjsip_endpt_create(&cp.factory, endpt_name, - &g_endpt); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to create SIP endpoint", status); - return status; - } + if (*samples_per_frame == 0) { + *samples_per_frame = *clock_rate * *channel_count * 20 / 1000; } - return PJ_SUCCESS; + return 0; } -/* - * Add UDP transport to endpoint. - */ -static pj_status_t util_add_udp_transport(int port) + +/* Dump memory pool usage. */ +static void dump_pool_usage( const char *app_name, pj_caching_pool *cp ) { - pj_sockaddr_in addr; - pj_status_t status; - - addr.sin_family = PJ_AF_INET; - addr.sin_addr.s_addr = 0; - addr.sin_port = port; - - status = pjsip_udp_transport_start( g_endpt, &addr, NULL, 1, NULL); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to start UDP transport", status); - return status; + pj_pool_t *p; + unsigned total_alloc = 0; + unsigned total_used = 0; + + /* Accumulate memory usage in active list. */ + p = cp->used_list.next; + while (p != (pj_pool_t*) &cp->used_list) { + total_alloc += pj_pool_get_capacity(p); + total_used += pj_pool_get_used_size(p); + p = p->next; } - return status; + PJ_LOG(3, (app_name, "Total pool memory allocated=%d KB, used=%d KB", + total_alloc / 1000, + total_used / 1000)); } - |