diff --git a/debian/bootstrap.sh b/debian/bootstrap.sh index 03953b36c0..edfe7f1077 100755 --- a/debian/bootstrap.sh +++ b/debian/bootstrap.sh @@ -937,12 +937,11 @@ genoverrides_per_mod () { test -f $f.tmpl && cat $f.tmpl >> $f } -genmodules_per_cat () { - echo "## $category" >> modules_.conf -} - -genmodules_per_mod () { - echo "$module" >> modules_.conf +genmodulesconf () { + genmodules_per_cat () { echo "## $category"; } + genmodules_per_mod () { echo "$module"; } + print_edit_warning + map_modules 'mod_filter' 'genmodules_per_cat' 'genmodules_per_mod' } genconf () { @@ -1142,6 +1141,18 @@ set_modules_non_dfsg () { done } +conf_merge () { + local of="$1" if="$2" + if [ -s $if ]; then + grep -v '^##\|^$' $if | while xread x; do + touch $of + if ! grep -e "$x" $of >/dev/null; then + printf '%s\n' "$x" >> $of + fi + done + fi +} + codename="sid" modulelist_opt="" while getopts "c:m:" o; do @@ -1165,6 +1176,8 @@ echo "Parsing control-modules..." >&2 parse_mod_control echo "Displaying includes/excludes..." >&2 map_modules 'mod_filter_show' '' '' +echo "Generating modules_.conf..." >&2 +genmodulesconf > modules_.conf echo "Generating control-modules.gen as sanity check..." >&2 (echo "# -*- mode:debian-control -*-"; \ echo "##### Author: Travis Cross "; echo; \ @@ -1187,21 +1200,13 @@ echo "Generating debian/ (lang)..." >&2 map_langs 'genlang' echo "Generating debian/ (modules)..." >&2 (echo "### modules"; echo) >> control -print_edit_warning > modules_.conf map_modules "mod_filter" \ - "gencontrol_per_cat genmodules_per_cat" \ - "gencontrol_per_mod geninstall_per_mod genoverrides_per_mod genmodules_per_mod" + "gencontrol_per_cat" \ + "gencontrol_per_mod geninstall_per_mod genoverrides_per_mod" echo "Generating debian/ (-all package)..." >&2 grep -e '^Package:' control | grep -v '^freeswitch-all$' | while xread l; do m="${l#*: }" - f=$m.install - if [ -s $f ]; then - grep -v '^##\|^$' $f | while xread x; do - if ! grep -e "$x" freeswitch-all.install >/dev/null; then - printf '%s\n' "$x" >> freeswitch-all.install - fi - done - fi + conf_merge freeswitch-all.install $m.install done for x in postinst postrm preinst prerm; do cp -a freeswitch.$x freeswitch-all.$x diff --git a/debian/util.sh b/debian/util.sh index 7825e13d54..66231c3d82 100755 --- a/debian/util.sh +++ b/debian/util.sh @@ -101,7 +101,7 @@ getlibs () { getlib http://downloads.mongodb.org/cxx-driver/mongodb-linux-x86_64-v1.8-latest.tgz getlib http://files.freeswitch.org/downloads/libs/json-c-0.9.tar.gz getlib http://files.freeswitch.org/downloads/libs/libmemcached-0.32.tar.gz - getlib http://files.freeswitch.org/downloads/libs/soundtouch-1.6.0.tar.gz + getlib http://files.freeswitch.org/downloads/libs/soundtouch-1.7.1.tar.gz getlib http://files.freeswitch.org/downloads/libs/flite-1.5.4-current.tar.bz2 getlib http://files.freeswitch.org/downloads/libs/sphinxbase-0.7.tar.gz getlib http://files.freeswitch.org/downloads/libs/pocketsphinx-0.7.tar.gz diff --git a/freeswitch.spec b/freeswitch.spec index 1454aa6779..d1ce880237 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -118,7 +118,7 @@ Source4: http://files.freeswitch.org/downloads/libs/libshout-2.2.2.tar.gz Source5: http://files.freeswitch.org/downloads/libs/mpg123-1.13.2.tar.gz #Source6: http://files.freeswitch.org/downloads/libs/openldap-2.4.11.tar.gz Source6: http://files.freeswitch.org/downloads/libs/pocketsphinx-0.7.tar.gz -Source7: http://files.freeswitch.org/downloads/libs/soundtouch-1.6.0.tar.gz +Source7: http://files.freeswitch.org/downloads/libs/soundtouch-1.7.1.tar.gz Source8: http://files.freeswitch.org/downloads/libs/sphinxbase-0.7.tar.gz Source9: http://files.freeswitch.org/downloads/libs/communicator_semi_6000_20080321.tar.gz Source10: http://files.freeswitch.org/downloads/libs/libmemcached-0.32.tar.gz diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 43c872b5cf..e2c5749e7d 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -2312,7 +2312,7 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload); SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_str, const char *list_name, const char **token); #define switch_check_network_list_ip(_ip_str, _list_name) switch_check_network_list_ip_token(_ip_str, _list_name, NULL) SWITCH_DECLARE(void) switch_time_set_monotonic(switch_bool_t enable); -SWITCH_DECLARE(void) switch_time_set_timerfd(switch_bool_t enable); +SWITCH_DECLARE(void) switch_time_set_timerfd(int enable); SWITCH_DECLARE(void) switch_time_set_nanosleep(switch_bool_t enable); SWITCH_DECLARE(void) switch_time_set_matrix(switch_bool_t enable); SWITCH_DECLARE(void) switch_time_set_cond_yield(switch_bool_t enable); @@ -2601,6 +2601,7 @@ SWITCH_DECLARE(int) switch_stream_system_fork(const char *cmd, switch_stream_han SWITCH_DECLARE(int) switch_stream_system(const char *cmd, switch_stream_handle_t *stream); SWITCH_DECLARE(switch_call_direction_t) switch_ice_direction(switch_core_session_t *session); +SWITCH_DECLARE(void) switch_core_session_debug_pool(switch_stream_handle_t *stream); SWITCH_END_EXTERN_C #endif diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index cfbe9921eb..d827385d62 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -310,11 +310,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core switch_media_type_t type, const char *iananame, switch_payload_t *ptP, - switch_payload_t *recv_ptP); + switch_payload_t *recv_ptP, + char **fmtpP); SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_session_t *session, switch_media_type_t type, const char *name, + const char *fmtp, switch_sdp_type_t sdp_type, uint32_t pt, uint32_t rate, diff --git a/src/include/switch_platform.h b/src/include/switch_platform.h index e0cf9cd51b..7efd84eaa8 100644 --- a/src/include/switch_platform.h +++ b/src/include/switch_platform.h @@ -227,9 +227,10 @@ typedef intptr_t switch_ssize_t; #ifdef WIN32 -#ifdef WIN64 +#ifdef _WIN64 #define SWITCH_SSIZE_T_FMT "lld" #define SWITCH_SIZE_T_FMT "lld" +#define FS_64BIT 1 #else #define SWITCH_SSIZE_T_FMT "d" #define SWITCH_SIZE_T_FMT "d" @@ -268,7 +269,7 @@ typedef intptr_t switch_ssize_t; #endif -#if UINTPTR_MAX == 0xffffffffffffffff || defined(_WIN64) +#if UINTPTR_MAX == 0xffffffffffffffff #define FS_64BIT 1 #endif diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 4a3153de5a..019e3f8563 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -34,7 +34,7 @@ * Rupa Schomaker * Joseph Sullivan * Raymond Chandler - * + * Seven Du * Garmt Boekholt * * mod_commands.c -- Misc. Command Module @@ -2276,6 +2276,9 @@ SWITCH_STANDARD_API(ctl_function) switch_core_session_ctl(command, &arg); stream->write_function(stream, "+OK\n"); + } else if (!strcasecmp(argv[0], "debug_pool")) { + switch_core_session_debug_pool(stream); + } else if (!strcasecmp(argv[0], "debug_sql")) { int x = 0; switch_core_session_ctl(SCSC_DEBUG_SQL, &x); @@ -6529,12 +6532,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add alias add"); + switch_console_set_complete("add alias stickyadd"); switch_console_set_complete("add alias del"); switch_console_set_complete("add coalesce"); switch_console_set_complete("add complete add"); switch_console_set_complete("add complete del"); switch_console_set_complete("add db_cache status"); switch_console_set_complete("add fsctl debug_level"); + switch_console_set_complete("add fsctl debug_pool"); switch_console_set_complete("add fsctl debug_sql"); switch_console_set_complete("add fsctl last_sps"); switch_console_set_complete("add fsctl default_dtmf_duration"); diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index dd3d6bb4bb..03fd1cdfc1 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -210,7 +210,8 @@ typedef enum { CFLAG_FLOOR_CHANGE = (1 << 18), CFLAG_VID_FLOOR_LOCK = (1 << 19), CFLAG_JSON_EVENTS = (1 << 20), - CFLAG_LIVEARRAY_SYNC = (1 << 21) + CFLAG_LIVEARRAY_SYNC = (1 << 21), + CFLAG_CONF_RESTART_AUTO_RECORD = (1 << 22) } conf_flag_t; typedef enum { @@ -1457,7 +1458,7 @@ static switch_status_t conference_record_stop(conference_obj_t *conference, swit switch_mutex_lock(conference->member_mutex); for (member = conference->members; member; member = member->next) { if (switch_test_flag(member, MFLAG_NOCHANNEL) && (!path || !strcmp(path, member->rec_path))) { - if (member->rec && member->rec->autorec) { + if (!switch_test_flag(conference, CFLAG_CONF_RESTART_AUTO_RECORD) && member->rec && member->rec->autorec) { stream->write_function(stream, "Stopped AUTO recording file %s (Auto Recording Now Disabled)\n", member->rec_path); conference->auto_record = 0; } else { @@ -7695,6 +7696,8 @@ static void set_cflags(const char *flags, uint32_t *f) *f |= CFLAG_VIDEO_BRIDGE; } else if (!strcasecmp(argv[i], "audio-always")) { *f |= CFLAG_AUDIO_ALWAYS; + } else if (!strcasecmp(argv[i], "restart-auto-record")) { + *f |= CFLAG_CONF_RESTART_AUTO_RECORD; } else if (!strcasecmp(argv[i], "json-events")) { *f |= CFLAG_JSON_EVENTS; } else if (!strcasecmp(argv[i], "livearray-sync")) { diff --git a/src/mod/applications/mod_soundtouch/Makefile b/src/mod/applications/mod_soundtouch/Makefile index 33d3e2b227..0afa65ca69 100644 --- a/src/mod/applications/mod_soundtouch/Makefile +++ b/src/mod/applications/mod_soundtouch/Makefile @@ -1,5 +1,5 @@ BASE=../../../.. -VERSION=soundtouch-1.6.0 +VERSION=soundtouch-1.7.1 SNDT_SRC=$(switch_srcdir)/libs/soundtouch SNDT_BUILD=$(switch_builddir)/libs/soundtouch LA=$(SNDT_BUILD)/source/SoundTouch/.libs/libSoundTouch.a diff --git a/src/mod/endpoints/mod_rtmp/mod_rtmp.c b/src/mod/endpoints/mod_rtmp/mod_rtmp.c index e25f38b861..4e6e10db8f 100644 --- a/src/mod/endpoints/mod_rtmp/mod_rtmp.c +++ b/src/mod/endpoints/mod_rtmp/mod_rtmp.c @@ -40,7 +40,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rtmp_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_rtmp_shutdown); -SWITCH_MODULE_DEFINITION(mod_rtmp, mod_rtmp_load, mod_rtmp_shutdown, NULL); +SWITCH_MODULE_RUNTIME_FUNCTION(mod_rtmp_runtime); +SWITCH_MODULE_DEFINITION(mod_rtmp, mod_rtmp_load, mod_rtmp_shutdown, mod_rtmp_runtime); static switch_status_t config_profile(rtmp_profile_t *profile, switch_bool_t reload); static switch_xml_config_item_t *get_instructions(rtmp_profile_t *profile); @@ -732,7 +733,7 @@ rtmp_session_t *rtmp_session_locate(const char *uuid) { rtmp_session_t *rsession = switch_core_hash_find_rdlock(rtmp_globals.session_hash, uuid, rtmp_globals.session_rwlock); - if (!rsession || rsession->state == RS_DESTROY) { + if (!rsession || rsession->state >= RS_DESTROY) { return NULL; } @@ -812,53 +813,95 @@ switch_status_t rtmp_session_request(rtmp_profile_t *profile, rtmp_session_t **n return SWITCH_STATUS_SUCCESS; } +static void rtmp_garbage_colletor(void) +{ + switch_hash_index_t *hi; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "RTMP Garbage Collection\n"); + + + switch_thread_rwlock_wrlock(rtmp_globals.session_rwlock); + + top: + + for (hi = switch_hash_first(NULL, rtmp_globals.session_hash); hi; hi = switch_hash_next(hi)) { + void *val; + const void *key; + switch_ssize_t keylen; + rtmp_session_t *rsession; + + switch_hash_this(hi, &key, &keylen, &val); + rsession = (rtmp_session_t *) val; + + if (rsession->state == RS_DESTROY) { + if (rtmp_real_session_destroy(&rsession) == SWITCH_STATUS_SUCCESS) { + goto top; + } + } + } + + switch_thread_rwlock_unlock(rtmp_globals.session_rwlock); +} + switch_status_t rtmp_session_destroy(rtmp_session_t **rsession) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + + switch_mutex_lock(rtmp_globals.mutex); + if (rsession && *rsession) { + (*rsession)->state = RS_DESTROY; + *rsession = NULL; + status = SWITCH_STATUS_SUCCESS; + } + switch_mutex_unlock(rtmp_globals.mutex); + + return status; +} + +switch_status_t rtmp_real_session_destroy(rtmp_session_t **rsession) { switch_hash_index_t *hi; switch_event_t *event; - - if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, RTMP_EVENT_DISCONNECT) == SWITCH_STATUS_SUCCESS) { - rtmp_event_fill(*rsession, event); - switch_event_fire(&event); - } - - switch_core_hash_delete_wrlock(rtmp_globals.session_hash, (*rsession)->uuid, rtmp_globals.session_rwlock); - switch_core_hash_delete_wrlock((*rsession)->profile->session_hash, (*rsession)->uuid, (*rsession)->profile->session_rwlock); - rtmp_clear_registration(*rsession, NULL, NULL); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "RTMP session ended [%s]\n", (*rsession)->uuid); - - (*rsession)->state = RS_DESTROY; + int sess = 0; switch_thread_rwlock_rdlock((*rsession)->session_rwlock); for (hi = switch_hash_first(NULL, (*rsession)->session_hash); hi; hi = switch_hash_next(hi)) { void *val; const void *key; switch_ssize_t keylen; - rtmp_private_t *tech_pvt; switch_channel_t *channel; switch_core_session_t *session; - switch_hash_this(hi, &key, &keylen, &val); - tech_pvt = (rtmp_private_t *)val; - - /* At this point we don't know if the session still exists, so request a fresh pointer to it from the core. */ - if ( (session = switch_core_session_locate((char *)key)) != NULL ) { - /* - * This is here so that if the FS session still exists and has the FS session write(or read) lock, then we won't destroy the rsession - * until the FS session is finished with it. But if the rsession is able to get the FS session - * write lock, before the FS session is hungup, then once the FS session does get the write lock - * the rsession pointer will be null, and the FS session will never try and touch the already destroyed rsession. - */ + switch_hash_this(hi, &key, &keylen, &val); + + /* If there are any sessions attached, abort the destroy operation */ + if ((session = switch_core_session_locate((char *)key)) != NULL ) { channel = switch_core_session_get_channel(session); - tech_pvt = switch_core_session_get_private(session); - if ( tech_pvt && tech_pvt->rtmp_session ) { - tech_pvt->rtmp_session = NULL; - } switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); switch_core_session_rwunlock(session); + sess++; } } switch_thread_rwlock_unlock((*rsession)->session_rwlock); + + if (sess) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "RTMP session [%s] %p still busy.\n", (*rsession)->uuid, (void *) *rsession); + return SWITCH_STATUS_FALSE; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "RTMP session [%s] %p will be destroyed.\n", (*rsession)->uuid, (void *) *rsession); + + + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, RTMP_EVENT_DISCONNECT) == SWITCH_STATUS_SUCCESS) { + rtmp_event_fill(*rsession, event); + switch_event_fire(&event); + } + + switch_core_hash_delete(rtmp_globals.session_hash, (*rsession)->uuid); + switch_core_hash_delete_wrlock((*rsession)->profile->session_hash, (*rsession)->uuid, (*rsession)->profile->session_rwlock); + rtmp_clear_registration(*rsession, NULL, NULL); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "RTMP session ended [%s]\n", (*rsession)->uuid); + switch_mutex_lock((*rsession)->profile->mutex); if ( (*rsession)->profile->calls < 1 ) { @@ -1137,7 +1180,7 @@ static void rtmp_clear_reg_auth(rtmp_session_t *rsession, const char *auth, cons switch_thread_rwlock_wrlock(rsession->profile->reg_rwlock); if ((reg = switch_core_hash_find(rsession->profile->reg_hash, auth))) { for (; reg; reg = reg->next) { - if (!strcmp(reg->uuid, rsession->uuid) && (zstr(nickname) || !strcmp(reg->nickname, nickname))) { + if (!zstr(reg->uuid) && !strcmp(reg->uuid, rsession->uuid) && (zstr(nickname) || !strcmp(reg->nickname, nickname))) { switch_event_t *event; if (prev) { prev->next = reg->next; @@ -1495,6 +1538,20 @@ done: return SWITCH_STATUS_SUCCESS; } +static const char *state2name(int state) +{ + switch(state) { + case RS_HANDSHAKE: + return "HANDSHAKE"; + case RS_HANDSHAKE2: + return "HANDSHAKE2"; + case RS_ESTABLISHED: + return "ESTABLISHED"; + default: + return "DESTROY (PENDING)"; + } +} + #define RTMP_FUNCTION_SYNTAX "profile [profilename] [start | stop | rescan | restart]\nstatus profile [profilename]\nstatus profile [profilename] [reg | sessions]\nsession [session_id] [kill | login [user@domain] | logout [user@domain]]" SWITCH_STANDARD_API(rtmp_function) { @@ -1571,7 +1628,7 @@ SWITCH_STANDARD_API(rtmp_function) { switch_hash_index_t *hi; stream->write_function(stream, "\nSessions:\n"); - stream->write_function(stream, "uuid,address,user,domain,flashVer\n"); + stream->write_function(stream, "uuid,address,user,domain,flashVer,state\n"); switch_thread_rwlock_rdlock(profile->session_rwlock); for (hi = switch_hash_first(NULL, profile->session_hash); hi; hi = switch_hash_next(hi)) { void *val; @@ -1581,11 +1638,11 @@ SWITCH_STANDARD_API(rtmp_function) switch_hash_this(hi, &key, &keylen, &val); item = (rtmp_session_t *)val; - stream->write_function(stream, "%s,%s:%d,%s,%s,%s\n", - item->uuid, item->remote_address, item->remote_port, - item->account ? item->account->user : NULL, - item->account ? item->account->domain : NULL, - item->flashVer); + stream->write_function(stream, "%s,%s:%d,%s,%s,%s,%s\n", + item->uuid, item->remote_address, item->remote_port, + item->account ? item->account->user : NULL, + item->account ? item->account->domain : NULL, + item->flashVer, state2name(item->state)); } switch_thread_rwlock_unlock(profile->session_rwlock); @@ -1862,6 +1919,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rtmp_load) switch_xml_free(xml); } } + + rtmp_globals.running = 1; return SWITCH_STATUS_SUCCESS; } @@ -1892,9 +1951,22 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_rtmp_shutdown) switch_core_hash_destroy(&rtmp_globals.session_hash); switch_core_hash_destroy(&rtmp_globals.invoke_hash); + rtmp_globals.running = 0; + return SWITCH_STATUS_SUCCESS; } +SWITCH_MODULE_RUNTIME_FUNCTION(mod_rtmp_runtime) +{ + + while(rtmp_globals.running) { + rtmp_garbage_colletor(); + switch_yield(10000000); + } + + return SWITCH_STATUS_TERM; +} + /* For Emacs: * Local Variables: * mode:c diff --git a/src/mod/endpoints/mod_rtmp/mod_rtmp.h b/src/mod/endpoints/mod_rtmp/mod_rtmp.h index 8a92c5b427..95eb17f017 100644 --- a/src/mod/endpoints/mod_rtmp/mod_rtmp.h +++ b/src/mod/endpoints/mod_rtmp/mod_rtmp.h @@ -336,6 +336,7 @@ struct mod_rtmp_globals { switch_hash_t *session_hash; switch_thread_rwlock_t *session_rwlock; switch_hash_t *invoke_hash; + int running; }; extern struct mod_rtmp_globals rtmp_globals; @@ -605,6 +606,7 @@ void rtmp_profile_release(rtmp_profile_t *profile); switch_status_t rtmp_tcp_init(rtmp_profile_t *profile, const char *bindaddr, rtmp_io_t **new_io, switch_memory_pool_t *pool); switch_status_t rtmp_session_request(rtmp_profile_t *profile, rtmp_session_t **newsession); switch_status_t rtmp_session_destroy(rtmp_session_t **session); +switch_status_t rtmp_real_session_destroy(rtmp_session_t **session); /**** Protocol ****/ void rtmp_set_chunksize(rtmp_session_t *rsession, uint32_t chunksize); diff --git a/src/switch_console.c b/src/switch_console.c index 63fe575856..d43f7702e1 100644 --- a/src/switch_console.c +++ b/src/switch_console.c @@ -1921,6 +1921,11 @@ SWITCH_DECLARE(switch_status_t) switch_console_set_alias(const char *string) switch_cache_db_handle_t *db = NULL; char *sql = NULL; + if (!strcmp(argv[1], argv[2])) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Alias and command cannot be the same, this will cause loop!\n"); + return SWITCH_STATUS_FALSE; + } + if (switch_core_db_handle(&db) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database Error\n"); free(mydata); diff --git a/src/switch_core.c b/src/switch_core.c index 8cefdd2e63..848fbf2150 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1934,7 +1934,19 @@ static void switch_load_core_config(const char *file) } else if (!strcasecmp(var, "enable-monotonic-timing")) { switch_time_set_monotonic(switch_true(val)); } else if (!strcasecmp(var, "enable-softtimer-timerfd")) { - switch_time_set_timerfd(switch_true(val)); + int ival = 0; + if (val) { + if (switch_true(val)) { + ival = 2; + } else { + if (strcasecmp(val, "broadcast")) { + ival = 1; + } else if (strcasecmp(val, "fd-per-timer")) { + ival = 2; + } + } + } + switch_time_set_timerfd(ival); } else if (!strcasecmp(var, "enable-clock-nanosleep")) { switch_time_set_nanosleep(switch_true(val)); } else if (!strcasecmp(var, "enable-cond-yield")) { diff --git a/src/switch_core_media.c b/src/switch_core_media.c index a7feca7e4a..426334466a 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -167,6 +167,7 @@ struct switch_media_handle_s { const switch_codec_implementation_t *negotiated_codecs[SWITCH_MAX_CODECS]; int num_negotiated_codecs; switch_payload_t ianacodes[SWITCH_MAX_CODECS]; + char *fmtps[SWITCH_MAX_CODECS]; int video_count; uint32_t owner_id; @@ -464,13 +465,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core switch_media_type_t type, const char *iananame, switch_payload_t *ptP, - switch_payload_t *recv_ptP) + switch_payload_t *recv_ptP, + char **fmtpP) { payload_map_t *pmap; switch_media_handle_t *smh; switch_rtp_engine_t *engine; switch_payload_t pt = 0, recv_pt = 0; int found = 0; + char *fmtp = NULL; switch_assert(session); @@ -488,6 +491,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core if (!strcasecmp(pmap->iananame, iananame)) { pt = pmap->pt; recv_pt = pmap->recv_pt; + fmtp = pmap->rm_fmtp; found++; } } @@ -500,6 +504,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core if (recv_ptP) { *recv_ptP = recv_pt; } + + if (!zstr(fmtp) && fmtpP) { + *fmtpP = fmtp; + } + return SWITCH_STATUS_SUCCESS; } @@ -511,6 +520,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_session_t *session, switch_media_type_t type, const char *name, + const char *fmtp, switch_sdp_type_t sdp_type, uint32_t pt, uint32_t rate, @@ -567,6 +577,10 @@ SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_se pmap->rate = rate; } + if (!zstr(fmtp) && (!pmap->rm_fmtp || strcmp(pmap->rm_fmtp, fmtp))) { + pmap->rm_fmtp = switch_core_strdup(session->pool, fmtp); + } + pmap->allocated = 1; pmap->recv_pt = (switch_payload_t)pt; @@ -3033,43 +3047,6 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s } x = 0; - - if (a_engine->cur_payload_map->rm_encoding && !(switch_media_handle_test_media_flag(smh, SCMF_LIBERAL_DTMF) || - switch_channel_test_flag(session->channel, CF_LIBERAL_DTMF))) { // && !switch_channel_test_flag(session->channel, CF_REINVITE)) { - char *remote_host = a_engine->cur_payload_map->remote_sdp_ip; - switch_port_t remote_port = a_engine->cur_payload_map->remote_sdp_port; - int same = 0; - - if (switch_rtp_ready(a_engine->rtp_session)) { - remote_host = switch_rtp_get_remote_host(a_engine->rtp_session); - remote_port = switch_rtp_get_remote_port(a_engine->rtp_session); - } - - for (map = m->m_rtpmaps; map; map = map->rm_next) { - if ((zstr(map->rm_encoding) || (smh->mparams->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { - match = (map->rm_pt == a_engine->cur_payload_map->pt) ? 1 : 0; - } else { - match = strcasecmp(switch_str_nil(map->rm_encoding), a_engine->cur_payload_map->iananame) ? 0 : 1; - } - - if (match && connection->c_address && remote_host && !strcmp(connection->c_address, remote_host) && m->m_port == remote_port) { - same = 1; - } else { - same = 0; - break; - } - } - - if (same) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, - "Our existing sdp is still good [%s %s:%d], let's keep it.\n", - a_engine->cur_payload_map->rm_encoding, a_engine->cur_payload_map->remote_sdp_ip, a_engine->cur_payload_map->remote_sdp_port); - got_audio = 1; - } else { - match = 0; - got_audio = 0; - } - } for (map = m->m_rtpmaps; map; map = map->rm_next) { int32_t i; @@ -3285,7 +3262,8 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s for(j = 0; j < m_idx; j++) { payload_map_t *pmap = switch_core_media_add_payload_map(session, SWITCH_MEDIA_TYPE_AUDIO, - matches[j].map->rm_encoding, + matches[j].map->rm_encoding, + matches[j].map->rm_fmtp, sdp_type, matches[j].map->rm_pt, matches[j].imp->samples_per_second, @@ -3534,6 +3512,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s payload_map_t *pmap = switch_core_media_add_payload_map(session, SWITCH_MEDIA_TYPE_VIDEO, matches[j].map->rm_encoding, + matches[j].map->rm_fmtp, sdp_type, matches[j].map->rm_pt, matches[j].imp->samples_per_second, @@ -5421,6 +5400,10 @@ static void generate_m(switch_core_session_t *session, char *buf, size_t buflen, } } + if (smh->fmtps[i]) { + fmtp = smh->fmtps[i]; + } + if (smh->ianacodes[i] > 95 || switch_channel_test_flag(session->channel, CF_VERBOSE_SDP)) { int channels = get_channels(imp->iananame, imp->number_of_channels); @@ -5695,7 +5678,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess const char *fmtp_out; const char *fmtp_out_var = switch_channel_get_variable(session->channel, "rtp_force_audio_fmtp"); switch_event_t *map = NULL, *ptmap = NULL; - const char *b_sdp = NULL; + //const char *b_sdp = NULL; const char *local_audio_crypto_key = switch_core_session_local_crypto_key(session, SWITCH_MEDIA_TYPE_AUDIO); const char *local_sdp_audio_zrtp_hash = switch_core_media_get_zrtp_hash(session, SWITCH_MEDIA_TYPE_AUDIO, SWITCH_TRUE); const char *local_sdp_video_zrtp_hash = switch_core_media_get_zrtp_hash(session, SWITCH_MEDIA_TYPE_VIDEO, SWITCH_TRUE); @@ -5780,6 +5763,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess for (i = 0; i < smh->mparams->num_codecs; i++) { const switch_codec_implementation_t *imp = smh->codecs[i]; switch_payload_t orig_pt = 0; + char *orig_fmtp = NULL; smh->ianacodes[i] = imp->ianacode; @@ -5795,8 +5779,12 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess if (orig_session && switch_core_session_get_payload_code(orig_session, imp->codec_type == SWITCH_CODEC_TYPE_AUDIO ? SWITCH_MEDIA_TYPE_AUDIO : SWITCH_MEDIA_TYPE_VIDEO, - imp->iananame, &orig_pt, NULL) == SWITCH_STATUS_SUCCESS) { + imp->iananame, &orig_pt, NULL, &orig_fmtp) == SWITCH_STATUS_SUCCESS) { smh->ianacodes[i] = orig_pt; + + if (orig_fmtp) { + smh->fmtps[i] = switch_core_session_strdup(session, orig_fmtp); + } } else { smh->ianacodes[i] = (switch_payload_t)smh->payload_space++; } @@ -5806,6 +5794,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess switch_core_media_add_payload_map(session, imp->codec_type == SWITCH_CODEC_TYPE_AUDIO ? SWITCH_MEDIA_TYPE_AUDIO : SWITCH_MEDIA_TYPE_VIDEO, imp->iananame, + NULL, sdp_type, smh->ianacodes[i], imp->samples_per_second, @@ -5858,9 +5847,9 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess return; } - if (!a_engine->cur_payload_map->rm_encoding && (b_sdp = switch_channel_get_variable(session->channel, SWITCH_B_SDP_VARIABLE))) { - switch_core_media_sdp_map(b_sdp, &map, &ptmap); - } + //if (!a_engine->cur_payload_map->rm_encoding && (b_sdp = switch_channel_get_variable(session->channel, SWITCH_B_SDP_VARIABLE))) { + //switch_core_media_sdp_map(b_sdp, &map, &ptmap); + //} if (zstr(sr)) { if ((var_val = switch_channel_get_variable(session->channel, "media_audio_mode"))) { @@ -6322,9 +6311,10 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess if (ov_fmtp) { pass_fmtp = ov_fmtp; - }// else { // seems to break eyebeam at least... - //pass_fmtp = switch_channel_get_variable(session->channel, "rtp_video_fmtp"); - //} + } else if (switch_true(switch_channel_get_variable_dup(session->channel, "rtp_mirror_fmtp", SWITCH_FALSE, -1))) { + // seems to break eyebeam at least... + pass_fmtp = switch_channel_get_variable(session->channel, "rtp_video_fmtp"); + } } if (pass_fmtp) { @@ -7868,6 +7858,7 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess switch_core_media_add_payload_map(session, m->m_type == sdp_media_audio ? SWITCH_MEDIA_TYPE_AUDIO : SWITCH_MEDIA_TYPE_VIDEO, map->rm_encoding, + map->rm_fmtp, sdp_type, map->rm_pt, map->rm_rate, diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 63aab9d583..0056e2d155 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -37,6 +37,8 @@ #include "switch_core.h" #include "private/switch_core_pvt.h" +#define DEBUG_THREAD_POOL + struct switch_session_manager session_manager; SWITCH_DECLARE(void) switch_core_session_set_dmachine(switch_core_session_t *session, switch_ivr_dmachine_t *dmachine, switch_digit_action_target_t target) @@ -2984,6 +2986,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_refresh_video(switch_core_se return SWITCH_STATUS_FALSE; } +SWITCH_DECLARE(void) switch_core_session_debug_pool(switch_stream_handle_t *stream) +{ + stream->write_function(stream, "Thread pool: running:%d busy:%d popping:%d\n", + session_manager.running, session_manager.busy, session_manager.popping); +} /* For Emacs: * Local Variables: diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index 0b4d8b9ede..c53fc75a40 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -52,6 +52,7 @@ struct switch_cache_db_handle { char creator[CACHE_DB_LEN]; char last_user[CACHE_DB_LEN]; uint32_t use_count; + uint64_t total_used_count; struct switch_cache_db_handle *next; }; @@ -102,6 +103,7 @@ static void add_handle(switch_cache_db_handle_t *dbh, const char *db_str, const dbh->thread_hash = switch_ci_hashfunc_default(thread_str, &hlen); dbh->use_count++; + dbh->total_used_count++; sql_manager.total_used_handles++; dbh->next = sql_manager.handle_pool; @@ -149,7 +151,7 @@ static switch_cache_db_handle_t *get_handle(const char *db_str, const char *user r = dbh_ptr; } } - + if (!r) { for (dbh_ptr = sql_manager.handle_pool; dbh_ptr; dbh_ptr = dbh_ptr->next) { if (dbh_ptr->hash == hash && (dbh_ptr->type != SCDB_TYPE_PGSQL || !dbh_ptr->use_count) && !switch_test_flag(dbh_ptr, CDF_PRUNE) && @@ -162,6 +164,7 @@ static switch_cache_db_handle_t *get_handle(const char *db_str, const char *user if (r) { r->use_count++; + r->total_used_count++; sql_manager.total_used_handles++; r->hash = switch_ci_hashfunc_default(db_str, &hlen); r->thread_hash = thread_hash; @@ -3510,11 +3513,12 @@ SWITCH_DECLARE(void) switch_cache_db_status(switch_stream_handle_t *stream) used++; } - stream->write_function(stream, "%s\n\tType: %s\n\tLast used: %d\n\tFlags: %s, %s(%d)\n" + stream->write_function(stream, "%s\n\tType: %s\n\tLast used: %d\n\tTotal used: %ld\n\tFlags: %s, %s(%d)\n" "\tCreator: %s\n\tLast User: %s\n", cleankey_str, switch_cache_db_type_name(dbh->type), diff, + dbh->total_used_count, locked ? "Locked" : "Unlocked", dbh->use_count ? "Attached" : "Detached", dbh->use_count, dbh->creator, dbh->last_user); } diff --git a/src/switch_pgsql.c b/src/switch_pgsql.c index 9917ea2653..20fe886193 100644 --- a/src/switch_pgsql.c +++ b/src/switch_pgsql.c @@ -461,7 +461,7 @@ SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_finish_results_real(const cha int done = 0; do { switch_pgsql_next_result(handle, &res); - if (res && res->err) { + if (res && res->err && !switch_stristr("already exists", res->err) && !switch_stristr("duplicate key name", res->err)) { switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Error executing query:\n%s\n", res->err); final_status = SWITCH_PGSQL_FAIL; } diff --git a/src/switch_time.c b/src/switch_time.c index 2a67a56b5e..c4b6b8b445 100644 --- a/src/switch_time.c +++ b/src/switch_time.c @@ -77,7 +77,7 @@ static int SYSTEM_TIME = 0; timerfd seems to work well as long as it exists so if you have timerfd we'll also enable clock_nanosleep by default. */ #if defined(HAVE_TIMERFD_CREATE) -static int TFD = 1; +static int TFD = 2; #if defined(HAVE_CLOCK_NANOSLEEP) static int NANO = 1; #else @@ -351,10 +351,10 @@ SWITCH_DECLARE(void) switch_time_set_use_system_time(switch_bool_t enable) } -SWITCH_DECLARE(void) switch_time_set_timerfd(switch_bool_t enable) +SWITCH_DECLARE(void) switch_time_set_timerfd(int enable) { #if defined(HAVE_TIMERFD_CREATE) - TFD = enable ? 1 : 0; + TFD = enable; switch_time_sync(); #else @@ -385,6 +385,133 @@ SWITCH_DECLARE(void) switch_time_set_cond_yield(switch_bool_t enable) switch_time_sync(); } +///////// +#ifdef HAVE_TIMERFD_CREATE + +#define MAX_INTERVAL 2000 /* ms */ + +struct interval_timer { + int fd; + switch_size_t tick; +}; +typedef struct interval_timer interval_timer_t; + +static switch_status_t timerfd_start_interval(interval_timer_t *it, int interval) +{ + struct itimerspec val; + int fd; + + it->tick = 0; + + fd = timerfd_create(CLOCK_MONOTONIC, 0); + + if (fd < 0) { + return SWITCH_STATUS_GENERR; + } + + val.it_interval.tv_sec = interval / 1000; + val.it_interval.tv_nsec = (interval % 1000) * 1000000; + val.it_value.tv_sec = 0; + val.it_value.tv_nsec = 100000; + + if (timerfd_settime(fd, 0, &val, NULL) < 0) { + close(fd); + return SWITCH_STATUS_GENERR; + } + + it->fd = fd; + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t timerfd_stop_interval(interval_timer_t *it) +{ + close(it->fd); + it->fd = -1; + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t _timerfd_init(switch_timer_t *timer) +{ + interval_timer_t *it; + int rc; + + if (timer->interval < 1 || timer->interval > MAX_INTERVAL) + return SWITCH_STATUS_GENERR; + + it = switch_core_alloc(timer->memory_pool, sizeof(*it)); + if ((rc = timerfd_start_interval(it, timer->interval)) == SWITCH_STATUS_SUCCESS) { + timer->private_info = it; + } + + return rc; +} + +static switch_status_t _timerfd_step(switch_timer_t *timer) +{ + timer->tick++; + timer->samplecount += timer->samples; + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t _timerfd_next(switch_timer_t *timer) +{ + interval_timer_t *it = timer->private_info; + uint64_t x, u64 = 0; + + if (read(it->fd, &u64, sizeof(u64)) < 0) { + return SWITCH_STATUS_GENERR; + } else { + for (x = 0; x < u64; x++) { + it->tick++; + _timerfd_step(timer); + } + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t _timerfd_sync(switch_timer_t *timer) +{ + interval_timer_t *it = timer->private_info; + + timer->tick = it->tick; + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t _timerfd_check(switch_timer_t *timer, switch_bool_t step) +{ + interval_timer_t *it = timer->private_info; + int diff = (int)(timer->tick - it->tick); + + if (diff > 0) { + /* still pending */ + timer->diff = diff; + return SWITCH_STATUS_FALSE; + } else { + /* timer pending */ + timer->diff = 0; + if (step) { + _timerfd_step(timer); + } + return SWITCH_STATUS_SUCCESS; + } +} + +static switch_status_t _timerfd_destroy(switch_timer_t *timer) +{ + interval_timer_t *it = timer->private_info; + int rc; + + rc = timerfd_stop_interval(it); + return rc; +} + +#endif +//////// + + static switch_time_t time_now(int64_t offset) { switch_time_t now; @@ -549,6 +676,12 @@ static switch_status_t timer_init(switch_timer_t *timer) timer_private_t *private_info; int sanity = 0; +#ifdef HAVE_TIMERFD_CREATE + if (TFD == 2) { + return _timerfd_init(timer); + } +#endif + while (globals.STARTED == 0) { do_sleep(100000); if (++sanity == 300) { @@ -607,9 +740,17 @@ static switch_status_t timer_init(switch_timer_t *timer) static switch_status_t timer_step(switch_timer_t *timer) { - timer_private_t *private_info = timer->private_info; + timer_private_t *private_info; uint64_t samples; +#ifdef HAVE_TIMERFD_CREATE + if (TFD == 2) { + return _timerfd_step(timer); + } +#endif + + private_info = timer->private_info; + if (globals.RUNNING != 1 || private_info->ready == 0) { return SWITCH_STATUS_FALSE; } @@ -630,7 +771,15 @@ static switch_status_t timer_step(switch_timer_t *timer) static switch_status_t timer_sync(switch_timer_t *timer) { - timer_private_t *private_info = timer->private_info; + timer_private_t *private_info; + +#ifdef HAVE_TIMERFD_CREATE + if (TFD == 2) { + return _timerfd_sync(timer); + } +#endif + + private_info = timer->private_info; if (globals.RUNNING != 1 || private_info->ready == 0) { return SWITCH_STATUS_FALSE; @@ -648,14 +797,26 @@ static switch_status_t timer_sync(switch_timer_t *timer) static switch_status_t timer_next(switch_timer_t *timer) { - timer_private_t *private_info = timer->private_info; + timer_private_t *private_info; #ifdef DISABLE_1MS_COND int cond_index = timer->interval; #else int cond_index = 1; #endif - int delta = (int) (private_info->reference - TIMER_MATRIX[timer->interval].tick); + int delta; + +#ifdef HAVE_TIMERFD_CREATE + if (TFD == 2) { + return _timerfd_next(timer); + } +#endif + + private_info = timer->private_info; + + delta = (int) (private_info->reference - TIMER_MATRIX[timer->interval].tick); + + /* sync up timer if it's not been called for a while otherwise it will return instantly several times until it catches up */ if (delta < -1) { @@ -695,9 +856,17 @@ static switch_status_t timer_next(switch_timer_t *timer) static switch_status_t timer_check(switch_timer_t *timer, switch_bool_t step) { - timer_private_t *private_info = timer->private_info; + timer_private_t *private_info; switch_status_t status = SWITCH_STATUS_SUCCESS; +#ifdef HAVE_TIMERFD_CREATE + if (TFD == 2) { + return _timerfd_check(timer, step); + } +#endif + + private_info = timer->private_info; + if (globals.RUNNING != 1 || !private_info->ready) { return SWITCH_STATUS_SUCCESS; } @@ -724,7 +893,16 @@ static switch_status_t timer_check(switch_timer_t *timer, switch_bool_t step) static switch_status_t timer_destroy(switch_timer_t *timer) { - timer_private_t *private_info = timer->private_info; + timer_private_t *private_info; + +#ifdef HAVE_TIMERFD_CREATE + if (TFD == 2) { + return _timerfd_destroy(timer); + } +#endif + + private_info = timer->private_info; + if (timer->interval < MAX_ELEMENTS) { switch_mutex_lock(globals.mutex); TIMER_MATRIX[timer->interval].count--;