hptdm_api: aft_tdm_hp.c Source File

- Main Page
- Classes
- Files

# aft_tdm_hp.c

    00001 /*****************************************************************************
    00002 * aft_tdm_hp.c: Example code for HP TDM API Library
    00003 *
    00004 * Author(s):    Nenad Corbic <ncorbic@sangoma.com>
    00005 *
    00006 * Copyright:    (c) 2008 Sangoma Technologies Inc.
    00007 *
    00008 *               This program is free software; you can redistribute it and/or
    00009 *               modify it under the terms of the GNU General Public License
    00010 *               as published by the Free Software Foundation; either version
    00011 *               2 of the License, or (at your option) any later version.
    00012 * ============================================================================
    00013 * Description:
    00014 *
    00015 */
    00016
    00017 #include "aft_tdm_hp.h"
    00018
    00019
    00020 /*
    00021  * Global flags used by this program
    00022  */
    00023 static int system_flag=0;
    00024 static int system_threads=0;
    00025 static int system_debug=10;
    00026
    00027 /*
    00028  * Global defines for our program.  Create an array of spans and chans.
    00029  */
    00030 span_idx_t span_list[MAX_SPANS];
    00031 chan_idx_t chan_list[MAX_SPANS][MAX_CHANS];
    00032
    00033 /*------------------------------------------
    00034   Utilites
    00035  *-----------------------------------------*/
    00036
    00037 /*
    00038  * Utility used to print packets
    00039  */
    00040 void print_packet(unsigned char *buf, int len)
    00041 {
    00042         int x;
    00043         printf("{  | ");
    00044         for (x=0;x<len;x++){
    00045                 if (x && x%24 == 0){
    00046                         printf("\n  ");
    00047                 }
    00048                 if (x && x%8 == 0)
    00049                         printf(" | ");
    00050                 printf("%02x ",buf[x]);
    00051         }
    00052         printf("}\n");
    00053 }
    00054
    00055
    00056 /*
    00057  * Utility used to implement print to syslog
    00058  */
    00059 void __log_printf(int level, FILE *fp, char *file, const char *func, int line, char *fmt, ...)
    00060 {
    00061     char *data;
    00062     int ret = 0;
    00063     va_list ap;
    00064
    00065     if (socket < 0) {
    00066                 return;
    00067     }
    00068
    00069     if (level && level > system_debug) {
    00070                 return;
    00071     }
    00072
    00073     va_start(ap, fmt);
    00074 #ifdef SOLARIS
    00075     data = (char *) smg_malloc(2048);
    00076     vsnprintf(data, 2048, fmt, ap);
    00077 #else
    00078     ret = vasprintf(&data, fmt, ap);
    00079 #endif
    00080     va_end(ap);
    00081     if (ret == -1) {
    00082                 fprintf(stderr, "Memory Error\n");
    00083     } else {
    00084                 char date[80] = "";
    00085                 struct tm now;
    00086                 time_t epoch;
    00087
    00088                 if (time(&epoch) && localtime_r(&epoch, &now)) {
    00089                         strftime(date, sizeof(date), "%Y-%m-%d %T", &now);
    00090                 }
    00091
    00092 #ifdef USE_SYSLOG
    00093                 syslog(LOG_DEBUG | LOG_LOCAL2, data);
    00094 #else
    00095                 if (fp) {
    00096                 fprintf(fp, "[%d] %s %s:%d %s() %s", getpid(), date, file, line, func, data);
    00097                 }
    00098 #endif
    00099                 free(data);
    00100     }
    00101 #ifndef USE_SYSLOG
    00102     fflush(fp);
    00103 #endif
    00104 }
    00105
    00106 void sig_end(int sigid)
    00107 {
    00108         printf("%d: Got Signal %i\n",getpid(),sigid);
    00109         aft_clear_flag(system_flag,SYSTEM_RUNNING);
    00110 }
    00111
    00112
    00113
    00114 /*
    00115  * Main pthread thread used to implement a span->run_span() thread.
    00116  * All this thread does is call span->run_span() method.
    00117  * span->run-span method is defined in libsangoma library and it
    00118  * implements rx/tx/oob on span hw interface.
    00119  */
    00120 static void *hp_tdmapi_span_run(void *obj)
    00121 {
    00122         span_idx_t *span_idx = (span_idx_t*)obj;
    00123         int err;
    00124         sangoma_hptdm_span_t *span = span_idx->span;
    00125
    00126         span_idx->init = 1;
    00127
    00128         log_printf(0,NULL,"Starting span %i!\n",span->span_no+1);
    00129
    00130         while(aft_test_flag(system_flag,SYSTEM_RUNNING)){
    00131
    00132                 if (!span->run_span) {
    00133                         break;
    00134                 }
    00135
    00136                 err = span->run_span(span);
    00137                 if (err) {
    00138                         log_printf(0,NULL,"Span %i run_span exited err=%i!\n",span->span_no+1,err);
    00139                         usleep(5000);
    00140                         continue;
    00141                 }
    00142
    00143         }
    00144
    00145         if (span->close_span) {
    00146                 span->close_span(span);
    00147         }
    00148
    00149         span_idx->init = 0;
    00150
    00151         /* Arbitrary delay - implementation specific */
    00152         sleep(3);
    00153         log_printf(0,NULL,"Stopping span %i!\n",span->span_no+1);
    00154
    00155         pthread_exit(NULL);
    00156 }
    00157
    00158 /*
    00159  * Span Thrad Launcher.
    00160  * Spawn a span thread, give the thread span object poiner.
    00161  * This implementation should be user specific.
    00162  */
    00163 static int launch_hptdm_api_span_thread(pthread_t *threadid, void *span)
    00164 {
    00165         pthread_attr_t attr;
    00166         int result = 0;
    00167         struct sched_param param;
    00168
    00169         param.sched_priority = 5;
    00170         result = pthread_attr_init(&attr);
    00171         pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    00172         pthread_attr_setschedpolicy(&attr, SCHED_RR);
    00173         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    00174         pthread_attr_setstacksize(&attr, MGD_STACK_SIZE);
    00175
    00176         result = pthread_attr_setschedparam (&attr, &param);
    00177
    00178         result = pthread_create(threadid, &attr, hp_tdmapi_span_run, span);
    00179         if (result) {
    00180                 log_printf(0, NULL, "%s: Error: Creating Thread! %s\n",
    00181                            __FUNCTION__,strerror(errno));
    00182         }
    00183         pthread_attr_destroy(&attr);
    00184
    00185         return result;
    00186 }
    00187
    00188
    00189 /*
    00190  * Channel callback function. When channel has a chunk of data
    00191  * ready for us, this function will be called to deliver the
    00192  * rx chunk.  The user should implement the logic here of
    00193  * what to do with that rx chunk.
    00194  *
    00195  * If we return 0 - channel will continue to operate normally.
    00196  * If we return -1 - channel will get closed and we will not
    00197  *                  receive any more data on this channel until
    00198  *                  channel is opened again.
    00199  */
    00200
    00201 static int media_rx_ready(void *p, char *data, int len)
    00202 {
    00203         chan_idx_t *chan_idx = (chan_idx_t *)p;
    00204
    00205         if (!chan_idx->init) {
    00206                 return -1;
    00207         }
    00208
    00209         log_printf(15,NULL,"Chan s%ic%i Rx Data Len %i \n",
    00210                                 chan_idx->span_no+1,chan_idx->chan_no+1,len);
    00211
    00212 #if 0
    00213         print_packet((unsigned char*)data,len);
    00214 #endif
    00215
    00216         /* FIXME: ADD CODE HERE
    00217         Do something with rx chunk of data for this channel
    00218         */
    00219
    00220
    00221         /* If we return -1 here the library will close the channel */
    00222
    00223         return 0;
    00224 }
    00225
    00226
    00227 /*
    00228  * Main pthread thread used to implement a channel thread.
    00229  * Since this is a channel TX thread, user would wait on
    00230  * some UDP socket for data to be transmitted to this channel.
    00231  *
    00232  * The channel thread opens the channel on a span using
    00233  * the library span->open_chan method.  Once the channel
    00234  * object is obtained, this thread can start pushing
    00235  * arbitrary data chunks into the channel.
    00236  *
    00237  */
    00238 static void *hp_tdmapi_chan_run(void *obj)
    00239 {
    00240         chan_idx_t *chan_idx = (chan_idx_t*)obj;
    00241         int err;
    00242         char data[1024];
    00243         int len=160; /* 20ms worth of ulaw/alaw */
    00244
    00245         sangoma_hptdm_span_t *span;
    00246         sangoma_hptdm_chan_reg_t channel_reg;
    00247
    00248         /* Grab a span based on the span_no - integer starting from 0 */
    00249         span_idx_t *span_idx = &span_list[chan_idx->span_no];
    00250         span = span_idx->span;
    00251
    00252         log_printf(0,NULL,"Starting chan s%ic%i ...\n",
    00253                                 chan_idx->span_no+1,chan_idx->chan_no+1);
    00254
    00255         /* Configure channel registration structure */
    00256         memset(&channel_reg,0,sizeof(channel_reg));
    00257         channel_reg.p = (void*)chan_idx;
    00258         channel_reg.rx_data = media_rx_ready;
    00259
    00260         /* Set the local channel index to configured */
    00261         chan_idx->init = 1;
    00262
    00263         /* Open a channel based on chan_no integer starting from 0, on a specific span */
    00264         err = span->open_chan(span, &channel_reg, chan_idx->chan_no, &chan_idx->chan);
    00265         if (err){
    00266                 log_printf(0,NULL,"Error openeing chan s%ic%i ...\n",
    00267                                 chan_idx->span_no+1,chan_idx->chan_no+1);
    00268                 pthread_exit(NULL);
    00269         }
    00270
    00271
    00272         memset(data,0,sizeof(data));
    00273
    00274
    00275         while (aft_test_flag(system_flag,SYSTEM_RUNNING)) {
    00276
    00277                 /* FIXME: Wait for AUDIO from a UDP socket here
    00278                           once you receive data to tx to a channel
    00279                           use the push() funciton to pass the chunk
    00280                           into the channel.  The size can be of any length
    00281                           up to the MAX CHUNK SIZE */
    00282
    00283                 /* In this example we dont have a socket to wait on
    00284                    so we just use a delay */
    00285                 usleep(1000);
    00286
    00287                 err=chan_idx->chan->push(chan_idx->chan,
    00288                                          data,len);
    00289                 /*
    00290                 -1 = packet too large, -2 = channel closed, 1 = busy, 0 = tx ok
    00291                 */
    00292                 switch (err) {
    00293                 case 0:
    00294                         /* Data tx ok */
    00295                         break;
    00296                 case -1:
    00297                         /* packet too large */
    00298                         break;
    00299                 case -2:
    00300                         /* channel closed */
    00301                         break;
    00302                 case 1:
    00303                         /* failed to tx, channel busy - try again later - in 20ms or so */
    00304                         break;
    00305                 }
    00306         }
    00307
    00308         /* Once we are done, close the channel */
    00309         span->close_chan(chan_idx->chan);
    00310
    00311         /* Set the local channel index to free */
    00312         chan_idx->init = 0;
    00313
    00314         pthread_exit(NULL);
    00315 }
    00316
    00317 /*
    00318  * Channel Thrad Launcher.
    00319  * Spawn a channel thread, give the thread chan object poiner.
    00320  * This implementation should be user specific.
    00321  */
    00322 static int launch_hptdm_api_chan_thread(pthread_t *threadid, void *chan)
    00323 {
    00324     pthread_attr_t attr;
    00325     int result = 0;
    00326     struct sched_param param;
    00327
    00328     param.sched_priority = 1;
    00329     result = pthread_attr_init(&attr);
    00330     pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    00331     pthread_attr_setschedpolicy(&attr, SCHED_RR);
    00332     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    00333     pthread_attr_setstacksize(&attr, MGD_STACK_SIZE);
    00334
    00335     result = pthread_attr_setschedparam (&attr, &param);
    00336
    00337     result = pthread_create(threadid, &attr, hp_tdmapi_chan_run, chan);
    00338     if (result) {
    00339          log_printf(0, NULL, "%s: Error: Creating Thread! %s\n",
    00340                          __FUNCTION__,strerror(result));
    00341     }
    00342     pthread_attr_destroy(&attr);
    00343
    00344     return result;
    00345 }
    00346
    00347 /*
    00348  * Start all spans and channels.
    00349  *
    00350  * This exmaple codes automatically starts all spans and channels together.
    00351  * The real world application would start all spans on startup.
    00352  * Jowever the channels would only get started once the signalling stack indicates
    00353  * a call on that specific channel.
    00354  *
    00355  * This implementation should be user specific.
    00356  */
    00357 int smg_init_spans(void)
    00358 {
    00359         int span,i;
    00360         int err=-1;
    00361         sangoma_hptdm_span_reg_t lib_callback;
    00362         lib_callback.log=__log_printf;
    00363
    00364         for (span=0;span<16;span++) {
    00365                 span_list[span].span_no=span;
    00366                 span_list[span].span = sangoma_hptdm_api_span_init(span, &lib_callback);
    00367                 if (!span_list[span].span) {
    00368                         log_printf(0, NULL, "Error: Failed to initialize span %i\n",
    00369                                         span+1);
    00370                         break;
    00371                 } else {
    00372                         log_printf(0, NULL, "HP TDM API Span: %d configured...\n",
    00373                                         span+1);
    00374
    00375                         err=launch_hptdm_api_span_thread(&span_list[span].thread,&span_list[span]);
    00376                         if (err) {
    00377                                 return err;
    00378                         }
    00379
    00380                         for (i=0;i<31;i++) {
    00381                                 chan_list[span][i].chan_no=i;
    00382                                 chan_list[span][i].span_no=span;
    00383
    00384                                 err=launch_hptdm_api_chan_thread(&chan_list[span][i].thread,
    00385                                                                  &chan_list[span][i]);
    00386                                 if (err) {
    00387                                         return err;
    00388                                 }
    00389                         }
    00390                 }
    00391         }
    00392
    00393         return err;
    00394 }
    00395
    00396 /*
    00397  * Applicatoin Main Function
    00398  *
    00399  * This implementation should be user specific!
    00400  *
    00401  * Configure and initialize application
    00402  * Set a global sytem flag indicating that app is running.
    00403  *
    00404  * Start all SPANS by calling span init function and
    00405  * launching a thread per span. In span thread calling run_span().
    00406  *
    00407  * Start all channels by launching a thread per channel and
    00408  * calling span->chan_open.  Every 20ms send chunk down each channel.
    00409  *
    00410  * This implementation should be user specific!
    00411  */
    00412
    00413 int main(int argc, char* argv[])
    00414 {
    00415         int err=0;
    00416
    00417         nice(-10);
    00418
    00419         signal(SIGINT,&sig_end);
    00420         signal(SIGTERM,&sig_end);
    00421
    00422         aft_set_flag(system_flag,SYSTEM_RUNNING);
    00423
    00424         log_printf(0, NULL, "HP TDM API MAIN Process Starting\n");
    00425
    00426         err=smg_init_spans();
    00427         if (err) {
    00428                 aft_clear_flag(system_flag,SYSTEM_RUNNING);
    00429         }
    00430
    00431         while(aft_test_flag(system_flag,SYSTEM_RUNNING)){
    00432                 sleep(1);
    00433         }
    00434
    00435         sleep(5);
    00436         log_printf(0, NULL, "HP TDM API MAIN Process Exiting\n");
    00437
    00438         return 0;
    00439 };