pjsip logo pjsip.org
Open source SIP stack and media stack for presence, im/instant messaging, and multimedia communication

HOME

SIP/media Features
High Performance SIP
Small Footprint SIP
Symbian Port

FAQ

Documentation

Licensing

Download

Development (Trac)

Projects using pjsip

Mailing List

Open Source Links


About: PJLIB, PJLIB-UTIL, PJSIP, and PJMEDIA are created by: Benny Prijono
<bennylp@pjsip.org>


 

Home --> Documentations --> PJMEDIA Reference

Samples: Benchmarking Conference Bridge

Benchmarking pjmedia (conference bridge+resample). For my use only, and it only works in Win32.

This file is pjsip-apps/src/samples/confbench.c

00001 /* $Id: confbench.c 2039 2008-06-20 22:44:47Z bennylp $ */
00002 /* 
00003  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
00018  */
00019 
00020 
00033 #include <pjmedia.h>
00034 #include <pjlib-util.h> /* pj_getopt */
00035 #include <pjlib.h>
00036 #include <stdlib.h>     /* atoi() */
00037 #include <stdio.h>
00038 #include <windows.h>
00039 
00040 /* For logging purpose. */
00041 #define THIS_FILE   "confsample.c"
00042 
00043 
00044 /* Configurable:
00045  *   LARGE_SET will create in total of about 232 ports.
00046  *   HAS_RESAMPLE will activate resampling on about half
00047  *     the port.
00048  */
00049 #define TEST_SET            LARGE_SET
00050 #define HAS_RESAMPLE        0
00051 
00052 
00053 #define SMALL_SET           16
00054 #define LARGE_SET           100
00055 
00056 
00057 #define PORT_COUNT          254
00058 #define CLOCK_RATE          16000
00059 #define SAMPLES_PER_FRAME   (CLOCK_RATE/100)
00060 #if HAS_RESAMPLE
00061 #  define SINE_CLOCK        32000
00062 #else
00063 #  define SINE_CLOCK        CLOCK_RATE
00064 #endif
00065 #define SINE_PTIME          20
00066 #define DURATION            10
00067 
00068 #define SINE_COUNT          TEST_SET
00069 #define NULL_COUNT          TEST_SET
00070 #define IDLE_COUNT          32
00071 
00072 
00073 static void app_perror(const char *sender, const char *title, pj_status_t status)
00074 {
00075     char errmsg[PJ_ERR_MSG_SIZE];
00076 
00077     pj_strerror(status, errmsg, sizeof(errmsg));
00078     PJ_LOG(1,(sender, "%s: %s", title, errmsg));
00079 }
00080 
00081 
00082 struct Times
00083 {
00084     FILETIME        kernel_time;
00085     ULARGE_INTEGER  u_kernel_time;
00086     FILETIME        user_time;
00087     ULARGE_INTEGER  u_user_time;
00088     ULARGE_INTEGER  u_total;
00089 };
00090 
00091 static void process(struct Times *t)
00092 {
00093     pj_memcpy(&t->u_kernel_time, &t->kernel_time, sizeof(FILETIME));
00094     pj_memcpy(&t->u_user_time, &t->user_time, sizeof(FILETIME));
00095     t->u_total.QuadPart = t->u_kernel_time.QuadPart + t->u_user_time.QuadPart;
00096 }
00097 
00098 static void benchmark(void)
00099 {
00100     FILETIME creation_time, exit_time;
00101     struct Times start, end;
00102     DWORD ts, te;
00103     LARGE_INTEGER elapsed;
00104     BOOL rc;
00105     int i;
00106     double pct;
00107 
00108     puts("Test started!"); fflush(stdout);
00109 
00110     ts = GetTickCount();
00111     rc = GetProcessTimes(GetCurrentProcess(), &creation_time, &exit_time,
00112                          &start.kernel_time, &start.user_time);
00113     for (i=DURATION; i>0; --i) {
00114         printf("\r%d ", i); fflush(stdout);
00115         pj_thread_sleep(1000);
00116     }
00117     rc = GetProcessTimes(GetCurrentProcess(), &creation_time, &exit_time,
00118                          &end.kernel_time, &end.user_time);
00119     te = GetTickCount();
00120 
00121     process(&start);
00122     process(&end);
00123 
00124     elapsed.QuadPart = end.u_total.QuadPart - start.u_total.QuadPart;
00125 
00126     pct = elapsed.QuadPart * 100.0 / ((te-ts)*10000.0);
00127 
00128     printf("CPU usage=%6.4f%%\n", pct); fflush(stdout);
00129 }
00130 
00131 
00132 
00133 /* Struct attached to sine generator */
00134 typedef struct
00135 {
00136     pj_int16_t  *samples;       /* Sine samples.    */
00137 } port_data;
00138 
00139 
00140 /* This callback is called to feed more samples */
00141 static pj_status_t sine_get_frame( pjmedia_port *port, 
00142                                    pjmedia_frame *frame)
00143 {
00144     port_data *sine = port->port_data.pdata;
00145     pj_int16_t *samples = frame->buf;
00146     unsigned i, count, left, right;
00147 
00148     /* Get number of samples */
00149     count = frame->size / 2 / port->info.channel_count;
00150 
00151     left = 0;
00152     right = 0;
00153 
00154     for (i=0; i<count; ++i) {
00155         *samples++ = sine->samples[left];
00156         ++left;
00157 
00158         if (port->info.channel_count == 2) {
00159             *samples++ = sine->samples[right];
00160             right += 2; /* higher pitch so we can distinguish left and right. */
00161             if (right >= count)
00162                 right = 0;
00163         }
00164     }
00165 
00166     /* Must set frame->type correctly, otherwise the sound device
00167      * will refuse to play.
00168      */
00169     frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
00170 
00171     return PJ_SUCCESS;
00172 }
00173 
00174 #ifndef M_PI
00175 #define M_PI  (3.14159265)
00176 #endif
00177 
00178 /*
00179  * Create a media port to generate sine wave samples.
00180  */
00181 static pj_status_t create_sine_port(pj_pool_t *pool,
00182                                     unsigned sampling_rate,
00183                                     unsigned channel_count,
00184                                     pjmedia_port **p_port)
00185 {
00186     pjmedia_port *port;
00187     unsigned i;
00188     unsigned count;
00189     port_data *sine;
00190 
00191     PJ_ASSERT_RETURN(pool && channel_count > 0 && channel_count <= 2, 
00192                      PJ_EINVAL);
00193 
00194     port = pj_pool_zalloc(pool, sizeof(pjmedia_port));
00195     PJ_ASSERT_RETURN(port != NULL, PJ_ENOMEM);
00196 
00197     /* Fill in port info. */
00198     port->info.bits_per_sample = 16;
00199     port->info.channel_count = channel_count;
00200     port->info.encoding_name = pj_str("pcm");
00201     port->info.has_info = 1;
00202     port->info.name = pj_str("sine generator");
00203     port->info.need_info = 0;
00204     port->info.pt = 0xFF;
00205     port->info.clock_rate = sampling_rate;
00206     port->info.samples_per_frame = sampling_rate * SINE_PTIME / 1000 * channel_count;
00207     port->info.bytes_per_frame = port->info.samples_per_frame * 2;
00208     port->info.type = PJMEDIA_TYPE_AUDIO;
00209     
00210     /* Set the function to feed frame */
00211     port->get_frame = &sine_get_frame;
00212 
00213     /* Create sine port data */
00214     port->port_data.pdata = sine = pj_pool_zalloc(pool, sizeof(port_data));
00215 
00216     /* Create samples */
00217     count = port->info.samples_per_frame / channel_count;
00218     sine->samples = pj_pool_alloc(pool, count * sizeof(pj_int16_t));
00219     PJ_ASSERT_RETURN(sine->samples != NULL, PJ_ENOMEM);
00220 
00221     /* initialise sinusoidal wavetable */
00222     for( i=0; i<count; i++ )
00223     {
00224         sine->samples[i] = (pj_int16_t) (10000.0 * 
00225                 sin(((double)i/(double)count) * M_PI * 8.) );
00226     }
00227 
00228     *p_port = port;
00229 
00230     return PJ_SUCCESS;
00231 }
00232 
00233 int main()
00234 {
00235     pj_caching_pool cp;
00236     pjmedia_endpt *med_endpt;
00237     pj_pool_t *pool;
00238     pjmedia_conf *conf;
00239     int i;
00240     pjmedia_port *sine_port[SINE_COUNT], *null_port, *conf_port;
00241     pjmedia_port *nulls[NULL_COUNT];
00242     unsigned null_slots[NULL_COUNT];
00243     pjmedia_master_port *master_port;
00244     pj_status_t status;
00245 
00246 
00247     pj_log_set_level(3);
00248 
00249     status = pj_init();
00250     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00251 
00252     pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
00253     pool = pj_pool_create( &cp.factory,     /* pool factory         */
00254                            "wav",           /* pool name.           */
00255                            4000,            /* init size            */
00256                            4000,            /* increment size       */
00257                            NULL             /* callback on error    */
00258                            );
00259 
00260     status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
00261     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00262 
00263 
00264 
00265     status = pjmedia_conf_create( pool,
00266                                   PORT_COUNT,
00267                                   CLOCK_RATE,
00268                                   1, SAMPLES_PER_FRAME, 16,
00269                                   PJMEDIA_CONF_NO_DEVICE,
00270                                   &conf);
00271     if (status != PJ_SUCCESS) {
00272         app_perror(THIS_FILE, "Unable to create conference bridge", status);
00273         return 1;
00274     }
00275 
00276     printf("Resampling is %s\n", (HAS_RESAMPLE?"active":"disabled"));
00277 
00278     /* Create Null ports */
00279     printf("Creating %d null ports..\n", NULL_COUNT);
00280     for (i=0; i<NULL_COUNT; ++i) {
00281         status = pjmedia_null_port_create(pool, CLOCK_RATE, 1, SAMPLES_PER_FRAME*2, 16, &nulls[i]);
00282         PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00283 
00284         status = pjmedia_conf_add_port(conf, pool, nulls[i], NULL, &null_slots[i]);
00285         PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00286     }
00287 
00288     /* Create sine ports. */
00289     printf("Creating %d sine generator ports..\n", SINE_COUNT);
00290     for (i=0; i<SINE_COUNT; ++i) {
00291         unsigned j, slot;
00292 
00293         /* Load the WAV file to file port. */
00294         status = create_sine_port(pool, SINE_CLOCK, 1, &sine_port[i]);
00295         PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00296 
00297         /* Add the file port to conference bridge */
00298         status = pjmedia_conf_add_port( conf,           /* The bridge       */
00299                                         pool,           /* pool             */
00300                                         sine_port[i],   /* port to connect  */
00301                                         NULL,           /* Use port's name  */
00302                                         &slot           /* ptr for slot #   */
00303                                         );
00304         if (status != PJ_SUCCESS) {
00305             app_perror(THIS_FILE, "Unable to add conference port", status);
00306             return 1;
00307         }
00308 
00309         status = pjmedia_conf_connect_port(conf, slot, 0, 0);
00310         PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00311 
00312         for (j=0; j<NULL_COUNT; ++j) {
00313             status = pjmedia_conf_connect_port(conf, slot, null_slots[j], 0);
00314             PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00315         }
00316     }
00317 
00318     /* Create idle ports */
00319     printf("Creating %d idle ports..\n", IDLE_COUNT);
00320     for (i=0; i<IDLE_COUNT; ++i) {
00321         pjmedia_port *dummy;
00322         status = pjmedia_null_port_create(pool, CLOCK_RATE, 1, SAMPLES_PER_FRAME, 16, &dummy);
00323         PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00324         status = pjmedia_conf_add_port(conf, pool, dummy, NULL, NULL);
00325         PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00326     }
00327 
00328     /* Create null port */
00329     status = pjmedia_null_port_create(pool, CLOCK_RATE, 1, SAMPLES_PER_FRAME, 16,
00330                                       &null_port);
00331     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00332 
00333     conf_port = pjmedia_conf_get_master_port(conf);
00334 
00335     /* Create master port */
00336     status = pjmedia_master_port_create(pool, null_port, conf_port, 0, &master_port);
00337 
00338 
00339     pjmedia_master_port_start(master_port);
00340 
00341     puts("Waiting to settle.."); fflush(stdout);
00342     pj_thread_sleep(5000);
00343 
00344 
00345     benchmark();
00346 
00347 
00348     /* Done. */
00349     return 0;
00350 }
00351 
00352 

 


PJMEDIA small footprint Open Source media stack
(C)2003-2008 Benny Prijono