diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 63d4cd9644..3ac9bd0a36 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -719,14 +719,14 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch name = switch_channel_get_name(channel); if (!tech_pvt->ftdmchan) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "no ftdmchan set in channel %s!\n", name); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "no ftdmchan set in channel %s!\n", name); return SWITCH_STATUS_FALSE; } span_id = ftdm_channel_get_span_id(tech_pvt->ftdmchan); chan_id = ftdm_channel_get_id(tech_pvt->ftdmchan); if (switch_test_flag(tech_pvt, TFLAG_DEAD)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TFLAG_DEAD is set in channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "TFLAG_DEAD is set in channel %s device %d:%d!\n", name, span_id, chan_id); return SWITCH_STATUS_FALSE; } @@ -760,7 +760,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch } if (!switch_test_flag(tech_pvt, TFLAG_IO)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TFLAG_IO is not set in channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "TFLAG_IO is not set in channel %s device %d:%d!\n", name, span_id, chan_id); goto fail; } @@ -768,7 +768,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch status = ftdm_channel_wait(tech_pvt->ftdmchan, &wflags, chunk); if (status == FTDM_FAIL) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id); goto fail; } @@ -776,7 +776,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch if (!switch_test_flag(tech_pvt, TFLAG_HOLD)) { total_to -= chunk; if (total_to <= 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many timeouts while waiting I/O in channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_WARNING, "Too many timeouts while waiting I/O in channel %s device %d:%d!\n", name, span_id, chan_id); goto fail; } } @@ -789,9 +789,9 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch len = tech_pvt->read_frame.buflen; if (ftdm_channel_read(tech_pvt->ftdmchan, tech_pvt->read_frame.data, &len) != FTDM_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_WARNING, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id); if (++tech_pvt->read_error > FTDM_MAX_READ_WRITE_ERRORS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "too many I/O read errors on channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "too many I/O read errors on channel %s device %d:%d!\n", name, span_id, chan_id); goto fail; } } else { @@ -812,7 +812,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch for (p = dtmf; p && *p; p++) { if (is_dtmf(*p)) { _dtmf.digit = *p; - ftdm_log(FTDM_LOG_DEBUG, "Queuing DTMF [%c] in channel %s device %d:%d\n", *p, name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Queuing DTMF [%c] in channel %s device %d:%d\n", *p, name, span_id, chan_id); switch_channel_queue_dtmf(channel, &_dtmf); } } @@ -821,7 +821,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch return SWITCH_STATUS_SUCCESS; fail: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "clearing IO in channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "clearing IO in channel %s device %d:%d!\n", name, span_id, chan_id); switch_clear_flag_locked(tech_pvt, TFLAG_IO); return SWITCH_STATUS_GENERR; } @@ -844,7 +844,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc name = switch_channel_get_name(channel); if (!tech_pvt->ftdmchan) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "no ftdmchan set in channel %s!\n", name); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "no ftdmchan set in channel %s!\n", name); return SWITCH_STATUS_FALSE; } @@ -852,7 +852,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc chan_id = ftdm_channel_get_id(tech_pvt->ftdmchan); if (switch_test_flag(tech_pvt, TFLAG_DEAD)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TFLAG_DEAD is set in channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "TFLAG_DEAD is set in channel %s device %d:%d!\n", name, span_id, chan_id); return SWITCH_STATUS_FALSE; } @@ -861,7 +861,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc } if (!switch_test_flag(tech_pvt, TFLAG_IO)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TFLAG_IO is not set in channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "TFLAG_IO is not set in channel %s device %d:%d!\n", name, span_id, chan_id); goto fail; } @@ -879,15 +879,15 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc ftdm_channel_wait(tech_pvt->ftdmchan, &wflags, ftdm_channel_get_io_interval(tech_pvt->ftdmchan) * 10); if (!(wflags & FTDM_WRITE)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write not ready) in channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Dropping frame! (write not ready) in channel %s device %d:%d!\n", name, span_id, chan_id); return SWITCH_STATUS_SUCCESS; } len = frame->datalen; if (ftdm_channel_write(tech_pvt->ftdmchan, frame->data, frame->buflen, &len) != FTDM_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Failed to write to channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Failed to write to channel %s device %d:%d!\n", name, span_id, chan_id); if (++tech_pvt->write_error > FTDM_MAX_READ_WRITE_ERRORS) { - switch_log_printf(SWITCH_CHANNEL_LOG, + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Too many I/O write errors on channel %s device %d:%d!\n", name, span_id, chan_id); goto fail; } @@ -898,7 +898,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc return SWITCH_STATUS_SUCCESS; fail: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error writing to channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Error writing to channel %s device %d:%d!\n", name, span_id, chan_id); switch_clear_flag_locked(tech_pvt, TFLAG_IO); return SWITCH_STATUS_GENERR; @@ -1239,7 +1239,7 @@ static ftdm_status_t on_channel_found(ftdm_channel_t *fchan, ftdm_caller_data_t tech_init(hdata->tech_pvt, hdata->new_session, fchan, caller_data); snprintf(name, sizeof(name), "FreeTDM/%u:%u/%s", span_id, chan_id, caller_data->dnis.digits); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name); switch_channel_set_name(channel, name); switch_channel_set_variable(channel, "freetdm_span_name", ftdm_channel_get_span_name(fchan)); switch_channel_set_variable_printf(channel, "freetdm_span_number", "%d", span_id); @@ -1267,7 +1267,7 @@ static ftdm_status_t on_channel_found(ftdm_channel_t *fchan, ftdm_caller_data_t return FTDM_BREAK; } } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Attached session %s to channel %d:%d\n", sess_uuid, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Attached session %s to channel %d:%d\n", sess_uuid, span_id, chan_id); return FTDM_SUCCESS; } @@ -2294,7 +2294,6 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal) } } break; - case FTDM_SIGEVENT_SIGSTATUS_CHANGED: case FTDM_SIGEVENT_COLLECTED_DIGIT: /* Analog E&M */ { int span_id = ftdm_channel_get_span_id(sigmsg->channel); @@ -2336,6 +2335,9 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal) } } break; + case FTDM_SIGEVENT_SIGSTATUS_CHANGED: + /* span signaling status changed ... nothing to do here .. */ + break; default: { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n", diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c index c387d5a528..8cf43bbdfd 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c +++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c @@ -44,6 +44,8 @@ struct tm * localtime_r(const time_t *clock, struct tm *result); #endif +static FIO_SPAN_SET_SIG_STATUS_FUNCTION(analog_em_set_span_sig_status); + /* check if the given file is a wave file and skip the header if it is */ #define WAVE_CHUNK_ID "RIFF" #define WAVE_FMT "WAVEfmt " @@ -196,6 +198,23 @@ static ftdm_status_t ftdm_analog_em_start(ftdm_span_t *span) return ftdm_thread_create_detached(ftdm_analog_em_run, span); } +static void ftdm_analog_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status) +{ + ftdm_sigmsg_t sig; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Signalling link status changed to %s\n", ftdm_signaling_status2str(status)); + + memset(&sig, 0, sizeof(sig)); + sig.chan_id = ftdmchan->chan_id; + sig.span_id = ftdmchan->span_id; + sig.channel = ftdmchan; + sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sig.ev_data.sigstatus.status = status; + if (ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS) { + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to change channel status to %s\n", ftdm_signaling_status2str(status)); + } + return; +} + /** * \brief Stops EM span thread (monitor) * \param span Span to monitor @@ -206,6 +225,7 @@ static ftdm_status_t ftdm_analog_em_stop(ftdm_span_t *span) ftdm_analog_em_data_t *analog_data = span->signal_data; ftdm_clear_flag(analog_data, FTDM_ANALOG_EM_RUNNING); ftdm_sleep(100); + analog_em_set_span_sig_status(span, FTDM_SIG_STATE_SUSPENDED); return FTDM_SUCCESS; } @@ -215,10 +235,16 @@ static ftdm_status_t ftdm_analog_em_stop(ftdm_span_t *span) * \param status Pointer to set signalling status * \return Success or failure */ - static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_em_get_channel_sig_status) { - ftdm_unused_arg(ftdmchan); + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) { + *status = FTDM_SIG_STATE_DOWN; + return FTDM_SUCCESS; + } + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) { + *status = FTDM_SIG_STATE_SUSPENDED; + return FTDM_SUCCESS; + } *status = FTDM_SIG_STATE_UP; return FTDM_SUCCESS; } @@ -229,11 +255,82 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_em_get_channel_sig_status) * \param status Pointer to set signalling status * \return Success or failure */ - static FIO_SPAN_GET_SIG_STATUS_FUNCTION(analog_em_get_span_sig_status) { - ftdm_unused_arg(span); - *status = FTDM_SIG_STATE_UP; + ftdm_iterator_t *citer = NULL; + ftdm_iterator_t *chaniter = ftdm_span_get_chan_iterator(span, NULL); + if (!chaniter) { + ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name); + return FTDM_FAIL; + } + /* if ALL channels are in alarm, report DOWN, UP otherwise. */ + *status = FTDM_SIG_STATE_DOWN; + for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) { + ftdm_channel_t *fchan = ftdm_iterator_current(citer); + ftdm_channel_lock(fchan); + if (!ftdm_test_flag(fchan, FTDM_CHANNEL_IN_ALARM)) { + if (!ftdm_test_flag(fchan, FTDM_CHANNEL_SUSPENDED)) { + *status = FTDM_SIG_STATE_UP; + ftdm_channel_unlock(fchan); + break; + } else { + *status = FTDM_SIG_STATE_SUSPENDED; + } + } + ftdm_channel_unlock(fchan); + } + ftdm_iterator_free(chaniter); + return FTDM_SUCCESS; +} + +static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status) +{ + switch (status) { + case FTDM_SIG_STATE_DOWN: + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot bring channel down, perhaps you want to try '%s'\n", ftdm_signaling_status2str(FTDM_SIG_STATE_SUSPENDED)); + return FTDM_FAIL; + case FTDM_SIG_STATE_SUSPENDED: + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) { + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED); + ftdm_analog_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_SUSPENDED); + } + break; + case FTDM_SIG_STATE_UP: + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) { + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED); + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) { + ftdm_analog_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP); + } + } + break; + default: + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status); + return FTDM_FAIL; + } + return FTDM_SUCCESS; +} + +static FIO_SPAN_SET_SIG_STATUS_FUNCTION(analog_em_set_span_sig_status) +{ + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *citer = NULL; + + chaniter = ftdm_span_get_chan_iterator(span, NULL); + if (!chaniter) { + ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name); + return FTDM_FAIL; + } + /* iterate over all channels, setting them to the requested state */ + for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) { + ftdm_channel_t *fchan = ftdm_iterator_current(citer); + /* we set channel's state through analog_em_set_channel_sig_status(), since it already takes care of notifying the user when appropriate */ + ftdm_channel_lock(fchan); + if ((analog_em_set_channel_sig_status(fchan, status)) != FTDM_SUCCESS) { + ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to set signaling status to %s\n", ftdm_signaling_status2str(status)); + } + ftdm_channel_unlock(fchan); + } + ftdm_iterator_free(chaniter); return FTDM_SUCCESS; } @@ -334,6 +431,8 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span) span->outgoing_call = analog_em_outgoing_call; span->get_channel_sig_status = analog_em_get_channel_sig_status; span->get_span_sig_status = analog_em_get_span_sig_status; + span->set_channel_sig_status = analog_em_set_channel_sig_status; + span->set_span_sig_status = analog_em_set_span_sig_status; ftdm_span_load_tones(span, tonemap); if (immediate_ringback || !ftdm_strlen_zero(ringback_file)) { analog_data->immediate_ringback = FTDM_TRUE; @@ -384,7 +483,9 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) ftdm_sigmsg_t sig; int cas_bits = 0; uint32_t cas_answer = 0; + uint32_t cas_hangup = 0; int cas_answer_ms = 500; + int cas_hangup_ms = 500; FILE *ringback_f = NULL; ftdm_bool_t digits_sent = FTDM_FALSE; @@ -542,6 +643,23 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) case FTDM_CHANNEL_STATE_RING: { ftdm_sleep(interval); + if (ftdmchan->state == FTDM_CHANNEL_STATE_UP && cas_answer) { + cas_bits = 0; + ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_CAS_BITS, &cas_bits); + if (!(state_counter % 5000)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "CAS bits: 0x%X\n", cas_bits); + } + if (cas_bits == 0x0) { + cas_hangup += interval; + if (cas_hangup >= cas_hangup_ms) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Hanging up on CAS hangup signal persistence\n"); + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); + } + } else if (cas_hangup) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Resetting cas hangup to 0: 0x%X!\n", cas_bits); + cas_hangup = 0; + } + } continue; } break; @@ -859,6 +977,12 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e ftdm_mutex_lock(event->channel->mutex); locked++; + if (ftdm_test_flag(event->channel, FTDM_CHANNEL_SUSPENDED)) { + ftdm_log(FTDM_LOG_WARNING, "Ignoring event %s on channel %d:%d in state %s, channel is suspended\n", + ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state)); + goto done; + } + switch(event->enum_id) { case FTDM_OOB_ONHOOK: { @@ -893,6 +1017,9 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e } break; } + +done: + if (locked) { ftdm_mutex_unlock(event->channel->mutex); } @@ -911,6 +1038,7 @@ static void *ftdm_analog_em_run(ftdm_thread_t *me, void *obj) ftdm_unused_arg(me); ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM thread starting.\n"); + analog_em_set_span_sig_status(span, FTDM_SIG_STATE_UP); while(ftdm_running() && ftdm_test_flag(analog_data, FTDM_ANALOG_EM_RUNNING)) { int waitms = 10; diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index 5dc89e0a24..bd0253e8c0 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Tue Oct 22 16:25:25 CDT 2013 +Fri Oct 25 23:51:29 CDT 2013 diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport.c index aa257f79f8..62193e9135 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport.c @@ -2094,6 +2094,10 @@ void tport_close(tport_t *self) SU_DEBUG_5(("%s(%p): " TPN_FORMAT "\n", __func__, (void *)self, TPN_ARGS(self->tp_name))); + if (self->tp_refs == -1) { + self->tp_refs = 0; + } + if (self->tp_closed || !tport_is_secondary(self)) return; diff --git a/libs/spandsp/configure.ac b/libs/spandsp/configure.ac index de395ec4cc..423513100c 100644 --- a/libs/spandsp/configure.ac +++ b/libs/spandsp/configure.ac @@ -324,9 +324,11 @@ AX_CHECK_EXPORT_CAPABILITY([$host], saved_CFLAGS="$CFLAGS" AC_CACHE_CHECK([whether compiler supports -Wunused-but-set-variable], [ac_cv_gcc_unused_but_set_variable], [ -CFLAGS="$CFLAGS -Wunused-but-set-variable" -AC_TRY_COMPILE([],[return 0;],[ac_cv_gcc_unused_but_set_variable=yes],[ac_cv_gcc_unused_but_set_variable=no]) -]) + # We need to add -Werror here or clang doesn't fail (it just warns), even though it doesn't understand the + # -Wunused-but-set-variable tag + CFLAGS="$CFLAGS -Werror -Wunused-but-set-variable" + AC_TRY_COMPILE([],[return 0;],[ac_cv_gcc_unused_but_set_variable=yes],[ac_cv_gcc_unused_but_set_variable=no]) + ]) AC_MSG_RESULT($ac_cv_gcc_unused_but_set_variable) CFLAGS="$saved_CFLAGS" diff --git a/libs/spandsp/src/vector_int.c b/libs/spandsp/src/vector_int.c index 66166e52eb..c2ed12f98e 100644 --- a/libs/spandsp/src/vector_int.c +++ b/libs/spandsp/src/vector_int.c @@ -147,7 +147,7 @@ SPAN_DECLARE(int32_t) vec_dot_prodi16(const int16_t x[], const int16_t y[], int " emms;\n" : "=a" (z) : "S" (x), "D" (y), "a" (n) - : "cc" + : "cc", "rdx", "mm0", "mm1", "mm2" ); #elif defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__i386__) __asm__ __volatile__( @@ -245,7 +245,7 @@ SPAN_DECLARE(int32_t) vec_dot_prodi16(const int16_t x[], const int16_t y[], int " emms;\n" : "=a" (z) : "S" (x), "D" (y), "a" (n) - : "cc" + : "cc", "edx", "mm0", "mm1", "mm2" ); #else int i; @@ -436,7 +436,7 @@ SPAN_DECLARE(int32_t) vec_min_maxi16(const int16_t x[], int n, int16_t out[]) " emms;\n" : "=a" (max) : "S" (x), "a" (n), "d" (out), [lower] "m" (lower_bound), [upper] "m" (upper_bound) - : "ecx" + : "ecx", "mm0", "mm1", "mm2", "mm3", "mm4" ); #elif defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__i386__) static const int32_t lower_bound = 0x80008000; @@ -589,7 +589,7 @@ SPAN_DECLARE(int32_t) vec_min_maxi16(const int16_t x[], int n, int16_t out[]) " emms;\n" : "=a" (max) : "S" (x), "a" (n), "d" (out), [lower] "m" (lower_bound), [upper] "m" (upper_bound) - : "ecx" + : "ecx", "mm0", "mm1", "mm2", "mm3", "mm4" ); #else int i; diff --git a/src/include/switch_caller.h b/src/include/switch_caller.h index f0dc1c76fe..1fd5ecbd29 100644 --- a/src/include/switch_caller.h +++ b/src/include/switch_caller.h @@ -127,6 +127,7 @@ typedef struct profile_node_s { switch_memory_pool_t *pool; struct switch_caller_profile *next; switch_call_direction_t direction; + switch_call_direction_t logical_direction; profile_node_t *soft; char *uuid_str; char *clone_of; diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 234b692114..9e7c91f935 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -633,6 +633,7 @@ SWITCH_DECLARE(int) switch_channel_test_app_flag_key(const char *app, switch_cha SWITCH_DECLARE(void) switch_channel_set_bridge_time(switch_channel_t *channel); SWITCH_DECLARE(void) switch_channel_set_hangup_time(switch_channel_t *channel); SWITCH_DECLARE(switch_call_direction_t) switch_channel_direction(switch_channel_t *channel); +SWITCH_DECLARE(switch_call_direction_t) switch_channel_logical_direction(switch_channel_t *channel); SWITCH_DECLARE(void) switch_channel_set_direction(switch_channel_t *channel, switch_call_direction_t direction); SWITCH_DECLARE(switch_core_session_t *) switch_channel_get_session(switch_channel_t *channel); diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 11340c211c..43c872b5cf 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -82,18 +82,34 @@ typedef struct device_uuid_node_s { switch_channel_callstate_t callstate; switch_hold_record_t *hold_record; switch_caller_profile_t *hup_profile; + switch_call_direction_t direction; struct switch_device_record_s *parent; struct device_uuid_node_s *next; } switch_device_node_t; typedef struct switch_device_stats_s { uint32_t total; + uint32_t total_in; + uint32_t total_out; uint32_t offhook; + uint32_t offhook_in; + uint32_t offhook_out; uint32_t active; + uint32_t active_in; + uint32_t active_out; uint32_t held; + uint32_t held_in; + uint32_t held_out; uint32_t hup; + uint32_t hup_in; + uint32_t hup_out; uint32_t ringing; + uint32_t ringing_in; + uint32_t ringing_out; uint32_t early; + uint32_t early_in; + uint32_t early_out; + uint32_t ring_wait; } switch_device_stats_t; @@ -102,15 +118,22 @@ typedef struct switch_device_record_s { char *uuid; int refs; switch_device_stats_t stats; + switch_device_stats_t last_stats; switch_device_state_t state; switch_device_state_t last_state; switch_time_t active_start; switch_time_t active_stop; switch_time_t last_call_time; + switch_time_t ring_start; + switch_time_t ring_stop; + switch_time_t hold_start; + switch_time_t hold_stop; + switch_time_t call_start; struct device_uuid_node_s *uuid_list; struct device_uuid_node_s *uuid_tail; switch_mutex_t *mutex; switch_memory_pool_t *pool; + void *user_data; } switch_device_record_t; typedef void(*switch_device_state_function_t)(switch_core_session_t *session, switch_channel_callstate_t callstate, switch_device_record_t *drec); diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 7c90161d3a..8d042eae11 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -27,6 +27,7 @@ * Bret McDanel * Joseph Sullivan * Raymond Chandler + * Emmanuel Schmidbauer * * switch_types.h -- Data Types * @@ -666,6 +667,7 @@ typedef enum { SWITCH_RTP_FLAG_RTCP_MUX, SWITCH_RTP_FLAG_KILL_JB, SWITCH_RTP_FLAG_VIDEO_BREAK, + SWITCH_RTP_FLAG_PAUSE, SWITCH_RTP_FLAG_INVALID } switch_rtp_flag_t; @@ -968,6 +970,7 @@ typedef enum { SWITCH_MESSAGE_INDICATE_BLIND_TRANSFER_RESPONSE, SWITCH_MESSAGE_INDICATE_STUN_ERROR, SWITCH_MESSAGE_INDICATE_MEDIA_RENEG, + SWITCH_MESSAGE_REFER_EVENT, SWITCH_MESSAGE_ANSWER_EVENT, SWITCH_MESSAGE_PROGRESS_EVENT, SWITCH_MESSAGE_RING_EVENT, @@ -1137,6 +1140,7 @@ typedef enum { CCS_EARLY, CCS_ACTIVE, CCS_HELD, + CCS_RING_WAIT, CCS_HANGUP, CCS_UNHOLD } switch_channel_callstate_t; diff --git a/src/include/switch_version.h.template b/src/include/switch_version.h.template index 2e253dc69f..06169d603f 100644 --- a/src/include/switch_version.h.template +++ b/src/include/switch_version.h.template @@ -37,11 +37,17 @@ extern "C" { #endif +#if UINTPTR_MAX == 0xffffffffffffffff +#define _fs__bits "64bit" +#else +#define _fs__bits "32bit" +#endif + #define SWITCH_VERSION_MAJOR "@SWITCH_VERSION_MAJOR@" #define SWITCH_VERSION_MINOR "@SWITCH_VERSION_MINOR@" #define SWITCH_VERSION_MICRO "@SWITCH_VERSION_MICRO@" -#define SWITCH_VERSION_REVISION "@SWITCH_VERSION_REVISION@" -#define SWITCH_VERSION_REVISION_HUMAN "@SWITCH_VERSION_REVISION_HUMAN@" +#define SWITCH_VERSION_REVISION "@SWITCH_VERSION_REVISION@" "~" _fs__bits +#define SWITCH_VERSION_REVISION_HUMAN "@SWITCH_VERSION_REVISION_HUMAN@" " " _fs__bits #define SWITCH_VERSION_FULL SWITCH_VERSION_MAJOR "." SWITCH_VERSION_MINOR "." SWITCH_VERSION_MICRO SWITCH_VERSION_REVISION #define SWITCH_VERSION_FULL_HUMAN SWITCH_VERSION_MAJOR "." SWITCH_VERSION_MINOR "." SWITCH_VERSION_MICRO " " SWITCH_VERSION_REVISION_HUMAN diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 3f561ba386..2e4259817a 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -6085,9 +6085,257 @@ end: return SWITCH_STATUS_SUCCESS; } +SWITCH_STANDARD_JSON_API(json_channel_data_function) +{ + cJSON *reply, *data = cJSON_GetObjectItem(json, "data"); + switch_status_t status = SWITCH_STATUS_FALSE; + const char *uuid = cJSON_GetObjectCstr(data, "uuid"); + switch_core_session_t *tsession; + + + reply = cJSON_CreateObject(); + *json_reply = reply; + + if (zstr(uuid)) { + cJSON_AddItemToObject(reply, "response", cJSON_CreateString("INVALID INPUT")); + goto end; + } + + + if ((tsession = switch_core_session_locate(uuid))) { + cJSON *jevent; + + if (switch_ivr_generate_json_cdr(tsession, &jevent, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) { + cJSON_AddItemToObject(reply, "channelData", jevent); + } + + switch_core_session_rwunlock(tsession); + + status = SWITCH_STATUS_SUCCESS; + } else { + cJSON_AddItemToObject(reply, "response", cJSON_CreateString("Session does not exist")); + goto end; + } + + end: + + return status; +} + +SWITCH_STANDARD_JSON_API(json_execute_function) +{ + cJSON *reply, *data = cJSON_GetObjectItem(json, "data"); + switch_status_t status = SWITCH_STATUS_FALSE; + const char *uuid = cJSON_GetObjectCstr(data, "uuid"); + const char *app = cJSON_GetObjectCstr(data, "app"); + const char *arg = cJSON_GetObjectCstr(data, "arg"); + const char *einline = cJSON_GetObjectCstr(data, "inline"); + const char *edata = cJSON_GetObjectCstr(data, "extendedData"); + switch_core_session_t *tsession; + + + reply = cJSON_CreateObject(); + *json_reply = reply; + + if (!(uuid && app)) { + cJSON_AddItemToObject(reply, "response", cJSON_CreateString("INVALID INPUT")); + goto end; + } + + + if ((tsession = switch_core_session_locate(uuid))) { + if (switch_true(edata)) { + cJSON *jevent = NULL; + + if (switch_ivr_generate_json_cdr(tsession, &jevent, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) { + cJSON_AddItemToObject(reply, "channelData", jevent); + } + } else { + cJSON_AddItemToObject(reply, "channelName", cJSON_CreateString(switch_core_session_get_name(tsession))); + } + + if (switch_true(einline)) { + switch_core_session_execute_application(tsession, app, arg); + } else { + switch_core_session_execute_application_async(tsession, app, arg); + } + status = SWITCH_STATUS_SUCCESS; + + switch_core_session_rwunlock(tsession); + + } else { + cJSON_AddItemToObject(reply, "response", cJSON_CreateString("Session does not exist")); + goto end; + } + + + end: + + return status; +} + +SWITCH_STANDARD_JSON_API(json_api_function) +{ + cJSON *data, *cmd, *arg, *reply; + switch_stream_handle_t stream = { 0 }; + switch_status_t status = SWITCH_STATUS_SUCCESS; + + data = cJSON_GetObjectItem(json, "data"); + + cmd = cJSON_GetObjectItem(data, "cmd"); + arg = cJSON_GetObjectItem(data, "arg"); + + if (cmd && !cmd->valuestring) { + cmd = NULL; + } + + if (arg && !arg->valuestring) { + arg = NULL; + } + + reply = cJSON_CreateObject(); + + SWITCH_STANDARD_STREAM(stream); + + if (cmd && (status = switch_api_execute(cmd->valuestring, arg ? arg->valuestring : NULL, session, &stream)) == SWITCH_STATUS_SUCCESS) { + cJSON_AddItemToObject(reply, "message", cJSON_CreateString((char *) stream.data)); + } else { + cJSON_AddItemToObject(reply, "message", cJSON_CreateString("INVALID CALL")); + } + + switch_safe_free(stream.data); + + *json_reply = reply; + + return status; + +} + +#include +SWITCH_STANDARD_JSON_API(json_status_function) +{ + cJSON *o, *oo, *reply = cJSON_CreateObject(); + switch_core_time_duration_t duration = { 0 }; + int sps = 0, last_sps = 0, max_sps = 0, max_sps_fivemin = 0; + int sessions_peak = 0, sessions_peak_fivemin = 0; /* Max Concurrent Sessions buffers */ + switch_size_t cur = 0, max = 0; + + switch_core_measure_time(switch_core_uptime(), &duration); + + switch_core_session_ctl(SCSC_SESSIONS_PEAK, &sessions_peak); + switch_core_session_ctl(SCSC_SESSIONS_PEAK_FIVEMIN, &sessions_peak_fivemin); + switch_core_session_ctl(SCSC_LAST_SPS, &last_sps); + switch_core_session_ctl(SCSC_SPS, &sps); + switch_core_session_ctl(SCSC_SPS_PEAK, &max_sps); + switch_core_session_ctl(SCSC_SPS_PEAK_FIVEMIN, &max_sps_fivemin); + + cJSON_AddItemToObject(reply, "systemStatus", cJSON_CreateString(switch_core_ready() ? "ready" : "not ready")); + + o = cJSON_CreateObject(); + cJSON_AddItemToObject(o, "years", cJSON_CreateNumber(duration.yr)); + cJSON_AddItemToObject(o, "days", cJSON_CreateNumber(duration.day)); + cJSON_AddItemToObject(o, "hours", cJSON_CreateNumber(duration.hr)); + cJSON_AddItemToObject(o, "minutes", cJSON_CreateNumber(duration.min)); + cJSON_AddItemToObject(o, "seconds", cJSON_CreateNumber(duration.sec)); + cJSON_AddItemToObject(o, "milliseconds", cJSON_CreateNumber(duration.ms)); + cJSON_AddItemToObject(o, "microseconds", cJSON_CreateNumber(duration.mms)); + + cJSON_AddItemToObject(reply, "uptime", o); + cJSON_AddItemToObject(reply, "version", cJSON_CreateString(SWITCH_VERSION_FULL_HUMAN)); + + o = cJSON_CreateObject(); + cJSON_AddItemToObject(reply, "sessions", o); + + oo = cJSON_CreateObject(); + cJSON_AddItemToObject(o, "count", oo); + + cJSON_AddItemToObject(oo, "total", cJSON_CreateNumber(switch_core_session_id() - 1)); + cJSON_AddItemToObject(oo, "active", cJSON_CreateNumber(switch_core_session_count())); + cJSON_AddItemToObject(oo, "peak", cJSON_CreateNumber(sessions_peak)); + cJSON_AddItemToObject(oo, "peak5Min", cJSON_CreateNumber(sessions_peak_fivemin)); + cJSON_AddItemToObject(oo, "limit", cJSON_CreateNumber(switch_core_session_limit(0))); + + + + oo = cJSON_CreateObject(); + cJSON_AddItemToObject(o, "rate", oo); + cJSON_AddItemToObject(oo, "current", cJSON_CreateNumber(last_sps)); + cJSON_AddItemToObject(oo, "max", cJSON_CreateNumber(sps)); + cJSON_AddItemToObject(oo, "peak", cJSON_CreateNumber(max_sps)); + cJSON_AddItemToObject(oo, "peak5Min", cJSON_CreateNumber(max_sps_fivemin)); + + + o = cJSON_CreateObject(); + cJSON_AddItemToObject(reply, "idleCPU", o); + + cJSON_AddItemToObject(o, "used", cJSON_CreateNumber(switch_core_min_idle_cpu(-1.0))); + cJSON_AddItemToObject(o, "allowed", cJSON_CreateNumber(switch_core_idle_cpu())); + + + if (switch_core_get_stacksizes(&cur, &max) == SWITCH_STATUS_SUCCESS) { + o = cJSON_CreateObject(); + cJSON_AddItemToObject(reply, "stackSizeKB", o); + + cJSON_AddItemToObject(o, "current", cJSON_CreateNumber(cur / 1024)); + cJSON_AddItemToObject(o, "max", cJSON_CreateNumber(max / 1024)); + } + + + *json_reply = reply; + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_STANDARD_API(json_function) +{ + cJSON *jcmd = NULL, *format = NULL; + const char *message = ""; + char *response = NULL; + + if (zstr(cmd)) { + message = "No JSON supplied."; + goto err; + } + + jcmd = cJSON_Parse(cmd); + + if (!jcmd) { + message = "Parse error."; + goto err; + } + + format = cJSON_GetObjectItem(jcmd, "format"); + + switch_json_api_execute(jcmd, session, NULL); + + + if (format && format->valuestring && !strcasecmp(format->valuestring, "pretty")) { + response = cJSON_Print(jcmd); + } else { + response = cJSON_PrintUnformatted(jcmd); + } + + stream->write_function(stream, "%s\n", switch_str_nil(response)); + + switch_safe_free(response); + + cJSON_Delete(jcmd); + + return SWITCH_STATUS_SUCCESS; + + err: + + stream->write_function(stream, "-ERR %s\n", message); + + + return SWITCH_STATUS_SUCCESS; +} + SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) { switch_api_interface_t *commands_api_interface; + switch_json_api_interface_t *json_api_interface; + *module_interface = switch_loadable_module_create_module_interface(pool, modname); switch_thread_rwlock_create(&bgapi_rwlock, pool); @@ -6219,6 +6467,15 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "xml_locate", "Find some xml", xml_locate_function, "[root |
]"); SWITCH_ADD_API(commands_api_interface, "xml_wrap", "Wrap another api command in xml", xml_wrap_api_function, " "); SWITCH_ADD_API(commands_api_interface, "file_exists", "Check if a file exists on server", file_exists_function, ""); + SWITCH_ADD_API(commands_api_interface, "json", "JSON API", json_function, "JSON"); + + + SWITCH_ADD_JSON_API(json_api_interface, "status", "JSON status API", json_status_function, ""); + SWITCH_ADD_JSON_API(json_api_interface, "fsapi", "JSON FSAPI Gateway", json_api_function, ""); + SWITCH_ADD_JSON_API(json_api_interface, "execute", "JSON session execute application", json_execute_function, ""); + SWITCH_ADD_JSON_API(json_api_interface, "channelData", "JSON channel data application", json_channel_data_function, ""); + + switch_console_set_complete("add alias add"); switch_console_set_complete("add alias del"); diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index a847fb4ea2..8f3f1a81b8 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -33,6 +33,7 @@ * Joao Mesquita * Raymond Chandler * Seven Du + * Emmanuel Schmidbauer * * mod_conference.c -- Software Conference Bridge * @@ -100,6 +101,7 @@ static struct { uint32_t id_pool; int32_t running; uint32_t threads; + switch_event_channel_id_t event_channel_id; } globals; /* forward declaration for conference_obj and caller_control */ @@ -115,6 +117,7 @@ typedef struct conference_cdr_node_s { uint32_t flags; uint32_t id; conference_member_t *member; + switch_event_t *var_event; struct conference_cdr_node_s *next; } conference_cdr_node_t; @@ -204,7 +207,9 @@ typedef enum { CFLAG_ENDCONF_FORCED = (1 << 16), CFLAG_RFC4579 = (1 << 17), CFLAG_FLOOR_CHANGE = (1 << 18), - CFLAG_VID_FLOOR_LOCK = (1 << 19) + CFLAG_VID_FLOOR_LOCK = (1 << 19), + CFLAG_JSON_EVENTS = (1 << 20), + CFLAG_LIVEARRAY_SYNC = (1 << 21) } conf_flag_t; typedef enum { @@ -300,6 +305,8 @@ typedef struct conference_record { /* Conference Object */ typedef struct conference_obj { char *name; + char *la_name; + char *la_event_channel; char *desc; char *timer_name; char *tts_engine; @@ -338,6 +345,7 @@ typedef struct conference_obj { char *domain; char *caller_controls; char *moderator_controls; + switch_live_array_t *la; uint32_t flags; member_flag_t mflags; switch_call_cause_t bridge_hangup_cause; @@ -466,6 +474,8 @@ struct conference_member { char *kicked_sound; switch_queue_t *dtmf_queue; switch_thread_t *input_thread; + cJSON *json; + cJSON *status_field; }; typedef enum { @@ -564,6 +574,9 @@ static switch_status_t conf_api_sub_clear_vid_floor(conference_obj_t *conference static void conference_cdr_del(conference_member_t *member) { + if (member->channel) { + switch_channel_get_variables(member->channel, &member->cdr_node->var_event); + } member->cdr_node->leave_time = switch_epoch_time_now(NULL); member->cdr_node->flags = member->flags; member->cdr_node->member = NULL; @@ -1086,6 +1099,218 @@ static void conference_cdr_render(conference_obj_t *conference) switch_xml_free(cdr); } +static cJSON *conference_json_render(conference_obj_t *conference, cJSON *req) +{ + char tmp[30]; + const char *domain; const char *name; + char *dup_domain = NULL; + char *uri; + conference_cdr_node_t *np; + char *tmpp = tmp; + cJSON *json = cJSON_CreateObject(), *jusers = NULL, *jold_users = NULL, *juser = NULL, *jvars = NULL; + + switch_assert(json); + + switch_mutex_lock(conference->mutex); + switch_snprintf(tmp, sizeof(tmp), "%u", conference->doc_version); + conference->doc_version++; + switch_mutex_unlock(conference->mutex); + + if (!(name = conference->name)) { + name = "conference"; + } + + if (!(domain = conference->domain)) { + dup_domain = switch_core_get_domain(SWITCH_TRUE); + if (!(domain = dup_domain)) { + domain = "cluecon.com"; + } + } + + + uri = switch_mprintf("%s@%s", name, domain); + json_add_child_string(json, "entity", uri); + json_add_child_string(json, "conferenceDescription", conference->desc ? conference->desc : "FreeSWITCH Conference"); + json_add_child_string(json, "conferenceState", "active"); + switch_snprintf(tmp, sizeof(tmp), "%u", conference->count); + json_add_child_string(json, "userCount", tmp); + + jusers = json_add_child_array(json, "users"); + jold_users = json_add_child_array(json, "oldUsers"); + + switch_mutex_lock(conference->member_mutex); + + for (np = conference->cdr_nodes; np; np = np->next) { + char *user_uri = NULL; + switch_channel_t *channel = NULL; + switch_time_exp_t tm; + switch_size_t retsize; + const char *fmt = "%Y-%m-%dT%H:%M:%S%z"; + char *p; + + if (np->record_path || !np->cp) { + continue; + } + + //if (!np->cp || (np->member && !np->member->session) || np->leave_time) { /* for now we'll remove participants when they leave */ + //continue; + //} + + if (np->member && np->member->session) { + channel = switch_core_session_get_channel(np->member->session); + } + + juser = cJSON_CreateObject(); + + if (channel) { + const char *uri = switch_channel_get_variable_dup(channel, "conference_invite_uri", SWITCH_FALSE, -1); + + if (uri) { + user_uri = strdup(uri); + } + } + + if (np->cp) { + + if (!user_uri) { + user_uri = switch_mprintf("%s@%s", np->cp->caller_id_number, domain); + } + + json_add_child_string(juser, "entity", user_uri); + json_add_child_string(juser, "displayText", np->cp->caller_id_name); + } + + //if (np->record_path) { + //json_add_child_string(juser, "recordingPATH", np->record_path); + //} + + json_add_child_string(juser, "status", np->leave_time ? "disconnected" : "connected"); + + switch_time_exp_lt(&tm, (switch_time_t) conference->start_time * 1000000); + switch_strftime_nocheck(tmp, &retsize, sizeof(tmp), fmt, &tm); + p = end_of_p(tmpp) -1; + snprintf(p, 4, ":00"); + + json_add_child_string(juser, "joinTime", tmpp); + + snprintf(tmp, sizeof(tmp), "%u", np->id); + json_add_child_string(juser, "memberId", tmp); + + jvars = cJSON_CreateObject(); + + if (!np->member && np->var_event) { + switch_json_add_presence_data_cols(np->var_event, jvars, "PD-"); + } else if (np->member) { + const char *var; + const char *prefix = NULL; + switch_event_t *var_event = NULL; + switch_event_header_t *hp; + int all = 0; + + switch_channel_get_variables(channel, &var_event); + + if ((prefix = switch_event_get_header(var_event, "json_conf_var_prefix"))) { + all = strcasecmp(prefix, "__all__"); + } else { + prefix = "json_"; + } + + for(hp = var_event->headers; hp; hp = hp->next) { + if (all || !strncasecmp(hp->name, prefix, strlen(prefix))) { + json_add_child_string(jvars, hp->name, hp->value); + } + } + + switch_json_add_presence_data_cols(var_event, jvars, "PD-"); + + switch_event_destroy(&var_event); + + if ((var = switch_channel_get_variable(channel, "rtp_use_ssrc"))) { + json_add_child_string(juser, "rtpAudioSSRC", var); + } + + json_add_child_string(juser, "rtpAudioDirection", switch_channel_test_flag(channel, CF_HOLD) ? "sendonly" : "sendrecv"); + + + if (switch_channel_test_flag(channel, CF_VIDEO)) { + if ((var = switch_channel_get_variable(channel, "rtp_use_video_ssrc"))) { + json_add_child_string(juser, "rtpVideoSSRC", var); + } + + json_add_child_string(juser, "rtpVideoDirection", switch_channel_test_flag(channel, CF_HOLD) ? "sendonly" : "sendrecv"); + } + } + + if (jvars) { + json_add_child_obj(juser, "variables", jvars); + } + + cJSON_AddItemToArray(np->leave_time ? jold_users : jusers, juser); + + switch_safe_free(user_uri); + } + + switch_mutex_unlock(conference->member_mutex); + + switch_safe_free(dup_domain); + switch_safe_free(uri); + + return json; +} + +static void conference_la_event_channel_handler(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id) +{ + switch_live_array_parse_json(json, globals.event_channel_id); +} + +static void conference_event_channel_handler(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id) +{ + char *domain = NULL, *name = NULL; + conference_obj_t *conference = NULL; + cJSON *data, *reply = NULL, *conf_desc = NULL; + const char *action = NULL; + + if ((data = cJSON_GetObjectItem(json, "data"))) { + action = cJSON_GetObjectCstr(data, "action"); + } + + if (!action) action = ""; + + reply = cJSON_Duplicate(json, 1); + cJSON_DeleteItemFromObject(reply, "data"); + + if ((name = strchr(event_channel, '.'))) { + char *tmp = strdup(name + 1); + switch_assert(tmp); + name = tmp; + + if ((domain = strchr(name, '@'))) { + *domain++ = '\0'; + } + } + + if (!strcasecmp(action, "bootstrap")) { + if (!zstr(name) && (conference = conference_find(name, domain))) { + conf_desc = conference_json_render(conference, json); + } else { + conf_desc = cJSON_CreateObject(); + json_add_child_string(conf_desc, "conferenceDescription", "FreeSWITCH Conference"); + json_add_child_string(conf_desc, "conferenceState", "inactive"); + json_add_child_array(conf_desc, "users"); + json_add_child_array(conf_desc, "oldUsers"); + } + } else { + conf_desc = cJSON_CreateObject(); + json_add_child_string(conf_desc, "error", "Invalid action"); + } + + json_add_child_string(conf_desc, "action", "conferenceDescription"); + + cJSON_AddItemToObject(reply, "data", conf_desc); + + switch_event_channel_broadcast(event_channel, &reply, modname, globals.event_channel_id); + +} static switch_status_t conference_add_event_data(conference_obj_t *conference, switch_event_t *event) @@ -1340,6 +1565,42 @@ static switch_status_t member_del_relationship(conference_member_t *member, uint return status; } +static void send_json_event(conference_obj_t *conference) +{ + cJSON *event, *conf_desc = NULL; + char *name = NULL, *domain = NULL, *dup_domain = NULL; + char *event_channel = NULL; + + if (!switch_test_flag(conference, CFLAG_JSON_EVENTS)) { + return; + } + + conf_desc = conference_json_render(conference, NULL); + + if (!(name = conference->name)) { + name = "conference"; + } + + if (!(domain = conference->domain)) { + dup_domain = switch_core_get_domain(SWITCH_TRUE); + if (!(domain = dup_domain)) { + domain = "cluecon.com"; + } + } + + event_channel = switch_mprintf("conference.%q@%q", name, domain); + + event = cJSON_CreateObject(); + + json_add_child_string(event, "eventChannel", event_channel); + cJSON_AddItemToObject(event, "data", conf_desc); + + switch_event_channel_broadcast(event_channel, &event, modname, globals.event_channel_id); + + switch_safe_free(dup_domain); + switch_safe_free(event_channel); +} + static void send_rfc_event(conference_obj_t *conference) { switch_event_t *event; @@ -1422,6 +1683,73 @@ static void send_conference_notify(conference_obj_t *conference, const char *sta } +static void member_update_status_field(conference_member_t *member) +{ + char *str, *vstr = "", display[128] = ""; + + if (!member->conference->la) { + return; + } + + switch_live_array_lock(member->conference->la); + + if (!switch_test_flag(member, MFLAG_CAN_SPEAK)) { + str = "MUTE"; + } else if (switch_channel_test_flag(member->channel, CF_HOLD)) { + str = "HOLD"; + } else if (member == member->conference->floor_holder) { + if (switch_test_flag(member, MFLAG_TALKING)) { + str = "TALKING (FLOOR)"; + } else { + str = "FLOOR"; + } + } else if (switch_test_flag(member, MFLAG_TALKING)) { + str = "TALKING"; + } else { + str = "ACTIVE"; + } + + if (switch_channel_test_flag(member->channel, CF_VIDEO)) { + vstr = " VIDEO"; + if (member == member->conference->video_floor_holder) { + vstr = " VIDEO (FLOOR)"; + } + } + + switch_snprintf(display, sizeof(display), "%s%s", str, vstr); + + + free(member->status_field->valuestring); + member->status_field->valuestring = strdup(display); + + switch_live_array_add(member->conference->la, switch_core_session_get_uuid(member->session), -1, &member->json, SWITCH_FALSE); + switch_live_array_unlock(member->conference->la); +} + +static void adv_la(conference_obj_t *conference, conference_member_t *member, switch_bool_t join) +{ + if (conference && conference->la && member->session) { + cJSON *msg, *data; + const char *uuid = switch_core_session_get_uuid(member->session); + const char *cookie = switch_channel_get_variable(member->channel, "event_channel_cookie"); + + msg = cJSON_CreateObject(); + data = json_add_child_obj(msg, "pvtData", NULL); + + cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(uuid)); + cJSON_AddItemToObject(msg, "eventType", cJSON_CreateString("channelPvtData")); + + cJSON_AddItemToObject(data, "action", cJSON_CreateString(join ? "conference-liveArray-join" : "conference-liveArray-part")); + cJSON_AddItemToObject(data, "laChannel", cJSON_CreateString(conference->la_event_channel)); + cJSON_AddItemToObject(data, "laName", cJSON_CreateString(conference->la_name)); + + if (cookie) { + switch_event_channel_permission_modify(cookie, conference->la_event_channel, join); + } + + switch_event_channel_broadcast(uuid, &msg, modname, globals.event_channel_id); + } +} /* Gain exclusive access and add the member to the list */ static switch_status_t conference_add_member(conference_obj_t *conference, conference_member_t *member) @@ -1585,7 +1913,29 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe switch_mutex_unlock(member->audio_out_mutex); switch_mutex_unlock(member->audio_in_mutex); + if (conference->la && member->channel) { + member->json = cJSON_CreateArray(); + cJSON_AddItemToArray(member->json, cJSON_CreateStringPrintf("%0.4d", member->id)); + cJSON_AddItemToArray(member->json, cJSON_CreateString(switch_channel_get_variable(member->channel, "caller_id_number"))); + cJSON_AddItemToArray(member->json, cJSON_CreateString(switch_channel_get_variable(member->channel, "caller_id_name"))); + + cJSON_AddItemToArray(member->json, cJSON_CreateStringPrintf("%s@%s", + switch_channel_get_variable(member->channel, "original_read_codec"), + switch_channel_get_variable(member->channel, "original_read_rate") + )); + + member->status_field = cJSON_CreateString(""); + cJSON_AddItemToArray(member->json, member->status_field); + member_update_status_field(member); + //switch_live_array_add_alias(conference->la, switch_core_session_get_uuid(member->session), "conference"); + adv_la(conference, member, SWITCH_TRUE); + switch_live_array_add(conference->la, switch_core_session_get_uuid(member->session), -1, &member->json, SWITCH_FALSE); + + } + + send_rfc_event(conference); + send_json_event(conference); switch_mutex_unlock(conference->mutex); status = SWITCH_STATUS_SUCCESS; @@ -1637,12 +1987,14 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf //switch_channel_set_flag(member->channel, CF_VIDEO_PASSIVE); switch_core_session_refresh_video(member->session); conference->video_floor_holder = member; + member_update_status_field(member); } else { conference->video_floor_holder = NULL; } if (old_member) { old_id = old_member->id; + member_update_status_field(old_member); //switch_channel_clear_flag(old_member->channel, CF_VIDEO_PASSIVE); } @@ -1714,6 +2066,7 @@ static void conference_set_floor_holder(conference_obj_t *conference, conference switch_channel_get_name(member->channel)); conference->floor_holder = member; + member_update_status_field(member); } else { conference->floor_holder = NULL; } @@ -1721,6 +2074,7 @@ static void conference_set_floor_holder(conference_obj_t *conference, conference if (old_member) { old_id = old_member->id; + member_update_status_field(old_member); } switch_set_flag(conference, CFLAG_FLOOR_CHANGE); @@ -1881,8 +2235,14 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe switch_mutex_unlock(member->audio_in_mutex); + if (conference->la && member->session) { + switch_live_array_del(conference->la, switch_core_session_get_uuid(member->session)); + //switch_live_array_clear_alias(conference->la, switch_core_session_get_uuid(member->session), "conference"); + adv_la(conference, member, SWITCH_FALSE); + } + send_rfc_event(conference); - + send_json_event(conference); switch_mutex_unlock(conference->mutex); status = SWITCH_STATUS_SUCCESS; @@ -2062,6 +2422,11 @@ static void *SWITCH_THREAD_FUNC conference_video_thread_run(switch_thread_t *thr return NULL; } +static void conference_command_handler(switch_live_array_t *la, const char *cmd, const char *sessid, cJSON *jla, void *user_data) +{ + +} + /* Main monitor thread (1 per distinct conference room) */ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *obj) { @@ -2079,6 +2444,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v int32_t z = 0; int member_score_sum = 0; int divisor = 0; + conference_cdr_node_t *np; if (!(divisor = conference->rate / 8000)) { divisor = 1; @@ -2108,6 +2474,26 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "conference-create"); switch_event_fire(&event); + if (switch_test_flag(conference, CFLAG_LIVEARRAY_SYNC)) { + char *p; + + if (strchr(conference->name, '@')) { + conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s", conference->name); + } else { + conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s@%s", conference->name, conference->domain); + } + + conference->la_name = switch_core_strdup(conference->pool, conference->name); + if ((p = strchr(conference->la_name, '@'))) { + *p = '\0'; + } + + switch_live_array_create(conference->la_event_channel, conference->la_name, globals.event_channel_id, &conference->la); + switch_live_array_set_user_data(conference->la, conference); + switch_live_array_set_command_handler(conference->la, conference_command_handler); + } + + while (globals.running && !switch_test_flag(conference, CFLAG_DESTRUCT)) { switch_size_t file_sample_len = samples; switch_size_t file_data_len = samples * 2; @@ -2505,6 +2891,14 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v switch_mutex_lock(conference->mutex); conference_stop_file(conference, FILE_STOP_ASYNC); conference_stop_file(conference, FILE_STOP_ALL); + + for (np = conference->cdr_nodes; np; np = np->next) { + if (np->var_event) { + switch_event_destroy(&np->var_event); + } + } + + /* Close Unused Handles */ if (conference->fnode) { conference_file_node_t *fnode, *cur; @@ -2596,6 +2990,10 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v switch_thread_rwlock_unlock(conference->rwlock); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write Lock OFF\n"); + if (conference->la) { + switch_live_array_destroy(&conference->la); + } + if (conference->sh) { switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE; switch_core_speech_close(&conference->lsh, &flags); @@ -3241,7 +3639,6 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v break; } - /* if we have caller digits, feed them to the parser to find an action */ if (switch_channel_has_dtmf(channel)) { char dtmf[128] = ""; @@ -3251,7 +3648,12 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v if (switch_test_flag(member, MFLAG_DIST_DTMF)) { conference_send_all_dtmf(member, member->conference, dtmf); } else if (member->dmachine) { - switch_ivr_dmachine_feed(member->dmachine, dtmf, NULL); + char *p; + char str[2] = ""; + for (p = dtmf; p && *p; p++) { + str[0] = *p; + switch_ivr_dmachine_feed(member->dmachine, str, NULL); + } } } else if (member->dmachine) { switch_ivr_dmachine_ping(member->dmachine, NULL); @@ -3280,6 +3682,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v if (++hangover_hits >= hangover) { hangover_hits = hangunder_hits = 0; switch_clear_flag_locked(member, MFLAG_TALKING); + member_update_status_field(member); check_agc_levels(member); clear_avg(member); member->score_iir = 0; @@ -3398,7 +3801,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v if (!switch_test_flag(member, MFLAG_TALKING)) { switch_set_flag_locked(member, MFLAG_TALKING); - + member_update_status_field(member); if (test_eflag(member->conference, EFLAG_START_TALKING) && switch_test_flag(member, MFLAG_CAN_SPEAK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_add_event_member_data(member, event); @@ -3435,6 +3838,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v if (++hangover_hits >= hangover) { hangover_hits = hangunder_hits = 0; switch_clear_flag_locked(member, MFLAG_TALKING); + member_update_status_field(member); check_agc_levels(member); clear_avg(member); @@ -3680,6 +4084,7 @@ static void conference_loop_output(conference_member_t *member) const char *ann = switch_channel_get_variable(channel, "conference_auto_outcall_announce"); const char *prefix = switch_channel_get_variable(channel, "conference_auto_outcall_prefix"); const char *maxwait = switch_channel_get_variable(channel, "conference_auto_outcall_maxwait"); + const char *delimiter_val = switch_channel_get_variable(channel, "conference_auto_outcall_delimiter"); int to = 60; int wait_sec = 2; int loops = 0; @@ -3706,7 +4111,12 @@ static void conference_loop_output(conference_member_t *member) int x = 0; switch_assert(cpstr); - argc = switch_separate_string(cpstr, ',', argv, (sizeof(argv) / sizeof(argv[0]))); + if (!zstr(delimiter_val) && strlen(delimiter_val) == 1) { + char delimiter = *delimiter_val; + argc = switch_separate_string(cpstr, delimiter, argv, (sizeof(argv) / sizeof(argv[0]))); + } else { + argc = switch_separate_string(cpstr, ',', argv, (sizeof(argv) / sizeof(argv[0]))); + } for (x = 0; x < argc; x++) { char *dial_str = switch_mprintf("%s%s", switch_str_nil(prefix), argv[x]); switch_assert(dial_str); @@ -3763,6 +4173,15 @@ static void conference_loop_output(conference_member_t *member) switch_mutex_lock(member->write_mutex); + + if (switch_channel_test_flag(member->channel, CF_CONFERENCE_ADV)) { + if (member->conference->la) { + adv_la(member->conference, member, SWITCH_TRUE); + } + switch_channel_clear_flag(member->channel, CF_CONFERENCE_ADV); + } + + if (switch_core_session_dequeue_event(member->session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) { if (event->event_id == SWITCH_EVENT_MESSAGE) { char *from = switch_event_get_header(event, "from"); @@ -4864,6 +5283,8 @@ static switch_status_t conf_api_sub_mute(conference_member_t *member, switch_str switch_event_fire(&event); } + member_update_status_field(member); + return SWITCH_STATUS_SUCCESS; } @@ -4948,6 +5369,8 @@ static switch_status_t conf_api_sub_unmute(conference_member_t *member, switch_s switch_event_fire(&event); } + member_update_status_field(member); + return SWITCH_STATUS_SUCCESS; } @@ -7260,6 +7683,10 @@ 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], "json-events")) { + *f |= CFLAG_JSON_EVENTS; + } else if (!strcasecmp(argv[i], "livearray-sync")) { + *f |= CFLAG_LIVEARRAY_SYNC; } else if (!strcasecmp(argv[i], "rfc-4579")) { *f |= CFLAG_RFC4579; } @@ -9308,6 +9735,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_conference_load) switch_console_add_complete_func("::conference::list_conferences", list_conferences); + switch_event_channel_bind("conference", conference_event_channel_handler, &globals.event_channel_id); + switch_event_channel_bind("conference-liveArray", conference_la_event_channel_handler, &globals.event_channel_id); + /* build api interface help ".syntax" field string */ p = strdup(""); for (i = 0; i < CONFFUNCAPISIZE; i++) { @@ -9389,6 +9819,9 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_conference_shutdown) /* signal all threads to shutdown */ globals.running = 0; + switch_event_channel_unbind(NULL, conference_event_channel_handler); + switch_event_channel_unbind(NULL, conference_la_event_channel_handler); + switch_console_del_complete_func("::conference::list_conferences"); /* wait for all threads */ diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 8d7b5c6f37..b5b7718231 100755 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -3622,6 +3622,9 @@ static switch_call_cause_t pickup_outgoing_channel(switch_core_session_t *sessio switch_core_session_set_private(nsession, tech_pvt); nchannel = switch_core_session_get_channel(nsession); + switch_channel_set_cap(nchannel, CC_PROXY_MEDIA); + switch_channel_set_cap(nchannel, CC_BYPASS_MEDIA); + caller_profile = switch_caller_profile_clone(nsession, outbound_profile); switch_channel_set_caller_profile(nchannel, caller_profile); diff --git a/src/mod/applications/mod_esf/mod_esf.c b/src/mod/applications/mod_esf/mod_esf.c index bc04991bee..f6a9191877 100644 --- a/src/mod/applications/mod_esf/mod_esf.c +++ b/src/mod/applications/mod_esf/mod_esf.c @@ -30,6 +30,7 @@ * */ #include +#include SWITCH_MODULE_LOAD_FUNCTION(mod_esf_load); SWITCH_MODULE_DEFINITION(mod_esf, mod_esf_load, NULL, NULL); @@ -168,7 +169,7 @@ SWITCH_STANDARD_APP(bcast_function) if (ready == SEND_TYPE_RTP) { if (read_impl.ianacode != 0) { if (switch_core_codec_init(&codec, - "PCMU", + "L16", NULL, 8000, 20, @@ -200,8 +201,8 @@ SWITCH_STANDARD_APP(bcast_function) mcast_ip, mcast_port, 0, - 8000, - 20, flags, "soft", &err, switch_core_session_get_pool(session)); + 160, + 20000, flags, "soft", &err, switch_core_session_get_pool(session)); if (!switch_rtp_ready(rtp_session)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "RTP Error\n"); @@ -237,7 +238,22 @@ SWITCH_STANDARD_APP(bcast_function) continue; } if (ready == SEND_TYPE_RTP) { + short *dbuf; + unsigned char *ebuf; + uint32_t i; + unsigned char encoded_data[4192]; + + dbuf = read_frame->data; + ebuf = encoded_data; + + for (i = 0; i < read_frame->datalen / sizeof(short); i++) { + ebuf[i] = linear_to_ulaw(dbuf[i]); + } + read_frame->data = encoded_data; + read_frame->datalen = read_frame->datalen / 2; switch_rtp_write_frame(rtp_session, read_frame); + read_frame->data = dbuf; + read_frame->datalen = read_frame->datalen * 2; } else { bytes = read_frame->packetlen; switch_socket_sendto(socket, audio_addr, 0, read_frame->packet, &bytes); diff --git a/src/mod/applications/mod_fifo/mod_fifo.c b/src/mod/applications/mod_fifo/mod_fifo.c index 3c6bc7a169..e5c12c0998 100644 --- a/src/mod/applications/mod_fifo/mod_fifo.c +++ b/src/mod/applications/mod_fifo/mod_fifo.c @@ -1067,7 +1067,7 @@ static void do_unbridge(switch_core_session_t *consumer_session, switch_core_ses switch_channel_event_set_data(consumer_channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Name", MANUAL_QUEUE_NAME); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Action", "bridge-consumer-stop"); - if (use_count) { + if (outbound_id) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Outbound-ID", outbound_id); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Use-Count", "%d", use_count); } @@ -2218,7 +2218,7 @@ SWITCH_STANDARD_API(fifo_add_outbound_function) } -static void dec_use_count(switch_core_session_t *session, switch_bool_t send_event) +static void dec_use_count(switch_core_session_t *session, const char *type) { char *sql; const char *outbound_id = NULL; @@ -2226,8 +2226,6 @@ static void dec_use_count(switch_core_session_t *session, switch_bool_t send_eve long now = (long) switch_epoch_time_now(NULL); switch_channel_t *channel = switch_core_session_get_channel(session); - do_unbridge(session, NULL); - if ((outbound_id = switch_channel_get_variable(channel, "fifo_outbound_uuid"))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s untracking call on uuid %s!\n", switch_channel_get_name(channel), outbound_id); @@ -2242,11 +2240,14 @@ static void dec_use_count(switch_core_session_t *session, switch_bool_t send_eve fifo_dec_use_count(outbound_id); } - if (send_event) { + do_unbridge(session, NULL); + + if (type) { if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, FIFO_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Name", MANUAL_QUEUE_NAME); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Action", "channel-consumer-stop"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Type", type); if (outbound_id) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Outbound-ID", outbound_id); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Use-Count", "%d", fifo_get_use_count(outbound_id)); @@ -2262,7 +2263,7 @@ static switch_status_t hanguphook(switch_core_session_t *session) switch_channel_state_t state = switch_channel_get_state(channel); if (state >= CS_HANGUP && !switch_channel_test_app_flag_key(FIFO_APP_KEY, channel, FIFO_APP_DID_HOOK)) { - dec_use_count(session, SWITCH_TRUE); + dec_use_count(session, "manual"); switch_core_event_hook_remove_state_change(session, hanguphook); switch_channel_set_app_flag_key(FIFO_APP_KEY, channel, FIFO_APP_DID_HOOK); } @@ -2325,6 +2326,9 @@ SWITCH_STANDARD_APP(fifo_track_call_function) switch_channel_event_set_data(channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Name", MANUAL_QUEUE_NAME); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Action", "channel-consumer-start"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Outbound-ID", data); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Use-Count", "%d", fifo_get_use_count(data)); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Type", "manual"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Caller-CID-Name", cid_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Caller-CID-Number", cid_number); switch_event_fire(&event); @@ -2729,16 +2733,33 @@ SWITCH_STANDARD_APP(fifo_function) const char *url = NULL; const char *caller_uuid = NULL; const char *outbound_id = switch_channel_get_variable(channel, "fifo_outbound_uuid"); + switch_event_t *event; + const char *cid_name = NULL, *cid_number = NULL; //const char *track_use_count = switch_channel_get_variable(channel, "fifo_track_use_count"); //int do_track = switch_true(track_use_count); if (switch_core_event_hook_remove_receive_message(session, messagehook) == SWITCH_STATUS_SUCCESS) { - dec_use_count(session, SWITCH_FALSE); + dec_use_count(session, NULL); switch_core_event_hook_remove_state_change(session, hanguphook); switch_channel_clear_app_flag_key(FIFO_APP_KEY, channel, FIFO_APP_TRACKING); } + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { + cid_name = switch_channel_get_variable(channel, "callee_id_name"); + cid_number = switch_channel_get_variable(channel, "callee_id_number"); + + if (!cid_name) { + cid_name = switch_channel_get_variable(channel, "destination_number"); + } + if (!cid_number) { + cid_number = cid_name; + } + } else { + cid_name = switch_channel_get_variable(channel, "caller_id_name"); + cid_number = switch_channel_get_variable(channel, "caller_id_number"); + } + if (!zstr(strat_str)) { if (!strcasecmp(strat_str, "more_ppl")) { strat = STRAT_MORE_PPL; @@ -3148,6 +3169,22 @@ SWITCH_STANDARD_APP(fifo_function) } + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, FIFO_EVENT) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(channel, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Name", argv[0]); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Action", "channel-consumer-start"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Type", "onhook"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Caller-CID-Name", cid_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Caller-CID-Number", cid_number); + if (outbound_id) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Outbound-ID", outbound_id); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Use-Count", "%d", fifo_get_use_count(outbound_id)); + } + switch_event_fire(&event); + } + + + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, FIFO_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Name", argv[0]); @@ -3221,6 +3258,19 @@ SWITCH_STANDARD_APP(fifo_function) } + + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, FIFO_EVENT) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(channel, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Name", arg_fifo_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Action", "channel-consumer-stop"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Type", "onhook"); + if (outbound_id) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Outbound-ID", outbound_id); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Use-Count", "%d", fifo_get_use_count(outbound_id)); + } + switch_event_fire(&event); + } + del_bridge_call(switch_core_session_get_uuid(session)); del_bridge_call(switch_core_session_get_uuid(other_session)); diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 953ea6d8f0..a34b8cfd74 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -305,7 +305,7 @@ static switch_status_t channel_on_init(switch_core_session_t *session) static switch_status_t channel_on_destroy(switch_core_session_t *session) { - crtp_private_t *tech_pvt = switch_core_session_get_private(session); + crtp_private_t *tech_pvt = NULL; if ((tech_pvt = switch_core_session_get_private(session))) { diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 9000ec96b3..f2194487d4 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -5960,7 +5960,40 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } if (r_sdp) { - if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { + if (switch_channel_test_flag(channel, CF_PROXY_MODE) && r_sdp) { + char ibuf[35] = "", pbuf[35] = ""; + const char *ptr; + + if ((ptr = switch_stristr("c=IN IP4", r_sdp))) { + int i = 0; + + ptr += 8; + + while(*ptr == ' ') { + ptr++; + } + while(*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { + ibuf[i++] = *ptr++; + } + + switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, ibuf); + } + + if ((ptr = switch_stristr("m=audio", r_sdp))) { + int i = 0; + + ptr += 7; + + while(*ptr == ' ') { + ptr++; + } + while(*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { + pbuf[i++] = *ptr++; + } + + switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, pbuf); + } + if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) && switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) { switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA"); } @@ -6893,6 +6926,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t exten = (char *) refer_to->r_url->url_user; } + switch_core_session_queue_indication(session, SWITCH_MESSAGE_REFER_EVENT); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Process REFER to [%s@%s]\n", exten, (char *) refer_to->r_url->url_host); switch_channel_set_variable(tech_pvt->channel, "transfer_disposition", "recv_replace"); diff --git a/src/mod/formats/mod_local_stream/mod_local_stream.c b/src/mod/formats/mod_local_stream/mod_local_stream.c index 6d91f9b653..c94958ea87 100644 --- a/src/mod/formats/mod_local_stream/mod_local_stream.c +++ b/src/mod/formats/mod_local_stream/mod_local_stream.c @@ -311,16 +311,17 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2)) { used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2); if (source->total) { - + uint32_t bused = 0; switch_mutex_lock(source->mutex); for (cp = source->context_list; cp && RUNNING; cp = cp->next) { if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) { continue; } switch_mutex_lock(cp->audio_mutex); - if (switch_buffer_inuse(cp->audio_buffer) > source->samples * 768) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Leaking stream handle! [%s() %s:%d]\n", cp->func, cp->file, - cp->line); + bused = switch_buffer_inuse(cp->audio_buffer); + if (bused > source->samples * 768) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Flushing Stream Handle Buffer [%s() %s:%d] size: %u samples: %ld\n", + cp->func, cp->file, cp->line, bused, (long)source->samples); switch_buffer_zero(cp->audio_buffer); } else { switch_buffer_write(cp->audio_buffer, dist_buf, used); diff --git a/src/mod/languages/mod_lua/mod_lua.cpp b/src/mod/languages/mod_lua/mod_lua.cpp index 3d79dd8d0e..9715f0dc74 100644 --- a/src/mod/languages/mod_lua/mod_lua.cpp +++ b/src/mod/languages/mod_lua/mod_lua.cpp @@ -45,7 +45,6 @@ SWITCH_MODULE_DEFINITION_EX(mod_lua, mod_lua_load, mod_lua_shutdown, NULL, SMODF static struct { switch_memory_pool_t *pool; char *xml_handler; - switch_event_node_t *node; } globals; int luaopen_freeswitch(lua_State * L); @@ -339,18 +338,22 @@ static switch_status_t do_config(void) char *script = (char *) switch_xml_attr_soft(hook, "script"); switch_event_types_t evtype; + if (!zstr(script)) { + script = switch_core_strdup(globals.pool, script); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "hook params: '%s' | '%s' | '%s'\n", event, subclass, script); if (switch_name_event(event,&evtype) == SWITCH_STATUS_SUCCESS) { if (!zstr(script)) { - if (switch_event_bind_removable(modname, evtype, !zstr(subclass) ? subclass : SWITCH_EVENT_SUBCLASS_ANY, - lua_event_handler, script, &globals.node) == SWITCH_STATUS_SUCCESS) { + if (switch_event_bind(modname, evtype, !zstr(subclass) ? subclass : SWITCH_EVENT_SUBCLASS_ANY, + lua_event_handler, script) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "event handler for '%s' set to '%s'\n", switch_event_name(evtype), script); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot set event handler: unsuccessful bind\n"); } } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot set event handler: no script name\n", event); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot set event handler: no script name for event type '%s'\n", event); } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot set event handler: unknown event type '%s'\n", event); @@ -691,7 +694,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_lua_load) SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_lua_shutdown) { - switch_event_unbind(&globals.node); + switch_event_unbind_callback(lua_event_handler); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c index 6cbb553261..af3bb638f8 100644 --- a/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c +++ b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c @@ -46,6 +46,23 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_xml_radius_shutdown); SWITCH_MODULE_DEFINITION(mod_xml_radius, mod_xml_radius_load, mod_xml_radius_shutdown, NULL); int GLOBAL_DEBUG = 0; +/* + * Time format 0: + * 20:16:33.479 UTC Thu May 02 2013 + * + * Time format 1: + * 2013-05-03T00:53:26.139798+0400 + * + */ +int GLOBAL_TIME_FORMAT = 0; +char *GLOBAL_TIME_ZONE = "UTC"; +static char radattrdays[7][4] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; +static char radattrmonths[12][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; switch_status_t mod_xml_radius_new_handle(rc_handle **new_handle, switch_xml_t xml) { switch_xml_t server, param; @@ -186,7 +203,26 @@ switch_status_t do_config() } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Could not find 'auth_invite' section in config file.\n"); } - + + if ((tmp = switch_xml_child(cfg, "global")) != NULL ) { + for (param = switch_xml_child(tmp, "param"); param; param = param->next) { + char *name = (char *) switch_xml_attr_soft(param, "name"); + char *value = (char *) switch_xml_attr_soft(param, "value"); + if ( strncmp(name, "time_format", 11) == 0 && value != NULL ) { + GLOBAL_TIME_FORMAT = atoi(value); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Time format changed to %d\n", GLOBAL_TIME_FORMAT); + } + if ( strncmp(name, "time_zone", 9) == 0 && value != NULL ) { + GLOBAL_TIME_ZONE = value; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Time zone changed to %s\n", GLOBAL_TIME_ZONE); + } + if ( strncmp(name, "debug", 5) == 0 && value != NULL ) { + GLOBAL_DEBUG = atoi(value); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Debug changed to %d\n", GLOBAL_DEBUG); + } + } + } + serv = timeout = deadtime = retries = dict = seq = 0; if ((tmp = switch_xml_dup(switch_xml_child(cfg, "auth_app"))) != NULL ) { if ( (server = switch_xml_child(tmp, "connection")) != NULL) { @@ -375,11 +411,19 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch } switch_time_exp_lt(&tm, time); - av_value = switch_mprintf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, - tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600); + if ( GLOBAL_TIME_FORMAT == 1 ) { + av_value = switch_mprintf("%02u:%02u:%02u.%03u %s %s %s %02u %04u", + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec/1000, + GLOBAL_TIME_ZONE, radattrdays[tm.tm_wday], radattrmonths[tm.tm_mon], + tm.tm_mday, tm.tm_year + 1900); + } else { + av_value = switch_mprintf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, + tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600); + } + if (rc_avpair_add(handle, send, attr_num, av_value, -1, vend_num) == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n"); goto err; @@ -397,12 +441,19 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch } switch_time_exp_lt(&tm, time); - - av_value = switch_mprintf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, - tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600); - + + if ( GLOBAL_TIME_FORMAT == 1 ) { + av_value = switch_mprintf("%02u:%02u:%02u.%03u %s %s %s %02u %04u", + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec/1000, + GLOBAL_TIME_ZONE, radattrdays[tm.tm_wday], radattrmonths[tm.tm_mon], + tm.tm_mday, tm.tm_year + 1900); + } else { + av_value = switch_mprintf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, + tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600); + } + if (rc_avpair_add(handle, send, attr_num, av_value, -1, vend_num) == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n"); goto err; @@ -424,12 +475,19 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch } switch_time_exp_lt(&tm, time); - - av_value = switch_mprintf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, - tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600); - + + if ( GLOBAL_TIME_FORMAT == 1 ) { + av_value = switch_mprintf("%02u:%02u:%02u.%03u MSD %s %s %02u %04u", + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec/1000, + GLOBAL_TIME_FORMAT, radattrdays[tm.tm_wday], radattrmonths[tm.tm_mon], + tm.tm_mday, tm.tm_year + 1900); + } else { + av_value = switch_mprintf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, + tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600); + } + if (rc_avpair_add(handle, send, attr_num, av_value, -1, vend_num) == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n"); goto err; diff --git a/src/switch_channel.c b/src/switch_channel.c index 4bc93573a6..21b9dedc6f 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -139,6 +139,7 @@ typedef enum { struct switch_channel { char *name; switch_call_direction_t direction; + switch_call_direction_t logical_direction; switch_queue_t *dtmf_queue; switch_queue_t *dtmf_log_queue; switch_mutex_t*dtmf_mutex; @@ -240,6 +241,7 @@ static struct switch_callstate_table CALLSTATE_CHART[] = { {"EARLY", CCS_EARLY}, {"ACTIVE", CCS_ACTIVE}, {"HELD", CCS_HELD}, + {"RING_WAIT", CCS_RING_WAIT}, {"HANGUP", CCS_HANGUP}, {"UNHOLD", CCS_UNHOLD}, {NULL, 0} @@ -277,7 +279,11 @@ SWITCH_DECLARE(void) switch_channel_perform_set_callstate(switch_channel_t *chan switch_channel_callstate2str(o_callstate), switch_channel_callstate2str(callstate)); switch_channel_check_device_state(channel, channel->callstate); - + + if (callstate == CCS_HANGUP) { + process_device_hup(channel); + } + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_CALLSTATE) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Original-Channel-Call-State", switch_channel_callstate2str(o_callstate)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Call-State-Number", "%d", callstate); @@ -388,7 +394,7 @@ SWITCH_DECLARE(switch_channel_timetable_t *) switch_channel_get_timetable(switch SWITCH_DECLARE(void) switch_channel_set_direction(switch_channel_t *channel, switch_call_direction_t direction) { if (!switch_core_session_in_thread(channel->session)) { - channel->direction = direction; + channel->direction = channel->logical_direction = direction; } } @@ -397,6 +403,11 @@ SWITCH_DECLARE(switch_call_direction_t) switch_channel_direction(switch_channel_ return channel->direction; } +SWITCH_DECLARE(switch_call_direction_t) switch_channel_logical_direction(switch_channel_t *channel) +{ + return channel->logical_direction; +} + SWITCH_DECLARE(switch_status_t) switch_channel_alloc(switch_channel_t **channel, switch_call_direction_t direction, switch_memory_pool_t *pool) { switch_assert(pool != NULL); @@ -418,7 +429,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_alloc(switch_channel_t **channel, switch_mutex_init(&(*channel)->profile_mutex, SWITCH_MUTEX_NESTED, pool); (*channel)->hangup_cause = SWITCH_CAUSE_NONE; (*channel)->name = ""; - (*channel)->direction = direction; + (*channel)->direction = (*channel)->logical_direction = direction; switch_channel_set_variable(*channel, "direction", switch_channel_direction(*channel) == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound"); return SWITCH_STATUS_SUCCESS; @@ -1753,6 +1764,24 @@ SWITCH_DECLARE(void) switch_channel_set_flag_value(switch_channel_t *channel, sw channel->flags[flag] = value; switch_mutex_unlock(channel->flag_mutex); + if (flag == CF_ORIGINATOR && switch_channel_test_flag(channel, CF_ANSWERED) && switch_channel_up_nosig(channel)) { + switch_channel_set_callstate(channel, CCS_RING_WAIT); + } + + if (flag == CF_DIALPLAN) { + if (channel->direction == SWITCH_CALL_DIRECTION_INBOUND) { + channel->logical_direction = SWITCH_CALL_DIRECTION_OUTBOUND; + if (channel->device_node) { + channel->device_node->direction = SWITCH_CALL_DIRECTION_INBOUND; + } + } else { + channel->logical_direction = SWITCH_CALL_DIRECTION_INBOUND; + if (channel->device_node) { + channel->device_node->direction = SWITCH_CALL_DIRECTION_OUTBOUND; + } + } + } + if (HELD) { switch_hold_record_t *hr; const char *brto = switch_channel_get_partner_uuid(channel); @@ -1921,6 +1950,15 @@ SWITCH_DECLARE(void) switch_channel_clear_flag(switch_channel_t *channel, switch channel->flags[flag] = 0; switch_mutex_unlock(channel->flag_mutex); + if (flag == CF_DIALPLAN) { + if (channel->direction == SWITCH_CALL_DIRECTION_OUTBOUND) { + channel->logical_direction = SWITCH_CALL_DIRECTION_OUTBOUND; + if (channel->device_node) { + channel->device_node->direction = SWITCH_CALL_DIRECTION_INBOUND; + } + } + } + if (ACTIVE) { switch_channel_set_callstate(channel, CCS_UNHOLD); switch_mutex_lock(channel->profile_mutex); @@ -1935,6 +1973,10 @@ SWITCH_DECLARE(void) switch_channel_clear_flag(switch_channel_t *channel, switch switch_mutex_unlock(channel->profile_mutex); } + if (flag == CF_ORIGINATOR && switch_channel_test_flag(channel, CF_ANSWERED) && switch_channel_up_nosig(channel)) { + switch_channel_set_callstate(channel, CCS_ACTIVE); + } + if (flag == CF_OUTBOUND) { switch_channel_set_variable(channel, "is_outbound", NULL); } @@ -2602,6 +2644,7 @@ SWITCH_DECLARE(void) switch_channel_set_caller_profile(switch_channel_t *channel switch_assert(caller_profile != NULL); caller_profile->direction = channel->direction; + caller_profile->logical_direction = channel->logical_direction; uuid = switch_core_session_get_uuid(channel->session); if (!caller_profile->uuid || strcasecmp(caller_profile->uuid, uuid)) { @@ -2684,6 +2727,7 @@ SWITCH_DECLARE(void) switch_channel_set_hunt_caller_profile(switch_channel_t *ch channel->caller_profile->hunt_caller_profile = NULL; if (channel->caller_profile && caller_profile) { caller_profile->direction = channel->direction; + caller_profile->logical_direction = channel->logical_direction; channel->caller_profile->hunt_caller_profile = caller_profile; } switch_mutex_unlock(channel->profile_mutex); @@ -3137,8 +3181,6 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_hangup(switch_chan channel->state = CS_HANGUP; switch_mutex_unlock(channel->state_mutex); - process_device_hup(channel); - channel->hangup_cause = hangup_cause; switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_channel_get_uuid(channel), SWITCH_LOG_NOTICE, "Hangup %s [%s] [%s]\n", channel->name, state_names[last_state], switch_channel_cause2str(channel->hangup_cause)); @@ -4664,28 +4706,73 @@ static void fetch_device_stats(switch_device_record_t *drec) { switch_device_node_t *np; + memset(&drec->stats, 0, sizeof(switch_device_stats_t)); switch_mutex_lock(drec->mutex); for(np = drec->uuid_list; np; np = np->next) { drec->stats.total++; + if (np->direction == SWITCH_CALL_DIRECTION_INBOUND) { + drec->stats.total_in++; + } else { + drec->stats.total_out++; + } if (!np->hup_profile) { drec->stats.offhook++; + if (np->direction == SWITCH_CALL_DIRECTION_INBOUND) { + drec->stats.offhook_in++; + } else { + drec->stats.offhook_out++; + } if (np->callstate == CCS_HELD) { drec->stats.held++; + if (np->direction == SWITCH_CALL_DIRECTION_INBOUND) { + drec->stats.held_in++; + } else { + drec->stats.held_out++; + } } else { if (np->callstate == CCS_EARLY) { drec->stats.early++; + if (np->direction == SWITCH_CALL_DIRECTION_INBOUND) { + drec->stats.early_in++; + } else { + drec->stats.early_out++; + } } else if (np->callstate == CCS_RINGING) { drec->stats.ringing++; + if (np->direction == SWITCH_CALL_DIRECTION_INBOUND) { + drec->stats.ringing_in++; + } else { + drec->stats.ringing_out++; + } + } else if (np->callstate == CCS_RING_WAIT) { + drec->stats.ring_wait++; + } else if (np->callstate == CCS_HANGUP) { + drec->stats.hup++; + if (np->direction == SWITCH_CALL_DIRECTION_INBOUND) { + drec->stats.hup_in++; + } else { + drec->stats.hup_out++; + } } else if (np->callstate != CCS_DOWN) { drec->stats.active++; + if (np->direction == SWITCH_CALL_DIRECTION_INBOUND) { + drec->stats.active_in++; + } else { + drec->stats.active_out++; + } } } } else { drec->stats.hup++; + if (np->direction == SWITCH_CALL_DIRECTION_INBOUND) { + drec->stats.hup_in++; + } else { + drec->stats.hup_out++; + } } } switch_mutex_unlock(drec->mutex); @@ -4826,7 +4913,7 @@ static void switch_channel_check_device_state(switch_channel_t *channel, switch_ drec->state = SDS_HANGUP; } else { if (drec->stats.active == 0) { - if ((drec->stats.ringing + drec->stats.early) > 0) { + if ((drec->stats.ringing_out + drec->stats.early_out) > 0 || drec->stats.ring_wait > 0) { drec->state = SDS_RINGING; } else { if (drec->stats.held > 0) { @@ -4848,22 +4935,47 @@ static void switch_channel_check_device_state(switch_channel_t *channel, switch_ return; } + if (!drec->call_start) { + drec->call_start = switch_micro_time_now(); + } + switch(drec->state) { + case SDS_RINGING: + if (!drec->ring_start) { + drec->ring_start = switch_micro_time_now(); + drec->ring_stop = 0; + } + break; case SDS_ACTIVE: case SDS_ACTIVE_MULTI: - if (drec->last_state != SDS_HELD && drec->active_start) { - drec->active_stop = switch_micro_time_now(); - } else if (!drec->active_start) { + if (!drec->active_start) { drec->active_start = switch_micro_time_now(); + drec->active_stop = 0; + } + break; + case SDS_HELD: + if (!drec->hold_start) { + drec->hold_start = switch_micro_time_now(); + drec->hold_stop = 0; } break; default: - if (drec->last_state != SDS_HELD) { - drec->active_stop = switch_micro_time_now(); - } break; } + if (drec->active_start && drec->state != SDS_ACTIVE && drec->state != SDS_ACTIVE_MULTI) { + drec->active_stop = switch_micro_time_now(); + } + + if (drec->ring_start && !drec->ring_stop && drec->state != SDS_RINGING) { + drec->ring_stop = switch_micro_time_now(); + } + + if (drec->hold_start && !drec->hold_stop && drec->state != SDS_HELD) { + drec->hold_stop = switch_micro_time_now(); + } + + if (switch_event_create(&event, SWITCH_EVENT_DEVICE_STATE) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Device-ID", drec->device_id); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Last-Device-State", switch_channel_device_state2str(drec->last_state)); @@ -4884,7 +4996,8 @@ static void switch_channel_check_device_state(switch_channel_t *channel, switch_ } switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, - "%s device: %s\nState: %s Dev State: %s/%s Total:%u Offhook:%u Ringing:%u Early:%u Active:%u Held:%u Hungup:%u Dur: %u %s\n", + "%s device: %s\nState: %s Dev State: %s/%s Total:%u Offhook:%u " + "Ringing:%u Early:%u Active:%u Held:%u Hungup:%u Dur: %u Ringtime: %u Holdtime: %u %s\n", switch_channel_get_name(channel), drec->device_id, switch_channel_callstate2str(callstate), @@ -4898,12 +5011,16 @@ static void switch_channel_check_device_state(switch_channel_t *channel, switch_ drec->stats.held, drec->stats.hup, drec->active_stop ? (uint32_t)(drec->active_stop - drec->active_start) / 1000 : 0, + drec->ring_stop ? (uint32_t)(drec->ring_stop - drec->ring_start) / 1000 : 0, + drec->hold_stop ? (uint32_t)(drec->hold_stop - drec->hold_start) / 1000 : 0, switch_channel_test_flag(channel, CF_FINAL_DEVICE_LEG) ? "FINAL LEG" : ""); for (ptr = globals.device_bindings; ptr; ptr = ptr->next) { ptr->function(channel->session, callstate, drec); } + drec->last_stats = drec->stats; + if (drec->active_stop) { drec->active_start = drec->active_stop = 0; if (drec->state == SDS_ACTIVE || drec->state == SDS_ACTIVE_MULTI) { @@ -4911,6 +5028,20 @@ static void switch_channel_check_device_state(switch_channel_t *channel, switch_ } } + if (drec->hold_stop) { + drec->hold_start = drec->hold_stop = 0; + if (drec->state == SDS_HELD) { + drec->hold_start = switch_micro_time_now(); + } + } + + if (drec->ring_stop) { + drec->ring_start = drec->ring_stop = 0; + if (drec->state == SDS_RINGING) { + drec->ring_start = switch_micro_time_now(); + } + } + drec->last_call_time = switch_micro_time_now(); drec->last_state = drec->state; @@ -4938,6 +5069,8 @@ static void add_uuid(switch_device_record_t *drec, switch_channel_t *channel) node->uuid = switch_core_strdup(drec->pool, switch_core_session_get_uuid(channel->session)); node->parent = drec; node->callstate = channel->callstate; + node->direction = channel->logical_direction == SWITCH_CALL_DIRECTION_INBOUND ? SWITCH_CALL_DIRECTION_OUTBOUND : SWITCH_CALL_DIRECTION_INBOUND; + channel->device_node = node; if (!drec->uuid_list) { diff --git a/src/switch_core_io.c b/src/switch_core_io.c index 47f6289a73..b1b42c7f1f 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -295,6 +295,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi switch_thread_rwlock_rdlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { + ok = SWITCH_TRUE; + if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) { continue; } @@ -357,6 +359,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi if (session->bugs && switch_test_flag((*frame), SFF_CNG)) { switch_thread_rwlock_rdlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { + ok = SWITCH_TRUE; + if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) { continue; } @@ -651,6 +655,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi switch_thread_rwlock_rdlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { + ok = SWITCH_TRUE; + if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) { continue; } @@ -700,6 +706,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi switch_thread_rwlock_rdlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { + ok = SWITCH_TRUE; + if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) { continue; } @@ -866,6 +874,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi int prune = 0; switch_thread_rwlock_rdlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { + ok = SWITCH_TRUE; + if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) { continue; } @@ -936,6 +946,8 @@ static switch_status_t perform_write(switch_core_session_t *session, switch_fram switch_thread_rwlock_rdlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { + ok = SWITCH_TRUE; + if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) { continue; } @@ -1237,6 +1249,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess switch_thread_rwlock_rdlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { switch_bool_t ok = SWITCH_TRUE; + if (!bp->ready) { continue; } diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 322d4a63da..d18b648546 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -73,6 +73,7 @@ typedef struct codec_params_s { char *iananame; switch_payload_t pt; unsigned long rm_rate; + unsigned long adv_rm_rate; uint32_t codec_ms; uint32_t bitrate; @@ -192,13 +193,13 @@ struct switch_media_handle_s { }; -static int get_channels(const switch_codec_implementation_t *imp) +static int get_channels(const char *name, int dft) { - if (!strcasecmp(imp->iananame, "opus")) { + if (!strcasecmp(name, "opus")) { return 2; /* IKR???*/ } - return imp->number_of_channels; + return dft ? dft : 1; } static void _switch_core_media_pass_zrtp_hash2(switch_core_session_t *aleg_session, switch_core_session_t *bleg_session, switch_media_type_t type) @@ -1436,6 +1437,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session engine->codec_params.rm_encoding = switch_core_session_strdup(smh->session, imp->iananame); engine->codec_params.rm_fmtp = NULL; engine->codec_params.rm_rate = imp->samples_per_second; + engine->codec_params.adv_rm_rate = imp->samples_per_second; + if (strcasecmp(imp->iananame, "g722")) { + engine->codec_params.rm_rate = imp->actual_samples_per_second; + } engine->codec_params.codec_ms = imp->microseconds_per_packet / 1000; engine->codec_params.bitrate = imp->bits_per_second; engine->codec_params.channels = 1; @@ -2799,9 +2804,6 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s if (!strcasecmp(attr->a_name, "fingerprint") && !zstr(attr->a_value)) { got_crypto = 1; - if (sdp_type == SDP_TYPE_REQUEST) { - switch_channel_set_variable(session->channel, "answer_delay", "2500"); - } } } } @@ -2983,6 +2985,8 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s const switch_codec_implementation_t *imp = codec_array[i]; uint32_t bit_rate = imp->bits_per_second; uint32_t codec_rate = imp->samples_per_second; + char *samp = NULL; + if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) { continue; } @@ -3009,24 +3013,41 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s match = 0; } + if (!zstr(map->rm_fmtp)) { + samp = strstr(map->rm_fmtp, "samplerate="); + } + if (!strcasecmp(map->rm_encoding, "opus") && !strcasecmp(rm_encoding, imp->iananame) && samp) { + char *rate_str = samp + 11; + + if (rate_str && *rate_str) { + near_rate = atoi(rate_str); + near_match = imp; + near_map = mmap = map; + match = 0; + goto near_match; + } + } + if (match) { if (scrooge) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Bah HUMBUG! Sticking with %s@%uh@%ui\n", imp->iananame, imp->samples_per_second, imp->microseconds_per_packet / 1000); - } else if (!near_match) { - if ((ptime && codec_ms && codec_ms * 1000 != imp->microseconds_per_packet) || map->rm_rate != codec_rate) { + } else if ((ptime && codec_ms && codec_ms * 1000 != imp->microseconds_per_packet) || map->rm_rate != codec_rate) { + /* ptime does not match */ + match = 0; + + /* save first near_match */ + if (!near_match) { near_rate = map->rm_rate; near_match = imp; near_map = mmap = map; - match = 0; if (switch_true(switch_channel_get_variable_dup(channel, "rtp_negotiate_near_match", SWITCH_FALSE, -1))) { goto near_match; } - - continue; } + continue; } mimp = imp; mmap = map; @@ -3061,10 +3082,8 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s if (num) { mimp = search[0]; - mmap = map; } else { mimp = near_match; - mmap = map; } if (!maxptime || mimp->microseconds_per_packet / 1000 <= maxptime) { @@ -3087,6 +3106,10 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s a_engine->codec_params.iananame = switch_core_session_strdup(session, (char *) mimp->iananame); a_engine->codec_params.pt = (switch_payload_t) mmap->rm_pt; a_engine->codec_params.rm_rate = mimp->samples_per_second; + a_engine->codec_params.adv_rm_rate = mimp->samples_per_second; + if (strcasecmp(mimp->iananame, "g722")) { + a_engine->codec_params.rm_rate = mimp->actual_samples_per_second; + } a_engine->codec_params.codec_ms = mimp->microseconds_per_packet / 1000; a_engine->codec_params.bitrate = mimp->bits_per_second; a_engine->codec_params.channels = mmap->rm_params ? atoi(mmap->rm_params) : 1; @@ -3346,7 +3369,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s SWITCH_DECLARE(int) switch_core_media_toggle_hold(switch_core_session_t *session, int sendonly) { int changed = 0; - switch_rtp_engine_t *a_engine;//, *v_engine; + switch_rtp_engine_t *a_engine, *v_engine; switch_media_handle_t *smh; switch_core_session_t *b_session = NULL; switch_channel_t *b_channel = NULL; @@ -3358,7 +3381,7 @@ SWITCH_DECLARE(int) switch_core_media_toggle_hold(switch_core_session_t *session } a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO]; - //v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO]; + v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO]; if (switch_core_session_get_partner(session, &b_session) == SWITCH_STATUS_SUCCESS) { @@ -3386,6 +3409,11 @@ SWITCH_DECLARE(int) switch_core_media_toggle_hold(switch_core_session_t *session msg = "hold-private"; } } + + switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE); + if (v_engine->rtp_session) { + switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE); + } switch_channel_set_flag(session->channel, CF_PROTO_HOLD); switch_channel_mark_hold(session->channel, SWITCH_TRUE); @@ -3418,6 +3446,12 @@ SWITCH_DECLARE(int) switch_core_media_toggle_hold(switch_core_session_t *session if (switch_channel_test_flag(session->channel, CF_HOLD_LOCK)) { switch_channel_set_flag(session->channel, CF_PROTO_HOLD); switch_channel_mark_hold(session->channel, SWITCH_TRUE); + + switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE); + if (v_engine->rtp_session) { + switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE); + } + changed = 1; } @@ -3445,6 +3479,12 @@ SWITCH_DECLARE(int) switch_core_media_toggle_hold(switch_core_session_t *session switch_channel_clear_flag(session->channel, CF_PROTO_HOLD); switch_channel_mark_hold(session->channel, SWITCH_FALSE); switch_channel_presence(session->channel, "unknown", "unhold", NULL); + + switch_rtp_clear_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE); + if (v_engine->rtp_session) { + switch_rtp_clear_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE); + } + changed = 1; } } @@ -5164,7 +5204,7 @@ static void generate_m(switch_core_session_t *session, char *buf, size_t buflen, } if (smh->ianacodes[i] > 95 || switch_channel_test_flag(session->channel, CF_VERBOSE_SDP)) { - int channels = get_channels(imp); + int channels = get_channels(imp->iananame, imp->number_of_channels); if (channels > 1) { switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d %s/%d/%d\n", smh->ianacodes[i], imp->iananame, rate, channels); @@ -5644,11 +5684,11 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "\n"); - rate = a_engine->codec_params.rm_rate; + rate = a_engine->codec_params.adv_rm_rate; - //if (!strcasecmp(a_engine->codec_params.rm_encoding, "opus")) { - // a_engine->codec_params.adv_channels = 2; - //} + if (!a_engine->codec_params.adv_channels) { + a_engine->codec_params.adv_channels = get_channels(a_engine->codec_params.rm_encoding, 1); + } if (a_engine->codec_params.adv_channels > 1) { switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d/%d\n", @@ -6023,7 +6063,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess rate = imp->samples_per_second; } - channels = get_channels(imp); + channels = get_channels(imp->iananame, imp->number_of_channels); if (!strcasecmp(imp->iananame, "VP8")) { vp8 = ianacode; @@ -6439,6 +6479,7 @@ SWITCH_DECLARE(void) switch_core_media_patch_sdp(switch_core_session_t *session) } a_engine->codec_params.iananame = switch_core_session_strdup(session, "PROXY"); a_engine->codec_params.rm_rate = 8000; + a_engine->codec_params.adv_rm_rate = 8000; a_engine->codec_params.codec_ms = 20; } @@ -6467,11 +6508,11 @@ SWITCH_DECLARE(void) switch_core_media_patch_sdp(switch_core_session_t *session) strncpy(q, p, 7); p += 7; q += 7; - strncpy(q, strchr(a_engine->codec_params.local_sdp_ip, ':') ? "6 " : "4 ", 2); + strncpy(q, strchr(a_engine->codec_params.adv_sdp_ip, ':') ? "6 " : "4 ", 2); p +=2; q +=2; - strncpy(q, a_engine->codec_params.local_sdp_ip, strlen(a_engine->codec_params.local_sdp_ip)); - q += strlen(a_engine->codec_params.local_sdp_ip); + strncpy(q, a_engine->codec_params.adv_sdp_ip, strlen(a_engine->codec_params.adv_sdp_ip)); + q += strlen(a_engine->codec_params.adv_sdp_ip); while (p && *p && ((*p >= '0' && *p <= '9') || *p == '.' || *p == ':' || (*p >= 'A' && *p <= 'F') || (*p >= 'a' && *p <= 'f'))) { if (p >= pe) { @@ -6584,6 +6625,7 @@ SWITCH_DECLARE(void) switch_core_media_patch_sdp(switch_core_session_t *session) switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_VIDEO, 1); v_engine->codec_params.rm_encoding = "PROXY-VID"; v_engine->codec_params.rm_rate = 90000; + v_engine->codec_params.adv_rm_rate = 90000; v_engine->codec_params.codec_ms = 0; switch_snprintf(vport_buf, sizeof(vport_buf), "%u", v_engine->codec_params.adv_sdp_port); if (switch_channel_media_ready(session->channel) && !switch_rtp_ready(v_engine->rtp_session)) { @@ -6937,7 +6979,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se if (ok) { switch_rtp_clear_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_USE_TIMER); - switch_rtp_clear_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_NOBLOCK); + //switch_rtp_clear_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_NOBLOCK); switch_channel_set_flag(session->channel, CF_NOTIMER_DURING_BRIDGE); } @@ -6985,7 +7027,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se if (!switch_rtp_test_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_UDPTL) && !switch_rtp_test_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA)) { switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_USE_TIMER); - switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_NOBLOCK); + //switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_NOBLOCK); } switch_channel_clear_flag(session->channel, CF_NOTIMER_DURING_BRIDGE); } @@ -7686,6 +7728,7 @@ SWITCH_DECLARE(void) switch_core_media_check_outgoing_proxy(switch_core_session_ a_engine->codec_params.iananame = switch_core_session_strdup(session, "PROXY"); a_engine->codec_params.rm_rate = 8000; + a_engine->codec_params.adv_rm_rate = 8000; a_engine->codec_params.codec_ms = 20; @@ -7693,6 +7736,7 @@ SWITCH_DECLARE(void) switch_core_media_check_outgoing_proxy(switch_core_session_ switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_VIDEO, 1); v_engine->codec_params.rm_encoding = "PROXY-VID"; v_engine->codec_params.rm_rate = 90000; + v_engine->codec_params.adv_rm_rate = 90000; v_engine->codec_params.codec_ms = 0; switch_channel_set_flag(session->channel, CF_VIDEO); switch_channel_set_flag(session->channel, CF_VIDEO_POSSIBLE); @@ -7764,6 +7808,7 @@ SWITCH_DECLARE(void) switch_core_media_proxy_codec(switch_core_session_t *sessio for (map = m->m_rtpmaps; map; map = map->rm_next) { a_engine->codec_params.iananame = switch_core_session_strdup(session, map->rm_encoding); a_engine->codec_params.rm_rate = map->rm_rate; + a_engine->codec_params.adv_rm_rate = map->rm_rate; a_engine->codec_params.codec_ms = ptime; switch_core_media_set_codec(session, 0, smh->mparams->codec_flags); break; @@ -7841,6 +7886,7 @@ SWITCH_DECLARE (void) switch_core_media_recover_session(switch_core_session_t *s if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_codec_rate"))) { a_engine->codec_params.rm_rate = atoi(tmp); + a_engine->codec_params.adv_rm_rate = a_engine->codec_params.rm_rate; } if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_codec_ptime"))) { @@ -7895,6 +7941,7 @@ SWITCH_DECLARE (void) switch_core_media_recover_session(switch_core_session_t *s if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_video_codec_rate"))) { v_engine->codec_params.rm_rate = atoi(tmp); + v_engine->codec_params.adv_rm_rate = v_engine->codec_params.rm_rate; } if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_video_codec_ptime"))) { diff --git a/src/switch_core_session.c b/src/switch_core_session.c index a08b548fee..63aab9d583 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -264,12 +264,14 @@ SWITCH_DECLARE(switch_console_callback_match_t *) switch_core_session_findall_ma switch_memory_pool_t *pool; struct str_node *head = NULL, *np; switch_console_callback_match_t *my_matches = NULL; + const char *like = NULL; + + if (var_val && *var_val == '~') { + like = var_val + 1; + } switch_core_new_memory_pool(&pool); - if (!var_val) - return NULL; - switch_mutex_lock(runtime.session_hash_mutex); for (hi = switch_hash_first(NULL, session_manager.session_table); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, NULL, NULL, &val); @@ -290,7 +292,8 @@ SWITCH_DECLARE(switch_console_callback_match_t *) switch_core_session_findall_ma if ((session = switch_core_session_locate(np->str))) { const char *this_val; if (switch_channel_up_nosig(session->channel) && - (this_val = switch_channel_get_variable_dup(session->channel, var_name, SWITCH_FALSE, -1)) && (!strcmp(this_val, var_val))) { + (this_val = switch_channel_get_variable_dup(session->channel, var_name, SWITCH_FALSE, -1)) && + (!var_val || (like && switch_stristr(like, var_val)) || !strcmp(this_val, var_val))) { switch_console_push_match(&my_matches, (const char *) np->str); } switch_core_session_rwunlock(session); diff --git a/src/switch_event.c b/src/switch_event.c index 0a0a532628..48743a7c30 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -3055,6 +3055,7 @@ struct switch_live_array_s { switch_live_array_command_handler_t command_handler; void *user_data; alias_node_t *aliases; + int refs; }; static switch_status_t la_broadcast(switch_live_array_t *la, cJSON **json) @@ -3215,9 +3216,21 @@ SWITCH_DECLARE(switch_status_t) switch_live_array_destroy(switch_live_array_t ** switch_live_array_t *la = *live_arrayP; switch_memory_pool_t *pool; alias_node_t *np; + int done = 0; *live_arrayP = NULL; + switch_mutex_lock(la->mutex); + if (la->refs) { + la->refs--; + } + if (la->refs) done = 1; + switch_mutex_unlock(la->mutex); + + if (done) { + return SWITCH_STATUS_SUCCESS; + } + pool = la->pool; switch_live_array_clear(la); @@ -3311,7 +3324,6 @@ SWITCH_DECLARE(switch_bool_t) switch_live_array_add_alias(switch_live_array_t *l return !exist; } - SWITCH_DECLARE(switch_status_t) switch_live_array_create(const char *event_channel, const char *name, switch_event_channel_id_t channel_id, switch_live_array_t **live_arrayP) { @@ -3346,6 +3358,10 @@ SWITCH_DECLARE(switch_status_t) switch_live_array_create(const char *event_chann switch_mutex_unlock(event_channel_manager.lamutex); } + switch_mutex_lock(la->mutex); + la->refs++; + switch_mutex_unlock(la->mutex); + *live_arrayP = la; return SWITCH_STATUS_SUCCESS; @@ -3559,14 +3575,16 @@ SWITCH_DECLARE(void) switch_live_array_parse_json(cJSON *json, switch_event_chan const char *sessid = cJSON_GetObjectCstr(json, "sessid"); if (command) { - switch_live_array_create(context, name, channel_id, &la); + if (switch_live_array_create(context, name, channel_id, &la) == SWITCH_STATUS_SUCCESS) { - if (!strcasecmp(command, "bootstrap")) { - switch_live_array_bootstrap(la, sessid, channel_id); - } else { - if (la->command_handler) { - la->command_handler(la, command, sessid, jla, la->user_data); + if (!strcasecmp(command, "bootstrap")) { + switch_live_array_bootstrap(la, sessid, channel_id); + } else { + if (la->command_handler) { + la->command_handler(la, command, sessid, jla, la->user_data); + } } + switch_live_array_destroy(&la); } } } diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index 356e03f43d..089301da0e 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -1695,6 +1695,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(const char *originator_uu } } + if (switch_channel_direction(originatee_channel) == SWITCH_CALL_DIRECTION_OUTBOUND && switch_channel_test_flag(originatee_channel, CF_DIALPLAN)) { + switch_channel_clear_flag(originatee_channel, CF_DIALPLAN); + } + cleanup_proxy_mode_a(originator_session); cleanup_proxy_mode_a(originatee_session); diff --git a/src/switch_rtp.c b/src/switch_rtp.c index ff621e1826..4d644adf0c 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -1890,21 +1890,22 @@ static switch_status_t enable_remote_rtcp_socket(switch_rtp_t *rtp_session, cons "Setting RTCP remote addr to %s:%d\n", host, rtp_session->remote_rtcp_port); } - if (!(rtp_session->rtcp_sock_input && rtp_session->rtcp_sock_output)) { - if (rtp_session->rtcp_sock_input && switch_sockaddr_get_family(rtp_session->rtcp_remote_addr) == - switch_sockaddr_get_family(rtp_session->rtcp_local_addr)) { - rtp_session->rtcp_sock_output = rtp_session->rtcp_sock_input; - } else { - if (rtp_session->rtcp_sock_output && rtp_session->rtcp_sock_output != rtp_session->rtcp_sock_input) { - switch_socket_close(rtp_session->rtcp_sock_output); - } - if ((status = switch_socket_create(&rtp_session->rtcp_sock_output, - switch_sockaddr_get_family(rtp_session->rtcp_remote_addr), - SOCK_DGRAM, 0, rtp_session->pool)) != SWITCH_STATUS_SUCCESS) { - *err = "RTCP Socket Error!"; - } + if (rtp_session->rtcp_sock_input && switch_sockaddr_get_family(rtp_session->rtcp_remote_addr) == + switch_sockaddr_get_family(rtp_session->rtcp_local_addr)) { + rtp_session->rtcp_sock_output = rtp_session->rtcp_sock_input; + } else { + + if (rtp_session->rtcp_sock_output && rtp_session->rtcp_sock_output != rtp_session->rtcp_sock_input) { + switch_socket_close(rtp_session->rtcp_sock_output); + } + + if ((status = switch_socket_create(&rtp_session->rtcp_sock_output, + switch_sockaddr_get_family(rtp_session->rtcp_remote_addr), + SOCK_DGRAM, 0, rtp_session->pool)) != SWITCH_STATUS_SUCCESS) { + *err = "RTCP Socket Error!"; } } + } else { *err = "RTCP NOT ACTIVE!"; } @@ -2510,12 +2511,42 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_del_dtls(switch_rtp_t *rtp_session, d if (rtp_session->dtls) { free_dtls(&rtp_session->dtls); } + + if (rtp_session->jb) { + stfu_n_reset(rtp_session->jb); + } + } if ((type & DTLS_TYPE_RTCP) && rtp_session->rtcp_dtls) { free_dtls(&rtp_session->rtcp_dtls); } + +#ifdef ENABLE_SRTP + if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_SEND]) { + int x; + for(x = 0; x < 2; x++) { + if (rtp_session->send_ctx[x]) { + srtp_dealloc(rtp_session->send_ctx[x]); + rtp_session->send_ctx[x] = NULL; + } + } + rtp_session->flags[SWITCH_RTP_FLAG_SECURE_SEND] = 0; + } + + if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV]) { + int x; + for (x = 0; x < 2; x++) { + if (rtp_session->recv_ctx[x]) { + srtp_dealloc(rtp_session->recv_ctx[x]); + rtp_session->recv_ctx[x] = NULL; + } + } + rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV] = 0; + } +#endif + return SWITCH_STATUS_SUCCESS; } @@ -2560,7 +2591,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d dtls->pvt = switch_core_sprintf(rtp_session->pool, "%s%s%s.key", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR, DTLS_SRTP_FNAME); dtls->rsa = switch_core_sprintf(rtp_session->pool, "%s%s%s.crt", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR, DTLS_SRTP_FNAME); - //dtls->ca = switch_core_sprintf(rtp_session->pool, "%s%sca-bundle.crt", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR); + dtls->ca = switch_core_sprintf(rtp_session->pool, "%s%sca-bundle.crt", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR); dtls->ssl_ctx = SSL_CTX_new(DTLSv1_method()); switch_assert(dtls->ssl_ctx); @@ -2603,7 +2634,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d return SWITCH_STATUS_FALSE; } - if (!zstr(dtls->ca) && (ret=SSL_CTX_load_verify_locations(dtls->ssl_ctx, dtls->ca, NULL)) != 1) { + if (!zstr(dtls->ca) && switch_file_exists(dtls->ca, rtp_session->pool) == SWITCH_STATUS_SUCCESS + && (ret = SSL_CTX_load_verify_locations(dtls->ssl_ctx, dtls->ca, NULL)) != 1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "%s DTLS check chain cert failed [%d]\n", rtp_type(rtp_session) , SSL_get_error(dtls->ssl, ret)); @@ -2964,7 +2996,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session "Starting timer [%s] %d bytes per %dms\n", timer_name, samples_per_interval, ms_per_packet / 1000); } else { memset(&rtp_session->timer, 0, sizeof(rtp_session->timer)); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "Error starting timer [%s], async RTP disabled\n", timer_name); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, + "Error Starting timer [%s] %d bytes per %dms, async RTP disabled\n", timer_name, samples_per_interval, ms_per_packet / 1000); switch_rtp_clear_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER); } } else { @@ -3360,7 +3393,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_sessio ice->ice_params = ice_params; ice->pass = ""; ice->rpass = ""; - + ice->ready = 0; + ice->rready = 0; ice->next_run = switch_micro_time_now(); if (password) { @@ -4014,6 +4048,21 @@ static void do_flush(switch_rtp_t *rtp_session, int force) READ_DEC(rtp_session); } +static int jb_valid(switch_rtp_t *rtp_session) +{ + if (rtp_session->ice.ice_user) { + if (!rtp_session->ice.ready && rtp_session->ice.rready) { + return 0; + } + } + + if (rtp_session->dtls && rtp_session->dtls->state != DS_READY) { + return 0; + } + + return 1; +} + #define return_cng_frame() do_cng = 1; goto timer_check static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t *bytes, switch_frame_flag_t *flags, switch_bool_t return_jb_packet) @@ -4157,14 +4206,13 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t if (!rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA] && !rtp_session->flags[SWITCH_RTP_FLAG_UDPTL] && rtp_session->recv_msg.header.version == 2 && rtp_session->recv_msg.header.x) { /* header extensions */ + uint16_t length; rtp_session->recv_msg.ext = (switch_rtp_hdr_ext_t *) rtp_session->recv_msg.body; + length = ntohs((uint16_t)rtp_session->recv_msg.ext->length); - rtp_session->recv_msg.ext->length = ntohs((uint16_t)rtp_session->recv_msg.ext->length); - rtp_session->recv_msg.ext->profile = ntohs((uint16_t)rtp_session->recv_msg.ext->profile); - - if (rtp_session->recv_msg.ext->length < SWITCH_RTP_MAX_BUF_LEN_WORDS) { - rtp_session->recv_msg.ebody = rtp_session->recv_msg.body + (rtp_session->recv_msg.ext->length * 4) + 4; + if (length < SWITCH_RTP_MAX_BUF_LEN_WORDS) { + rtp_session->recv_msg.ebody = rtp_session->recv_msg.body + (length * 4) + 4; } } @@ -4222,7 +4270,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t if (!rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA] && !rtp_session->flags[SWITCH_RTP_FLAG_UDPTL] && !rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && *bytes && (!rtp_session->recv_te || rtp_session->recv_msg.header.pt != rtp_session->recv_te) && - ts && !rtp_session->jb && !rtp_session->pause_jb && ts == rtp_session->last_cng_ts) { + ts && !rtp_session->jb && !rtp_session->pause_jb && jb_valid(rtp_session) && ts == rtp_session->last_cng_ts) { /* we already sent this frame..... */ *bytes = 0; return SWITCH_STATUS_SUCCESS; @@ -4340,7 +4388,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t } - if (rtp_session->jb && !rtp_session->pause_jb && rtp_session->recv_msg.header.version == 2 && *bytes) { + if (rtp_session->jb && !rtp_session->pause_jb && jb_valid(rtp_session) && rtp_session->recv_msg.header.version == 2 && *bytes) { if (rtp_session->recv_msg.header.m && rtp_session->recv_msg.header.pt != rtp_session->recv_te && !rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && !(rtp_session->rtp_bugs & RTP_BUG_IGNORE_MARK_BIT)) { stfu_n_reset(rtp_session->jb); @@ -4365,7 +4413,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t *bytes = 0; } - if (rtp_session->jb && !rtp_session->pause_jb) { + if (rtp_session->jb && !rtp_session->pause_jb && jb_valid(rtp_session)) { if ((jb_frame = stfu_n_read_a_frame(rtp_session->jb))) { memcpy(RTP_BODY(rtp_session), jb_frame->data, jb_frame->dlen); @@ -4545,7 +4593,14 @@ static switch_status_t read_rtcp_packet(switch_rtp_t *rtp_session, switch_size_t return status; } +static int using_ice(switch_rtp_t *rtp_session) +{ + if (rtp_session->ice.ice_user || rtp_session->rtcp_ice.ice_user) { + return 1; + } + return 0; +} static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_type, switch_frame_flag_t *flags, switch_io_flag_t io_flags) { @@ -4693,7 +4748,10 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ pt = 100000; } - + if (using_ice(rtp_session)) { + pt = 20000; + } + poll_status = switch_poll(rtp_session->read_pollfd, 1, &fdr, pt); @@ -4780,20 +4838,19 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ } } - if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) { + if (using_ice(rtp_session)) { if (check_rtcp_and_ice(rtp_session) == -1) { ret = -1; goto end; } - goto recvfrom; - } + } if ((!(io_flags & SWITCH_IO_FLAG_NOBLOCK)) && (rtp_session->dtmf_data.out_digit_dur == 0)) { return_cng_frame(); } } - + rtcp: if (rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP]) { @@ -5749,7 +5806,9 @@ static int rtp_common_write(switch_rtp_t *rtp_session, send = 0; } - + if (rtp_session->flags[SWITCH_RTP_FLAG_PAUSE]) { + send = 0; + } if (send) { send_msg->header.seq = htons(++rtp_session->seq);