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 };

Generated on Mon Aug 18 00:00:36 2008 for hptdm_api by  doxygen 1.4.7