BLOG | DOCUMENTATION | TRAC

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

 


PJMEDIA small footprint Open Source media stack
Copyright (C) 2006-2008 Teluu Inc.