[commit] r5172 - in freeswitch/branches/greenlizard: . build conf libs libs/curl libs/iax/src libs/libedit libs/libedit/doc libs/libedit/examples libs/libedit/src libs/portaudio libs/sofia-sip/libsofia-sip-ua libs/sofia-sip/libsofia-sip-ua-glib/su-glib libs/sofia-sip/libsofia-sip-ua/bnf libs/sofia-sip/libsofia-sip-ua/docs libs/sofia-sip/libsofia-sip-ua/features libs/sofia-sip/libsofia-sip-ua/http libs/sofia-sip/libsofia-sip-ua/ipt libs/sofia-sip/libsofia-sip-ua/iptsec libs/sofia-sip/li
Author: greenlizard Date: Mon May 14 10:50:37 2007 New Revision: 5172 Added: freeswitch/branches/greenlizard/build/ignore_helper.pl - copied unchanged from r5170, /freeswitch/trunk/build/ignore_helper.pl freeswitch/branches/greenlizard/src/mod/event_handlers/mod_radius_cdr/ - copied from r5170, /freeswitch/trunk/src/mod/event_handlers/mod_radius_cdr/ Modified: freeswitch/branches/greenlizard/ (props changed) freeswitch/branches/greenlizard/Makefile.am freeswitch/branches/greenlizard/bootstrap.sh freeswitch/branches/greenlizard/conf/default_context.xml freeswitch/branches/greenlizard/conf/directory.xml freeswitch/branches/greenlizard/conf/iax.conf.xml freeswitch/branches/greenlizard/conf/sofia.conf.xml freeswitch/branches/greenlizard/conf/xml_curl.conf.xml freeswitch/branches/greenlizard/libs/ (props changed) freeswitch/branches/greenlizard/libs/curl/ (props changed) freeswitch/branches/greenlizard/libs/iax/src/iax-client.h freeswitch/branches/greenlizard/libs/iax/src/iax-mutex.c freeswitch/branches/greenlizard/libs/iax/src/iax.c freeswitch/branches/greenlizard/libs/iax/src/iax.h freeswitch/branches/greenlizard/libs/iax/src/iax2-parser.h freeswitch/branches/greenlizard/libs/iax/src/iax2.h freeswitch/branches/greenlizard/libs/iax/src/jitterbuf.c freeswitch/branches/greenlizard/libs/iax/src/jitterbuf.h freeswitch/branches/greenlizard/libs/iax/src/md5.h freeswitch/branches/greenlizard/libs/libedit/ (props changed) freeswitch/branches/greenlizard/libs/libedit/doc/ (props changed) freeswitch/branches/greenlizard/libs/libedit/examples/ (props changed) freeswitch/branches/greenlizard/libs/libedit/src/ (props changed) freeswitch/branches/greenlizard/libs/portaudio/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/Makefile.am freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/bnf/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/docs/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/features/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/http/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/ipt/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/iptsec/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/msg/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/nea/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/nta/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/nth/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/nua/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/nua/nua.c freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/sdp/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/sip/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/soa/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/sresolv/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/stun/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/su/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/tport/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/url/ (props changed) freeswitch/branches/greenlizard/libs/sofia-sip/utils/ (props changed) freeswitch/branches/greenlizard/libs/xmlrpc-c/src/cpp/ (props changed) freeswitch/branches/greenlizard/scripts/socket/socket2me/ (props changed) freeswitch/branches/greenlizard/src/include/switch_buffer.h freeswitch/branches/greenlizard/src/include/switch_caller.h freeswitch/branches/greenlizard/src/include/switch_channel.h freeswitch/branches/greenlizard/src/include/switch_core.h freeswitch/branches/greenlizard/src/include/switch_cpp.h freeswitch/branches/greenlizard/src/include/switch_loadable_module.h freeswitch/branches/greenlizard/src/include/switch_regex.h freeswitch/branches/greenlizard/src/include/switch_rtp.h freeswitch/branches/greenlizard/src/include/switch_scheduler.h freeswitch/branches/greenlizard/src/include/switch_types.h freeswitch/branches/greenlizard/src/include/switch_utils.h freeswitch/branches/greenlizard/src/mod/applications/mod_commands/mod_commands.c freeswitch/branches/greenlizard/src/mod/applications/mod_conference/mod_conference.c freeswitch/branches/greenlizard/src/mod/applications/mod_dptools/mod_dptools.c freeswitch/branches/greenlizard/src/mod/applications/mod_enum/mod_enum.c freeswitch/branches/greenlizard/src/mod/applications/mod_esf/ (props changed) freeswitch/branches/greenlizard/src/mod/codecs/mod_speex/mod_speex.c freeswitch/branches/greenlizard/src/mod/endpoints/mod_alsa/mod_alsa.c freeswitch/branches/greenlizard/src/mod/endpoints/mod_dingaling/mod_dingaling.c freeswitch/branches/greenlizard/src/mod/endpoints/mod_iax/mod_iax.c freeswitch/branches/greenlizard/src/mod/endpoints/mod_portaudio/mod_portaudio.c freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/ (props changed) freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/Makefile.am freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/mod_sofia.c freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/mod_sofia.h freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/sofia.c freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/sofia_reg.c freeswitch/branches/greenlizard/src/mod/endpoints/mod_wanpipe/mod_wanpipe.c freeswitch/branches/greenlizard/src/mod/endpoints/mod_woomera/mod_woomera.c freeswitch/branches/greenlizard/src/mod/event_handlers/mod_cdr/basecdr.h freeswitch/branches/greenlizard/src/mod/event_handlers/mod_cdr/mod_cdr.cpp freeswitch/branches/greenlizard/src/mod/languages/mod_python/freeswitch_python.cpp freeswitch/branches/greenlizard/src/mod/languages/mod_python/freeswitch_python.h freeswitch/branches/greenlizard/src/mod/languages/mod_python/mod_python.c freeswitch/branches/greenlizard/src/mod/languages/mod_python/mod_python_wrap.cpp freeswitch/branches/greenlizard/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c freeswitch/branches/greenlizard/src/mod/xml_int/mod_xml_curl/mod_xml_curl.c freeswitch/branches/greenlizard/src/switch_buffer.c freeswitch/branches/greenlizard/src/switch_caller.c freeswitch/branches/greenlizard/src/switch_channel.c freeswitch/branches/greenlizard/src/switch_core.c freeswitch/branches/greenlizard/src/switch_core_session.c freeswitch/branches/greenlizard/src/switch_cpp.cpp freeswitch/branches/greenlizard/src/switch_ivr_async.c freeswitch/branches/greenlizard/src/switch_ivr_play_say.c freeswitch/branches/greenlizard/src/switch_loadable_module.c freeswitch/branches/greenlizard/src/switch_regex.c freeswitch/branches/greenlizard/src/switch_rtp.c freeswitch/branches/greenlizard/src/switch_scheduler.c freeswitch/branches/greenlizard/src/switch_utils.c freeswitch/branches/greenlizard/w32/Library/FreeSwitchCore.vcproj Log: Sync up changes from trunk version 5123 to 5170 Modified: freeswitch/branches/greenlizard/Makefile.am ============================================================================== --- freeswitch/branches/greenlizard/Makefile.am (original) +++ freeswitch/branches/greenlizard/Makefile.am Mon May 14 10:50:37 2007 @@ -139,7 +139,7 @@ libs/libedit/Makefile: - cd libs/libedit && ./configure --disable-shared --with-pic + cd libs/libedit && ./configure CFLAGS="-D_XOPEN_SOURCE=600 -D_BSD_SOURCE=1" --disable-shared --with-pic libs/libedit/src/.libs/libedit.a: libs/libedit/Makefile cd libs/libedit && $(MAKE) Modified: freeswitch/branches/greenlizard/bootstrap.sh ============================================================================== --- freeswitch/branches/greenlizard/bootstrap.sh (original) +++ freeswitch/branches/greenlizard/bootstrap.sh Mon May 14 10:50:37 2007 @@ -33,6 +33,7 @@ fi # automake 1.7 or newer + am_version=`${AUTOMAKE:-automake} --version 2>/dev/null|sed -e 's/^[^0-9]*//;s/[a-z]* *$//;s/[- ].*//g;q'` if test -z "$am_version"; then echo "bootstrap: automake not found." @@ -40,6 +41,8 @@ echo " to build FreeSWITCH from SVN." exit 1 fi +IFS=_; set $am_version; IFS=' ' +am_version=$1 IFS=.; set $am_version; IFS=' ' if test "$1" = "1" -a "$2" -lt "7"; then echo "bootstrap: automake version $am_version found." Modified: freeswitch/branches/greenlizard/conf/default_context.xml ============================================================================== --- freeswitch/branches/greenlizard/conf/default_context.xml (original) +++ freeswitch/branches/greenlizard/conf/default_context.xml Mon May 14 10:50:37 2007 @@ -42,8 +42,8 @@ <extension name="set_codec" continue="true"> <condition field="source" expression="mod_portaudio"> - <action application="set" data="absolute_codec_string=PCMU"/> - <action application="set" data="export_vars=absolute_codec_string"/> + <action application="export" data="absolute_codec_string=$${global_codec_prefs}"/> + <action application="export" data="nolocal:jitterbuffer_msec=180"/> </condition> </extension> Modified: freeswitch/branches/greenlizard/conf/directory.xml ============================================================================== --- freeswitch/branches/greenlizard/conf/directory.xml (original) +++ freeswitch/branches/greenlizard/conf/directory.xml Mon May 14 10:50:37 2007 @@ -9,6 +9,8 @@ <!--<param name="username" value="cluecon"/>--> <!--/// auth realm: *optional* same as gateway name, if blank ///--> <!--<param name="realm" value="asterlink.com"/>--> + <!--/// domain to use in from: *optional* same as realm, if blank ///--> + <!--<param name="from-domain" value="asterlink.com"/>--> <!--/// account password *required* ///--> <!--<param name="password" value="2007"/>--> <!--/// replace the INVITE from user with the channel's caller-id ///--> @@ -21,6 +23,10 @@ <!--<param name="expire-seconds" value="60"/>--> <!--/// do not register ///--> <!--<param name="register" value="false"/>--> + <!--How many seconds before a retry when a failure or timeout occurs --> + <!--<param name="retry_seconds" value="30"/>--> + <!--Use the callerid of an inbound call in the from field on outbound calls via this gateway --> + <!--<param name="caller-id-in-from" value="false"/>--> <!--</gateway>--> </gateways> <params> Modified: freeswitch/branches/greenlizard/conf/iax.conf.xml ============================================================================== --- freeswitch/branches/greenlizard/conf/iax.conf.xml (original) +++ freeswitch/branches/greenlizard/conf/iax.conf.xml Mon May 14 10:50:37 2007 @@ -1,7 +1,7 @@ <configuration name="iax.conf" description="IAX Configuration"> <settings> <param name="debug" value="0"/> - <!-- <param name="ip" value="1.2.3.4"> --> + <!-- <param name="ip" value="1.2.3.4"/> --> <param name="port" value="4569"/> <param name="dialplan" value="XML"/> <param name="codec-prefs" value="PCMU@20i,PCMA,speex,L16"/> Modified: freeswitch/branches/greenlizard/conf/sofia.conf.xml ============================================================================== --- freeswitch/branches/greenlizard/conf/sofia.conf.xml (original) +++ freeswitch/branches/greenlizard/conf/sofia.conf.xml Mon May 14 10:50:37 2007 @@ -12,6 +12,8 @@ <!--<param name="username" value="cluecon"/>--> <!--/// auth realm: *optional* same as gateway name, if blank ///--> <!--<param name="realm" value="asterlink.com"/>--> + <!--/// domain to use in from: *optional* same as realm, if blank ///--> + <!--<param name="from-domain" value="asterlink.com"/>--> <!--/// account password *required* ///--> <!--<param name="password" value="2007"/>--> <!--/// replace the INVITE from user with the channel's caller-id ///--> @@ -26,6 +28,8 @@ <!--<param name="register" value="false"/>--> <!--How many seconds before a retry when a failure or timeout occurs --> <!--<param name="retry_seconds" value="30"/>--> + <!--Use the callerid of an inbound call in the from field on outbound calls via this gateway --> + <!--<param name="caller-id-in-from" value="false"/>--> <!--</gateway>--> </gateways> Modified: freeswitch/branches/greenlizard/conf/xml_curl.conf.xml ============================================================================== --- freeswitch/branches/greenlizard/conf/xml_curl.conf.xml (original) +++ freeswitch/branches/greenlizard/conf/xml_curl.conf.xml Mon May 14 10:50:37 2007 @@ -8,6 +8,8 @@ <param name="gateway-url" value="http://www.mydomain.com/test.cgi" bindings="dialplan"/> <!-- set this to provide authentication credentials to the server --> <!--<param name="gateway-credentials" value="muser:mypass"/>--> + <!-- set to true to disable Expect: 100-continue lighttpd requires this setting --> + <!--<param name="disable-100-continue" value="true"/>--> </binding> </bindings> </configuration> Modified: freeswitch/branches/greenlizard/libs/iax/src/iax-client.h ============================================================================== --- freeswitch/branches/greenlizard/libs/iax/src/iax-client.h (original) +++ freeswitch/branches/greenlizard/libs/iax/src/iax-client.h Mon May 14 10:50:37 2007 @@ -81,6 +81,7 @@ #define IAX_EVENT_REGREJ 30 /* Registration reply */ #define IAX_EVENT_LINKURL 31 /* Unlink */ #define IAX_EVENT_CNG 32 /* Comfort-noise (almost silence) */ +#define IAX_EVENT_POKE 33 /* moved from iax.c to support attended transfer */ #define IAX_EVENT_REREQUEST 999 @@ -161,6 +162,9 @@ extern int iax_send_ping(struct iax_session *session); extern int iax_load_complete(struct iax_session *session); extern int iax_reject(struct iax_session *session, char *reason); +int iax_reject_registration(struct iax_session *session, char *reason); +int iax_ack_registration(struct iax_session *session); +int iax_auth_registration(struct iax_session *session); extern int iax_busy(struct iax_session *session); extern int iax_congestion(struct iax_session *session); extern int iax_hangup(struct iax_session *session, char *byemsg); @@ -225,6 +229,10 @@ extern char iax_pref_codec_add(struct iax_session *session, unsigned int format); extern void iax_pref_codec_del(struct iax_session *session, unsigned int format); extern int iax_pref_codec_get(struct iax_session *session, unsigned int *array, int len); + +/* Fine tune jitterbuffer */ +extern void iax_set_jb_target_extra( long value ); + extern char *iax_get_peer_ip(struct iax_session *session); extern char *iax_event_get_apparent_ip(struct iax_event *event); extern void iax_set_samplerate(struct iax_session *session, unsigned short samplemask); Modified: freeswitch/branches/greenlizard/libs/iax/src/iax-mutex.c ============================================================================== --- freeswitch/branches/greenlizard/libs/iax/src/iax-mutex.c (original) +++ freeswitch/branches/greenlizard/libs/iax/src/iax-mutex.c Mon May 14 10:50:37 2007 @@ -17,7 +17,8 @@ * */ - +#define _XOPEN_SOURCE 600 +#include <stdlib.h> #include "iax-mutex.h" @@ -40,22 +41,40 @@ mutex_status_t iax_mutex_create(mutex_t **mutex) { + mutex_status_t status = MUTEX_FAILURE; +#ifndef WIN32 + pthread_mutexattr_t attr; +#endif mutex_t *check = NULL; check = (mutex_t *)malloc(sizeof(**mutex)); if (!check) - return MUTEX_FAILURE; + goto done; #ifdef WIN32 InitializeCriticalSection(&check->mutex); #else - if (pthread_mutex_init(&check->mutex, NULL)) - return MUTEX_FAILURE; + if (pthread_mutexattr_init(&attr)) + goto done; -#endif + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) + goto fail; + if (pthread_mutex_init(&check->mutex, &attr)) + goto fail; + + goto success; + +fail: + pthread_mutexattr_destroy(&attr); + goto done; + +success: +#endif *mutex = check; + status = MUTEX_SUCCESS; - return MUTEX_SUCCESS; +done: + return status; } mutex_status_t iax_mutex_destroy(mutex_t *mutex) Modified: freeswitch/branches/greenlizard/libs/iax/src/iax.c ============================================================================== --- freeswitch/branches/greenlizard/libs/iax/src/iax.c (original) +++ freeswitch/branches/greenlizard/libs/iax/src/iax.c Mon May 14 10:50:37 2007 @@ -40,16 +40,12 @@ #else +#define _BSD_SOURCE 1 #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/time.h> #include <stdlib.h> -#ifdef __GNUC__ -#ifndef __USE_SVID -#define __USE_SVID -#endif -#endif #include <string.h> #include <stdarg.h> #include <stdio.h> @@ -60,7 +56,7 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <time.h> - + #endif #include "iax2.h" @@ -70,7 +66,7 @@ #ifdef NEWJB #include "jitterbuf.h" #endif - +#include "iax-mutex.h" /* work around jitter-buffer shrinking in asterisk: channels/chan_iax2.c:schedule_delivery() shrinks jitter buffer by 2. @@ -144,6 +140,9 @@ /* Max timeouts */ static int maxretries = 10; +/* configurable jitterbuffer options */ +static long jb_target_extra = -1; + static int do_shutdown = 0; /* external global networking replacements */ @@ -330,6 +329,8 @@ struct iax_sched *next; }; +static mutex_t *sched_mutex = NULL; +static mutex_t *session_mutex = NULL; static struct iax_sched *schedq = NULL; static struct iax_session *sessions = NULL; static int callnums = 1; @@ -412,6 +413,7 @@ sched->func = func; sched->arg = arg; /* Put it in the list, in order */ + iax_mutex_lock(sched_mutex); cur = schedq; while(cur && cur->when <= sched->when) { prev = cur; @@ -423,6 +425,7 @@ } else { schedq = sched; } + iax_mutex_unlock(sched_mutex); return 0; } else { DEBU(G "Out of memory!\n"); @@ -433,7 +436,9 @@ static int iax_sched_del(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, int all) { struct iax_sched *cur, *tmp, *prev = NULL; + int ret = 0; + iax_mutex_lock(sched_mutex); cur = schedq; while (cur) { if (cur->event == event && cur->frame == frame && cur->func == func && cur->arg == arg) { @@ -444,13 +449,18 @@ tmp = cur; cur = cur->next; free(tmp); - if (!all) - return -1; + if (!all) { + ret = -1; + goto done; + } } else { prev = cur; cur = cur->next; } } + done: + iax_mutex_unlock(sched_mutex); + return 0; } @@ -458,24 +468,31 @@ time_in_ms_t iax_time_to_next_event(void) { - struct iax_sched *cur = schedq; + struct iax_sched *cur = NULL; time_in_ms_t minimum = 999999999; + iax_mutex_lock(sched_mutex); + cur = schedq; + /* If there are no pending events, we don't need to timeout */ - if (!cur) + if (!cur) { + iax_mutex_unlock(sched_mutex); return -1; - + } while(cur) { if (cur->when < minimum) { minimum = cur->when; } cur = cur->next; } + iax_mutex_unlock(sched_mutex); if (minimum <= 0) { return -1; } + + return minimum - current_time_in_ms(); } @@ -497,7 +514,7 @@ callnums = 1; s->peercallno = 0; s->transferpeer = 0; /* for attended transfer */ - s->next = sessions; + s->sendto = iax_sendto; s->pingid = -1; #ifdef NEWJB @@ -507,10 +524,14 @@ jbconf.max_jitterbuf = 0; jbconf.resync_threshold = 1000; jbconf.max_contig_interp = 0; + jbconf.target_extra = jb_target_extra; jb_setconf(s->jb, &jbconf); } #endif + iax_mutex_lock(session_mutex); + s->next = sessions; sessions = s; + iax_mutex_unlock(session_mutex); } return s; } @@ -518,12 +539,19 @@ static int iax_session_valid(struct iax_session *session) { /* Return -1 on a valid iax session pointer, 0 on a failure */ - struct iax_session *cur = sessions; + struct iax_session *cur; + + iax_mutex_lock(session_mutex); + cur = sessions; while(cur) { - if (session == cur) + if (session == cur) { + iax_mutex_unlock(session_mutex); return -1; + } cur = cur->next; } + iax_mutex_unlock(session_mutex); + return 0; } @@ -764,9 +792,22 @@ return cnt; } +static inline int get_interp_len(int format) +{ + return (format == AST_FORMAT_ILBC) ? 30 : 20; +} + static int get_sample_cnt(struct iax_event *e) { int cnt = 0; + + /* + * In the case of zero length frames, do not return a cnt of 0 + */ + if ( e->datalen == 0 ) { + return get_interp_len( e->subclass ) * 8; + } + switch (e->subclass) { case AST_FORMAT_SPEEX: cnt = speex_get_samples(e->data, e->datalen); @@ -865,26 +906,29 @@ int __iax_shutdown(void) { + struct iax_sched *sp, *fp; + /* Hangup Calls */ if (sessions) { struct iax_session *sp = NULL, *fp = NULL; + iax_mutex_lock(session_mutex); for(sp = sessions; sp ;) { iax_hangup(sp, "System Shutdown"); fp = sp; sp = sp->next; destroy_session(fp); } + iax_mutex_unlock(session_mutex); } /* Clear Scheduler */ - if(schedq) { - struct iax_sched *sp, *fp; - for(sp = schedq; sp ;) { - fp = sp; - sp = sp->next; - free(fp); - } + iax_mutex_lock(sched_mutex); + for(sp = schedq; sp ;) { + fp = sp; + sp = sp->next; + free(fp); } + iax_mutex_unlock(sched_mutex); if (netfd > -1) { shutdown(netfd, 2); @@ -893,6 +937,9 @@ time_end(); + iax_mutex_destroy(sched_mutex); + iax_mutex_destroy(session_mutex); + return 0; } @@ -901,6 +948,12 @@ return do_shutdown++; } +void iax_set_jb_target_extra( long value ) +{ + /* store in jb_target_extra, a static global */ + jb_target_extra = value ; +} + int iax_init(char *ip, int preferredportno) { int portno = preferredportno; @@ -910,6 +963,9 @@ init_time(); + iax_mutex_create(&sched_mutex); + iax_mutex_create(&session_mutex); + if(iax_recvfrom == (recvfrom_t) recvfrom) { if (netfd > -1) { /* Sokay, just don't do anything */ @@ -923,23 +979,35 @@ return -1; } - if (preferredportno == 0) - preferredportno = IAX_DEFAULT_PORTNO; - - if (preferredportno > 0) { - sin.sin_family = AF_INET; - if (ip) { - inet_aton(ip, &sin.sin_addr); - } else { - sin.sin_addr.s_addr = 0; - } - - sin.sin_port = htons((short)preferredportno); - if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0) { - DEBU(G "Unable to bind to preferred port. Using random one instead."); - } - } - sinlen = sizeof(sin); + if (preferredportno == 0) preferredportno = IAX_DEFAULT_PORTNO; + if (preferredportno < 0) preferredportno = 0; + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = 0; + sin.sin_port = htons((short)preferredportno); + if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0) + { +#if defined(WIN32) || defined(_WIN32_WCE) + if (WSAGetLastError() == WSAEADDRINUSE) +#else + if (errno == EADDRINUSE) +#endif + { + /*the port is already in use, so bind to a free port chosen by the IP stack*/ + DEBU(G "Unable to bind to preferred port - port is in use. Trying to bind to a free one"); + sin.sin_port = htons((short)0); + if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0) + { + IAXERROR "Unable to bind UDP socket\n"); + return -1; + } + } else + { + IAXERROR "Unable to bind UDP socket\n"); + return -1; + } + } + sinlen = sizeof(sin); if (getsockname(netfd, (struct sockaddr *) &sin, &sinlen) < 0) { close(netfd); netfd = -1; @@ -1187,7 +1255,11 @@ #endif int r; r = __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1, 0); - if (r >= 0) destroy_session(i); + if (r >= 0) { + iax_mutex_lock(session_mutex); + destroy_session(i); + iax_mutex_unlock(session_mutex); + } return r; } @@ -1229,12 +1301,14 @@ { struct iax_sched *sch; + iax_mutex_lock(sched_mutex); sch = schedq; while(sch) { if (sch->frame && (sch->frame->session == session)) sch->frame->retries = -1; sch = sch->next; } + iax_mutex_unlock(sched_mutex); } /* stop_transfer */ static void complete_transfer(struct iax_session *session, int peercallno, int xfr2peer, int preserveSeq) @@ -1356,14 +1430,18 @@ static struct iax_session *iax_find_session2(short callno) { - struct iax_session *cur = sessions; + struct iax_session *cur; + iax_mutex_lock(session_mutex); + cur = sessions; while(cur) { if (callno == cur->callno && callno != 0) { + iax_mutex_unlock(session_mutex); return cur; } cur = cur->next; } + iax_mutex_unlock(session_mutex); return NULL; } @@ -1431,6 +1509,8 @@ struct iax_session *cur, *prev=NULL; struct iax_sched *curs, *prevs=NULL, *nexts=NULL; int loop_cnt=0; + + iax_mutex_lock(sched_mutex); curs = schedq; while(curs) { nexts = curs->next; @@ -1451,7 +1531,9 @@ curs = nexts; loop_cnt++; } - + iax_mutex_unlock(sched_mutex); + + cur = sessions; while(cur) { if (cur == session) { @@ -1505,6 +1587,12 @@ iax_send_pong(event->session, event->ts); iax_event_free(event); break; + case IAX_EVENT_POKE: + event->etype = IAX_EVENT_PONG; + iax_send_pong(event->session, event->ts); + iax_destroy(event->session); + iax_event_free(event); + break; default: return event; } @@ -1585,6 +1673,24 @@ return res; } +int iax_reject_registration(struct iax_session *session, char *reason) +{ + struct iax_ie_data ied; + memset(&ied, 0, sizeof(ied)); + iax_ie_append_str(&ied, IAX_IE_CAUSE, reason ? (unsigned char *) reason : (unsigned char *) "Unspecified"); + return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REGREJ, 0, ied.buf, ied.pos, -1); +} + +int iax_ack_registration(struct iax_session *session) +{ + return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, NULL, 0, -1); +} + +int iax_auth_registration(struct iax_session *session) +{ + return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, NULL, 0, -1); +} + int iax_reject(struct iax_session *session, char *reason) { struct iax_ie_data ied; @@ -2081,9 +2187,13 @@ short dcallno, int makenew) { - struct iax_session *cur = sessions; + struct iax_session *cur; + + iax_mutex_lock(session_mutex); + cur = sessions; while(cur) { if (forward_match(sin, callno, dcallno, cur)) { + iax_mutex_unlock(session_mutex); return cur; } cur = cur->next; @@ -2092,11 +2202,14 @@ cur = sessions; while(cur) { if (reverse_match(sin, callno, cur)) { + iax_mutex_unlock(session_mutex); return cur; } cur = cur->next; } + iax_mutex_unlock(session_mutex); + if (makenew && !dcallno) { cur = iax_session_new(); cur->peercallno = callno; @@ -2108,6 +2221,7 @@ } else { DEBU(G "No session, peer = %d, us = %d\n", callno, dcallno); } + return cur; } @@ -2428,6 +2542,7 @@ for (x=session->rseqno; x != fh->iseqno; x++) { /* Ack the packet with the given timestamp */ DEBU(G "Cancelling transmission of packet %d\n", x); + iax_mutex_lock(sched_mutex); sch = schedq; while(sch) { if (sch->frame && (sch->frame->session == session) && @@ -2435,6 +2550,7 @@ sch->frame->retries = -1; sch = sch->next; } + iax_mutex_unlock(sched_mutex); } /* Note how much we've received acknowledgement for */ session->rseqno = fh->iseqno; @@ -2586,8 +2702,11 @@ e->ts = ts; e = schedule_delivery(e, ts, updatehistory); break; + case IAX_COMMAND_POKE: + e->etype = IAX_EVENT_POKE; + e->ts = ts; + break; case IAX_COMMAND_PING: - case IAX_COMMAND_POKE: /* PINGS and PONGS don't get scheduled; */ e->etype = IAX_EVENT_PING; e->ts = ts; @@ -2622,6 +2741,14 @@ } e = schedule_delivery(e, ts, updatehistory); break; + case IAX_COMMAND_REGREQ: + e->etype = IAX_EVENT_REGREQ; + e = schedule_delivery(e, ts, updatehistory); + break; + case IAX_COMMAND_REGREL: + e->etype = IAX_EVENT_REGREQ; + e = schedule_delivery(e, ts, updatehistory); + break; case IAX_COMMAND_REGACK: e->etype = IAX_EVENT_REGACK; e = schedule_delivery(e, ts, updatehistory); @@ -2846,15 +2973,17 @@ void iax_destroy(struct iax_session *session) { + iax_mutex_lock(session_mutex); destroy_session(session); + iax_mutex_unlock(session_mutex); } static struct iax_event *iax_net_read(void) { unsigned char buf[65536]; - int res; + int res, sinlen; struct sockaddr_in sin; - unsigned int sinlen; + sinlen = sizeof(sin); res = iax_recvfrom(netfd, buf, sizeof(buf), 0, (struct sockaddr *) &sin, &sinlen); @@ -2894,6 +3023,7 @@ if (!ies.transferid) { return NULL; /* TXCNT without proper IAX_IE_TRANSFERID */ } + iax_mutex_lock(session_mutex); for( cur=sessions; cur; cur=cur->next ) { if ((cur->transferring) && (cur->transferid == ies.transferid) && (cur->callno == dcallno) && (cur->transfercallno == callno)) { @@ -2906,6 +3036,7 @@ break; } } + iax_mutex_unlock(session_mutex); return cur; } @@ -2923,6 +3054,7 @@ if (len < sizeof(struct ast_iax2_full_hdr)) { DEBU(G "Short header received from %s\n", inet_ntoa(sin->sin_addr)); IAXERROR "Short header received from %s\n", inet_ntoa(sin->sin_addr)); + return NULL; } /* Only allow it to make new sessions on types where that makes sense */ if ((fh->type == AST_FRAME_IAX) && ((subclass == IAX_COMMAND_NEW) || @@ -2945,6 +3077,7 @@ if (len < sizeof(struct ast_iax2_mini_hdr)) { DEBU(G "Short header received from %s\n", inet_ntoa(sin->sin_addr)); IAXERROR "Short header received from %s\n", inet_ntoa(sin->sin_addr)); + return NULL; } /* Miniature, voice frame */ session = iax_find_session(sin, ntohs(fh->scallno), 0, 0); @@ -2958,6 +3091,7 @@ static struct iax_sched *iax_get_sched(time_in_ms_t time_in_ms) { struct iax_sched *cur, *prev=NULL; + iax_mutex_lock(sched_mutex); cur = schedq; /* Check the event schedule first. */ while(cur) { @@ -2968,10 +3102,12 @@ } else { schedq = cur->next; } + iax_mutex_unlock(sched_mutex); return cur; } cur = cur->next; } + iax_mutex_unlock(sched_mutex); return NULL; } @@ -3005,8 +3141,11 @@ if (frame->retries < 0) { /* It's been acked. No need to send it. Destroy the old frame. If final, destroy the session. */ - if (frame->final) + if (frame->final) { + iax_mutex_lock(session_mutex); destroy_session(frame->session); + iax_mutex_unlock(session_mutex); + } if (frame->data) free(frame->data); free(frame); @@ -3023,7 +3162,9 @@ /* We haven't been able to get an ACK on this packet. If a final frame, destroy the session, otherwise, pass up timeout */ if (frame->final) { + iax_mutex_lock(session_mutex); destroy_session(frame->session); + iax_mutex_unlock(session_mutex); if (frame->data) free(frame->data); free(frame); @@ -3070,54 +3211,58 @@ { struct iax_session *cur; jb_frame frame; + iax_mutex_lock(session_mutex); for(cur=sessions; cur; cur=cur->next) { - int ret; - time_in_ms_t now; - time_in_ms_t next; - - now = time_in_ms - cur->rxcore; - if(now > (next = jb_next(cur->jb))) { - /* FIXME don't hardcode interpolation frame length in jb_get */ - ret = jb_get(cur->jb,&frame,now,20); - switch(ret) { - case JB_OK: -// if(frame.type == JB_TYPE_VOICE && next + 20 != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(cur->jb), next); - event = frame.data; - event = handle_event(event); - if (event) { - return event; - } - break; - case JB_INTERP: -// if(next + 20 != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(cur->jb), next); - /* create an interpolation frame */ - //fprintf(stderr, "Making Interpolation frame\n"); - event = (struct iax_event *)malloc(sizeof(struct iax_event)); - if (event) { - event->etype = IAX_EVENT_VOICE; - event->subclass = cur->voiceformat; - event->ts = now; /* XXX: ??? applications probably ignore this anyway */ - event->session = cur; - event->datalen = 0; - event = handle_event(event); - if(event) - return event; - } - break; - case JB_DROP: -// if(next != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not next %ld!\n", jb_next(cur->jb), next); - iax_event_free(frame.data); - break; - case JB_NOFRAME: - case JB_EMPTY: - /* do nothing */ - break; - default: - /* shouldn't happen */ - break; - } - } + int ret; + time_in_ms_t now; + time_in_ms_t next; + + now = time_in_ms - cur->rxcore; + if(now > (next = jb_next(cur->jb))) { + ret = jb_get(cur->jb,&frame,now,get_interp_len(cur->voiceformat)); + switch(ret) { + case JB_OK: + // if(frame.type == JB_TYPE_VOICE && next + 20 != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(cur->jb), next); + event = frame.data; + event = handle_event(event); + if (event) { + iax_mutex_unlock(session_mutex); + return event; + } + break; + case JB_INTERP: + // if(next + 20 != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(cur->jb), next); + /* create an interpolation frame */ + //fprintf(stderr, "Making Interpolation frame\n"); + event = (struct iax_event *)malloc(sizeof(struct iax_event)); + if (event) { + event->etype = IAX_EVENT_VOICE; + event->subclass = cur->voiceformat; + event->ts = now; /* XXX: ??? applications probably ignore this anyway */ + event->session = cur; + event->datalen = 0; + event = handle_event(event); + if(event) { + iax_mutex_unlock(session_mutex); + return event; + } + } + break; + case JB_DROP: + // if(next != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not next %ld!\n", jb_next(cur->jb), next); + iax_event_free(frame.data); + break; + case JB_NOFRAME: + case JB_EMPTY: + /* do nothing */ + break; + default: + /* shouldn't happen */ + break; + } + } } + iax_mutex_unlock(session_mutex); } #endif @@ -3169,8 +3314,10 @@ void iax_session_destroy(struct iax_session **session) { + iax_mutex_lock(session_mutex); destroy_session(*session); *session = NULL; + iax_mutex_unlock(session_mutex); } void iax_event_free(struct iax_event *event) @@ -3185,7 +3332,9 @@ case IAX_EVENT_HANGUP: /* Destroy this session -- it's no longer valid */ if (event->session) { /* maybe the user did it already */ + iax_mutex_lock(session_mutex); destroy_session(event->session); + iax_mutex_unlock(session_mutex); } break; } Modified: freeswitch/branches/greenlizard/libs/iax/src/iax.h ============================================================================== --- freeswitch/branches/greenlizard/libs/iax/src/iax.h (original) +++ freeswitch/branches/greenlizard/libs/iax/src/iax.h Mon May 14 10:50:37 2007 @@ -8,7 +8,7 @@ * Mark Spencer <markster@linux-support.net> * * This program is free software, distributed under the terms of - * the GNU General Public License + * the GNU Lesser (Library) General Public License */ #ifndef _IAX_H Modified: freeswitch/branches/greenlizard/libs/iax/src/iax2-parser.h ============================================================================== --- freeswitch/branches/greenlizard/libs/iax/src/iax2-parser.h (original) +++ freeswitch/branches/greenlizard/libs/iax/src/iax2-parser.h Mon May 14 10:50:37 2007 @@ -8,7 +8,7 @@ * Mark Spencer <markster@digium.com> * * This program is free software, distributed under the terms of - * the GNU General Public License + * the GNU Lesser (Library) General Public License */ #ifndef _IAX2_PARSER_H Modified: freeswitch/branches/greenlizard/libs/iax/src/iax2.h ============================================================================== --- freeswitch/branches/greenlizard/libs/iax/src/iax2.h (original) +++ freeswitch/branches/greenlizard/libs/iax/src/iax2.h Mon May 14 10:50:37 2007 @@ -8,7 +8,7 @@ * Mark Spencer <markster@linux-support.net> * * This program is free software, distributed under the terms of - * the GNU General Public License + * the GNU Lesser (Library) General Public License */ #ifndef _IAX2_H Modified: freeswitch/branches/greenlizard/libs/iax/src/jitterbuf.c ============================================================================== --- freeswitch/branches/greenlizard/libs/iax/src/jitterbuf.c (original) +++ freeswitch/branches/greenlizard/libs/iax/src/jitterbuf.c Mon May 14 10:50:37 2007 @@ -1,810 +1,834 @@ -/* - * jitterbuf: an application-independent jitterbuffer - * - * Copyrights: - * Copyright (C) 2004-2005, Horizon Wimba, Inc. - * - * Contributors: - * Steve Kann <stevek@stevek.com> - * - * This program is free software, distributed under the terms of - * the GNU Lesser (Library) General Public License - * - * Copyright on this file is disclaimed to Digium for inclusion in Asterisk - */ - -#include "iax2.h" -#include "jitterbuf.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -/* define these here, just for ancient compiler systems */ -#define JB_LONGMAX 2147483647L -#define JB_LONGMIN (-JB_LONGMAX - 1L) - -/* MS VC can't do __VA_ARGS__ */ -#if defined(WIN32) && defined(_MSC_VER) -#define jb_warn if (warnf) warnf -#define jb_err if (errf) errf -#define jb_dbg if (dbgf) dbgf - -#ifdef DEEP_DEBUG - #define jb_dbg2 if (dbgf) dbgf -#else - #define jb_dbg2 if (0) dbgf -#endif - -#else - -#define jb_warn(...) (warnf ? warnf(__VA_ARGS__) : (void)0) -#define jb_err(...) (errf ? errf(__VA_ARGS__) : (void)0) -#define jb_dbg(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0) - -#ifdef DEEP_DEBUG -#define jb_dbg2(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0) -#else -#define jb_dbg2(...) ((void)0) -#endif - -#endif - -static jb_output_function_t warnf, errf, dbgf; - -void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg) -{ - errf = err; - warnf = warn; - dbgf = dbg; -} - -static void increment_losspct(jitterbuf *jb) -{ - jb->info.losspct = (100000 + 499 * jb->info.losspct)/500; -} - -static void decrement_losspct(jitterbuf *jb) -{ - jb->info.losspct = (499 * jb->info.losspct)/500; -} - -void jb_reset(jitterbuf *jb) -{ - /* only save settings */ - jb_conf s = jb->info.conf; - memset(jb,0,sizeof(jitterbuf)); - jb->info.conf = s; - - /* initialize length */ - jb->info.current = jb->info.target = JB_TARGET_EXTRA; - jb->info.silence_begin_ts = -1; -} - -jitterbuf * jb_new() -{ - jitterbuf *jb; - - - jb = malloc(sizeof(jitterbuf)); - if(!jb) return NULL; - - jb_reset(jb); - - jb_dbg2("jb_new() = %x\n", jb); - return jb; -} - -void jb_destroy(jitterbuf *jb) -{ - jb_frame *frame; - jb_dbg2("jb_destroy(%x)\n", jb); - - /* free all the frames on the "free list" */ - frame = jb->free; - while(frame != NULL) { - jb_frame *next = frame->next; - free(frame); - frame = next; - } - - /* free ourselves! */ - free(jb); -} - - - -/* simple history manipulation */ -/* maybe later we can make the history buckets variable size, or something? */ -/* drop parameter determines whether we will drop outliers to minimize - * delay */ -#if 0 -static int longcmp(const void *a, const void *b) -{ - return *(long *)a - *(long *)b; -} -#endif - -static int history_put(jitterbuf *jb, time_in_ms_t ts, time_in_ms_t now, long ms) -{ - time_in_ms_t delay = now - (ts - jb->info.resync_offset); - time_in_ms_t threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold; - time_in_ms_t kicked; - - /* don't add special/negative times to history */ - if (ts <= 0) - return 0; - - /* check for drastic change in delay */ - if (jb->info.conf.resync_threshold != -1) { - if (iax_abs(delay - jb->info.last_delay) > threshold) { - jb->info.cnt_delay_discont++; - if (jb->info.cnt_delay_discont > 3) { - /* resync the jitterbuffer */ - jb->info.cnt_delay_discont = 0; - jb->hist_ptr = 0; - jb->hist_maxbuf_valid = 0; - - jb_warn("Resyncing the jb. last_delay %ld, this delay %ld, threshold %ld, new offset %ld\n", jb->info.last_delay, delay, threshold, ts - now); - jb->info.resync_offset = ts - now; - jb->info.last_delay = delay = 0; /* after resync, frame is right on time */ - } else { - return -1; - } - } else { - jb->info.last_delay = delay; - jb->info.cnt_delay_discont = 0; - } - } - - kicked = jb->history[jb->hist_ptr & JB_HISTORY_SZ]; - - jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay; - - /* optimization; the max/min buffers don't need to be recalculated, if this packet's - * entry doesn't change them. This happens if this packet is not involved, _and_ any packet - * that got kicked out of the history is also not involved - * We do a number of comparisons, but it's probably still worthwhile, because it will usually - * succeed, and should be a lot faster than going through all 500 packets in history */ - if(!jb->hist_maxbuf_valid) - return 0; - - /* don't do this until we've filled history - * (reduces some edge cases below) */ - if(jb->hist_ptr < JB_HISTORY_SZ) - goto invalidate; - - /* if the new delay would go into min */ - if(delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) - goto invalidate; - - /* or max.. */ - if(delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) - goto invalidate; - - /* or the kicked delay would be in min */ - if(kicked <= jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) - goto invalidate; - - if(kicked >= jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) - goto invalidate; - - /* if we got here, we don't need to invalidate, 'cause this delay didn't - * affect things */ - return 0; - /* end optimization */ - - -invalidate: - jb->hist_maxbuf_valid = 0; - return 0; -} - -static void history_calc_maxbuf(jitterbuf *jb) -{ - int i,j; - - if(jb->hist_ptr == 0) return; - - - /* initialize maxbuf/minbuf to the latest value */ - for(i=0;i<JB_HISTORY_MAXBUF_SZ;i++) { -/* - * jb->hist_maxbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ]; - * jb->hist_minbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ]; - */ - jb->hist_maxbuf[i] = JB_LONGMIN; - jb->hist_minbuf[i] = JB_LONGMAX; - } - - /* use insertion sort to populate maxbuf */ - /* we want it to be the top "n" values, in order */ - - /* start at the beginning, or JB_HISTORY_SZ frames ago */ - i = (jb->hist_ptr > JB_HISTORY_SZ) ? (jb->hist_ptr - JB_HISTORY_SZ) : 0; - - for(;i<jb->hist_ptr;i++) { - time_in_ms_t toins = jb->history[i % JB_HISTORY_SZ]; - - /* if the maxbuf should get this */ - if(toins > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) { - - /* insertion-sort it into the maxbuf */ - for(j=0;j<JB_HISTORY_MAXBUF_SZ;j++) { - /* found where it fits */ - if(toins > jb->hist_maxbuf[j]) { - /* move over */ - memmove(jb->hist_maxbuf+j+1,jb->hist_maxbuf+j, (JB_HISTORY_MAXBUF_SZ-(j+1)) * sizeof(long)); - /* insert */ - jb->hist_maxbuf[j] = toins; - - break; - } - } - } - - /* if the minbuf should get this */ - if(toins < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) { - - /* insertion-sort it into the maxbuf */ - for(j=0;j<JB_HISTORY_MAXBUF_SZ;j++) { - /* found where it fits */ - if(toins < jb->hist_minbuf[j]) { - /* move over */ - memmove(jb->hist_minbuf+j+1,jb->hist_minbuf+j, (JB_HISTORY_MAXBUF_SZ-(j+1)) * sizeof(long)); - /* insert */ - jb->hist_minbuf[j] = toins; - - break; - } - } - } - - if(0) { - int k; - fprintf(stderr, "toins = %ld\n", toins); - fprintf(stderr, "maxbuf ="); - for(k=0;k<JB_HISTORY_MAXBUF_SZ;k++) - fprintf(stderr, "%ld ", jb->hist_maxbuf[k]); - fprintf(stderr, "\nminbuf ="); - for(k=0;k<JB_HISTORY_MAXBUF_SZ;k++) - fprintf(stderr, "%ld ", jb->hist_minbuf[k]); - fprintf(stderr, "\n"); - } - } - - jb->hist_maxbuf_valid = 1; -} - -static void history_get(jitterbuf *jb) -{ - time_in_ms_t max, min, jitter; - int index; - int count; - - if(!jb->hist_maxbuf_valid) - history_calc_maxbuf(jb); - - /* count is how many items in history we're examining */ - count = (jb->hist_ptr < JB_HISTORY_SZ) ? jb->hist_ptr : JB_HISTORY_SZ; - - /* index is the "n"ths highest/lowest that we'll look for */ - index = count * JB_HISTORY_DROPPCT / 100; - - /* sanity checks for index */ - if(index > (JB_HISTORY_MAXBUF_SZ - 1)) index = JB_HISTORY_MAXBUF_SZ - 1; - - - if(index < 0) { - jb->info.min = 0; - jb->info.jitter = 0; - return; - } - - max = jb->hist_maxbuf[index]; - min = jb->hist_minbuf[index]; - - jitter = max - min; - - /* these debug stmts compare the difference between looking at the absolute jitter, and the - * values we get by throwing away the outliers */ - /* - fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", index, min, max, jitter); - fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", 0, jb->hist_minbuf[0], jb->hist_maxbuf[0], jb->hist_maxbuf[0]-jb->hist_minbuf[0]); - */ - - jb->info.min = min; - jb->info.jitter = jitter; -} - -/* returns 1 if frame was inserted into head of queue, 0 otherwise */ -static int queue_put(jitterbuf *jb, void *data, int type, long ms, time_in_ms_t ts) -{ - jb_frame *frame; - jb_frame *p; - int head = 0; - time_in_ms_t resync_ts = ts - jb->info.resync_offset; - - frame = jb->free; - if(frame) { - jb->free = frame->next; - } else { - frame = malloc(sizeof(jb_frame)); - } - - if(!frame) { - jb_err("cannot allocate frame\n"); - return 0; - } - - jb->info.frames_cur++; - - frame->data = data; - frame->ts = resync_ts; - frame->ms = ms; - frame->type = type; - - /* - * frames are a circular list, jb-frames points to to the lowest ts, - * jb->frames->prev points to the highest ts - */ - - if(!jb->frames) { /* queue is empty */ - jb->frames = frame; - frame->next = frame; - frame->prev = frame; - head = 1; - } else if (resync_ts < jb->frames->ts) { - frame->next = jb->frames; - frame->prev = jb->frames->prev; - - frame->next->prev = frame; - frame->prev->next = frame; - - /* frame is out of order */ - jb->info.frames_ooo++; - - jb->frames = frame; - head = 1; - } else { - p = jb->frames; - - /* frame is out of order */ - if(ts < p->prev->ts) jb->info.frames_ooo++; - - while (resync_ts < p->prev->ts && p->prev != jb->frames) - p = p->prev; - - frame->next = p; - frame->prev = p->prev; - - frame->next->prev = frame; - frame->prev->next = frame; - } - return head; -} - -static time_in_ms_t queue_next(jitterbuf *jb) -{ - if(jb->frames) return jb->frames->ts; - else return -1; -} - -static time_in_ms_t queue_last(jitterbuf *jb) -{ - if(jb->frames) return jb->frames->prev->ts; - else return -1; -} - -static jb_frame *_queue_get(jitterbuf *jb, time_in_ms_t ts, int all) -{ - jb_frame *frame; - frame = jb->frames; - - if(!frame) - return NULL; - - /*jb_warn("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); */ - - if(all || ts >= frame->ts) { - /* remove this frame */ - frame->prev->next = frame->next; - frame->next->prev = frame->prev; - - if(frame->next == frame) - jb->frames = NULL; - else - jb->frames = frame->next; - - - /* insert onto "free" single-linked list */ - frame->next = jb->free; - jb->free = frame; - - jb->info.frames_cur--; - - /* we return the frame pointer, even though it's on free list, - * but caller must copy data */ - return frame; - } - - return NULL; -} - -static jb_frame *queue_get(jitterbuf *jb, time_in_ms_t ts) -{ - return _queue_get(jb,ts,0); -} - -static jb_frame *queue_getall(jitterbuf *jb) -{ - return _queue_get(jb,0,1); -} - -#if 0 -/* some diagnostics */ -static void jb_dbginfo(jitterbuf *jb) -{ - if(dbgf == NULL) return; - - jb_dbg("\njb info: fin=%ld fout=%ld flate=%ld flost=%ld fdrop=%ld fcur=%ld\n", - jb->info.frames_in, jb->info.frames_out, jb->info.frames_late, jb->info.frames_lost, jb->info.frames_dropped, jb->info.frames_cur); - - jb_dbg(" jitter=%ld current=%ld target=%ld min=%ld sil=%d len=%d len/fcur=%ld\n", - jb->info.jitter, jb->info.current, jb->info.target, jb->info.min, jb->info.silence_begin_ts, jb->info.current - jb->info.min, - jb->info.frames_cur ? (jb->info.current - jb->info.min)/jb->info.frames_cur : -8); - if(jb->info.frames_in > 0) - jb_dbg("jb info: Loss PCT = %ld%%, Late PCT = %ld%%\n", - jb->info.frames_lost * 100/(jb->info.frames_in + jb->info.frames_lost), - jb->info.frames_late * 100/jb->info.frames_in); - jb_dbg("jb info: queue %d -> %d. last_ts %d (queue len: %d) last_ms %d\n", - queue_next(jb), - queue_last(jb), - jb->info.next_voice_ts, - queue_last(jb) - queue_next(jb), - jb->info.last_voice_ms); -} -#endif - -#ifdef DEEP_DEBUG -static void jb_chkqueue(jitterbuf *jb) -{ - int i=0; - jb_frame *p = jb->frames; - - if(!p) { - return; - } - - do { - if(p->next == NULL) { - jb_err("Queue is BROKEN at item [%d]", i); - } - i++; - p=p->next; - } while (p->next != jb->frames); -} - -static void jb_dbgqueue(jitterbuf *jb) -{ - int i=0; - jb_frame *p = jb->frames; - - jb_dbg("queue: "); - - if(!p) { - jb_dbg("EMPTY\n"); - return; - } - - do { - jb_dbg("[%d]=%ld ", i++, p->ts); - p=p->next; - } while (p->next != jb->frames); - - jb_dbg("\n"); -} -#endif - -int jb_put(jitterbuf *jb, void *data, int type, long ms, time_in_ms_t ts, time_in_ms_t now) -{ - jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now); - - jb->info.frames_in++; - - if(type == JB_TYPE_VOICE) { - /* presently, I'm only adding VOICE frames to history and drift calculations; mostly because with the - * IAX integrations, I'm sending retransmitted control frames with their awkward timestamps through */ - if (history_put(jb,ts,now,ms)) - return JB_DROP; - } - - /* if put into head of queue, caller needs to reschedule */ - if (queue_put(jb,data,type,ms,ts)) { - return JB_SCHED; - } - - return JB_OK; -} - - -static int _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long interpl) -{ - jb_frame *frame; - time_in_ms_t diff; - - /*if((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */ - /* get jitter info */ - history_get(jb); - - - /* target */ - jb->info.target = jb->info.jitter + jb->info.min + JB_TARGET_EXTRA; - - /* if a hard clamp was requested, use it */ - if((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) { - jb_dbg("clamping target from %d to %d\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf); - jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf; - } - - diff = jb->info.target - jb->info.current; - - /* jb_warn("diff = %d lms=%d last = %d now = %d\n", diff, */ - /* jb->info.last_voice_ms, jb->info.last_adjustment, now); */ - - /* let's work on non-silent case first */ - if(!jb->info.silence_begin_ts) { - /* we want to grow */ - if( (diff > 0) && - /* we haven't grown in the delay length */ - (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) || - /* we need to grow more than the "length" we have left */ - (diff > queue_last(jb) - queue_next(jb)) ) ) { - /* grow by interp frame len */ - jb->info.current += interpl; - jb->info.next_voice_ts += interpl; - jb->info.last_voice_ms = interpl; - jb->info.last_adjustment = now; - jb->info.cnt_contig_interp++; - jb_dbg("G"); - /* assume silence instead of continuing to interpolate */ - if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) - jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current; - return JB_INTERP; - } - - frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current); - - /* not a voice frame; just return it. */ - if(frame && frame->type != JB_TYPE_VOICE) { - /* track start of silence */ - if(frame->type == JB_TYPE_SILENCE) { - jb->info.silence_begin_ts = frame->ts; - jb->info.cnt_contig_interp = 0; - } - - *frameout = *frame; - jb->info.frames_out++; - jb_dbg("o"); - return JB_OK; - } - - /* voice frame is later than expected */ - if(frame && frame->ts + jb->info.current < jb->info.next_voice_ts) { - if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) { - /* either we interpolated past this frame in the last jb_get */ - /* or the frame is still in order, but came a little too quick */ - *frameout = *frame; - /* reset expectation for next frame */ - jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms; - jb->info.frames_out++; - decrement_losspct(jb); - jb->info.cnt_contig_interp = 0; - jb_dbg("v"); - return JB_OK; - } else { - /* voice frame is late */ - *frameout = *frame; - jb->info.frames_out++; - decrement_losspct(jb); - jb->info.frames_late++; - jb->info.frames_lost--; - jb_dbg("l"); - /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb)); - jb_warninfo(jb); */ - return JB_DROP; - } - } - - /* keep track of frame sizes, to allow for variable sized-frames */ - if(frame && frame->ms > 0) { - jb->info.last_voice_ms = frame->ms; - } - - /* we want to shrink; shrink at 1 frame / 500ms */ - /* unless we don't have a frame, then shrink 1 frame */ - /* every 80ms (though perhaps we can shrink even faster */ - /* in this case) */ - if(diff < -JB_TARGET_EXTRA && - ((!frame && jb->info.last_adjustment + 80 < now) || - (jb->info.last_adjustment + 500 < now))) { - jb->info.last_adjustment = now; - jb->info.cnt_contig_interp = 0; - - if(frame) { - *frameout = *frame; - /* shrink by frame size we're throwing out */ - jb->info.current -= frame->ms; - jb->info.frames_out++; - decrement_losspct(jb); - jb->info.frames_dropped++; - jb_dbg("s"); - return JB_DROP; - } else { - /* shrink by last_voice_ms */ - jb->info.current -= jb->info.last_voice_ms; - jb->info.frames_lost++; - increment_losspct(jb); - jb_dbg("S"); - return JB_NOFRAME; - } - } - - /* lost frame */ - if(!frame) { - /* this is a bit of a hack for now, but if we're close to - * target, and we find a missing frame, it makes sense to - * grow, because the frame might just be a bit late; - * otherwise, we presently get into a pattern where we return - * INTERP for the lost frame, then it shows up next, and we - * throw it away because it's late */ - /* I've recently only been able to replicate this using - * iaxclient talking to app_echo on asterisk. In this case, - * my outgoing packets go through asterisk's (old) - * jitterbuffer, and then might get an unusual increasing delay - * there if it decides to grow?? */ - /* Update: that might have been a different bug, that has been fixed.. - * But, this still seemed like a good idea, except that it ended up making a single actual - * lost frame get interpolated two or more times, when there was "room" to grow, so it might - * be a bit of a bad idea overall */ - /*if(diff > -1 * jb->info.last_voice_ms) { - jb->info.current += jb->info.last_voice_ms; - jb->info.last_adjustment = now; - jb_warn("g"); - return JB_INTERP; - } */ - jb->info.frames_lost++; - increment_losspct(jb); - jb->info.next_voice_ts += interpl; - jb->info.last_voice_ms = interpl; - jb->info.cnt_contig_interp++; - /* assume silence instead of continuing to interpolate */ - if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) - jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current; - jb_dbg("L"); - return JB_INTERP; - } - - /* normal case; return the frame, increment stuff */ - *frameout = *frame; - jb->info.next_voice_ts += frame->ms; - jb->info.frames_out++; - decrement_losspct(jb); - jb->info.cnt_contig_interp = 0; - jb_dbg("v"); - return JB_OK; - } else { - /* TODO: after we get the non-silent case down, we'll make the - * silent case -- basically, we'll just grow and shrink faster - * here, plus handle next_voice_ts a bit differently */ - - /* to disable silent special case altogether, just uncomment this: */ - /* jb->info.silence_begin_ts = 0; */ - - /* shrink interpl len every 10ms during silence */ - if (diff < -JB_TARGET_EXTRA && - jb->info.last_adjustment + 10 <= now) { - jb->info.current -= interpl; - jb->info.last_adjustment = now; - } - - frame = queue_get(jb, now - jb->info.current); - if(!frame) { - return JB_NOFRAME; - } else if (frame->type != JB_TYPE_VOICE) { - /* normal case; in silent mode, got a non-voice frame */ - *frameout = *frame; - jb->info.frames_out++; - return JB_OK; - } - if (frame->ts < jb->info.silence_begin_ts) { - /* voice frame is late */ - *frameout = *frame; - jb->info.frames_out++; - decrement_losspct(jb); - jb->info.frames_late++; - jb->info.frames_lost--; - jb_dbg("l"); - /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb)); - jb_warninfo(jb); */ - return JB_DROP; - } else { - /* voice frame */ - /* try setting current to target right away here */ - jb->info.current = jb->info.target; - jb->info.silence_begin_ts = 0; - jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms; - jb->info.last_voice_ms = frame->ms; - jb->info.frames_out++; - decrement_losspct(jb); - *frameout = *frame; - jb_dbg("V"); - return JB_OK; - } - } -} - -time_in_ms_t jb_next(jitterbuf *jb) -{ - if(jb->info.silence_begin_ts) { - time_in_ms_t next = queue_next(jb); - if(next > 0) { - /* shrink during silence */ - if (jb->info.target - jb->info.current < -JB_TARGET_EXTRA) - return jb->info.last_adjustment + 10; - return next + jb->info.target; - } - else return JB_LONGMAX; - } else { - return jb->info.next_voice_ts; - } -} - -int jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long interpl) -{ - int ret = _jb_get(jb,frameout,now,interpl); -#if 0 - static int lastts=0; - int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0; - jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb, frameout, now, ret, thists); - if(thists && thists < lastts) jb_warn("XXXX timestamp roll-back!!!\n"); - lastts = thists; -#endif - return ret; -} - -int jb_getall(jitterbuf *jb, jb_frame *frameout) -{ - jb_frame *frame; - frame = queue_getall(jb); - - if(!frame) { - return JB_NOFRAME; - } - - *frameout = *frame; - return JB_OK; -} - - -int jb_getinfo(jitterbuf *jb, jb_info *stats) -{ - - history_get(jb); - - *stats = jb->info; - - return JB_OK; -} - -int jb_setconf(jitterbuf *jb, jb_conf *conf) -{ - /* take selected settings from the struct */ - - jb->info.conf.max_jitterbuf = conf->max_jitterbuf; - jb->info.conf.resync_threshold = conf->resync_threshold; - jb->info.conf.max_contig_interp = conf->max_contig_interp; - - return JB_OK; -} - - +/* + * jitterbuf: an application-independent jitterbuffer + * + * Copyrights: + * Copyright (C) 2004-2005, Horizon Wimba, Inc. + * + * Contributors: + * Steve Kann <stevek@stevek.com> + * + * This program is free software, distributed under the terms of + * the GNU Lesser (Library) General Public License + * + * Copyright on this file is disclaimed to Digium for inclusion in Asterisk + */ + +#include "iax2.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "jitterbuf.h" + +/* define these here, just for ancient compiler systems */ +#define JB_LONGMAX 2147483647L +#define JB_LONGMIN (-JB_LONGMAX - 1L) + +/* MS VC can't do __VA_ARGS__ */ +#if (defined(WIN32) || defined(_WIN32_WCE)) && defined(_MSC_VER) +#define jb_warn if (warnf) warnf +#define jb_err if (errf) errf +#define jb_dbg if (dbgf) dbgf + +#ifdef DEEP_DEBUG + #define jb_dbg2 if (dbgf) dbgf +#else + #define jb_dbg2 if (0) dbgf +#endif + +#else + +#define jb_warn(...) (warnf ? warnf(__VA_ARGS__) : (void)0) +#define jb_err(...) (errf ? errf(__VA_ARGS__) : (void)0) +#define jb_dbg(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0) + +#ifdef DEEP_DEBUG +#define jb_dbg2(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0) +#else +#define jb_dbg2(...) ((void)0) +#endif + +#endif + +static jb_output_function_t warnf, errf, dbgf; + +void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg) +{ + errf = err; + warnf = warn; + dbgf = dbg; +} + +static void increment_losspct(jitterbuf *jb) +{ + jb->info.losspct = (100000 + 499 * jb->info.losspct)/500; +} + +static void decrement_losspct(jitterbuf *jb) +{ + jb->info.losspct = (499 * jb->info.losspct)/500; +} + +void jb_reset(jitterbuf *jb) +{ + /* only save settings */ + jb_conf s = jb->info.conf; + memset(jb, 0, sizeof(*jb)); + jb->info.conf = s; + + /* initialize length, using the configured value */ + jb->info.current = jb->info.target = jb->info.conf.target_extra; + jb->info.silence_begin_ts = -1; +} + +jitterbuf * jb_new() +{ + jitterbuf *jb; + + if (!(jb = (jitterbuf *)malloc(sizeof(*jb)))) + return NULL; + + jb->info.conf.target_extra = JB_TARGET_EXTRA; + + jb_reset(jb); + + jb_dbg2("jb_new() = %x\n", jb); + return jb; +} + +void jb_destroy(jitterbuf *jb) +{ + jb_frame *frame; + jb_dbg2("jb_destroy(%x)\n", jb); + + /* free all the frames on the "free list" */ + frame = jb->free; + while (frame != NULL) { + jb_frame *next = frame->next; + free(frame); + frame = next; + } + + /* free ourselves! */ + free(jb); +} + + + +#if 0 +static int longcmp(const void *a, const void *b) +{ + return *(long *)a - *(long *)b; +} +#endif + +/* simple history manipulation */ +/* maybe later we can make the history buckets variable size, or something? */ +/* drop parameter determines whether we will drop outliers to minimize + * delay */ +static int history_put(jitterbuf *jb, time_in_ms_t ts, time_in_ms_t now, long ms) +{ + time_in_ms_t delay = now - (ts - jb->info.resync_offset); + time_in_ms_t threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold; + time_in_ms_t kicked; + + /* don't add special/negative times to history */ + if (ts <= 0) + return 0; + + /* check for drastic change in delay */ + if (jb->info.conf.resync_threshold != -1) { + if (iax_abs(delay - jb->info.last_delay) > threshold) { + jb->info.cnt_delay_discont++; + if (jb->info.cnt_delay_discont > 3) { + /* resync the jitterbuffer */ + jb->info.cnt_delay_discont = 0; + jb->hist_ptr = 0; + jb->hist_maxbuf_valid = 0; + + jb_warn("Resyncing the jb. last_delay %ld, this delay %ld, threshold %ld, new offset %ld\n", jb->info.last_delay, delay, threshold, ts - now); + jb->info.resync_offset = ts - now; + jb->info.last_delay = delay = 0; /* after resync, frame is right on time */ + } else { + return -1; + } + } else { + jb->info.last_delay = delay; + jb->info.cnt_delay_discont = 0; + } + } + + kicked = jb->history[jb->hist_ptr % JB_HISTORY_SZ]; + + jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay; + + /* optimization; the max/min buffers don't need to be recalculated, + * if this packet's entry doesn't change them. This happens if this + * packet is not involved, _and_ any packet that got kicked out of + * the history is also not involved. We do a number of comparisons, + * but it's probably still worthwhile, because it will usually + * succeed, and should be a lot faster than going through all 500 + * packets in history */ + if (!jb->hist_maxbuf_valid) + return 0; + + /* don't do this until we've filled history + * (reduces some edge cases below) */ + if (jb->hist_ptr < JB_HISTORY_SZ) + goto invalidate; + + /* if the new delay would go into min */ + if (delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) + goto invalidate; + + /* or max.. */ + if (delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) + goto invalidate; + + /* or the kicked delay would be in min */ + if (kicked <= jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) + goto invalidate; + + if (kicked >= jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) + goto invalidate; + + /* if we got here, we don't need to invalidate, 'cause this delay didn't + * affect things */ + return 0; + /* end optimization */ + + +invalidate: + jb->hist_maxbuf_valid = 0; + return 0; +} + +static void history_calc_maxbuf(jitterbuf *jb) +{ + int i,j; + + if (jb->hist_ptr == 0) + return; + + + /* initialize maxbuf/minbuf to the latest value */ + for (i=0;i<JB_HISTORY_MAXBUF_SZ;i++) { + /* + * jb->hist_maxbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ]; + * jb->hist_minbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ]; + */ + jb->hist_maxbuf[i] = JB_LONGMIN; + jb->hist_minbuf[i] = JB_LONGMAX; + } + + /* use insertion sort to populate maxbuf */ + /* we want it to be the top "n" values, in order */ + + /* start at the beginning, or JB_HISTORY_SZ frames ago */ + i = (jb->hist_ptr > JB_HISTORY_SZ) ? (jb->hist_ptr - JB_HISTORY_SZ) : 0; + + for (;i<jb->hist_ptr;i++) { + time_in_ms_t toins = jb->history[i % JB_HISTORY_SZ]; + + /* if the maxbuf should get this */ + if (toins > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) { + + /* insertion-sort it into the maxbuf */ + for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) { + /* found where it fits */ + if (toins > jb->hist_maxbuf[j]) { + /* move over */ + memmove(jb->hist_maxbuf + j + 1, jb->hist_maxbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_maxbuf[0])); + /* insert */ + jb->hist_maxbuf[j] = toins; + + break; + } + } + } + + /* if the minbuf should get this */ + if (toins < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) { + + /* insertion-sort it into the maxbuf */ + for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) { + /* found where it fits */ + if (toins < jb->hist_minbuf[j]) { + /* move over */ + memmove(jb->hist_minbuf + j + 1, jb->hist_minbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_minbuf[0])); + /* insert */ + jb->hist_minbuf[j] = toins; + + break; + } + } + } + + if (0) { + int k; + fprintf(stderr, "toins = %ld\n", toins); + fprintf(stderr, "maxbuf ="); + for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++) + fprintf(stderr, "%ld ", jb->hist_maxbuf[k]); + fprintf(stderr, "\nminbuf ="); + for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++) + fprintf(stderr, "%ld ", jb->hist_minbuf[k]); + fprintf(stderr, "\n"); + } + } + + jb->hist_maxbuf_valid = 1; +} + +static void history_get(jitterbuf *jb) +{ + time_in_ms_t max, min, jitter; + int index; + int count; + + if (!jb->hist_maxbuf_valid) + history_calc_maxbuf(jb); + + /* count is how many items in history we're examining */ + count = (jb->hist_ptr < JB_HISTORY_SZ) ? jb->hist_ptr : JB_HISTORY_SZ; + + /* index is the "n"ths highest/lowest that we'll look for */ + index = count * JB_HISTORY_DROPPCT / 100; + + /* sanity checks for index */ + if (index > (JB_HISTORY_MAXBUF_SZ - 1)) + index = JB_HISTORY_MAXBUF_SZ - 1; + + + if (index < 0) { + jb->info.min = 0; + jb->info.jitter = 0; + return; + } + + max = jb->hist_maxbuf[index]; + min = jb->hist_minbuf[index]; + + jitter = max - min; + + /* these debug stmts compare the difference between looking at the absolute jitter, and the + * values we get by throwing away the outliers */ + /* + fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", index, min, max, jitter); + fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", 0, jb->hist_minbuf[0], jb->hist_maxbuf[0], jb->hist_maxbuf[0]-jb->hist_minbuf[0]); + */ + + jb->info.min = min; + jb->info.jitter = jitter; +} + +/* returns 1 if frame was inserted into head of queue, 0 otherwise */ +static int queue_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, time_in_ms_t ts) +{ + jb_frame *frame; + jb_frame *p; + int head = 0; + time_in_ms_t resync_ts = ts - jb->info.resync_offset; + + if ((frame = jb->free)) { + jb->free = frame->next; + } else if (!(frame = (jb_frame *)malloc(sizeof(*frame)))) { + jb_err("cannot allocate frame\n"); + return 0; + } + + jb->info.frames_cur++; + + frame->data = data; + frame->ts = resync_ts; + frame->ms = ms; + frame->type = type; + + /* + * frames are a circular list, jb-frames points to to the lowest ts, + * jb->frames->prev points to the highest ts + */ + + if (!jb->frames) { /* queue is empty */ + jb->frames = frame; + frame->next = frame; + frame->prev = frame; + head = 1; + } else if (resync_ts < jb->frames->ts) { + frame->next = jb->frames; + frame->prev = jb->frames->prev; + + frame->next->prev = frame; + frame->prev->next = frame; + + /* frame is out of order */ + jb->info.frames_ooo++; + + jb->frames = frame; + head = 1; + } else { + p = jb->frames; + + /* frame is out of order */ + if (resync_ts < p->prev->ts) jb->info.frames_ooo++; + + while (resync_ts < p->prev->ts && p->prev != jb->frames) + p = p->prev; + + frame->next = p; + frame->prev = p->prev; + + frame->next->prev = frame; + frame->prev->next = frame; + } + return head; +} + +static time_in_ms_t queue_next(jitterbuf *jb) +{ + if (jb->frames) + return jb->frames->ts; + else + return -1; +} + +static time_in_ms_t queue_last(jitterbuf *jb) +{ + if (jb->frames) + return jb->frames->prev->ts; + else + return -1; +} + +static jb_frame *_queue_get(jitterbuf *jb, time_in_ms_t ts, int all) +{ + jb_frame *frame; + frame = jb->frames; + + if (!frame) + return NULL; + + /*jb_warn("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); */ + + if (all || ts >= frame->ts) { + /* remove this frame */ + frame->prev->next = frame->next; + frame->next->prev = frame->prev; + + if (frame->next == frame) + jb->frames = NULL; + else + jb->frames = frame->next; + + + /* insert onto "free" single-linked list */ + frame->next = jb->free; + jb->free = frame; + + jb->info.frames_cur--; + + /* we return the frame pointer, even though it's on free list, + * but caller must copy data */ + return frame; + } + + return NULL; +} + +static jb_frame *queue_get(jitterbuf *jb, time_in_ms_t ts) +{ + return _queue_get(jb,ts,0); +} + +static jb_frame *queue_getall(jitterbuf *jb) +{ + return _queue_get(jb,0,1); +} + +#if 0 +/* some diagnostics */ +static void jb_dbginfo(jitterbuf *jb) +{ + if (dbgf == NULL) + return; + + jb_dbg("\njb info: fin=%ld fout=%ld flate=%ld flost=%ld fdrop=%ld fcur=%ld\n", + jb->info.frames_in, jb->info.frames_out, jb->info.frames_late, jb->info.frames_lost, jb->info.frames_dropped, jb->info.frames_cur); + + jb_dbg("jitter=%ld current=%ld target=%ld min=%ld sil=%d len=%d len/fcur=%ld\n", + jb->info.jitter, jb->info.current, jb->info.target, jb->info.min, jb->info.silence_begin_ts, jb->info.current - jb->info.min, + jb->info.frames_cur ? (jb->info.current - jb->info.min)/jb->info.frames_cur : -8); + if (jb->info.frames_in > 0) + jb_dbg("jb info: Loss PCT = %ld%%, Late PCT = %ld%%\n", + jb->info.frames_lost * 100/(jb->info.frames_in + jb->info.frames_lost), + jb->info.frames_late * 100/jb->info.frames_in); + jb_dbg("jb info: queue %d -> %d. last_ts %d (queue len: %d) last_ms %d\n", + queue_next(jb), + queue_last(jb), + jb->info.next_voice_ts, + queue_last(jb) - queue_next(jb), + jb->info.last_voice_ms); +} +#endif + +#ifdef DEEP_DEBUG +static void jb_chkqueue(jitterbuf *jb) +{ + int i=0; + jb_frame *p = jb->frames; + + if (!p) { + return; + } + + do { + if (p->next == NULL) { + jb_err("Queue is BROKEN at item [%d]", i); + } + i++; + p=p->next; + } while (p->next != jb->frames); +} + +static void jb_dbgqueue(jitterbuf *jb) +{ + int i=0; + jb_frame *p = jb->frames; + + jb_dbg("queue: "); + + if (!p) { + jb_dbg("EMPTY\n"); + return; + } + + do { + jb_dbg("[%d]=%ld ", i++, p->ts); + p=p->next; + } while (p->next != jb->frames); + + jb_dbg("\n"); +} +#endif + +enum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, time_in_ms_t ts, time_in_ms_t now) +{ + jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now); + + jb->info.frames_in++; + + if (type == JB_TYPE_VOICE) { + /* presently, I'm only adding VOICE frames to history and drift + * calculations; mostly because with the IAX integrations, I'm + * sending retransmitted control frames with their awkward + * timestamps through + */ + if (history_put(jb,ts,now,ms)) + return JB_DROP; + } + + /* if put into head of queue, caller needs to reschedule */ + if (queue_put(jb,data,type,ms,ts)) { + return JB_SCHED; + } + + return JB_OK; +} + + +static enum jb_return_code _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long interpl) +{ + jb_frame *frame; + time_in_ms_t diff; + + /*if ((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */ + /* get jitter info */ + history_get(jb); + + + /* target */ + jb->info.target = jb->info.jitter + jb->info.min + jb->info.conf.target_extra; + + /* if a hard clamp was requested, use it */ + if ((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) { + jb_dbg("clamping target from %d to %d\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf); + jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf; + } + + diff = jb->info.target - jb->info.current; + + /* jb_warn("diff = %d lms=%d last = %d now = %d\n", diff, */ + /* jb->info.last_voice_ms, jb->info.last_adjustment, now); */ + + /* let's work on non-silent case first */ + if (!jb->info.silence_begin_ts) { + /* we want to grow */ + if ((diff > 0) && + /* we haven't grown in the delay length */ + (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) || + /* we need to grow more than the "length" we have left */ + (diff > queue_last(jb) - queue_next(jb)) ) ) { + /* grow by interp frame length */ + jb->info.current += interpl; + jb->info.next_voice_ts += interpl; + jb->info.last_voice_ms = interpl; + jb->info.last_adjustment = now; + jb->info.cnt_contig_interp++; + /* assume silence instead of continuing to interpolate */ + if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) { + jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current; + } + jb_dbg("G"); + return JB_INTERP; + } + + frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current); + + /* not a voice frame; just return it. */ + if (frame && frame->type != JB_TYPE_VOICE) { + /* track start of silence */ + if (frame->type == JB_TYPE_SILENCE) { + jb->info.silence_begin_ts = frame->ts; + jb->info.cnt_contig_interp = 0; + } + + *frameout = *frame; + jb->info.frames_out++; + jb_dbg("o"); + return JB_OK; + } + + /* voice frame is later than expected */ + if (frame && frame->ts + jb->info.current < jb->info.next_voice_ts) { + if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) { + /* either we interpolated past this frame in the last jb_get */ + /* or the frame is still in order, but came a little too quick */ + *frameout = *frame; + /* reset expectation for next frame */ + jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms; + jb->info.frames_out++; + decrement_losspct(jb); + jb->info.cnt_contig_interp = 0; + jb_dbg("v"); + return JB_OK; + } else { + /* voice frame is late */ + *frameout = *frame; + jb->info.frames_out++; + decrement_losspct(jb); + jb->info.frames_late++; + jb->info.frames_lost--; + jb_dbg("l"); + /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb)); + jb_warninfo(jb); */ + return JB_DROP; + } + } + + /* keep track of frame sizes, to allow for variable sized-frames */ + if (frame && frame->ms > 0) { + jb->info.last_voice_ms = frame->ms; + } + + /* we want to shrink; shrink at 1 frame / 500ms */ + /* unless we don't have a frame, then shrink 1 frame */ + /* every 80ms (though perhaps we can shrink even faster */ + /* in this case) */ + if (diff < -jb->info.conf.target_extra && + ((!frame && jb->info.last_adjustment + 80 < now) || + (jb->info.last_adjustment + 500 < now))) { + + jb->info.last_adjustment = now; + jb->info.cnt_contig_interp = 0; + + if (frame) { + *frameout = *frame; + /* shrink by frame size we're throwing out */ + jb->info.current -= frame->ms; + jb->info.frames_out++; + decrement_losspct(jb); + jb->info.frames_dropped++; + jb_dbg("s"); + return JB_DROP; + } else { + /* shrink by last_voice_ms */ + jb->info.current -= jb->info.last_voice_ms; + jb->info.frames_lost++; + increment_losspct(jb); + jb_dbg("S"); + return JB_NOFRAME; + } + } + + /* lost frame */ + if (!frame) { + /* this is a bit of a hack for now, but if we're close to + * target, and we find a missing frame, it makes sense to + * grow, because the frame might just be a bit late; + * otherwise, we presently get into a pattern where we return + * INTERP for the lost frame, then it shows up next, and we + * throw it away because it's late */ + /* I've recently only been able to replicate this using + * iaxclient talking to app_echo on asterisk. In this case, + * my outgoing packets go through asterisk's (old) + * jitterbuffer, and then might get an unusual increasing delay + * there if it decides to grow?? */ + /* Update: that might have been a different bug, that has been fixed.. + * But, this still seemed like a good idea, except that it ended up making a single actual + * lost frame get interpolated two or more times, when there was "room" to grow, so it might + * be a bit of a bad idea overall */ + /*if (diff > -1 * jb->info.last_voice_ms) { + jb->info.current += jb->info.last_voice_ms; + jb->info.last_adjustment = now; + jb_warn("g"); + return JB_INTERP; + } */ + jb->info.frames_lost++; + increment_losspct(jb); + jb->info.next_voice_ts += interpl; + jb->info.last_voice_ms = interpl; + jb->info.cnt_contig_interp++; + /* assume silence instead of continuing to interpolate */ + if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) { + jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current; + } + jb_dbg("L"); + return JB_INTERP; + } + + /* normal case; return the frame, increment stuff */ + *frameout = *frame; + jb->info.next_voice_ts += frame->ms; + jb->info.frames_out++; + jb->info.cnt_contig_interp = 0; + decrement_losspct(jb); + jb_dbg("v"); + return JB_OK; + } else { + /* TODO: after we get the non-silent case down, we'll make the + * silent case -- basically, we'll just grow and shrink faster + * here, plus handle next_voice_ts a bit differently */ + + /* to disable silent special case altogether, just uncomment this: */ + /* jb->info.silence_begin_ts = 0; */ + + /* shrink interpl len every 10ms during silence */ + if (diff < -jb->info.conf.target_extra && + jb->info.last_adjustment + 10 <= now) { + jb->info.current -= interpl; + jb->info.last_adjustment = now; + } + + frame = queue_get(jb, now - jb->info.current); + if (!frame) { + return JB_NOFRAME; + } else if (frame->type != JB_TYPE_VOICE) { + /* normal case; in silent mode, got a non-voice frame */ + *frameout = *frame; + jb->info.frames_out++; + return JB_OK; + } + if (frame->ts < jb->info.silence_begin_ts) { + /* voice frame is late */ + *frameout = *frame; + jb->info.frames_out++; + decrement_losspct(jb); + jb->info.frames_late++; + jb->info.frames_lost--; + jb_dbg("l"); + /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb)); + jb_warninfo(jb); */ + return JB_DROP; + } else { + /* voice frame */ + /* try setting current to target right away here */ + jb->info.current = jb->info.target; + jb->info.silence_begin_ts = 0; + jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms; + jb->info.last_voice_ms = frame->ms; + jb->info.frames_out++; + decrement_losspct(jb); + *frameout = *frame; + jb_dbg("V"); + return JB_OK; + } + } +} + +time_in_ms_t jb_next(jitterbuf *jb) +{ + if (jb->info.silence_begin_ts) { + if (jb->frames) { + time_in_ms_t next = queue_next(jb); + history_get(jb); + /* shrink during silence */ + if (jb->info.target - jb->info.current < -jb->info.conf.target_extra) + return jb->info.last_adjustment + 10; + return next + jb->info.target; + } + else + return JB_LONGMAX; + } else { + return jb->info.next_voice_ts; + } +} + +enum jb_return_code jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long interpl) +{ + enum jb_return_code ret = _jb_get(jb, frameout, now, interpl); +#if 0 + static int lastts=0; + int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0; + jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb, frameout, now, ret, thists); + if (thists && thists < lastts) jb_warn("XXXX timestamp roll-back!!!\n"); + lastts = thists; +#endif + return ret; +} + +enum jb_return_code jb_getall(jitterbuf *jb, jb_frame *frameout) +{ + jb_frame *frame; + frame = queue_getall(jb); + + if (!frame) { + return JB_NOFRAME; + } + + *frameout = *frame; + return JB_OK; +} + + +enum jb_return_code jb_getinfo(jitterbuf *jb, jb_info *stats) +{ + history_get(jb); + + *stats = jb->info; + + return JB_OK; +} + +enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf) +{ + /* take selected settings from the struct */ + + jb->info.conf.max_jitterbuf = conf->max_jitterbuf; + jb->info.conf.resync_threshold = conf->resync_threshold; + jb->info.conf.max_contig_interp = conf->max_contig_interp; + + /* -1 indicates use of the default JB_TARGET_EXTRA value */ + jb->info.conf.target_extra = ( conf->target_extra == -1 ) + ? JB_TARGET_EXTRA + : conf->target_extra + ; + + /* update these to match new target_extra setting */ + jb->info.current = jb->info.conf.target_extra; + jb->info.target = jb->info.conf.target_extra; + + return JB_OK; +} + + Modified: freeswitch/branches/greenlizard/libs/iax/src/jitterbuf.h ============================================================================== --- freeswitch/branches/greenlizard/libs/iax/src/jitterbuf.h (original) +++ freeswitch/branches/greenlizard/libs/iax/src/jitterbuf.h Mon May 14 10:50:37 2007 @@ -1,160 +1,162 @@ -/* - * jitterbuf: an application-independent jitterbuffer - * - * Copyrights: - * Copyright (C) 2004-2005, Horizon Wimba, Inc. - * - * Contributors: - * Steve Kann <stevek@stevek.com> - * - * This program is free software, distributed under the terms of - * the GNU Lesser (Library) General Public License - * - * Copyright on this file is disclaimed to Digium for inclusion in Asterisk - */ - -#ifndef _JITTERBUF_H_ -#define _JITTERBUF_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* configuration constants */ - /* Number of historical timestamps to use in calculating jitter and drift */ -#define JB_HISTORY_SZ 500 - /* what percentage of timestamps should we drop from the history when we examine it; - * this might eventually be something made configurable */ -#define JB_HISTORY_DROPPCT 3 - /* the maximum droppct we can handle (say it was configurable). */ -#define JB_HISTORY_DROPPCT_MAX 4 - /* the size of the buffer we use to keep the top and botton timestamps for dropping */ -#define JB_HISTORY_MAXBUF_SZ JB_HISTORY_SZ * JB_HISTORY_DROPPCT_MAX / 100 - /* amount of additional jitterbuffer adjustment */ -#define JB_TARGET_EXTRA 40 - /* ms between growing and shrinking; may not be honored if jitterbuffer runs out of space */ -#define JB_ADJUST_DELAY 40 - - -/* return codes */ -#define JB_OK 0 -#define JB_EMPTY 1 -#define JB_NOFRAME 2 -#define JB_INTERP 3 -#define JB_DROP 4 -#define JB_SCHED 5 - -/* frame types */ -#define JB_TYPE_CONTROL 0 -#define JB_TYPE_VOICE 1 -#define JB_TYPE_VIDEO 2 /* reserved */ -#define JB_TYPE_SILENCE 3 - - -typedef struct jb_conf { - /* settings */ - long max_jitterbuf; /* defines a hard clamp to use in setting the jitter buffer delay */ - long resync_threshold; /* the jb will resync when delay increases to (2 * jitter) + this param */ - long max_contig_interp; /* the max interp frames to return in a row */ -} jb_conf; - -typedef struct jb_info { - jb_conf conf; - - /* statistics */ - long frames_in; /* number of frames input to the jitterbuffer.*/ - long frames_out; /* number of frames output from the jitterbuffer.*/ - long frames_late; /* number of frames which were too late, and dropped.*/ - long frames_lost; /* number of missing frames.*/ - long frames_dropped; /* number of frames dropped (shrinkage) */ - long frames_ooo; /* number of frames received out-of-order */ - long frames_cur; /* number of frames presently in jb, awaiting delivery.*/ - time_in_ms_t jitter; /* jitter measured within current history interval*/ - time_in_ms_t min; /* minimum lateness within current history interval */ - time_in_ms_t current; /* the present jitterbuffer adjustment */ - time_in_ms_t target; /* the target jitterbuffer adjustment */ - long losspct; /* recent lost frame percentage (* 1000) */ - time_in_ms_t next_voice_ts; /* the ts of the next frame to be read from the jb - in receiver's time */ - long last_voice_ms; /* the duration of the last voice frame */ - time_in_ms_t silence_begin_ts; /* the time of the last CNG frame, when in silence */ - time_in_ms_t last_adjustment; /* the time of the last adjustment */ - time_in_ms_t last_delay; /* the last now added to history */ - long cnt_delay_discont; /* the count of discontinuous delays */ - time_in_ms_t resync_offset; /* the amount to offset ts to support resyncs */ - long cnt_contig_interp; /* the number of contiguous interp frames returned */ -} jb_info; - -typedef struct jb_frame { - void *data; /* the frame data */ - time_in_ms_t ts; /* the relative delivery time expected */ - long ms; /* the time covered by this frame, in sec/8000 */ - int type; /* the type of frame */ - struct jb_frame *next, *prev; -} jb_frame; - -typedef struct jitterbuf { - jb_info info; - - /* history */ - time_in_ms_t history[JB_HISTORY_SZ]; /* history */ - int hist_ptr; /* points to index in history for next entry */ - time_in_ms_t hist_maxbuf[JB_HISTORY_MAXBUF_SZ]; /* a sorted buffer of the max delays (highest first) */ - time_in_ms_t hist_minbuf[JB_HISTORY_MAXBUF_SZ]; /* a sorted buffer of the min delays (lowest first) */ - int hist_maxbuf_valid; /* are the "maxbuf"/minbuf valid? */ - - - jb_frame *frames; /* queued frames */ - jb_frame *free; /* free frames (avoid malloc?) */ -} jitterbuf; - - -/* new jitterbuf */ -extern jitterbuf * jb_new(void); - -/* destroy jitterbuf */ -extern void jb_destroy(jitterbuf *jb); - -/* reset jitterbuf */ -/* NOTE: The jitterbuffer should be empty before you call this, otherwise - * you will leak queued frames, and some internal structures */ -extern void jb_reset(jitterbuf *jb); - -/* queue a frame data=frame data, timings (in ms): ms=length of frame (for voice), ts=ts (sender's time) - * now=now (in receiver's time) return value is one of - * JB_OK: Frame added. Last call to jb_next() still valid - * JB_DROP: Drop this frame immediately - * JB_SCHED: Frame added. Call jb_next() to get a new time for the next frame - */ -extern int jb_put(jitterbuf *jb, void *data, int type, long ms, time_in_ms_t ts, time_in_ms_t now); - -/* get a frame for time now (receiver's time) return value is one of - * JB_OK: You've got frame! - * JB_DROP: Here's an audio frame you should just drop. Ask me again for this time.. - * JB_NOFRAME: There's no frame scheduled for this time. - * JB_INTERP: Please interpolate an interpl-length frame for this time (either we need to grow, or there was a lost frame) - * JB_EMPTY: The jb is empty. - */ -extern int jb_get(jitterbuf *jb, jb_frame *frame, time_in_ms_t now, long interpl); - -/* unconditionally get frames from jitterbuf until empty */ -extern int jb_getall(jitterbuf *jb, jb_frame *frameout); - -/* when is the next frame due out, in receiver's time (0=EMPTY) - * This value may change as frames are added (esp non-audio frames) */ -extern time_in_ms_t jb_next(jitterbuf *jb); - -/* get jitterbuf info: only "statistics" may be valid */ -extern int jb_getinfo(jitterbuf *jb, jb_info *stats); - -/* set jitterbuf conf */ -extern int jb_setconf(jitterbuf *jb, jb_conf *conf); - -typedef void (*jb_output_function_t)(const char *fmt, ...); -extern void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg); - -#ifdef __cplusplus -} -#endif - - -#endif +/* + * jitterbuf: an application-independent jitterbuffer + * + * Copyrights: + * Copyright (C) 2004-2005, Horizon Wimba, Inc. + * + * Contributors: + * Steve Kann <stevek@stevek.com> + * + * This program is free software, distributed under the terms of + * the GNU Lesser (Library) General Public License + * + * Copyright on this file is disclaimed to Digium for inclusion in Asterisk + */ + +#ifndef _JITTERBUF_H_ +#define _JITTERBUF_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* configuration constants */ + /* Number of historical timestamps to use in calculating jitter and drift */ +#define JB_HISTORY_SZ 500 + /* what percentage of timestamps should we drop from the history when we examine it; + * this might eventually be something made configurable */ +#define JB_HISTORY_DROPPCT 3 + /* the maximum droppct we can handle (say it was configurable). */ +#define JB_HISTORY_DROPPCT_MAX 4 + /* the size of the buffer we use to keep the top and botton timestamps for dropping */ +#define JB_HISTORY_MAXBUF_SZ JB_HISTORY_SZ * JB_HISTORY_DROPPCT_MAX / 100 + /* amount of additional jitterbuffer adjustment */ +#define JB_TARGET_EXTRA 40 + /* ms between growing and shrinking; may not be honored if jitterbuffer runs out of space */ +#define JB_ADJUST_DELAY 40 + +enum jb_return_code { + /* return codes */ + JB_OK, /* 0 */ + JB_EMPTY, /* 1 */ + JB_NOFRAME, /* 2 */ + JB_INTERP, /* 3 */ + JB_DROP, /* 4 */ + JB_SCHED /* 5 */ +}; + +enum jb_frame_type { +/* frame types */ + JB_TYPE_CONTROL, /* 0 */ + JB_TYPE_VOICE, /* 1 */ + JB_TYPE_VIDEO, /* 2 - reserved */ + JB_TYPE_SILENCE /* 3 */ +}; + +typedef struct jb_conf { + /* settings */ + long max_jitterbuf; /* defines a hard clamp to use in setting the jitter buffer delay */ + long resync_threshold; /* the jb will resync when delay increases to (2 * jitter) + this param */ + long max_contig_interp; /* the max interp frames to return in a row */ + long target_extra; /* amount of additional jitterbuffer adjustment, overrides JB_TARGET_EXTRA */ +} jb_conf; + +typedef struct jb_info { + jb_conf conf; + + /* statistics */ + long frames_in; /* number of frames input to the jitterbuffer.*/ + long frames_out; /* number of frames output from the jitterbuffer.*/ + long frames_late; /* number of frames which were too late, and dropped.*/ + long frames_lost; /* number of missing frames.*/ + long frames_dropped; /* number of frames dropped (shrinkage) */ + long frames_ooo; /* number of frames received out-of-order */ + long frames_cur; /* number of frames presently in jb, awaiting delivery.*/ + time_in_ms_t jitter; /* jitter measured within current history interval*/ + time_in_ms_t min; /* minimum lateness within current history interval */ + time_in_ms_t current; /* the present jitterbuffer adjustment */ + time_in_ms_t target; /* the target jitterbuffer adjustment */ + long losspct; /* recent lost frame percentage (* 1000) */ + time_in_ms_t next_voice_ts; /* the ts of the next frame to be read from the jb - in receiver's time */ + long last_voice_ms; /* the duration of the last voice frame */ + time_in_ms_t silence_begin_ts; /* the time of the last CNG frame, when in silence */ + time_in_ms_t last_adjustment; /* the time of the last adjustment */ + time_in_ms_t last_delay; /* the last now added to history */ + long cnt_delay_discont; /* the count of discontinuous delays */ + time_in_ms_t resync_offset; /* the amount to offset ts to support resyncs */ + long cnt_contig_interp; /* the number of contiguous interp frames returned */ +} jb_info; + +typedef struct jb_frame { + void *data; /* the frame data */ + time_in_ms_t ts; /* the relative delivery time expected */ + long ms; /* the time covered by this frame, in sec/8000 */ + enum jb_frame_type type; /* the type of frame */ + struct jb_frame *next, *prev; +} jb_frame; + +typedef struct jitterbuf { + jb_info info; + + /* history */ + time_in_ms_t history[JB_HISTORY_SZ]; /* history */ + int hist_ptr; /* points to index in history for next entry */ + time_in_ms_t hist_maxbuf[JB_HISTORY_MAXBUF_SZ]; /* a sorted buffer of the max delays (highest first) */ + time_in_ms_t hist_minbuf[JB_HISTORY_MAXBUF_SZ]; /* a sorted buffer of the min delays (lowest first) */ + int hist_maxbuf_valid; /* are the "maxbuf"/minbuf valid? */ + + jb_frame *frames; /* queued frames */ + jb_frame *free; /* free frames (avoid malloc?) */ +} jitterbuf; + + +/* new jitterbuf */ +jitterbuf * jb_new(void); + +/* destroy jitterbuf */ +void jb_destroy(jitterbuf *jb); + +/* reset jitterbuf */ +/* NOTE: The jitterbuffer should be empty before you call this, otherwise + * you will leak queued frames, and some internal structures */ +void jb_reset(jitterbuf *jb); + +/* queue a frame data=frame data, timings (in ms): ms=length of frame (for voice), ts=ts (sender's time) + * now=now (in receiver's time) return value is one of + * JB_OK: Frame added. Last call to jb_next() still valid + * JB_DROP: Drop this frame immediately + * JB_SCHED: Frame added. Call jb_next() to get a new time for the next frame + */ +enum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, time_in_ms_t ts, time_in_ms_t now); + +/* get a frame for time now (receiver's time) return value is one of + * JB_OK: You've got frame! + * JB_DROP: Here's an audio frame you should just drop. Ask me again for this time.. + * JB_NOFRAME: There's no frame scheduled for this time. + * JB_INTERP: Please interpolate an interpl-length frame for this time (either we need to grow, or there was a lost frame) + * JB_EMPTY: The jb is empty. + */ +enum jb_return_code jb_get(jitterbuf *jb, jb_frame *frame, time_in_ms_t now, long interpl); + +/* unconditionally get frames from jitterbuf until empty */ +enum jb_return_code jb_getall(jitterbuf *jb, jb_frame *frameout); + +/* when is the next frame due out, in receiver's time (0=EMPTY) + * This value may change as frames are added (esp non-audio frames) */ +time_in_ms_t jb_next(jitterbuf *jb); + +/* get jitterbuf info: only "statistics" may be valid */ +enum jb_return_code jb_getinfo(jitterbuf *jb, jb_info *stats); + +/* set jitterbuf conf */ +enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf); + +typedef void (*jb_output_function_t)(const char *fmt, ...); +extern void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg); + +#ifdef __cplusplus +} +#endif + + +#endif Modified: freeswitch/branches/greenlizard/libs/iax/src/md5.h ============================================================================== --- freeswitch/branches/greenlizard/libs/iax/src/md5.h (original) +++ freeswitch/branches/greenlizard/libs/iax/src/md5.h Mon May 14 10:50:37 2007 @@ -1,7 +1,7 @@ #ifndef MD5_H #define MD5_H -#ifdef __alpha +#if defined(__alpha) || defined(__x86_64) typedef unsigned int uint32; #else typedef unsigned long uint32; Modified: freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/Makefile.am ============================================================================== --- freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/Makefile.am (original) +++ freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/Makefile.am Mon May 14 10:50:37 2007 @@ -30,7 +30,7 @@ DOXYGEN = doxygen -lib_LTLIBRARIES = libsofia-sip-ua.la +noinst_LTLIBRARIES = libsofia-sip-ua.la libsofia_sip_ua_la_SOURCES = libsofia_sip_ua_la_LIBADD = bnf/libbnf.la \ Modified: freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/nua/nua.c ============================================================================== --- freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/nua/nua.c (original) +++ freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/nua/nua.c Mon May 14 10:50:37 2007 @@ -927,7 +927,7 @@ size_t len, xtra, e_len, l_len = 0, l_xtra = 0; ta_list ta; - if (nua == NULL || (nua->nua_shutdown_started && event != nua_r_shutdown)) + if (nua == NULL) return; ta_start(ta, tag, value); Modified: freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c ============================================================================== --- freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c (original) +++ freeswitch/branches/greenlizard/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c Mon May 14 10:50:37 2007 @@ -378,7 +378,8 @@ 901, "Stack is going down", NULL); } - else switch (event) { + + switch (event) { case nua_r_get_params: nua_stack_get_params(nua, nh ? nh : nua->nua_dhandle, event, tags); break; @@ -485,8 +486,7 @@ su_timer_set(t, nua_stack_timer, a); if (nua->nua_shutdown) { - nua_stack_shutdown(nua); - return; + nua_stack_shutdown(nua); } for (nh = nua->nua_handles; nh; nh = nh_next) { Modified: freeswitch/branches/greenlizard/src/include/switch_buffer.h ============================================================================== --- freeswitch/branches/greenlizard/src/include/switch_buffer.h (original) +++ freeswitch/branches/greenlizard/src/include/switch_buffer.h Mon May 14 10:50:37 2007 @@ -117,7 +117,7 @@ * \param datalen amount of data to be written * \return int amount of buffer used after the write, or 0 if no space available */ -SWITCH_DECLARE(switch_size_t) switch_buffer_write(switch_buffer_t *buffer, void *data, switch_size_t datalen); +SWITCH_DECLARE(switch_size_t) switch_buffer_write(switch_buffer_t *buffer, const void *data, switch_size_t datalen); /*! \brief Remove data from the buffer * \param buffer any buffer of type switch_buffer_t Modified: freeswitch/branches/greenlizard/src/include/switch_caller.h ============================================================================== --- freeswitch/branches/greenlizard/src/include/switch_caller.h (original) +++ freeswitch/branches/greenlizard/src/include/switch_caller.h Mon May 14 10:50:37 2007 @@ -128,7 +128,7 @@ \param extension_number extension number \return a new extension object allocated from the session's memory pool */ -SWITCH_DECLARE(switch_caller_extension_t *) switch_caller_extension_new(switch_core_session_t *session, char *extension_name, char *extension_number); +SWITCH_DECLARE(switch_caller_extension_t *) switch_caller_extension_new(switch_core_session_t *session, const char *extension_name, const char *extension_number); /*! \brief Add an application (instruction) to the given extension @@ -138,7 +138,7 @@ \param extra_data optional argument to the application */ SWITCH_DECLARE(void) switch_caller_extension_add_application(switch_core_session_t *session, - switch_caller_extension_t *caller_extension, char *application_name, char *extra_data); + switch_caller_extension_t *caller_extension, const char *application_name, const char *extra_data); /*! @@ -147,7 +147,7 @@ \param name the name \note this function is meant for situations where the name paramater is the contents of the variable */ -SWITCH_DECLARE(char *) switch_caller_get_field_by_name(switch_caller_profile_t *caller_profile, char *name); +SWITCH_DECLARE(char *) switch_caller_get_field_by_name(switch_caller_profile_t *caller_profile, const char *name); /*! \brief Create a new caller profile object @@ -191,7 +191,7 @@ \param event the event to add the information to */ -SWITCH_DECLARE(void) switch_caller_profile_event_set_data(switch_caller_profile_t *caller_profile, char *prefix, switch_event_t *event); +SWITCH_DECLARE(void) switch_caller_profile_event_set_data(switch_caller_profile_t *caller_profile, const char *prefix, switch_event_t *event); SWITCH_END_EXTERN_C /** @} */ Modified: freeswitch/branches/greenlizard/src/include/switch_channel.h ============================================================================== --- freeswitch/branches/greenlizard/src/include/switch_channel.h (original) +++ freeswitch/branches/greenlizard/src/include/switch_channel.h Mon May 14 10:50:37 2007 @@ -89,7 +89,7 @@ \param str the string to check \return the code */ -SWITCH_DECLARE(switch_call_cause_t) switch_channel_str2cause(char *str); +SWITCH_DECLARE(switch_call_cause_t) switch_channel_str2cause(const char *str); /*! \brief return the cause code for a given channel @@ -103,7 +103,7 @@ \param cause the code to check \return the string */ -SWITCH_DECLARE(char *) switch_channel_cause2str(switch_call_cause_t cause); +SWITCH_DECLARE(const char *) switch_channel_cause2str(switch_call_cause_t cause); /*! \brief View the timetable of a channel @@ -136,7 +136,7 @@ \param rpid the rpid if for the icon to use \param status the status message */ -SWITCH_DECLARE(void) switch_channel_presence(switch_channel_t *channel, char *rpid, char *status); +SWITCH_DECLARE(void) switch_channel_presence(switch_channel_t *channel, const char *rpid, const char *status); /*! \brief Uninitalize a channel @@ -218,7 +218,7 @@ \param varname the name of the variable \return the value of the requested variable */ -SWITCH_DECLARE(char *) switch_channel_get_variable(switch_channel_t *channel, char *varname); +SWITCH_DECLARE(char *) switch_channel_get_variable(switch_channel_t *channel, const char *varname); /*! * Start iterating over the entries in the channel variable list. @@ -373,7 +373,7 @@ \param private_info void pointer to private data \return SWITCH_STATUS_SUCCESS if data was set */ -SWITCH_DECLARE(switch_status_t) switch_channel_set_private(switch_channel_t *channel, char *key, void *private_info); +SWITCH_DECLARE(switch_status_t) switch_channel_set_private(switch_channel_t *channel, const char *key, const void *private_info); /*! \brief Retrieve private from a given channel @@ -381,7 +381,7 @@ \param key unique keyname to retrieve your private data \return void pointer to channel's private data */ -SWITCH_DECLARE(void *) switch_channel_get_private(switch_channel_t *channel, char *key); +SWITCH_DECLARE(void *) switch_channel_get_private(switch_channel_t *channel, const char *key); /*! \brief Assign a name to a given channel @@ -389,7 +389,7 @@ \param name name to assign \return SWITCH_STATUS_SUCCESS if name was assigned */ -SWITCH_DECLARE(switch_status_t) switch_channel_set_name(switch_channel_t *channel, char *name); +SWITCH_DECLARE(switch_status_t) switch_channel_set_name(switch_channel_t *channel, const char *name); /*! \brief Retrieve the name of a given channel @@ -423,7 +423,7 @@ \param dtmf string of digits to queue \return SWITCH_STATUS_SUCCESS if successful */ -SWITCH_DECLARE(switch_status_t) switch_channel_queue_dtmf(switch_channel_t *channel, char *dtmf); +SWITCH_DECLARE(switch_status_t) switch_channel_queue_dtmf(switch_channel_t *channel, const char *dtmf); /*! \brief Retrieve DTMF digits from a given channel @@ -446,7 +446,7 @@ \param name the name of the state \return the enum value (numeric) */ -SWITCH_DECLARE(switch_channel_state_t) switch_channel_name_state(char *name); +SWITCH_DECLARE(switch_channel_state_t) switch_channel_name_state(const char *name); /*! \brief Add information about a given channel to an event object Modified: freeswitch/branches/greenlizard/src/include/switch_core.h ============================================================================== --- freeswitch/branches/greenlizard/src/include/switch_core.h (original) +++ freeswitch/branches/greenlizard/src/include/switch_core.h Mon May 14 10:50:37 2007 @@ -220,7 +220,7 @@ \param err a pointer to set any errors to \note to be called at application startup */ -SWITCH_DECLARE(switch_status_t) switch_core_init(char *console, const char **err); +SWITCH_DECLARE(switch_status_t) switch_core_init(const char *console, const char **err); /*! \brief Initilize the core and load modules @@ -228,7 +228,7 @@ \param err a pointer to set any errors to \note to be called at application startup instead of switch_core_init. Includes module loading. */ -SWITCH_DECLARE(switch_status_t) switch_core_init_and_modload(char *console, const char **err); +SWITCH_DECLARE(switch_status_t) switch_core_init_and_modload(const char *console, const char **err); /*! \brief Set/Get Session Limit @@ -428,12 +428,15 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request(const switch_endpoint_interface_t *endpoint_interface, switch_memory_pool_t **pool); + +SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t **session, const char *file, const char *func, int line); + /*! \brief Destroy a session and return the memory pool to the core \param session pointer to a pointer of the session to destroy \return */ -SWITCH_DECLARE(void) switch_core_session_destroy(switch_core_session_t **session); +#define switch_core_session_destroy(session) switch_core_session_perform_destroy(session, __FILE__, __SWITCH_FUNC__, __LINE__) /*! \brief Provide the total number of sessions @@ -458,8 +461,9 @@ /*! \brief Launch the session thread (state machine) on a given session \param session the session to activate the state machine on + \return SWITCH_STATUS_SUCCESS if the thread was launched */ -SWITCH_DECLARE(void) switch_core_session_thread_launch(switch_core_session_t *session); +SWITCH_DECLARE(switch_status_t) switch_core_session_thread_launch(switch_core_session_t *session); /*! \brief Retrieve a pointer to the channel object associated with a given session @@ -499,7 +503,7 @@ #ifdef SWITCH_DEBUG_RWLOCKS #define switch_core_session_locate(uuid_str) switch_core_session_perform_locate(uuid_str, __FILE__, __SWITCH_FUNC__, __LINE__) #else -SWITCH_DECLARE(switch_core_session_t *) switch_core_session_locate(char *uuid_str); +SWITCH_DECLARE(switch_core_session_t *) switch_core_session_locate(const char *uuid_str); #endif /*! @@ -507,14 +511,14 @@ \param varname the name of the variable \return the value of the desired variable */ -SWITCH_DECLARE(char *) switch_core_get_variable(char *varname); +SWITCH_DECLARE(char *) switch_core_get_variable(const char *varname); /*! \brief Add a global variable to the core \param varname the name of the variable \param value the value of the variable */ -SWITCH_DECLARE(void) switch_core_set_variable(char *varname, char *value); +SWITCH_DECLARE(void) switch_core_set_variable(const char *varname, const char *value); /*! \brief Hangup All Sessions @@ -1391,7 +1395,7 @@ \brief Set the output console to the desired file \param console the file path */ -SWITCH_DECLARE(switch_status_t) switch_core_set_console(char *console); +SWITCH_DECLARE(switch_status_t) switch_core_set_console(const char *console); /*! \brief Breakdown a number of milliseconds into various time spec Modified: freeswitch/branches/greenlizard/src/include/switch_cpp.h ============================================================================== --- freeswitch/branches/greenlizard/src/include/switch_cpp.h (original) +++ freeswitch/branches/greenlizard/src/include/switch_cpp.h Mon May 14 10:50:37 2007 @@ -26,7 +26,7 @@ int preAnswer(); void hangup(char *cause); void setVariable(char *var, char *val); - void getVariable(char *var, char *val); + char *getVariable(char *var); int playFile(char *file, char *timer_name); void setDTMFCallback(switch_input_callback_function_t cb, void *buf, uint32_t buflen); int speakText(char *text); Modified: freeswitch/branches/greenlizard/src/include/switch_loadable_module.h ============================================================================== --- freeswitch/branches/greenlizard/src/include/switch_loadable_module.h (original) +++ freeswitch/branches/greenlizard/src/include/switch_loadable_module.h Mon May 14 10:50:37 2007 @@ -97,21 +97,21 @@ \param name the name of the endpoint \return the desired endpoint interface */ -SWITCH_DECLARE(switch_endpoint_interface_t *) switch_loadable_module_get_endpoint_interface(char *name); +SWITCH_DECLARE(switch_endpoint_interface_t *) switch_loadable_module_get_endpoint_interface(const char *name); /*! \brief Retrieve the codec interface by it's registered name \param name the name of the codec \return the desired codec interface */ -SWITCH_DECLARE(switch_codec_interface_t *) switch_loadable_module_get_codec_interface(char *name); +SWITCH_DECLARE(switch_codec_interface_t *) switch_loadable_module_get_codec_interface(const char *name); /*! \brief Retrieve the dialplan interface by it's registered name \param name the name of the dialplan \return the desired dialplan interface */ -SWITCH_DECLARE(switch_dialplan_interface_t *) switch_loadable_module_get_dialplan_interface(char *name); +SWITCH_DECLARE(switch_dialplan_interface_t *) switch_loadable_module_get_dialplan_interface(const char *name); /*! \brief build a dynamic module object and register it (for use in double embeded modules) @@ -132,70 +132,70 @@ \param name the name of the timer \return the desired timer interface */ -SWITCH_DECLARE(switch_timer_interface_t *) switch_loadable_module_get_timer_interface(char *name); +SWITCH_DECLARE(switch_timer_interface_t *) switch_loadable_module_get_timer_interface(const char *name); /*! \brief Retrieve the application interface by it's registered name \param name the name of the application \return the desired application interface */ -SWITCH_DECLARE(switch_application_interface_t *) switch_loadable_module_get_application_interface(char *name); +SWITCH_DECLARE(switch_application_interface_t *) switch_loadable_module_get_application_interface(const char *name); /*! \brief Retrieve the API interface by it's registered name \param name the name of the API \return the desired API interface */ -SWITCH_DECLARE(switch_api_interface_t *) switch_loadable_module_get_api_interface(char *name); +SWITCH_DECLARE(switch_api_interface_t *) switch_loadable_module_get_api_interface(const char *name); /*! \brief Retrieve the file format interface by it's registered name \param name the name of the file format \return the desired file format interface */ -SWITCH_DECLARE(switch_file_interface_t *) switch_loadable_module_get_file_interface(char *name); +SWITCH_DECLARE(switch_file_interface_t *) switch_loadable_module_get_file_interface(const char *name); /*! \brief Retrieve the speech interface by it's registered name \param name the name of the speech interface \return the desired speech interface */ -SWITCH_DECLARE(switch_speech_interface_t *) switch_loadable_module_get_speech_interface(char *name); +SWITCH_DECLARE(switch_speech_interface_t *) switch_loadable_module_get_speech_interface(const char *name); /*! \brief Retrieve the asr interface by it's registered name \param name the name of the asr interface \return the desired asr interface */ -SWITCH_DECLARE(switch_asr_interface_t *) switch_loadable_module_get_asr_interface(char *name); +SWITCH_DECLARE(switch_asr_interface_t *) switch_loadable_module_get_asr_interface(const char *name); /*! \brief Retrieve the directory interface by it's registered name \param name the name of the directory interface \return the desired directory interface */ -SWITCH_DECLARE(switch_directory_interface_t *) switch_loadable_module_get_directory_interface(char *name); +SWITCH_DECLARE(switch_directory_interface_t *) switch_loadable_module_get_directory_interface(const char *name); /*! \brief Retrieve the chat interface by it's registered name \param name the name of the chat interface \return the desired chat interface */ -SWITCH_DECLARE(switch_chat_interface_t *) switch_loadable_module_get_chat_interface(char *name); +SWITCH_DECLARE(switch_chat_interface_t *) switch_loadable_module_get_chat_interface(const char *name); /*! \brief Retrieve the say interface by it's registered name \param name the name of the say interface \return the desired say interface */ -SWITCH_DECLARE(switch_say_interface_t *) switch_loadable_module_get_say_interface(char *name); +SWITCH_DECLARE(switch_say_interface_t *) switch_loadable_module_get_say_interface(const char *name); /*! \brief Retrieve the management interface by it's registered name \param relative_oid the relative oid of the management interface \return the desired management interface */ -SWITCH_DECLARE(switch_management_interface_t *) switch_loadable_module_get_management_interface(char *relative_oid); +SWITCH_DECLARE(switch_management_interface_t *) switch_loadable_module_get_management_interface(const char *relative_oid); /*! \brief Retrieve the list of loaded codecs into an array @@ -226,7 +226,7 @@ \param stream stream for output \return the status returned by the API call */ -SWITCH_DECLARE(switch_status_t) switch_api_execute(char *cmd, char *arg, switch_core_session_t *session, switch_stream_handle_t *stream); +SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char *arg, switch_core_session_t *session, switch_stream_handle_t *stream); /*! \brief Load a module Modified: freeswitch/branches/greenlizard/src/include/switch_regex.h ============================================================================== --- freeswitch/branches/greenlizard/src/include/switch_regex.h (original) +++ freeswitch/branches/greenlizard/src/include/switch_regex.h Mon May 14 10:50:37 2007 @@ -49,8 +49,8 @@ SWITCH_DECLARE(void) switch_regex_free(void *data); -SWITCH_DECLARE(int) switch_regex_perform(char *field, char *expression, switch_regex_t **new_re, int *ovector, uint32_t olen); -SWITCH_DECLARE(void) switch_perform_substitution(switch_regex_t *re, int match_count, char *data, char *field_data, +SWITCH_DECLARE(int) switch_regex_perform(const char *field, const char *expression, switch_regex_t **new_re, int *ovector, uint32_t olen); +SWITCH_DECLARE(void) switch_perform_substitution(switch_regex_t *re, int match_count, const char *data, const char *field_data, char *substituted, uint32_t len, int *ovector); /*! @@ -59,7 +59,7 @@ \param expression The regular expression to run against the string \return Boolean if a match was found or not */ -SWITCH_DECLARE(switch_status_t) switch_regex_match(char *target, char *expression); +SWITCH_DECLARE(switch_status_t) switch_regex_match(const char *target, const char *expression); #define switch_regex_safe_free(re) if (re) {\ switch_regex_free(re);\ Modified: freeswitch/branches/greenlizard/src/include/switch_rtp.h ============================================================================== --- freeswitch/branches/greenlizard/src/include/switch_rtp.h (original) +++ freeswitch/branches/greenlizard/src/include/switch_rtp.h Mon May 14 10:50:37 2007 @@ -111,9 +111,9 @@ \param pool a memory pool to use for the session \return the new RTP session or NULL on failure */ -SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(char *rx_host, +SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host, switch_port_t rx_port, - char *tx_host, + const char *tx_host, switch_port_t tx_port, switch_payload_t payload, uint32_t samples_per_interval, @@ -128,7 +128,7 @@ \param port the remote port \param err pointer for error messages */ -SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_session, char *host, switch_port_t port, const char **err); +SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_session, const char *host, switch_port_t port, const char **err); /*! \brief Assign a local address to the RTP session @@ -138,7 +138,7 @@ \param err pointer for error messages \note this call also binds the RTP session's socket to the new address */ -SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_session, char *host, switch_port_t port, const char **err); +SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_session, const char *host, switch_port_t port, const char **err); /*! \brief Kill the socket on an existing RTP session Modified: freeswitch/branches/greenlizard/src/include/switch_scheduler.h ============================================================================== --- freeswitch/branches/greenlizard/src/include/switch_scheduler.h (original) +++ freeswitch/branches/greenlizard/src/include/switch_scheduler.h Mon May 14 10:50:37 2007 @@ -62,7 +62,7 @@ */ SWITCH_DECLARE(uint32_t) switch_scheduler_add_task(time_t task_runtime, switch_scheduler_func_t func, - char *desc, char *group, uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags); + const char *desc, const char *group, uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags); /*! \brief Delete a scheduled task @@ -76,7 +76,7 @@ \param group the group name \return the number of jobs deleted */ -SWITCH_DECLARE(uint32_t) switch_scheduler_del_task_group(char *group); +SWITCH_DECLARE(uint32_t) switch_scheduler_del_task_group(const char *group); /*! Modified: freeswitch/branches/greenlizard/src/include/switch_types.h ============================================================================== --- freeswitch/branches/greenlizard/src/include/switch_types.h (original) +++ freeswitch/branches/greenlizard/src/include/switch_types.h Mon May 14 10:50:37 2007 @@ -1013,12 +1013,21 @@ typedef void (*switch_application_function_t) (switch_core_session_t *, char *); typedef void (*switch_event_callback_t) (switch_event_t *); typedef switch_caller_extension_t *(*switch_dialplan_hunt_function_t) (switch_core_session_t *, void *, switch_caller_profile_t *); + typedef struct switch_scheduler_task switch_scheduler_task_t; + typedef void (*switch_scheduler_func_t) (switch_scheduler_task_t *task); + +#define SWITCH_STANDARD_SCHED_FUNC(name) static void name (switch_scheduler_task_t *task) + typedef switch_status_t (*switch_state_handler_t) (switch_core_session_t *); typedef struct switch_stream_handle switch_stream_handle_t; typedef switch_status_t (*switch_stream_handle_write_function_t) (switch_stream_handle_t *handle, const char *fmt, ...); -typedef switch_status_t (*switch_api_function_t) (char *in, switch_core_session_t *session, switch_stream_handle_t *stream); + +typedef switch_status_t (*switch_api_function_t) (const char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream); + +#define SWITCH_STANDARD_API(name) static switch_status_t name (const char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream) + typedef switch_status_t (*switch_input_callback_function_t) (switch_core_session_t *session, void *input, switch_input_type_t input_type, void *buf, unsigned int buflen); typedef struct switch_say_interface switch_say_interface_t; Modified: freeswitch/branches/greenlizard/src/include/switch_utils.h ============================================================================== --- freeswitch/branches/greenlizard/src/include/switch_utils.h (original) +++ freeswitch/branches/greenlizard/src/include/switch_utils.h Mon May 14 10:50:37 2007 @@ -55,7 +55,7 @@ #define switch_is_file_path(file) ((*file == '/') || strstr(file, SWITCH_URL_SEPARATOR)) #endif -static inline switch_bool_t switch_is_digit_string(char *s) { +static inline switch_bool_t switch_is_digit_string(const char *s) { while(s && *s) { if (*s < 48 || *s > 57) { @@ -104,7 +104,7 @@ \param priority the priority to get the name of \return the printable form of the priority */ -SWITCH_DECLARE(char *) switch_priority_name(switch_priority_t priority); +SWITCH_DECLARE(const char *) switch_priority_name(switch_priority_t priority); /*! \brief Return the RFC2833 character based on an event id @@ -260,7 +260,7 @@ \param in the string \return the epoch time in usec */ -SWITCH_DECLARE(switch_time_t) switch_str_time(char *in); +SWITCH_DECLARE(switch_time_t) switch_str_time(const char *in); /*! \brief Declares a function designed to set a dymaic global string @@ -288,7 +288,7 @@ \param esc the escape character \return the escaped string */ -SWITCH_DECLARE(char *) switch_escape_char(switch_memory_pool_t *pool, char *in, char *delim, char esc); +SWITCH_DECLARE(char *) switch_escape_char(switch_memory_pool_t *pool, char *in, const char *delim, char esc); /*! \brief Wait for a socket Modified: freeswitch/branches/greenlizard/src/mod/applications/mod_commands/mod_commands.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/applications/mod_commands/mod_commands.c (original) +++ freeswitch/branches/greenlizard/src/mod/applications/mod_commands/mod_commands.c Mon May 14 10:50:37 2007 @@ -57,7 +57,7 @@ static switch_api_interface_t sched_transfer_api_interface; static switch_api_interface_t sched_hangup_api_interface; -static switch_status_t status_function(char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(status_function) { uint8_t html = 0; switch_core_time_duration_t duration; @@ -107,18 +107,18 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t ctl_function(char *data, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(ctl_function) { int argc; char *mydata, *argv[5]; uint32_t arg = 0; - if (switch_strlen_zero(data)) { + if (switch_strlen_zero(cmd)) { stream->write_function(stream, "USAGE: %s\n", ctl_api_interface.syntax); return SWITCH_STATUS_SUCCESS; } - if ((mydata = strdup(data))) { + if ((mydata = strdup(cmd))) { argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); if (!strcmp(argv[0], "hupall")) { @@ -149,7 +149,7 @@ } -static switch_status_t load_function(char *mod, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(load_function) { const char *err; @@ -157,12 +157,12 @@ return SWITCH_STATUS_FALSE; } - if (switch_strlen_zero(mod)) { + if (switch_strlen_zero(cmd)) { stream->write_function(stream, "USAGE: %s\n", load_api_interface.syntax); return SWITCH_STATUS_SUCCESS; } - if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) mod, SWITCH_TRUE, &err) == SWITCH_STATUS_SUCCESS) { + if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, SWITCH_TRUE, &err) == SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "OK\n"); } else { stream->write_function(stream, "ERROR [%s]\n", err); @@ -171,7 +171,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t unload_function(char *mod, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(unload_function) { const char *err; @@ -179,12 +179,12 @@ return SWITCH_STATUS_FALSE; } - if (switch_strlen_zero(mod)) { + if (switch_strlen_zero(cmd)) { stream->write_function(stream, "USAGE: %s\n", unload_api_interface.syntax); return SWITCH_STATUS_SUCCESS; } - if (switch_loadable_module_unload_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) mod, &err) == SWITCH_STATUS_SUCCESS) { + if (switch_loadable_module_unload_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, &err) == SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "OK\n"); } else { stream->write_function(stream, "ERROR [%s]\n", err); @@ -193,7 +193,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t reload_function(char *args, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(reload_function) { const char *err; switch_xml_t xml_root; @@ -211,20 +211,20 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t kill_function(char *dest, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(kill_function) { - switch_core_session_t *session = NULL; + switch_core_session_t *ksession = NULL; - if (isession) { + if (session) { return SWITCH_STATUS_FALSE; } - if (!dest) { + if (!cmd) { stream->write_function(stream, "USAGE: %s\n", kill_api_interface.syntax); - } else if ((session = switch_core_session_locate(dest))) { - switch_channel_t *channel = switch_core_session_get_channel(session); + } else if ((ksession = switch_core_session_locate(cmd))) { + switch_channel_t *channel = switch_core_session_get_channel(ksession); switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); - switch_core_session_rwunlock(session); + switch_core_session_rwunlock(ksession); stream->write_function(stream, "OK\n"); } else { stream->write_function(stream, "No Such Channel!\n"); @@ -233,56 +233,62 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t transfer_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(transfer_function) { - switch_core_session_t *session = NULL; - char *argv[4] = { 0 }; + switch_core_session_t *tsession = NULL; + char *mycmd = NULL, *argv[4] = { 0 }; int argc = 0; - if (isession) { + if (session) { return SWITCH_STATUS_FALSE; } - argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); - - if (switch_strlen_zero(cmd) || argc < 2 || argc > 4) { - stream->write_function(stream, "USAGE: %s\n", transfer_api_interface.syntax); - } else { - char *uuid = argv[0]; - char *dest = argv[1]; - char *dp = argv[2]; - char *context = argv[3]; + if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + if (argc >= 2 && argc <= 4) { + char *uuid = argv[0]; + char *dest = argv[1]; + char *dp = argv[2]; + char *context = argv[3]; + + if ((tsession = switch_core_session_locate(uuid))) { + + if (switch_ivr_session_transfer(tsession, dest, dp, context) == SWITCH_STATUS_SUCCESS) { + stream->write_function(stream, "OK\n"); + } else { + stream->write_function(stream, "ERROR\n"); + } - if ((session = switch_core_session_locate(uuid))) { + switch_core_session_rwunlock(tsession); - if (switch_ivr_session_transfer(session, dest, dp, context) == SWITCH_STATUS_SUCCESS) { - stream->write_function(stream, "OK\n"); } else { - stream->write_function(stream, "ERROR\n"); + stream->write_function(stream, "No Such Channel!\n"); } - - switch_core_session_rwunlock(session); - - } else { - stream->write_function(stream, "No Such Channel!\n"); + goto done; } } + stream->write_function(stream, "USAGE: %s\n", transfer_api_interface.syntax); + +done: + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } -static switch_status_t sched_transfer_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(sched_transfer_function) { - switch_core_session_t *session = NULL; - char *argv[6] = { 0 }; + switch_core_session_t *tsession = NULL; + char *mycmd = NULL, *argv[6] = { 0 }; int argc = 0; - if (isession) { + if (session) { return SWITCH_STATUS_FALSE; } - argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } if (switch_strlen_zero(cmd) || argc < 2 || argc > 5) { stream->write_function(stream, "USAGE: %s\n", sched_transfer_api_interface.syntax); @@ -299,29 +305,32 @@ when = atol(argv[0]); } - if ((session = switch_core_session_locate(uuid))) { + if ((tsession = switch_core_session_locate(uuid))) { switch_ivr_schedule_transfer(when, uuid, dest, dp, context); stream->write_function(stream, "OK\n"); - switch_core_session_rwunlock(session); + switch_core_session_rwunlock(tsession); } else { stream->write_function(stream, "No Such Channel!\n"); } } + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } -static switch_status_t sched_hangup_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(sched_hangup_function) { - switch_core_session_t *session = NULL; - char *argv[4] = { 0 }; + switch_core_session_t *hsession = NULL; + char *mycmd = NULL, *argv[4] = { 0 }; int argc = 0; - if (isession) { + if (session) { return SWITCH_STATUS_FALSE; } - argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } if (switch_strlen_zero(cmd) || argc < 1) { stream->write_function(stream, "USAGE: %s\n", sched_hangup_api_interface.syntax); @@ -341,30 +350,33 @@ cause = switch_channel_str2cause(cause_str); } - if ((session = switch_core_session_locate(uuid))) { + if ((hsession = switch_core_session_locate(uuid))) { switch_ivr_schedule_hangup(when, uuid, cause, SWITCH_FALSE); stream->write_function(stream, "OK\n"); - switch_core_session_rwunlock(session); + switch_core_session_rwunlock(hsession); } else { stream->write_function(stream, "No Such Channel!\n"); } } + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } -static switch_status_t uuid_media_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(uuid_media_function) { - char *argv[4] = { 0 }; + char *mycmd = NULL, *argv[4] = { 0 }; int argc = 0; switch_status_t status = SWITCH_STATUS_FALSE; - if (isession) { + if (session) { return status; } - argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } if (switch_strlen_zero(cmd) || argc < 1) { stream->write_function(stream, "USAGE: %s\n", media_api_interface.syntax); @@ -382,21 +394,24 @@ stream->write_function(stream, "-ERR Operation Failed\n"); } + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } -static switch_status_t uuid_broadcast_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(uuid_broadcast_function) { - char *argv[4] = { 0 }; + char *mycmd = NULL, *argv[4] = { 0 }; int argc = 0; switch_status_t status = SWITCH_STATUS_FALSE; - if (isession) { + if (session) { return status; } - argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } if (switch_strlen_zero(cmd) || argc < 2) { stream->write_function(stream, "USAGE: %s\n", broadcast_api_interface.syntax); @@ -419,21 +434,24 @@ stream->write_function(stream, "+OK Message Sent\n"); } + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } -static switch_status_t sched_broadcast_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(sched_broadcast_function) { - char *argv[4] = { 0 }; + char *mycmd = NULL, *argv[4] = { 0 }; int argc = 0; switch_status_t status = SWITCH_STATUS_FALSE; - if (isession) { + if (session) { return status; } - argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } if (switch_strlen_zero(cmd) || argc < 3) { stream->write_function(stream, "USAGE: %s\n", sched_broadcast_api_interface.syntax); @@ -463,20 +481,23 @@ stream->write_function(stream, "+OK Message Scheduled\n"); } + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } -static switch_status_t uuid_hold_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(uuid_hold_function) { - char *argv[4] = { 0 }; + char *mycmd = NULL, *argv[4] = { 0 }; int argc = 0; switch_status_t status = SWITCH_STATUS_FALSE; - if (isession) { + if (session) { return status; } - argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } if (switch_strlen_zero(cmd) || argc < 1) { stream->write_function(stream, "USAGE: %s\n", hold_api_interface.syntax); @@ -494,19 +515,22 @@ stream->write_function(stream, "-ERR Operation Failed\n"); } + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } -static switch_status_t uuid_bridge_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(uuid_bridge_function) { - char *argv[4] = { 0 }; + char *mycmd = NULL, *argv[4] = { 0 }; int argc = 0; - if (isession) { + if (session) { return SWITCH_STATUS_FALSE; } - argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } if (switch_strlen_zero(cmd) || argc != 2) { stream->write_function(stream, "USAGE: %s\n", uuid_bridge_api_interface.syntax); @@ -516,17 +540,18 @@ } } + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } -static switch_status_t session_record_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(session_record_function) { - switch_core_session_t *session = NULL; - char *argv[4] = { 0 }; + switch_core_session_t *rsession = NULL; + char *mycmd = NULL, *argv[4] = { 0 }; char *uuid = NULL, *action = NULL, *path = NULL; int argc = 0; - if (isession) { + if (session) { return SWITCH_STATUS_FALSE; } @@ -534,7 +559,11 @@ goto usage; } - if ((argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) != 3) { + if (!(mycmd = strdup(cmd))) { + goto usage; + } + + if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) != 3) { goto usage; } @@ -542,7 +571,7 @@ action = argv[1]; path = argv[2]; - if (!(session = switch_core_session_locate(uuid))) { + if (!(rsession = switch_core_session_locate(uuid))) { stream->write_function(stream, "-Error Cannot locate session!\n"); return SWITCH_STATUS_SUCCESS; } @@ -552,9 +581,9 @@ } if (!strcasecmp(action, "start")) { - switch_ivr_record_session(session, path, NULL); + switch_ivr_record_session(rsession, path, NULL); } else if (!strcasecmp(action, "stop")) { - switch_ivr_stop_record_session(session, path); + switch_ivr_stop_record_session(rsession, path); } else { goto usage; } @@ -564,28 +593,32 @@ usage: stream->write_function(stream, "USAGE: %s\n", session_record_api_interface.syntax); + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; done: if (session) { - switch_core_session_rwunlock(session); + switch_core_session_rwunlock(rsession); } + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } -static switch_status_t pause_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(pause_function) { - switch_core_session_t *session = NULL; - char *argv[4] = { 0 }; + switch_core_session_t *psession = NULL; + char *mycmd = NULL, *argv[4] = { 0 }; int argc = 0; - if (isession) { + if (session) { return SWITCH_STATUS_FALSE; } - argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } if (switch_strlen_zero(cmd) || argc < 2) { stream->write_function(stream, "USAGE: %s\n", pause_api_interface.syntax); @@ -593,8 +626,8 @@ char *uuid = argv[0]; char *dest = argv[1]; - if ((session = switch_core_session_locate(uuid))) { - switch_channel_t *channel = switch_core_session_get_channel(session); + if ((psession = switch_core_session_locate(uuid))) { + switch_channel_t *channel = switch_core_session_get_channel(psession); if (!strcasecmp(dest, "on")) { switch_channel_set_flag(channel, CF_HOLD); @@ -602,36 +635,40 @@ switch_channel_clear_flag(channel, CF_HOLD); } - switch_core_session_rwunlock(session); + switch_core_session_rwunlock(psession); } else { stream->write_function(stream, "No Such Channel!\n"); } } + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } -static switch_status_t originate_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(originate_function) { switch_channel_t *caller_channel; switch_core_session_t *caller_session = NULL; - char *argv[7] = { 0 }; + char *mycmd = NULL, *argv[7] = { 0 }; int i = 0, x, argc = 0; char *aleg, *exten, *dp, *context, *cid_name, *cid_num; uint32_t timeout = 60; switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING; uint8_t machine = 1; - if (isession) { + if (session) { stream->write_function(stream, "Illegal Usage\n"); return SWITCH_STATUS_SUCCESS; } - argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } if (switch_strlen_zero(cmd) || argc < 2 || argc > 7) { stream->write_function(stream, "USAGE: %s\n", originate_api_interface.syntax); + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } @@ -671,6 +708,7 @@ } else { stream->write_function(stream, "Cannot Create Outgoing Channel! [%s] cause: %s\n", aleg, switch_channel_cause2str(cause)); } + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } @@ -694,6 +732,7 @@ if ((extension = switch_caller_extension_new(caller_session, app_name, arg)) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "memory error!\n"); switch_channel_hangup(caller_channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + switch_safe_free(mycmd); return SWITCH_STATUS_MEMERR; } switch_caller_extension_add_application(caller_session, extension, app_name, arg); @@ -713,6 +752,7 @@ switch_core_session_rwunlock(caller_session); } + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } @@ -735,7 +775,7 @@ switch_safe_free(stream.data); } -static switch_status_t sched_del_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(sched_del_function) { uint32_t cnt = 0; @@ -754,7 +794,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t xml_wrap_api_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(xml_wrap_api_function) { char *dcommand, *edata = NULL, *send = NULL, *command, *arg = NULL; switch_stream_handle_t mystream = { 0 }; @@ -803,7 +843,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t sched_api_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(sched_api_function) { char *tm = NULL, *dcmd, *group; time_t when; @@ -939,7 +979,7 @@ return 0; } -static switch_status_t show_function(char *data, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(show_function) { char sql[1024]; char *errmsg; @@ -948,18 +988,15 @@ int help = 0; char *mydata = NULL, *argv[6] = {0}; int argc; - char *cmd = NULL, *as = NULL; + char *command = NULL, *as = NULL; if (session) { return SWITCH_STATUS_FALSE; } - if (data) { - if ((mydata = strdup(data))) { - argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); - } - - cmd = argv[0]; + if (cmd && (mydata = strdup(cmd))) { + argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + command = argv[0]; if (argv[2] && !strcasecmp(argv[1], "as")) { as = argv[2]; } @@ -973,25 +1010,25 @@ // If you changes the field qty or order of any of these select // statmements, you must also change show_callback and friends to match! - if (!cmd) { + if (!command) { stream->write_function(stream, "USAGE: %s\n", show_api_interface.syntax); return SWITCH_STATUS_SUCCESS; - } else if (!strcmp(cmd, "codec") || !strcmp(cmd, "dialplan") || !strcmp(cmd, "file") || !strcmp(cmd, "timer")) { - sprintf(sql, "select type, name from interfaces where type = '%s'", cmd); - } else if (!strcmp(cmd, "tasks")) { - sprintf(sql, "select * from %s", cmd); - } else if (!strcmp(cmd, "application") || !strcmp(cmd, "api")) { - sprintf(sql, "select name, description, syntax from interfaces where type = '%s' and description != ''", cmd); - } else if (!strcmp(cmd, "calls")) { + } else if (!strcmp(command, "codec") || !strcmp(command, "dialplan") || !strcmp(command, "file") || !strcmp(command, "timer")) { + sprintf(sql, "select type, name from interfaces where type = '%s'", command); + } else if (!strcmp(command, "tasks")) { + sprintf(sql, "select * from %s", command); + } else if (!strcmp(command, "application") || !strcmp(command, "api")) { + sprintf(sql, "select name, description, syntax from interfaces where type = '%s' and description != ''", command); + } else if (!strcmp(command, "calls")) { sprintf(sql, "select * from calls"); - } else if (!strcmp(cmd, "channels")) { + } else if (!strcmp(command, "channels")) { sprintf(sql, "select * from channels"); - } else if (!strncasecmp(cmd, "help", 4)) { + } else if (!strncasecmp(command, "help", 4)) { char *cmdname = NULL; help = 1; holder.print_title = 0; - if ((cmdname = strchr(cmd, ' ')) != 0) { + if ((cmdname = strchr(command, ' ')) != 0) { *cmdname++ = '\0'; snprintf(sql, sizeof(sql) - 1, "select name, syntax, description from interfaces where type = 'api' and name = '%s'", cmdname); } else { @@ -1063,7 +1100,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t version_function(char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(version_function) { char version_string[1024]; snprintf(version_string, sizeof(version_string) - 1, "FreeSwitch Version %s\n", SWITCH_VERSION_FULL); @@ -1072,7 +1109,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t help_function(char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(help_function) { char showcmd[1024]; int all = 0; Modified: freeswitch/branches/greenlizard/src/mod/applications/mod_conference/mod_conference.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/applications/mod_conference/mod_conference.c (original) +++ freeswitch/branches/greenlizard/src/mod/applications/mod_conference/mod_conference.c Mon May 14 10:50:37 2007 @@ -292,7 +292,7 @@ static switch_status_t conference_play_file(conference_obj_t * conference, char *file, uint32_t leadin, switch_channel_t *channel, uint8_t async); static switch_status_t conference_say(conference_obj_t * conference, const char *text, uint32_t leadin); static void conference_list(conference_obj_t * conference, switch_stream_handle_t *stream, char *delim); -static switch_status_t conf_api_main(char *buf, switch_core_session_t *session, switch_stream_handle_t *stream); +static switch_status_t conf_api_main(const char *buf, switch_core_session_t *session, switch_stream_handle_t *stream); static switch_status_t audio_bridge_on_ring(switch_core_session_t *session); static switch_status_t conference_outcall(conference_obj_t * conference, char *conference_name, @@ -3445,7 +3445,7 @@ } /* API Interface Function */ -static switch_status_t conf_api_main(char *buf, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(conf_api_main) { char *lbuf = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; @@ -3453,8 +3453,8 @@ int argc; char *argv[25] = { 0 }; - if (!buf) { - buf = "help"; + if (!cmd) { + cmd = "help"; } if (session) { @@ -3470,7 +3470,7 @@ stream->write_function(stream, "<pre>\n"); } - if (!(lbuf = strdup(buf))) { + if (!(lbuf = strdup(cmd))) { return status; } @@ -3486,7 +3486,7 @@ goto done; } if (argc >= 2) { - conf_api_dispatch(conference, stream, argc, argv, (const char *) buf, 1); + conf_api_dispatch(conference, stream, argc, argv, cmd, 1); } else { stream->write_function(stream, "Conference command, not specified.\nTry 'help'\n"); } Modified: freeswitch/branches/greenlizard/src/mod/applications/mod_dptools/mod_dptools.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/applications/mod_dptools/mod_dptools.c (original) +++ freeswitch/branches/greenlizard/src/mod/applications/mod_dptools/mod_dptools.c Mon May 14 10:50:37 2007 @@ -502,14 +502,14 @@ } -static switch_status_t strepoch_api_function(char *data, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(strepoch_api_function) { switch_time_t out; - if (switch_strlen_zero(data)) { + if (switch_strlen_zero(cmd)) { out = switch_time_now(); } else { - out = switch_str_time(data); + out = switch_str_time(cmd); } stream->write_function(stream, "%d", (uint32_t) ((out) / (int64_t) (1000000))); @@ -517,7 +517,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t strftime_api_function(char *fmt, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(strftime_api_function) { switch_size_t retsize; @@ -525,20 +525,20 @@ char date[80] = ""; switch_time_exp_lt(&tm, switch_time_now()); - switch_strftime(date, &retsize, sizeof(date), fmt ? fmt : "%Y-%m-%d %T", &tm); + switch_strftime(date, &retsize, sizeof(date), cmd ? cmd : "%Y-%m-%d %T", &tm); stream->write_function(stream, "%s", date); return SWITCH_STATUS_SUCCESS; } -static switch_status_t presence_api_function(char *fmt, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(presence_api_function) { switch_event_t *event; char *lbuf, *argv[4]; int argc = 0; switch_event_types_t type = SWITCH_EVENT_PRESENCE_IN; - if (fmt && (lbuf = strdup(fmt)) + if (cmd && (lbuf = strdup(cmd)) && (argc = switch_separate_string(lbuf, '|', argv, (sizeof(argv) / sizeof(argv[0])))) > 0) { if (!strcasecmp(argv[0], "out")) { type = SWITCH_EVENT_PRESENCE_OUT; @@ -568,12 +568,12 @@ } -static switch_status_t chat_api_function(char *fmt, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(chat_api_function) { char *lbuf, *argv[4]; int argc = 0; - if (fmt && (lbuf = strdup(fmt)) + if (cmd && (lbuf = strdup(cmd)) && (argc = switch_separate_string(lbuf, '|', argv, (sizeof(argv) / sizeof(argv[0])))) == 4) { switch_chat_interface_t *ci; Modified: freeswitch/branches/greenlizard/src/mod/applications/mod_enum/mod_enum.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/applications/mod_enum/mod_enum.c (original) +++ freeswitch/branches/greenlizard/src/mod/applications/mod_enum/mod_enum.c Mon May 14 10:50:37 2007 @@ -625,7 +625,7 @@ } -static switch_status_t enum_function(char *data, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(enum_function) { int argc = 0; @@ -640,7 +640,7 @@ return SWITCH_STATUS_FALSE; } - if (!(mydata = strdup(data))) { + if (!cmd || !(mydata = strdup(cmd))) { stream->write_function(stream, "Error!\n"); return SWITCH_STATUS_FALSE; } @@ -649,7 +649,7 @@ dest = argv[0]; root = argv[1] ? argv[1] : globals.root; - if (!enum_lookup(root, data, &results) == SWITCH_STATUS_SUCCESS) { + if (!enum_lookup(root, dest, &results) == SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "No Match!\n"); return SWITCH_STATUS_SUCCESS; } Modified: freeswitch/branches/greenlizard/src/mod/codecs/mod_speex/mod_speex.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/codecs/mod_speex/mod_speex.c (original) +++ freeswitch/branches/greenlizard/src/mod/codecs/mod_speex/mod_speex.c Mon May 14 10:50:37 2007 @@ -302,7 +302,73 @@ /*.next */ &speex_32k_implementation }; -static const switch_codec_implementation_t speex_8k_implementation = { + +static const switch_codec_implementation_t speex_8k_60ms_implementation = { + /*.codec_type */ SWITCH_CODEC_TYPE_AUDIO, + /*.ianacode */ 98, + /*.iananame */ "speex", + /*.fmtp */ NULL, + /*.samples_per_second */ 8000, + /*.bits_per_second */ 3300, + /*.nanoseconds_per_frame */ 60000, + /*.samples_per_frame */ 480, + /*.bytes_per_frame */ 960, + /*.encoded_bytes_per_frame */ 0, + /*.number_of_channels */ 1, + /*.pref_frames_per_packet */ 1, + /*.max_frames_per_packet */ 1, + /*.init */ switch_speex_init, + /*.encode */ switch_speex_encode, + /*.decode */ switch_speex_decode, + /*.destroy */ switch_speex_destroy, + /*.next */ &speex_16k_implementation +}; + +static const switch_codec_implementation_t speex_8k_40ms_implementation = { + /*.codec_type */ SWITCH_CODEC_TYPE_AUDIO, + /*.ianacode */ 98, + /*.iananame */ "speex", + /*.fmtp */ NULL, + /*.samples_per_second */ 8000, + /*.bits_per_second */ 22000, + /*.nanoseconds_per_frame */ 40000, + /*.samples_per_frame */ 240, + /*.bytes_per_frame */ 640, + /*.encoded_bytes_per_frame */ 0, + /*.number_of_channels */ 1, + /*.pref_frames_per_packet */ 1, + /*.max_frames_per_packet */ 1, + /*.init */ switch_speex_init, + /*.encode */ switch_speex_encode, + /*.decode */ switch_speex_decode, + /*.destroy */ switch_speex_destroy, + /*.next */ &speex_8k_60ms_implementation + +}; + + +static const switch_codec_implementation_t speex_8k_30ms_implementation = { + /*.codec_type */ SWITCH_CODEC_TYPE_AUDIO, + /*.ianacode */ 98, + /*.iananame */ "speex", + /*.fmtp */ NULL, + /*.samples_per_second */ 8000, + /*.bits_per_second */ 1650, + /*.nanoseconds_per_frame */ 30000, + /*.samples_per_frame */ 240, + /*.bytes_per_frame */ 480, + /*.encoded_bytes_per_frame */ 0, + /*.number_of_channels */ 1, + /*.pref_frames_per_packet */ 1, + /*.max_frames_per_packet */ 1, + /*.init */ switch_speex_init, + /*.encode */ switch_speex_encode, + /*.decode */ switch_speex_decode, + /*.destroy */ switch_speex_destroy, + /*.next */ &speex_8k_40ms_implementation +}; + +static const switch_codec_implementation_t speex_8k_20ms_implementation = { /*.codec_type */ SWITCH_CODEC_TYPE_AUDIO, /*.ianacode */ 98, /*.iananame */ "speex", @@ -320,12 +386,12 @@ /*.encode */ switch_speex_encode, /*.decode */ switch_speex_decode, /*.destroy */ switch_speex_destroy, - /*.next */ &speex_16k_implementation + /*.next */ &speex_8k_30ms_implementation }; static const switch_codec_interface_t speex_codec_interface = { /*.interface_name */ "speex", - /*.implementations */ &speex_8k_implementation + /*.implementations */ &speex_8k_20ms_implementation }; static switch_loadable_module_interface_t speex_module_interface = { Modified: freeswitch/branches/greenlizard/src/mod/endpoints/mod_alsa/mod_alsa.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/endpoints/mod_alsa/mod_alsa.c (original) +++ freeswitch/branches/greenlizard/src/mod/endpoints/mod_alsa/mod_alsa.c Mon May 14 10:50:37 2007 @@ -1504,9 +1504,15 @@ switch_set_flag_locked(tech_pvt, TFLAG_ANSWER); switch_channel_mark_answered(channel); switch_channel_set_state(channel, CS_INIT); - switch_core_session_thread_launch(tech_pvt->session); - add_pvt(tech_pvt, PA_MASTER); - stream->write_function(stream, "SUCCESS:%s:%s\n", tech_pvt->call_id, switch_core_session_get_uuid(tech_pvt->session)); + + if (switch_core_session_thread_launch(tech_pvt->session) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n"); + switch_core_session_destroy(&session); + stream->write_function(stream, "FAIL:Thread Error!\n"); + } else { + add_pvt(tech_pvt, PA_MASTER); + stream->write_function(stream, "SUCCESS:%s:%s\n", tech_pvt->call_id, switch_core_session_get_uuid(tech_pvt->session)); + } } else { switch_core_session_destroy(&session); stream->write_function(stream, "FAIL:Device Error!\n"); @@ -1516,7 +1522,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t pa_cmd(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(pa_cmd) { char *argv[1024] = { 0 }; int argc = 0; Modified: freeswitch/branches/greenlizard/src/mod/endpoints/mod_dingaling/mod_dingaling.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/endpoints/mod_dingaling/mod_dingaling.c (original) +++ freeswitch/branches/greenlizard/src/mod/endpoints/mod_dingaling/mod_dingaling.c Mon May 14 10:50:37 2007 @@ -191,10 +191,10 @@ SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_string, globals.codec_string) SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_rates_string, globals.codec_rates_string) -static switch_status_t dl_login(char *arg, switch_core_session_t *session, switch_stream_handle_t *stream); -static switch_status_t dl_logout(char *profile_name, switch_core_session_t *session, switch_stream_handle_t *stream); -static switch_status_t dl_pres(char *profile_name, switch_core_session_t *session, switch_stream_handle_t *stream); -static switch_status_t dl_debug(char *profile_name, switch_core_session_t *session, switch_stream_handle_t *stream); +static switch_status_t dl_login(const char *arg, switch_core_session_t *session, switch_stream_handle_t *stream); +static switch_status_t dl_logout(const char *profile_name, switch_core_session_t *session, switch_stream_handle_t *stream); +static switch_status_t dl_pres(const char *profile_name, switch_core_session_t *session, switch_stream_handle_t *stream); +static switch_status_t dl_debug(const char *profile_name, switch_core_session_t *session, switch_stream_handle_t *stream); static switch_status_t channel_on_init(switch_core_session_t *session); static switch_status_t channel_on_hangup(switch_core_session_t *session); static switch_status_t channel_on_ring(switch_core_session_t *session); @@ -2028,7 +2028,7 @@ } } -static switch_status_t dl_debug(char *tf, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(dl_debug) { int on, cur; @@ -2036,8 +2036,8 @@ return SWITCH_STATUS_FALSE; } - if (tf) { - on = switch_true(tf); + if (cmd) { + on = switch_true(cmd); cur = ldl_global_debug(on); } else { cur = ldl_global_debug(-1); @@ -2049,7 +2049,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t dl_pres(char *profile_name, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(dl_pres) { mdl_profile_t *profile; @@ -2057,26 +2057,26 @@ return SWITCH_STATUS_FALSE; } - if (!profile_name) { + if (!cmd) { stream->write_function(stream, "USAGE: %s\n", pres_api_interface.syntax); return SWITCH_STATUS_SUCCESS; } - if ((profile = switch_core_hash_find(globals.profile_hash, profile_name))) { + if ((profile = switch_core_hash_find(globals.profile_hash, cmd))) { if (profile->user_flags & LDL_FLAG_COMPONENT) { sign_on(profile); stream->write_function(stream, "OK\n"); } else { - stream->write_function(stream, "NO PROFILE %s NOT A COMPONENT\n", profile_name); + stream->write_function(stream, "NO PROFILE %s NOT A COMPONENT\n", cmd); } } else { - stream->write_function(stream, "NO SUCH PROFILE %s\n", profile_name); + stream->write_function(stream, "NO SUCH PROFILE %s\n", cmd); } return SWITCH_STATUS_SUCCESS; } -static switch_status_t dl_logout(char *profile_name, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(dl_logout) { mdl_profile_t *profile; @@ -2084,22 +2084,22 @@ return SWITCH_STATUS_FALSE; } - if (!profile_name) { + if (!cmd) { stream->write_function(stream, "USAGE: %s\n", logout_api_interface.syntax); return SWITCH_STATUS_SUCCESS; } - if ((profile = switch_core_hash_find(globals.profile_hash, profile_name))) { + if ((profile = switch_core_hash_find(globals.profile_hash, cmd))) { ldl_handle_stop(profile->handle); stream->write_function(stream, "OK\n"); } else { - stream->write_function(stream, "NO SUCH PROFILE %s\n", profile_name); + stream->write_function(stream, "NO SUCH PROFILE %s\n", cmd); } return SWITCH_STATUS_SUCCESS; } -static switch_status_t dl_login(char *arg, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(dl_login) { char *argv[10] = { 0 }; int argc = 0; @@ -2111,16 +2111,16 @@ return SWITCH_STATUS_FALSE; } - if (switch_strlen_zero(arg)) { + if (switch_strlen_zero(cmd)) { stream->write_function(stream, "USAGE: %s\n", login_api_interface.syntax); return SWITCH_STATUS_SUCCESS; } - myarg = strdup(arg); + myarg = strdup(cmd); argc = switch_separate_string(myarg, ';', argv, (sizeof(argv) / sizeof(argv[0]))); - if (switch_strlen_zero(arg) || argc != 1) { + if (switch_strlen_zero(cmd) || argc != 1) { stream->write_function(stream, "USAGE: %s\n", login_api_interface.syntax); return SWITCH_STATUS_SUCCESS; } @@ -2720,7 +2720,12 @@ tech_pvt->dlsession = dlsession; switch_channel_set_name(channel, "DingaLing/new"); switch_channel_set_state(channel, CS_INIT); - switch_core_session_thread_launch(session); + if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n"); + terminate_session(&session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + status = LDL_STATUS_FALSE; + goto done; + } } else { status = LDL_STATUS_FALSE; goto done; Modified: freeswitch/branches/greenlizard/src/mod/endpoints/mod_iax/mod_iax.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/endpoints/mod_iax/mod_iax.c (original) +++ freeswitch/branches/greenlizard/src/mod/endpoints/mod_iax/mod_iax.c Mon May 14 10:50:37 2007 @@ -1036,6 +1036,10 @@ case IAX_EVENT_REGREJ: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Registration failed.\n"); break; + case IAX_EVENT_REGREQ: + /* what is the right way to handle this? */ + iax_reject_registration(iaxevent->session, NULL); + break; case IAX_EVENT_TIMEOUT: break; case IAX_EVENT_ACCEPT: @@ -1128,7 +1132,10 @@ iax_accept(tech_pvt->iax_session, tech_pvt->codec); iax_ring_announce(tech_pvt->iax_session); switch_channel_set_state(channel, CS_INIT); - switch_core_session_thread_launch(session); + if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n"); + switch_core_session_destroy(&session); + } } } } Modified: freeswitch/branches/greenlizard/src/mod/endpoints/mod_portaudio/mod_portaudio.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/endpoints/mod_portaudio/mod_portaudio.c (original) +++ freeswitch/branches/greenlizard/src/mod/endpoints/mod_portaudio/mod_portaudio.c Mon May 14 10:50:37 2007 @@ -155,8 +155,8 @@ static switch_status_t load_config(void); static int get_dev_by_name(char *name, int in); static int get_dev_by_number(int number, int in); - static switch_status_t pa_cmd(char *dest, switch_core_session_t *session, switch_stream_handle_t *stream); - static switch_status_t padep(char *dest, switch_core_session_t *session, switch_stream_handle_t *stream); + static switch_status_t pa_cmd(const char *dest, switch_core_session_t *session, switch_stream_handle_t *stream); + static switch_status_t padep(const char *dest, switch_core_session_t *session, switch_stream_handle_t *stream); /* @@ -1694,9 +1694,14 @@ switch_set_flag_locked(tech_pvt, TFLAG_ANSWER); switch_channel_mark_answered(channel); switch_channel_set_state(channel, CS_INIT); - switch_core_session_thread_launch(tech_pvt->session); - add_pvt(tech_pvt, PA_MASTER); - stream->write_function(stream, "SUCCESS:%s:%s\n", tech_pvt->call_id, switch_core_session_get_uuid(tech_pvt->session)); + if (switch_core_session_thread_launch(tech_pvt->session) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n"); + switch_core_session_destroy(&session); + stream->write_function(stream, "FAIL:Thread Error!\n"); + } else { + add_pvt(tech_pvt, PA_MASTER); + stream->write_function(stream, "SUCCESS:%s:%s\n", tech_pvt->call_id, switch_core_session_get_uuid(tech_pvt->session)); + } } else { switch_core_session_destroy(&session); stream->write_function(stream, "FAIL:Device Error!\n"); @@ -1706,13 +1711,13 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t padep(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(padep) { stream->write_function(stream, "This command no longer exists (try 'pa help')\n"); return SWITCH_STATUS_SUCCESS; } -static switch_status_t pa_cmd(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(pa_cmd) { char *argv[1024] = { 0 }; int argc = 0; Modified: freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/Makefile.am ============================================================================== --- freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/Makefile.am (original) +++ freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/Makefile.am Mon May 14 10:50:37 2007 @@ -1,6 +1,6 @@ AM_CFLAGS = $(SWITCH_AM_CFLAGS) AM_CPPFLAGS = $(SWITCH_AM_CXXFLAGS) -AM_LDFLAGS = $(SWITCH_AM_LDFLAGS) +#AM_LDFLAGS = $(SWITCH_AM_LDFLAGS) #we should set all these vars from configure, no reason to have these in each Makefile.am LIBTOOL = echo "`link=\`echo $@|grep .la;echo $@|grep .so;echo $@|grep .dll\`;if test -n "$$link"; then echo Creating $@;fi`";`if test -z "$(VERBOSE)" ; \ then echo $(SHELL) $(switch_builddir)/quiet_libtool ;else echo $(SHELL) $(switch_builddir)/libtool; fi` @@ -12,9 +12,7 @@ MODNAME=mod_sofia -BASE=../../../.. - -SOFIA_DIR=$(BASE)/libs/sofia-sip +SOFIA_DIR=$(switch_builddir)/libs/sofia-sip SOFIAUA_DIR=$(SOFIA_DIR)/libsofia-sip-ua SOFIALA=$(SOFIAUA_DIR)/libsofia-sip-ua.la @@ -30,8 +28,8 @@ mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/soa -I$(SOFIAUA_DIR)/sresolv mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/stun -I$(SOFIAUA_DIR)/su mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/tport -I$(SOFIAUA_DIR)/url -mod_sofia_la_LIBADD = $(SOFIALA) $(switch_builddir)/libfreeswitch.la -mod_sofia_la_LDFLAGS = -module -avoid-version -no-undefined +mod_sofia_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(SOFIALA) +mod_sofia_la_LDFLAGS = -avoid-version -module -no-undefined if ADD_ODBC mod_sofia_la_CFLAGS += -DSWITCH_HAVE_ODBC @@ -51,12 +49,12 @@ ../../../../libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h: $(SOFIALA) -install-data-am: $(DESTDIR)$(PREFIX)/$(moddir)/$(MODNAME).$(DYNAMIC_LIB_EXTEN) +#install-data-am: $(DESTDIR)$(PREFIX)/$(moddir)/$(MODNAME).$(DYNAMIC_LIB_EXTEN) -$(DESTDIR)$(PREFIX)/$(moddir)/$(MODNAME).$(DYNAMIC_LIB_EXTEN): $(MODNAME).la - @echo installing $(MODNAME).$(DYNAMIC_LIB_EXTEN) - @if [ -f .libs/$(MODNAME).$(DYNAMIC_LIB_EXTEN) ] ; then \ - $(LIBTOOL) --mode=install $(INSTALL) .libs/$(MODNAME).$(DYNAMIC_LIB_EXTEN) $(DESTDIR)$(PREFIX)/$(moddir) >/dev/null ; \ - else \ - $(LIBTOOL) --mode=install $(INSTALL) $(MODNAME).$(DYNAMIC_LIB_EXTEN) $(DESTDIR)$(PREFIX)/$(moddir) >/dev/null ; \ - fi +#$(DESTDIR)$(PREFIX)/$(moddir)/$(MODNAME).$(DYNAMIC_LIB_EXTEN): $(MODNAME).la +# @echo installing $(MODNAME).$(DYNAMIC_LIB_EXTEN) +# @if [ -f .libs/$(MODNAME).$(DYNAMIC_LIB_EXTEN) ] ; then \ +# $(LIBTOOL) --mode=install $(INSTALL) .libs/$(MODNAME).$(DYNAMIC_LIB_EXTEN) $(DESTDIR)$(PREFIX)/$(moddir) >/dev/null ; \ +# else \ +# $(LIBTOOL) --mode=install $(INSTALL) $(MODNAME).$(DYNAMIC_LIB_EXTEN) $(DESTDIR)$(PREFIX)/$(moddir) >/dev/null ; \ +# fi Modified: freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/mod_sofia.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/mod_sofia.c (original) +++ freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/mod_sofia.c Mon May 14 10:50:37 2007 @@ -339,7 +339,7 @@ tech_pvt = (private_object_t *) switch_core_session_get_private(session); assert(tech_pvt != NULL); - if (switch_test_flag(tech_pvt, TFLAG_HUP) || !sofia_test_pflag(tech_pvt->profile, PFLAG_RUNNING)) { + if (switch_test_flag(tech_pvt, TFLAG_HUP)) { return SWITCH_STATUS_FALSE; } @@ -411,7 +411,7 @@ } } - if (switch_test_flag(tech_pvt, TFLAG_HUP) || !sofia_test_pflag(tech_pvt->profile, PFLAG_RUNNING)) { + if (switch_test_flag(tech_pvt, TFLAG_HUP)) { return SWITCH_STATUS_FALSE; } @@ -443,7 +443,7 @@ tech_pvt = (private_object_t *) switch_core_session_get_private(session); assert(tech_pvt != NULL); - if (switch_test_flag(tech_pvt, TFLAG_HUP) || !sofia_test_pflag(tech_pvt->profile, PFLAG_RUNNING)) { + if (switch_test_flag(tech_pvt, TFLAG_HUP)) { return SWITCH_STATUS_FALSE; } @@ -538,7 +538,7 @@ } } - if (switch_test_flag(tech_pvt, TFLAG_HUP) || !sofia_test_pflag(tech_pvt->profile, PFLAG_RUNNING)) { + if (switch_test_flag(tech_pvt, TFLAG_HUP)) { return SWITCH_STATUS_FALSE; } @@ -1140,7 +1140,7 @@ if (!strcasecmp(argv[1], "stop") || !strcasecmp(argv[1], "restart")) { - int rsec = 30; + int rsec = 3; int diff = (int) (time(NULL) - profile->started); int remain = rsec - diff; if (diff < rsec) { @@ -1175,7 +1175,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t sofia_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(sofia_function) { char *argv[1024] = { 0 }; int argc = 0; @@ -1190,7 +1190,7 @@ "sofia status [[profile | gateway] <name>]\n" "--------------------------------------------------------------------------------\n"; - if (isession) { + if (session) { return SWITCH_STATUS_FALSE; } Modified: freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/mod_sofia.h ============================================================================== --- freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/mod_sofia.h (original) +++ freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/mod_sofia.h Mon May 14 10:50:37 2007 @@ -242,6 +242,7 @@ switch_thread_rwlock_t *rwlock; switch_mutex_t *flag_mutex; uint32_t inuse; + uint32_t soft_max; time_t started; #ifdef SWITCH_HAVE_ODBC char *odbc_dsn; Modified: freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/sofia.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/sofia.c (original) +++ freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/sofia.c Mon May 14 10:50:37 2007 @@ -363,11 +363,6 @@ su_root_step(profile->s_root, 1000); } - while(profile->inuse) { - switch_yield(500000); - } - - //sofia_reg_check_expire(profile, 0); //sofia_reg_check_gateway(profile, 0); @@ -481,7 +476,8 @@ *proxy = NULL, *context = "default", *expire_seconds = "3600", - *retry_seconds = "30"; + *retry_seconds = "30", + *from_domain = ""; gateway->pool = profile->pool; gateway->profile = profile; @@ -515,6 +511,8 @@ expire_seconds = val; } else if (!strcmp(var, "retry-seconds")) { retry_seconds = val; + } else if (!strcmp(var, "from-domain")) { + from_domain = val; } } @@ -544,6 +542,10 @@ gateway->state = REG_STATE_NOREG; } + if (switch_strlen_zero(from_domain)) { + from_domain = realm; + } + gateway->retry_seconds = atoi(retry_seconds); if (gateway->retry_seconds < 10) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "INVALID: retry_seconds correcting the value to 30\n"); @@ -557,7 +559,7 @@ if (switch_true(caller_id_in_from)) { switch_set_flag(gateway, REG_FLAG_CALLERID); } - gateway->register_from = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, realm); + gateway->register_from = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, from_domain); gateway->register_contact = switch_core_sprintf(gateway->pool, "sip:%s@%s:%d", extension, profile->sipip, profile->sip_port); if (!strncasecmp(proxy, "sip:", 4)) { @@ -1708,10 +1710,17 @@ const char *context = NULL; char network_ip[80]; switch_event_t *v_event = NULL; + uint32_t sess_count = switch_core_session_count(); + uint32_t sess_max = switch_core_session_limit(0); + + if ((profile->soft_max && sess_count >= profile->soft_max) || sess_count >= sess_max) { + nua_respond(nh, 480, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END()); + return; + } if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n"); - nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); + nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END()); return; } @@ -1911,7 +1920,33 @@ switch_copy_string(tech_pvt->sofia_private->uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt->sofia_private->uuid)); nua_handle_bind(nh, tech_pvt->sofia_private); tech_pvt->nh = nh; - switch_core_session_thread_launch(session); + + if (switch_core_session_thread_launch(session) == SWITCH_STATUS_SUCCESS) { + return; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "LUKE: I'm hit, but not bad.\n"); + + switch_mutex_lock(profile->flag_mutex); + + profile->soft_max = sess_count - 10; + switch_core_session_limit(profile->soft_max); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "LUKE'S VOICE: Artoo, see what you can do with it. Hang on back there....\n" + "Green laserfire moves past the beeping little robot as his head turns. " + "After a few beeps and a twist of his mechanical arm,\n" + "Artoo reduces the max sessions to %d thus, saving the switch from certian doom.\n", + profile->soft_max); + + switch_mutex_unlock(profile->flag_mutex); + + if (tech_pvt->hash_key) { + switch_core_hash_delete(tech_pvt->profile->chat_hash, tech_pvt->hash_key); + } + + nua_handle_bind(nh, NULL); + free(tech_pvt->sofia_private); + switch_core_session_destroy(&session); + nua_respond(nh, 480, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END()); } void sofia_handle_sip_i_options(int status, Modified: freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/sofia_reg.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/sofia_reg.c (original) +++ freeswitch/branches/greenlizard/src/mod/endpoints/mod_sofia/sofia_reg.c Mon May 14 10:50:37 2007 @@ -281,7 +281,7 @@ if (!from_user || !from_host) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can not do authorization without a complete from header\n"); - nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); + nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), TAG_END()); return 1; } Modified: freeswitch/branches/greenlizard/src/mod/endpoints/mod_wanpipe/mod_wanpipe.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/endpoints/mod_wanpipe/mod_wanpipe.c (original) +++ freeswitch/branches/greenlizard/src/mod/endpoints/mod_wanpipe/mod_wanpipe.c Mon May 14 10:50:37 2007 @@ -1562,6 +1562,12 @@ switch_copy_string(chanmap->map[pevent->ring.channel], switch_core_session_get_uuid(session), sizeof(chanmap->map[pevent->ring.channel])); switch_channel_set_state(channel, CS_INIT); + if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n"); + switch_core_session_destroy(&session); + ret = 0; + goto done; + } switch_core_session_thread_launch(session); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create new Inbound Channel!\n"); Modified: freeswitch/branches/greenlizard/src/mod/endpoints/mod_woomera/mod_woomera.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/endpoints/mod_woomera/mod_woomera.c (original) +++ freeswitch/branches/greenlizard/src/mod/endpoints/mod_woomera/mod_woomera.c Mon May 14 10:50:37 2007 @@ -1240,7 +1240,11 @@ break; } switch_channel_set_state(channel, CS_INIT); - switch_core_session_thread_launch(session); + if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n"); + switch_core_session_destroy(&session); + break; + } } } } Modified: freeswitch/branches/greenlizard/src/mod/event_handlers/mod_cdr/basecdr.h ============================================================================== --- freeswitch/branches/greenlizard/src/mod/event_handlers/mod_cdr/basecdr.h (original) +++ freeswitch/branches/greenlizard/src/mod/event_handlers/mod_cdr/basecdr.h Mon May 14 10:50:37 2007 @@ -90,7 +90,7 @@ switch_time_t callenddate; switch_time_t calltransferdate; switch_call_cause_t hangupcause; - char *hangupcause_text; + const char *hangupcause_text; char clid[80]; bool originated; // Did they originate this call? char dialplan[80]; Modified: freeswitch/branches/greenlizard/src/mod/event_handlers/mod_cdr/mod_cdr.cpp ============================================================================== --- freeswitch/branches/greenlizard/src/mod/event_handlers/mod_cdr/mod_cdr.cpp (original) +++ freeswitch/branches/greenlizard/src/mod/event_handlers/mod_cdr/mod_cdr.cpp Mon May 14 10:50:37 2007 @@ -45,11 +45,11 @@ static CDRContainer *newcdrcontainer; static switch_memory_pool_t *module_pool; static switch_status_t my_on_hangup(switch_core_session_t *session); -static switch_status_t modcdr_reload(char *dest, switch_core_session_t *isession, switch_stream_handle_t *stream); -static switch_status_t modcdr_queue_pause(char *dest, switch_core_session_t *isession, switch_stream_handle_t *stream); -static switch_status_t modcdr_queue_resume(char *dest, switch_core_session_t *isession, switch_stream_handle_t *stream); -static switch_status_t modcdr_show_active(char *dest, switch_core_session_t *isession, switch_stream_handle_t *stream); -static switch_status_t modcdr_show_available(char *dest, switch_core_session_t *isession, switch_stream_handle_t *stream); +static switch_status_t modcdr_reload(const char *dest, switch_core_session_t *isession, switch_stream_handle_t *stream); +static switch_status_t modcdr_queue_pause(const char *dest, switch_core_session_t *isession, switch_stream_handle_t *stream); +static switch_status_t modcdr_queue_resume(const char *dest, switch_core_session_t *isession, switch_stream_handle_t *stream); +static switch_status_t modcdr_show_active(const char *dest, switch_core_session_t *isession, switch_stream_handle_t *stream); +static switch_status_t modcdr_show_available(const char *dest, switch_core_session_t *isession, switch_stream_handle_t *stream); static switch_thread_rwlock_t *cdr_rwlock; /* Now begins the glue that will tie this into the system. @@ -151,7 +151,7 @@ return RUNNING ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_TERM; } -static switch_status_t modcdr_reload(char *dest=0, switch_core_session_t *isession=0, switch_stream_handle_t *stream=0) +SWITCH_STANDARD_API(modcdr_reload) { #ifdef SWITCH_QUEUE_ENHANCED switch_thread_rwlock_wrlock(cdr_rwlock); @@ -164,7 +164,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t modcdr_queue_pause(char *dest=0, switch_core_session_t *isession=0, switch_stream_handle_t *stream=0) +SWITCH_STANDARD_API(modcdr_queue_pause) { #ifdef SWITCH_QUEUE_ENHANCED newcdrcontainer->queue_pause(stream); @@ -174,7 +174,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t modcdr_queue_resume(char *dest=0, switch_core_session_t *isession=0, switch_stream_handle_t *stream=0) +SWITCH_STANDARD_API(modcdr_queue_resume) { #ifdef SWITCH_QUEUE_ENHANCED newcdrcontainer->queue_resume(stream); @@ -184,13 +184,13 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t modcdr_show_active(char *dest=0, switch_core_session_t *isession=0, switch_stream_handle_t *stream=0) +SWITCH_STANDARD_API(modcdr_show_active) { newcdrcontainer->active(stream); return SWITCH_STATUS_SUCCESS; } -static switch_status_t modcdr_show_available(char *dest=0, switch_core_session_t *isession=0, switch_stream_handle_t *stream=0) +SWITCH_STANDARD_API(modcdr_show_available) { newcdrcontainer->available(stream); return SWITCH_STATUS_SUCCESS; Modified: freeswitch/branches/greenlizard/src/mod/languages/mod_python/freeswitch_python.cpp ============================================================================== --- freeswitch/branches/greenlizard/src/mod/languages/mod_python/freeswitch_python.cpp (original) +++ freeswitch/branches/greenlizard/src/mod/languages/mod_python/freeswitch_python.cpp Mon May 14 10:50:37 2007 @@ -51,10 +51,10 @@ switch_channel_set_variable(channel, var, val); } -void SessionContainer::get_variable(char *var, char *val) +char *SessionContainer::get_variable(char *var) { - sanity_check(); - switch_channel_get_variable(channel, var); + sanity_check(NULL); + return switch_channel_get_variable(channel, var); } void SessionContainer::execute(char *app, char *data) Modified: freeswitch/branches/greenlizard/src/mod/languages/mod_python/freeswitch_python.h ============================================================================== --- freeswitch/branches/greenlizard/src/mod/languages/mod_python/freeswitch_python.h (original) +++ freeswitch/branches/greenlizard/src/mod/languages/mod_python/freeswitch_python.h Mon May 14 10:50:37 2007 @@ -34,7 +34,7 @@ int pre_answer(); void hangup(char *cause); void set_variable(char *var, char *val); - void get_variable(char *var, char *val); + char *get_variable(char *var); int play_file(char *file, char *timer_name); void set_dtmf_callback(PyObject * pyfunc); int speak_text(char *text); Modified: freeswitch/branches/greenlizard/src/mod/languages/mod_python/mod_python.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/languages/mod_python/mod_python.c (original) +++ freeswitch/branches/greenlizard/src/mod/languages/mod_python/mod_python.c Mon May 14 10:50:37 2007 @@ -161,14 +161,14 @@ return NULL; } -static switch_status_t launch_python(char *text, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(launch_python) { switch_thread_t *thread; switch_threadattr_t *thd_attr = NULL; switch_memory_pool_t *pool; struct switch_py_thread *pt; - if (switch_strlen_zero(text)) { + if (switch_strlen_zero(cmd)) { stream->write_function(stream, "USAGE: %s\n", python_run_interface.syntax); return SWITCH_STATUS_SUCCESS; } @@ -180,7 +180,7 @@ assert(pt != NULL); pt->pool = pool; - pt->args = switch_core_strdup(pt->pool, text); + pt->args = switch_core_strdup(pt->pool, cmd); switch_threadattr_create(&thd_attr, pt->pool); switch_threadattr_detach_set(thd_attr, 1); Modified: freeswitch/branches/greenlizard/src/mod/languages/mod_python/mod_python_wrap.cpp ============================================================================== --- freeswitch/branches/greenlizard/src/mod/languages/mod_python/mod_python_wrap.cpp (original) +++ freeswitch/branches/greenlizard/src/mod/languages/mod_python/mod_python_wrap.cpp Mon May 14 10:50:37 2007 @@ -1045,14 +1045,14 @@ PyObject *resultobj; SessionContainer *arg1 = (SessionContainer *) 0 ; char *arg2 ; - char *arg3 ; + char *result; PyObject * obj0 = 0 ; - if(!PyArg_ParseTuple(args,(char *)"Oss:SessionContainer_get_variable",&obj0,&arg2,&arg3)) goto fail; + if(!PyArg_ParseTuple(args,(char *)"Os:SessionContainer_get_variable",&obj0,&arg2)) goto fail; if ((SWIG_ConvertPtr(obj0,(void **) &arg1, SWIGTYPE_p_SessionContainer,SWIG_POINTER_EXCEPTION | 0 )) == -1) SWIG_fail; - (arg1)->get_variable(arg2,arg3); + result = (char *)(arg1)->get_variable(arg2); - Py_INCREF(Py_None); resultobj = Py_None; + resultobj = result ? PyString_FromString(result) : Py_BuildValue((char*)""); return resultobj; fail: return NULL; Modified: freeswitch/branches/greenlizard/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c (original) +++ freeswitch/branches/greenlizard/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c Mon May 14 10:50:37 2007 @@ -45,6 +45,7 @@ static JSBool session_construct(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval); static JSBool session_originate(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval); static switch_api_interface_t js_run_interface; +static switch_api_interface_t jsapi_interface; static struct { size_t gStackChunkSize; @@ -111,6 +112,190 @@ int32 bufsize; }; +struct request_obj { + const char *cmd; + switch_core_session_t *session; + switch_stream_handle_t *stream; +}; + + +/* Request Object */ +/*********************************************************************************/ + +static JSBool request_write(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval) +{ + struct request_obj *ro = JS_GetPrivate(cx, obj); + + if (!ro) { + *rval = BOOLEAN_TO_JSVAL(JS_FALSE); + return JS_TRUE; + } + + if (argc > 0) { + char *string = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); + ro->stream->write_function(ro->stream, "%s", string); + *rval = BOOLEAN_TO_JSVAL(JS_TRUE); + return JS_TRUE; + } + + *rval = BOOLEAN_TO_JSVAL(JS_FALSE); + return JS_TRUE; +} + +static JSBool request_add_header(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + struct request_obj *ro = JS_GetPrivate(cx, obj); + + if (!ro) { + *rval = BOOLEAN_TO_JSVAL(JS_FALSE); + return JS_TRUE; + } + + if (argc > 1) { + char *hname = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); + char *hval = JS_GetStringBytes(JS_ValueToString(cx, argv[1])); + switch_event_add_header(ro->stream->event, SWITCH_STACK_BOTTOM, hname, "%s", hval); + *rval = BOOLEAN_TO_JSVAL(JS_TRUE); + return JS_TRUE; + } + + *rval = BOOLEAN_TO_JSVAL(JS_FALSE); + return JS_TRUE; +} + +static JSBool request_get_header(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval) +{ + struct request_obj *ro = JS_GetPrivate(cx, obj); + + if (!ro) { + *rval = BOOLEAN_TO_JSVAL(JS_FALSE); + return JS_TRUE; + } + + + if (argc > 0) { + char *hname = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); + char *val = switch_event_get_header(ro->stream->event, hname); + *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, val)); + return JS_TRUE; + } + + *rval = BOOLEAN_TO_JSVAL(JS_FALSE); + return JS_TRUE; +} + +static JSBool request_dump_env(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + struct request_obj *ro = JS_GetPrivate(cx, obj); + char *how = "text"; + + if (!ro) { + *rval = BOOLEAN_TO_JSVAL(JS_FALSE); + return JS_TRUE; + } + + if (argc > 0) { + how = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); + } + + if (!strcasecmp(how, "xml")) { + switch_xml_t xml; + char *xmlstr; + if ((xml = switch_event_xmlize(ro->stream->event, NULL))) { + xmlstr = switch_xml_toxml(xml); + *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, xmlstr)); + return JS_TRUE; + } + } else { + char *buf; + switch_event_serialize(ro->stream->event, &buf); + if (buf) { + *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buf)); + free(buf); + return JS_TRUE; + } + } + + *rval = BOOLEAN_TO_JSVAL(JS_FALSE); + return JS_FALSE; +} + +static void request_destroy(JSContext * cx, JSObject * obj) +{ + +} + +enum request_tinyid { + REQUEST_COMMAND +}; + +static JSFunctionSpec request_methods[] = { + {"write", request_write, 1}, + {"getHeader", request_get_header, 1}, + {"addHeader", request_add_header, 1}, + {"dumpENV", request_dump_env, 1}, + {0} +}; + +static JSPropertySpec request_props[] = { + {"command", REQUEST_COMMAND, JSPROP_READONLY | JSPROP_PERMANENT}, + {0} +}; + + +static JSBool request_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSBool res = JS_TRUE; + struct request_obj *ro = JS_GetPrivate(cx, obj); + char *name; + int param = 0; + + if (!ro) { + *vp = BOOLEAN_TO_JSVAL(JS_FALSE); + return JS_TRUE; + } + + + name = JS_GetStringBytes(JS_ValueToString(cx, id)); + /* numbers are our props anything else is a method */ + if (name[0] >= 48 && name[0] <= 57) { + param = atoi(name); + } else { + return JS_TRUE; + } + + switch (param) { + case REQUEST_COMMAND: + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, ro->cmd)); + break; + } + + return res; +} + + +JSClass request_class = { + "Request", JSCLASS_HAS_PRIVATE, + JS_PropertyStub, JS_PropertyStub, request_getProperty, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, request_destroy, NULL, NULL, NULL, NULL +}; + + +static JSObject *new_request(JSContext *cx, JSObject *obj, struct request_obj *ro) +{ + JSObject *Request; + if ((Request = JS_DefineObject(cx, obj, "request", &request_class, NULL, 0))) { + if ((JS_SetPrivate(cx, Request, ro) && + JS_DefineProperties(cx, Request, request_props) && JS_DefineFunctions(cx, Request, request_methods))) { + return Request; + } + } + + return NULL; +} + + + struct event_obj { switch_event_t *event; int freed; @@ -402,8 +587,6 @@ }; - - static void js_error(JSContext * cx, const char *message, JSErrorReport * report) { const char *filename = __FILE__; @@ -2649,7 +2832,7 @@ return 1; } -static void js_parse_and_execute(switch_core_session_t *session, char *input_code) +static void js_parse_and_execute(switch_core_session_t *session, char *input_code, struct request_obj *ro) { JSObject *javascript_global_object = NULL; char buf[1024], *script, *arg, *argv[512]; @@ -2671,6 +2854,10 @@ if (session && new_js_session(cx, javascript_global_object, session, &jss, "session", flags)) { JS_SetPrivate(cx, javascript_global_object, session); } + if (ro) { + new_request(cx, javascript_global_object, ro); + } + } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Allocation Error!\n"); return; @@ -2683,7 +2870,11 @@ argc = switch_separate_string(arg, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); } - if (argc) { /* create a js doppleganger of this argc/argv */ + if (!argc) { + snprintf(buf, sizeof(buf), "~var argv = new Array();"); + eval_some_js(buf, cx, javascript_global_object, &rval); + } else { + /* create a js doppleganger of this argc/argv */ snprintf(buf, sizeof(buf), "~var argv = new Array(%d);", argc); eval_some_js(buf, cx, javascript_global_object, &rval); snprintf(buf, sizeof(buf), "~var argc = %d", argc); @@ -2701,14 +2892,16 @@ } } - - +static void js_dp_function(switch_core_session_t *session, char *input_code) +{ + js_parse_and_execute(session, input_code, NULL); +} static void *SWITCH_THREAD_FUNC js_thread_run(switch_thread_t * thread, void *obj) { char *input_code = obj; - js_parse_and_execute(NULL, input_code); + js_parse_and_execute(NULL, input_code, NULL); if (input_code) { free(input_code); @@ -2720,7 +2913,7 @@ static switch_memory_pool_t *module_pool = NULL; -static void js_thread_launch(char *text) +static void js_thread_launch(const char *text) { switch_thread_t *thread; switch_threadattr_t *thd_attr = NULL; @@ -2738,16 +2931,33 @@ switch_thread_create(&thread, thd_attr, js_thread_run, strdup(text), module_pool); } +SWITCH_STANDARD_API(jsapi_function) +{ + struct request_obj ro = {0}; + + if (switch_strlen_zero(cmd)) { + stream->write_function(stream, "USAGE: %s\n", jsapi_interface.syntax); + return SWITCH_STATUS_SUCCESS; + } + + ro.cmd = cmd; + ro.session = session; + ro.stream = stream; + js_parse_and_execute(session, (char *) cmd, &ro); + + return SWITCH_STATUS_SUCCESS; +} + -static switch_status_t launch_async(char *text, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(launch_async) { - if (switch_strlen_zero(text)) { + if (switch_strlen_zero(cmd)) { stream->write_function(stream, "USAGE: %s\n", js_run_interface.syntax); return SWITCH_STATUS_SUCCESS; } - js_thread_launch(text); + js_thread_launch(cmd); stream->write_function(stream, "OK\n"); return SWITCH_STATUS_SUCCESS; } @@ -2755,7 +2965,7 @@ static const switch_application_interface_t ivrtest_application_interface = { /*.interface_name */ "javascript", - /*.application_function */ js_parse_and_execute, + /*.application_function */ js_dp_function, /* long_desc */ "Run a javascript ivr on a channel", /* short_desc */ "Launch JS ivr.", /* syntax */ "<script> [additional_vars [...]]", @@ -2764,12 +2974,21 @@ /*.next */ NULL }; + +static switch_api_interface_t jsapi_interface = { + /*.interface_name */ "jsapi", + /*.desc */ "execute an api call", + /*.function */ jsapi_function, + /*.syntax */ "jsapi <script> [additional_vars [...]]", + /*.next */ NULL +}; + static switch_api_interface_t js_run_interface = { /*.interface_name */ "jsrun", /*.desc */ "run a script", /*.function */ launch_async, /*.syntax */ "jsrun <script> [additional_vars [...]]", - /*.next */ NULL + /*.next */ &jsapi_interface }; static switch_loadable_module_interface_t spidermonkey_module_interface = { Modified: freeswitch/branches/greenlizard/src/mod/xml_int/mod_xml_curl/mod_xml_curl.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/xml_int/mod_xml_curl/mod_xml_curl.c (original) +++ freeswitch/branches/greenlizard/src/mod/xml_int/mod_xml_curl/mod_xml_curl.c Mon May 14 10:50:37 2007 @@ -37,6 +37,7 @@ char *url; char *bindings; char *cred; + int disable100continue; }; typedef struct xml_binding xml_binding_t; @@ -68,6 +69,7 @@ char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; xml_binding_t *binding = (xml_binding_t *) user_data; char *file_url; + struct curl_slist *slist = NULL; if (!binding) { return NULL; @@ -115,6 +117,12 @@ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, file_callback); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &config_data); curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-xml/1.0"); + + if (binding->disable100continue) { + slist = curl_slist_append(slist,"Expect:"); + curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, slist); + } + curl_easy_perform(curl_handle); curl_easy_cleanup(curl_handle); close(config_data.fd); @@ -169,6 +177,7 @@ char *url = NULL; char *bind_cred = NULL; char *bind_mask = NULL; + int disable100continue = 0; for (param = switch_xml_child(binding_tag, "param"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); @@ -180,6 +189,8 @@ } } else if (!strcasecmp(var, "gateway-credentials")) { bind_cred = val; + } else if (!strcasecmp(var, "disable-100-continue") && switch_true(val)) { + disable100continue = 1; } } @@ -203,6 +214,8 @@ binding->cred = strdup(bind_cred); } + binding->disable100continue = disable100continue; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Binding [%s] XML Fetch Function [%s] [%s]\n", switch_strlen_zero(bname) ? "N/A" : bname, binding->url, binding->bindings ? binding->bindings : "all"); switch_xml_bind_search_function(xml_url_fetch, switch_xml_parse_section_string(binding->bindings), binding); Modified: freeswitch/branches/greenlizard/src/switch_buffer.c ============================================================================== --- freeswitch/branches/greenlizard/src/switch_buffer.c (original) +++ freeswitch/branches/greenlizard/src/switch_buffer.c Mon May 14 10:50:37 2007 @@ -193,7 +193,7 @@ return reading; } -SWITCH_DECLARE(switch_size_t) switch_buffer_write(switch_buffer_t *buffer, void *data, switch_size_t datalen) +SWITCH_DECLARE(switch_size_t) switch_buffer_write(switch_buffer_t *buffer, const void *data, switch_size_t datalen) { switch_size_t freespace, actual_freespace; Modified: freeswitch/branches/greenlizard/src/switch_caller.c ============================================================================== --- freeswitch/branches/greenlizard/src/switch_caller.c (original) +++ freeswitch/branches/greenlizard/src/switch_caller.c Mon May 14 10:50:37 2007 @@ -92,7 +92,7 @@ return profile; } -SWITCH_DECLARE(char *) switch_caller_get_field_by_name(switch_caller_profile_t *caller_profile, char *name) +SWITCH_DECLARE(char *) switch_caller_get_field_by_name(switch_caller_profile_t *caller_profile, const char *name) { if (!strcasecmp(name, "dialplan")) { return caller_profile->dialplan; @@ -136,7 +136,7 @@ return NULL; } -SWITCH_DECLARE(void) switch_caller_profile_event_set_data(switch_caller_profile_t *caller_profile, char *prefix, switch_event_t *event) +SWITCH_DECLARE(void) switch_caller_profile_event_set_data(switch_caller_profile_t *caller_profile, const char *prefix, switch_event_t *event) { char header_name[1024]; @@ -207,7 +207,7 @@ } -SWITCH_DECLARE(switch_caller_extension_t *) switch_caller_extension_new(switch_core_session_t *session, char *extension_name, char *extension_number) +SWITCH_DECLARE(switch_caller_extension_t *) switch_caller_extension_new(switch_core_session_t *session, const char *extension_name, const char *extension_number) { switch_caller_extension_t *caller_extension = NULL; @@ -222,7 +222,7 @@ SWITCH_DECLARE(void) switch_caller_extension_add_application(switch_core_session_t *session, - switch_caller_extension_t *caller_extension, char *application_name, char *application_data) + switch_caller_extension_t *caller_extension, const char *application_name, const char *application_data) { switch_caller_application_t *caller_application = NULL; Modified: freeswitch/branches/greenlizard/src/switch_channel.c ============================================================================== --- freeswitch/branches/greenlizard/src/switch_channel.c (original) +++ freeswitch/branches/greenlizard/src/switch_channel.c Mon May 14 10:50:37 2007 @@ -119,21 +119,21 @@ }; -SWITCH_DECLARE(char *) switch_channel_cause2str(switch_call_cause_t cause) +SWITCH_DECLARE(const char *) switch_channel_cause2str(switch_call_cause_t cause) { uint8_t x; - char *str = "UNKNOWN"; + const char *str = "UNKNOWN"; for (x = 0; CAUSE_CHART[x].name; x++) { if (CAUSE_CHART[x].cause == cause) { - str = (char *) CAUSE_CHART[x].name; + str = CAUSE_CHART[x].name; } } return str; } -SWITCH_DECLARE(switch_call_cause_t) switch_channel_str2cause(char *str) +SWITCH_DECLARE(switch_call_cause_t) switch_channel_str2cause(const char *str) { uint8_t x; switch_call_cause_t cause = SWITCH_CAUSE_UNALLOCATED; @@ -198,12 +198,12 @@ return has; } -SWITCH_DECLARE(switch_status_t) switch_channel_queue_dtmf(switch_channel_t *channel, char *dtmf) +SWITCH_DECLARE(switch_status_t) switch_channel_queue_dtmf(switch_channel_t *channel, const char *dtmf) { switch_status_t status; register switch_size_t len, inuse; switch_size_t wr = 0; - char *p; + const char *p; assert(channel != NULL); @@ -270,7 +270,7 @@ return SWITCH_STATUS_SUCCESS; } -SWITCH_DECLARE(void) switch_channel_presence(switch_channel_t *channel, char *rpid, char *status) +SWITCH_DECLARE(void) switch_channel_presence(switch_channel_t *channel, const char *rpid, const char *status) { char *id = switch_channel_get_variable(channel, "presence_id"); switch_event_t *event; @@ -302,7 +302,7 @@ } -SWITCH_DECLARE(char *) switch_channel_get_variable(switch_channel_t *channel, char *varname) +SWITCH_DECLARE(char *) switch_channel_get_variable(switch_channel_t *channel, const char *varname) { char *v = NULL; assert(channel != NULL); @@ -343,7 +343,7 @@ return hi; } -SWITCH_DECLARE(switch_status_t) switch_channel_set_private(switch_channel_t *channel, char *key, void *private_info) +SWITCH_DECLARE(switch_status_t) switch_channel_set_private(switch_channel_t *channel, const char *key, const void *private_info) { assert(channel != NULL); switch_mutex_lock(channel->profile_mutex); @@ -352,7 +352,7 @@ return SWITCH_STATUS_SUCCESS; } -SWITCH_DECLARE(void *) switch_channel_get_private(switch_channel_t *channel, char *key) +SWITCH_DECLARE(void *) switch_channel_get_private(switch_channel_t *channel, const char *key) { void *val; assert(channel != NULL); @@ -362,7 +362,7 @@ return val; } -SWITCH_DECLARE(switch_status_t) switch_channel_set_name(switch_channel_t *channel, char *name) +SWITCH_DECLARE(switch_status_t) switch_channel_set_name(switch_channel_t *channel, const char *name) { assert(channel != NULL); channel->name = NULL; @@ -532,7 +532,7 @@ } -SWITCH_DECLARE(switch_channel_state_t) switch_channel_name_state(char *name) +SWITCH_DECLARE(switch_channel_state_t) switch_channel_name_state(const char *name) { uint32_t x = 0; for (x = 0; state_names[x]; x++) { Modified: freeswitch/branches/greenlizard/src/switch_core.c ============================================================================== --- freeswitch/branches/greenlizard/src/switch_core.c (original) +++ freeswitch/branches/greenlizard/src/switch_core.c Mon May 14 10:50:37 2007 @@ -71,16 +71,16 @@ } } -static void heartbeat_callback(switch_scheduler_task_t *task) +SWITCH_STANDARD_SCHED_FUNC(heartbeat_callback) { send_heartbeat(); /* reschedule this task */ - task->runtime += 20; + task->runtime = time(NULL) + 20; } -SWITCH_DECLARE(switch_status_t) switch_core_set_console(char *console) +SWITCH_DECLARE(switch_status_t) switch_core_set_console(const char *console) { if ((runtime.console = fopen(console, "a")) == 0) { fprintf(stderr, "Cannot open output file %s.\n", console); @@ -135,12 +135,12 @@ } -SWITCH_DECLARE(char *) switch_core_get_variable(char *varname) +SWITCH_DECLARE(char *) switch_core_get_variable(const char *varname) { return (char *) switch_core_hash_find(runtime.global_vars, varname); } -SWITCH_DECLARE(void) switch_core_set_variable(char *varname, char *value) +SWITCH_DECLARE(void) switch_core_set_variable(const char *varname, const char *value) { switch_core_hash_insert(runtime.global_vars, switch_core_strdup(runtime.memory_pool, varname), switch_core_strdup(runtime.memory_pool, value)); } @@ -392,7 +392,7 @@ } -SWITCH_DECLARE(switch_status_t) switch_core_init(char *console, const char **err) +SWITCH_DECLARE(switch_status_t) switch_core_init(const char *console, const char **err) { switch_xml_t xml = NULL, cfg = NULL; switch_uuid_t uuid; @@ -538,7 +538,7 @@ if (sig); return; } -SWITCH_DECLARE(switch_status_t) switch_core_init_and_modload(char *console, const char **err) +SWITCH_DECLARE(switch_status_t) switch_core_init_and_modload(const char *console, const char **err) { switch_event_t *event; if (switch_core_init(console, err) != SWITCH_STATUS_SUCCESS) { Modified: freeswitch/branches/greenlizard/src/switch_core_session.c ============================================================================== --- freeswitch/branches/greenlizard/src/switch_core_session.c (original) +++ freeswitch/branches/greenlizard/src/switch_core_session.c Mon May 14 10:50:37 2007 @@ -45,9 +45,9 @@ #ifdef SWITCH_DEBUG_RWLOCKS -SWITCH_DECLARE(switch_core_session_t *) switch_core_session_perform_locate(char *uuid_str, const char *file, const char *func, int line) +SWITCH_DECLARE(switch_core_session_t *) switch_core_session_perform_locate(const char *uuid_str, const char *file, const char *func, int line) #else -SWITCH_DECLARE(switch_core_session_t *) switch_core_session_locate(char *uuid_str) +SWITCH_DECLARE(switch_core_session_t *) switch_core_session_locate(const char *uuid_str) #endif { switch_core_session_t *session = NULL; @@ -651,13 +651,15 @@ } -SWITCH_DECLARE(void) switch_core_session_destroy(switch_core_session_t **session) +SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t **session, const char *file, const char *func, int line) { switch_memory_pool_t *pool; switch_event_t *event; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Close Channel %s\n", switch_channel_get_name((*session)->channel)); - + switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, SWITCH_LOG_NOTICE, "Close Channel %s [%s]\n", + switch_channel_get_name((*session)->channel), + switch_channel_state_name(switch_channel_get_state((*session)->channel))); + switch_ivr_deactivate_unicast(*session); switch_scheduler_del_task_group((*session)->uuid_str); @@ -711,7 +713,7 @@ } -SWITCH_DECLARE(void) switch_core_session_thread_launch(switch_core_session_t *session) +SWITCH_DECLARE(switch_status_t) switch_core_session_thread_launch(switch_core_session_t *session) { switch_thread_t *thread; switch_threadattr_t *thd_attr;; @@ -720,10 +722,16 @@ if (!session->thread_running) { switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); - if (switch_thread_create(&thread, thd_attr, switch_core_session_thread, session, session->pool) != SWITCH_STATUS_SUCCESS) { - switch_core_session_destroy(&session); + if (switch_thread_create(&thread, thd_attr, switch_core_session_thread, session, session->pool) == SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_SUCCESS; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot create thread!\n"); } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot double-launch thread!\n"); } + + return SWITCH_STATUS_FALSE; } Modified: freeswitch/branches/greenlizard/src/switch_cpp.cpp ============================================================================== --- freeswitch/branches/greenlizard/src/switch_cpp.cpp (original) +++ freeswitch/branches/greenlizard/src/switch_cpp.cpp Mon May 14 10:50:37 2007 @@ -1,6 +1,10 @@ #include <switch.h> #include <switch_cpp.h> +#ifdef _MSC_VER +#pragma warning(disable:4127 4003) +#endif + #define sanity_check(x) do { if (!session) { switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_ERROR, "session is not initalized\n"); return x;}} while(0) #define init_vars() do { session = NULL; channel = NULL; uuid = NULL; tts_name = NULL; voice_name = NULL; memset(&args, 0, sizeof(args)); ap = NULL;} while(0) @@ -45,7 +49,7 @@ { switch_status_t status; sanity_check(-1); - switch_channel_pre_answer(channel); + status = switch_channel_pre_answer(channel); return status == SWITCH_STATUS_SUCCESS ? 1 : 0; } @@ -61,10 +65,10 @@ switch_channel_set_variable(channel, var, val); } -void CoreSession::getVariable(char *var, char *val) +char *CoreSession::getVariable(char *var) { - sanity_check(); - switch_channel_get_variable(channel, var); + sanity_check(NULL); + return switch_channel_get_variable(channel, var); } void CoreSession::execute(char *app, char *data) Modified: freeswitch/branches/greenlizard/src/switch_ivr_async.c ============================================================================== --- freeswitch/branches/greenlizard/src/switch_ivr_async.c (original) +++ freeswitch/branches/greenlizard/src/switch_ivr_async.c Mon May 14 10:50:37 2007 @@ -615,7 +615,7 @@ switch_call_cause_t cause; }; -static void sch_hangup_callback(switch_scheduler_task_t *task) +SWITCH_STANDARD_SCHED_FUNC(sch_hangup_callback) { struct hangup_helper *helper; switch_core_session_t *session, *other_session; @@ -665,7 +665,7 @@ char *context; }; -static void sch_transfer_callback(switch_scheduler_task_t *task) +SWITCH_STANDARD_SCHED_FUNC(sch_transfer_callback) { struct transfer_helper *helper; switch_core_session_t *session; @@ -732,7 +732,7 @@ switch_media_flag_t flags; }; -static void sch_broadcast_callback(switch_scheduler_task_t *task) +SWITCH_STANDARD_SCHED_FUNC(sch_broadcast_callback) { struct broadcast_helper *helper; assert(task); Modified: freeswitch/branches/greenlizard/src/switch_ivr_play_say.c ============================================================================== --- freeswitch/branches/greenlizard/src/switch_ivr_play_say.c (original) +++ freeswitch/branches/greenlizard/src/switch_ivr_play_say.c Mon May 14 10:50:37 2007 @@ -917,8 +917,7 @@ //Make sure we made it out alive if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); - break; + goto done; } //we only get one digit out of playback, see if thats all we needed and what we got if (max_digits == 1 && status == SWITCH_STATUS_BREAK) { @@ -938,8 +937,7 @@ //Make sure we made it out alive if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); - break; + goto done; } } } @@ -957,8 +955,7 @@ //Make sure we made it out alive if (status != SWITCH_STATUS_SUCCESS) { //Bail - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); - break; + goto done; } //see if we got enough if (min_digits <= strlen(digit_buffer)) { @@ -977,8 +974,7 @@ //Make sure we made it out alive if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); - break; + goto done; } } } @@ -989,6 +985,7 @@ } } + done: //if we got here, we got no digits or lost the channel digit_buffer = "\0"; return SWITCH_STATUS_FALSE; Modified: freeswitch/branches/greenlizard/src/switch_loadable_module.c ============================================================================== --- freeswitch/branches/greenlizard/src/switch_loadable_module.c (original) +++ freeswitch/branches/greenlizard/src/switch_loadable_module.c Mon May 14 10:50:37 2007 @@ -1110,7 +1110,7 @@ } -SWITCH_DECLARE(switch_endpoint_interface_t *) switch_loadable_module_get_endpoint_interface(char *name) +SWITCH_DECLARE(switch_endpoint_interface_t *) switch_loadable_module_get_endpoint_interface(const char *name) { switch_endpoint_interface_t *ptr; @@ -1121,7 +1121,7 @@ return ptr; } -SWITCH_DECLARE(switch_codec_interface_t *) switch_loadable_module_get_codec_interface(char *name) +SWITCH_DECLARE(switch_codec_interface_t *) switch_loadable_module_get_codec_interface(const char *name) { char altname[256] = ""; switch_codec_interface_t *codec; @@ -1143,57 +1143,57 @@ return codec; } -SWITCH_DECLARE(switch_dialplan_interface_t *) switch_loadable_module_get_dialplan_interface(char *name) +SWITCH_DECLARE(switch_dialplan_interface_t *) switch_loadable_module_get_dialplan_interface(const char *name) { return switch_core_hash_find_locked(loadable_modules.dialplan_hash, name, loadable_modules.mutex); } -SWITCH_DECLARE(switch_timer_interface_t *) switch_loadable_module_get_timer_interface(char *name) +SWITCH_DECLARE(switch_timer_interface_t *) switch_loadable_module_get_timer_interface(const char *name) { return switch_core_hash_find_locked(loadable_modules.timer_hash, name, loadable_modules.mutex); } -SWITCH_DECLARE(switch_application_interface_t *) switch_loadable_module_get_application_interface(char *name) +SWITCH_DECLARE(switch_application_interface_t *) switch_loadable_module_get_application_interface(const char *name) { return switch_core_hash_find_locked(loadable_modules.application_hash, name, loadable_modules.mutex); } -SWITCH_DECLARE(switch_api_interface_t *) switch_loadable_module_get_api_interface(char *name) +SWITCH_DECLARE(switch_api_interface_t *) switch_loadable_module_get_api_interface(const char *name) { return switch_core_hash_find_locked(loadable_modules.api_hash, name, loadable_modules.mutex); } -SWITCH_DECLARE(switch_file_interface_t *) switch_loadable_module_get_file_interface(char *name) +SWITCH_DECLARE(switch_file_interface_t *) switch_loadable_module_get_file_interface(const char *name) { return switch_core_hash_find_locked(loadable_modules.file_hash, name, loadable_modules.mutex); } -SWITCH_DECLARE(switch_speech_interface_t *) switch_loadable_module_get_speech_interface(char *name) +SWITCH_DECLARE(switch_speech_interface_t *) switch_loadable_module_get_speech_interface(const char *name) { return switch_core_hash_find_locked(loadable_modules.speech_hash, name, loadable_modules.mutex); } -SWITCH_DECLARE(switch_asr_interface_t *) switch_loadable_module_get_asr_interface(char *name) +SWITCH_DECLARE(switch_asr_interface_t *) switch_loadable_module_get_asr_interface(const char *name) { return switch_core_hash_find_locked(loadable_modules.asr_hash, name, loadable_modules.mutex); } -SWITCH_DECLARE(switch_directory_interface_t *) switch_loadable_module_get_directory_interface(char *name) +SWITCH_DECLARE(switch_directory_interface_t *) switch_loadable_module_get_directory_interface(const char *name) { return switch_core_hash_find_locked(loadable_modules.directory_hash, name, loadable_modules.mutex); } -SWITCH_DECLARE(switch_chat_interface_t *) switch_loadable_module_get_chat_interface(char *name) +SWITCH_DECLARE(switch_chat_interface_t *) switch_loadable_module_get_chat_interface(const char *name) { return switch_core_hash_find_locked(loadable_modules.chat_hash, name, loadable_modules.mutex); } -SWITCH_DECLARE(switch_say_interface_t *) switch_loadable_module_get_say_interface(char *name) +SWITCH_DECLARE(switch_say_interface_t *) switch_loadable_module_get_say_interface(const char *name) { return switch_core_hash_find_locked(loadable_modules.say_hash, name, loadable_modules.mutex); } -SWITCH_DECLARE(switch_management_interface_t *) switch_loadable_module_get_management_interface(char *relative_oid) +SWITCH_DECLARE(switch_management_interface_t *) switch_loadable_module_get_management_interface(const char *relative_oid) { return switch_core_hash_find_locked(loadable_modules.management_hash, relative_oid, loadable_modules.mutex); } @@ -1319,7 +1319,7 @@ return i; } -SWITCH_DECLARE(switch_status_t) switch_api_execute(char *cmd, char *arg, switch_core_session_t *session, switch_stream_handle_t *stream) +SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char *arg, switch_core_session_t *session, switch_stream_handle_t *stream) { switch_api_interface_t *api; switch_status_t status; Modified: freeswitch/branches/greenlizard/src/switch_regex.c ============================================================================== --- freeswitch/branches/greenlizard/src/switch_regex.c (original) +++ freeswitch/branches/greenlizard/src/switch_regex.c Mon May 14 10:50:37 2007 @@ -32,12 +32,19 @@ #include <switch.h> #include <pcre.h> - SWITCH_DECLARE(switch_regex_t *) switch_regex_compile(const char *pattern, - int options, const char **errorptr, int *erroroffset, const unsigned char *tables) + + +SWITCH_DECLARE(switch_regex_t *) switch_regex_compile(const char *pattern, + int options, const char **errorptr, int *erroroffset, +const unsigned char *tables) { - return pcre_compile(pattern, options, errorptr, erroroffset, tables); - } - SWITCH_DECLARE(int) switch_regex_copy_substring(const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int size) + +return pcre_compile(pattern, options, errorptr, erroroffset, tables); + +} + + +SWITCH_DECLARE(int) switch_regex_copy_substring(const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int size) { return pcre_copy_substring(subject, ovector, stringcount, stringnumber, buffer, size); } @@ -45,7 +52,10 @@ SWITCH_DECLARE(void) switch_regex_free(void *data) { pcre_free(data); - } SWITCH_DECLARE(int) switch_regex_perform(char *field, char *expression, switch_regex_t **new_re, int *ovector, uint32_t olen) + +} + +SWITCH_DECLARE(int) switch_regex_perform(const char *field, const char *expression, switch_regex_t **new_re, int *ovector, uint32_t olen) { const char *error = NULL; int erroffset = 0; @@ -87,7 +97,7 @@ } -SWITCH_DECLARE(void) switch_perform_substitution(switch_regex_t *re, int match_count, char *data, char *field_data, +SWITCH_DECLARE(void) switch_perform_substitution(switch_regex_t *re, int match_count, const char *data, const char *field_data, char *substituted, uint32_t len, int *ovector) { char index[10] = ""; @@ -124,7 +134,8 @@ } substituted[y++] = '\0'; } - SWITCH_DECLARE(switch_status_t) switch_regex_match(char *target, char *expression) + +SWITCH_DECLARE(switch_status_t) switch_regex_match(const char *target, const char *expression) { const char *error = NULL; //Used to hold any errors int error_offset = 0; //Holds the offset of an error Modified: freeswitch/branches/greenlizard/src/switch_rtp.c ============================================================================== --- freeswitch/branches/greenlizard/src/switch_rtp.c (original) +++ freeswitch/branches/greenlizard/src/switch_rtp.c Mon May 14 10:50:37 2007 @@ -319,7 +319,7 @@ } -SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_session, char *host, switch_port_t port, const char **err) +SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_session, const char *host, switch_port_t port, const char **err) { switch_socket_t *new_sock = NULL, *old_sock = NULL; switch_status_t status = SWITCH_STATUS_FALSE; @@ -389,7 +389,7 @@ return status; } -SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_session, char *host, switch_port_t port, const char **err) +SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_session, const char *host, switch_port_t port, const char **err) { *err = "Success"; @@ -545,9 +545,9 @@ return SWITCH_STATUS_SUCCESS; } -SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(char *rx_host, +SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host, switch_port_t rx_port, - char *tx_host, + const char *tx_host, switch_port_t tx_port, switch_payload_t payload, uint32_t samples_per_interval, Modified: freeswitch/branches/greenlizard/src/switch_scheduler.c ============================================================================== --- freeswitch/branches/greenlizard/src/switch_scheduler.c (original) +++ freeswitch/branches/greenlizard/src/switch_scheduler.c Mon May 14 10:50:37 2007 @@ -77,6 +77,11 @@ } else { int64_t now = time(NULL); if (now >= tp->task.runtime && !tp->in_thread) { + int32_t diff = (int32_t)(now - tp->task.runtime); + if (diff > 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Task was executed late by %d seconds %u %s (%s)\n", + diff, tp->task.task_id, tp->desc, switch_str_nil(tp->task.group)); + } tp->executed = now; if (switch_test_flag(tp, SSHF_OWN_THREAD)) { switch_thread_t *thread; @@ -144,7 +149,7 @@ SWITCH_DECLARE(uint32_t) switch_scheduler_add_task(time_t task_runtime, switch_scheduler_func_t func, - char *desc, char *group, uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags) + const char *desc, const char *group, uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags) { switch_scheduler_task_container_t *container, *tp; switch_event_t *event; @@ -218,7 +223,7 @@ return delcnt; } -SWITCH_DECLARE(uint32_t) switch_scheduler_del_task_group(char *group) +SWITCH_DECLARE(uint32_t) switch_scheduler_del_task_group(const char *group) { switch_scheduler_task_container_t *tp; switch_event_t *event; Modified: freeswitch/branches/greenlizard/src/switch_utils.c ============================================================================== --- freeswitch/branches/greenlizard/src/switch_utils.c (original) +++ freeswitch/branches/greenlizard/src/switch_utils.c Mon May 14 10:50:37 2007 @@ -177,7 +177,7 @@ } -SWITCH_DECLARE(switch_time_t) switch_str_time(char *in) +SWITCH_DECLARE(switch_time_t) switch_str_time(const char *in) { switch_time_exp_t tm = { 0 }; int proceed = 0, ovector[30]; @@ -229,7 +229,7 @@ } -SWITCH_DECLARE(char *) switch_priority_name(switch_priority_t priority) +SWITCH_DECLARE(const char *) switch_priority_name(switch_priority_t priority) { switch (priority) { /*lol */ case SWITCH_PRIORITY_NORMAL: @@ -284,9 +284,10 @@ return '\0'; } -SWITCH_DECLARE(char *) switch_escape_char(switch_memory_pool_t *pool, char *in, char *delim, char esc) +SWITCH_DECLARE(char *) switch_escape_char(switch_memory_pool_t *pool, char *in, const char *delim, char esc) { - char *data, *p, *d; + char *data; + const char *p, *d; int count = 1, i = 0; p = in; Modified: freeswitch/branches/greenlizard/w32/Library/FreeSwitchCore.vcproj ============================================================================== --- freeswitch/branches/greenlizard/w32/Library/FreeSwitchCore.vcproj (original) +++ freeswitch/branches/greenlizard/w32/Library/FreeSwitchCore.vcproj Mon May 14 10:50:37 2007 @@ -340,6 +340,30 @@ > </File> <File + RelativePath="..\..\src\switch_cpp.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0" + PrecompiledHeaderThrough="" + PrecompiledHeaderFile="" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0" + PrecompiledHeaderThrough="" + PrecompiledHeaderFile="" + /> + </FileConfiguration> + </File> + <File RelativePath="..\..\src\switch_event.c" > </File> @@ -450,11 +474,11 @@ > </File> <File - RelativePath="..\..\src\include\private\switch_core.h" + RelativePath="..\..\src\include\switch_core.h" > </File> <File - RelativePath="..\..\src\include\switch_core.h" + RelativePath="..\..\src\include\private\switch_core.h" > </File> <File @@ -466,6 +490,10 @@ > </File> <File + RelativePath="..\..\src\include\switch_cpp.h" + > + </File> + <File RelativePath="..\..\src\include\switch_event.h" > </File>
participants (1)
-
Freeswitch SVN