diff --git a/docs/phrase/phrase_en.xml b/docs/phrase/phrase_en.xml index fa9f4f7cc8..c9fa47ec59 100644 --- a/docs/phrase/phrase_en.xml +++ b/docs/phrase/phrase_en.xml @@ -590,7 +590,7 @@ - + diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c b/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c index fb478901b3..748b70a42f 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c +++ b/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c @@ -201,7 +201,7 @@ int lpwrap_start_timer(struct lpwrap_pri *spri, struct lpwrap_timer *timer, cons ftdm_mutex_lock(spri->timer_mutex); for (prev = &spri->timer_list, cur = spri->timer_list; cur; prev = &(*prev)->next, cur = cur->next) { - if (cur->timeout < timer->timeout) { + if (cur->timeout > timer->timeout) { *prev = timer; timer->next = cur; break; @@ -238,6 +238,10 @@ int lpwrap_stop_timer(struct lpwrap_pri *spri, struct lpwrap_timer *timer) ftdm_mutex_unlock(spri->timer_mutex); + if (!cur) { + ftdm_log_chan(spri->dchan, FTDM_LOG_WARNING, "-- Timer %p not found in list\n", timer); + } + timer->next = NULL; timer->timeout = 0; timer->callback = NULL; diff --git a/libs/spandsp/src/t31.c b/libs/spandsp/src/t31.c index 8e747c4d0f..01d948e357 100644 --- a/libs/spandsp/src/t31.c +++ b/libs/spandsp/src/t31.c @@ -1689,6 +1689,16 @@ static int restart_modem(t31_state_t *s, int new_modem) } s->at_state.transmit = TRUE; break; + case FAX_MODEM_V21_RX: + if (s->t38_mode) + { + } + else + { + t31_v21_rx(s); + fax_modems_set_rx_handler(t, (span_rx_handler_t) &fsk_rx, &t->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &t->v21_rx); + } + break; case FAX_MODEM_V21_TX: if (s->t38_mode) { @@ -1712,15 +1722,16 @@ static int restart_modem(t31_state_t *s, int new_modem) s->dled = FALSE; s->at_state.transmit = TRUE; break; - case FAX_MODEM_V21_RX: - if (s->t38_mode) - { - } - else + case FAX_MODEM_V17_RX: + case FAX_MODEM_V27TER_RX: + case FAX_MODEM_V29_RX: + if (!s->t38_mode) { + fax_modems_start_fast_modem(t, s->modem, s->bit_rate, s->short_train, use_hdlc); + /* Allow for +FCERROR/+FRH:3 */ t31_v21_rx(s); - fax_modems_set_rx_handler(t, (span_rx_handler_t) &fsk_rx, &t->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &t->v21_rx); } + s->at_state.transmit = FALSE; break; case FAX_MODEM_V17_TX: if (s->t38_mode) @@ -1755,17 +1766,6 @@ static int restart_modem(t31_state_t *s, int new_modem) s->tx.data_started = FALSE; s->at_state.transmit = TRUE; break; - case FAX_MODEM_V17_RX: - case FAX_MODEM_V27TER_RX: - case FAX_MODEM_V29_RX: - if (!s->t38_mode) - { - fax_modems_start_fast_modem(t, s->modem, s->bit_rate, s->short_train, use_hdlc); - /* Allow for +FCERROR/+FRH:3 */ - t31_v21_rx(s); - } - s->at_state.transmit = FALSE; - break; case FAX_MODEM_V27TER_TX: if (s->t38_mode) { diff --git a/libs/spandsp/src/t4_rx.c b/libs/spandsp/src/t4_rx.c index f3b34167b2..c17c377630 100644 --- a/libs/spandsp/src/t4_rx.c +++ b/libs/spandsp/src/t4_rx.c @@ -172,7 +172,7 @@ static int set_tiff_directory_info(t4_rx_state_t *s) } #if defined(SPANDSP_SUPPORT_TIFF_FX) TIFFSetField(t->tiff_file, TIFFTAG_PROFILETYPE, PROFILETYPE_G3_FAX); - TIFFSetField(t->tiff_file, TIFFTAG_FAXPROFILE, FAXPROFILE_S); + TIFFSetField(t->tiff_file, TIFFTAG_FAXPROFILE, FAXPROFILE_F); TIFFSetField(t->tiff_file, TIFFTAG_CODINGMETHODS, CODINGMETHODS_T4_1D | CODINGMETHODS_T4_2D | CODINGMETHODS_T6); TIFFSetField(t->tiff_file, TIFFTAG_VERSIONYEAR, "1998"); /* TIFFSetField(t->tiff_file, TIFFTAG_MODENUMBER, 0); */ @@ -304,10 +304,14 @@ static int write_tiff_image(t4_rx_state_t *s) return -1; /* Set up the TIFF directory info... */ set_tiff_directory_info(s); - /* ...and then write the image... */ + /* ...Put the directory in the file before the image data, to get them in the order specified + for TIFF/F files... */ + if (!TIFFCheckpointDirectory(t->tiff_file)) + span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to checkpoint directory for page %d.\n", t->file, s->current_page); + /* ...and write out the image... */ if (TIFFWriteEncodedStrip(t->tiff_file, 0, t->image_buffer, t->image_size) < 0) span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", t->file); - /* ...then the directory entry, and libtiff is happy. */ + /* ...then finalise the directory entry, and libtiff is happy. */ if (!TIFFWriteDirectory(t->tiff_file)) span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to write directory for page %d.\n", t->file, s->current_page); #if defined(SPANDSP_SUPPORT_TIFF_FX) @@ -316,7 +320,7 @@ static int write_tiff_image(t4_rx_state_t *s) if (!TIFFCreateCustomDirectory(t->tiff_file, &tiff_fx_field_array)) { TIFFSetField(t->tiff_file, TIFFTAG_FAXPROFILE, PROFILETYPE_G3_FAX); - TIFFSetField(t->tiff_file, TIFFTAG_PROFILETYPE, FAXPROFILE_S); + TIFFSetField(t->tiff_file, TIFFTAG_PROFILETYPE, FAXPROFILE_F); TIFFSetField(t->tiff_file, TIFFTAG_VERSIONYEAR, "1998"); offset = 0; diff --git a/libs/spandsp/test-data/etsi/fax/generate_etsi_300_242_pages.c b/libs/spandsp/test-data/etsi/fax/generate_etsi_300_242_pages.c index dda0d0fbc7..9a2a3e971e 100644 --- a/libs/spandsp/test-data/etsi/fax/generate_etsi_300_242_pages.c +++ b/libs/spandsp/test-data/etsi/fax/generate_etsi_300_242_pages.c @@ -623,6 +623,10 @@ int main(int argc, char *argv[]) tm->tm_sec); TIFFSetField(tiff_file, TIFFTAG_DATETIME, buf); image_length = sequence[i].length; + TIFFSetField(tiff_file, TIFFTAG_PAGENUMBER, 0, 1); + TIFFSetField(tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_CLEAN); + TIFFSetField(tiff_file, TIFFTAG_IMAGELENGTH, image_length); + TIFFCheckpointDirectory(tiff_file); /* Write the image first.... */ switch (sequence[i].type) @@ -662,8 +666,6 @@ int main(int argc, char *argv[]) } /* ....then the directory entry, and libtiff is happy. */ TIFFSetField(tiff_file, TIFFTAG_IMAGELENGTH, image_length); - TIFFSetField(tiff_file, TIFFTAG_PAGENUMBER, 0, 1); - TIFFSetField(tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_CLEAN); TIFFWriteDirectory(tiff_file); } diff --git a/libs/spandsp/test-data/itu/fax/generate_dithered_tif.c b/libs/spandsp/test-data/itu/fax/generate_dithered_tif.c index 31c8cb0cc8..03ae0e8602 100644 --- a/libs/spandsp/test-data/itu/fax/generate_dithered_tif.c +++ b/libs/spandsp/test-data/itu/fax/generate_dithered_tif.c @@ -137,6 +137,7 @@ int main(int argc, char *argv[]) TIFFSetField(tiff_file, TIFFTAG_PAGENUMBER, 0, 1); TIFFSetField(tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_CLEAN); TIFFSetField(tiff_file, TIFFTAG_IMAGEWIDTH, image_width); + TIFFCheckpointDirectory(tiff_file); /* Write the image first.... */ for (row = 0; row < image_length; row++) diff --git a/libs/spandsp/test-data/itu/fax/generate_sized_pages.c b/libs/spandsp/test-data/itu/fax/generate_sized_pages.c index bd7e8cdc91..a075f622e5 100644 --- a/libs/spandsp/test-data/itu/fax/generate_sized_pages.c +++ b/libs/spandsp/test-data/itu/fax/generate_sized_pages.c @@ -367,6 +367,7 @@ int main(int argc, char *argv[]) TIFFSetField(tiff_file, TIFFTAG_PAGENUMBER, 0, 1); TIFFSetField(tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_CLEAN); TIFFSetField(tiff_file, TIFFTAG_IMAGEWIDTH, sequence[i].width); + TIFFCheckpointDirectory(tiff_file); /* Write the image first.... */ for (row = 0; row < sequence[i].length; row++) diff --git a/libs/spandsp/test-data/itu/fax/generate_striped_pages.c b/libs/spandsp/test-data/itu/fax/generate_striped_pages.c index 0c3eafd149..63b8e755c7 100644 --- a/libs/spandsp/test-data/itu/fax/generate_striped_pages.c +++ b/libs/spandsp/test-data/itu/fax/generate_striped_pages.c @@ -103,6 +103,7 @@ int main(int argc, char *argv[]) TIFFSetField(tiff_file, TIFFTAG_IMAGEWIDTH, IMAGE_WIDTH); TIFFSetField(tiff_file, TIFFTAG_IMAGELENGTH, IMAGE_LENGTH); TIFFSetField(tiff_file, TIFFTAG_PAGENUMBER, 0, 1); + TIFFCheckpointDirectory(tiff_file); image_size = IMAGE_WIDTH*ROWS_PER_STRIPE/8; memset(image_buffer, 0x18, image_size); diff --git a/libs/spandsp/tests/t42_tests.c b/libs/spandsp/tests/t42_tests.c index 588bfdd3fe..8cddaa18cd 100644 --- a/libs/spandsp/tests/t42_tests.c +++ b/libs/spandsp/tests/t42_tests.c @@ -46,7 +46,7 @@ #include "spandsp.h" #if defined(SPANDSP_SUPPORT_TIFF_FX) -//#include +#include #endif //#define IN_FILE_NAME "../test-data/itu/t24/F21_200.TIF" @@ -156,7 +156,9 @@ int main(int argc, char *argv[]) logging = span_log_init(NULL, SPAN_LOG_FLOW, "T.42"); +#if defined(SPANDSP_SUPPORT_TIFF_FX) TIFF_FX_init(); +#endif set_lab_illuminant(&lab_param, 0.9638f, 1.0f, 0.8245f); set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE); @@ -189,7 +191,7 @@ int main(int argc, char *argv[]) YCbCrSubsampleHoriz = 0; YCbCrSubsampleVert = 0; TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING, &YCbCrSubsampleHoriz, &YCbCrSubsampleVert); - planar_config = 0; + planar_config = PLANARCONFIG_CONTIG; TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planar_config); off = 0; diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 2348a4cc54..f4655a23e6 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -642,6 +642,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_api_on(switch_channel_t *channel, SWITCH_DECLARE(switch_caller_extension_t *) switch_channel_get_queued_extension(switch_channel_t *channel); SWITCH_DECLARE(void) switch_channel_transfer_to_extension(switch_channel_t *channel, switch_caller_extension_t *caller_extension); SWITCH_DECLARE(const char *) switch_channel_get_partner_uuid(switch_channel_t *channel); +SWITCH_DECLARE(switch_hold_record_t *) switch_channel_get_hold_record(switch_channel_t *channel); SWITCH_END_EXTERN_C #endif diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 50ec7a965e..b340078f41 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -61,6 +61,16 @@ struct switch_app_log { struct switch_app_log *next; }; + +typedef struct switch_hold_record_s { + switch_time_t on; + switch_time_t off; + char *uuid; + struct switch_hold_record_s *next; +} switch_hold_record_t; + + + #define MESSAGE_STAMP_FFL(_m) _m->_file = __FILE__; _m->_func = __SWITCH_FUNC__; _m->_line = __LINE__ #define MESSAGE_STRING_ARG_MAX 10 diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 6104999c4c..db9cf5cb0e 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -906,6 +906,7 @@ typedef enum { SWITCH_MESSAGE_INDICATE_AUDIO_DATA, SWITCH_MESSAGE_INDICATE_BLIND_TRANSFER_RESPONSE, SWITCH_MESSAGE_INDICATE_STUN_ERROR, + SWITCH_MESSAGE_INDICATE_MEDIA_RENEG, SWITCH_MESSAGE_INVALID } switch_core_session_message_types_t; diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 19817c83c3..0a6c1d08ce 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -2739,6 +2739,49 @@ SWITCH_STANDARD_API(uuid_media_function) return SWITCH_STATUS_SUCCESS; } +#define MEDIA_RENEG_SYNTAX "[ ]" +SWITCH_STANDARD_API(uuid_media_neg_function) +{ + char *mycmd = NULL, *argv[2] = { 0 }; + int argc = 0; + switch_status_t status = SWITCH_STATUS_FALSE; + + if (!zstr(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } + + if (zstr(cmd) || argc < 1 || zstr(argv[0])) { + stream->write_function(stream, "-USAGE: %s\n", MEDIA_RENEG_SYNTAX); + } else { + switch_core_session_message_t msg = { 0 }; + switch_core_session_t *lsession = NULL; + char *uuid = argv[0]; + + msg.message_id = SWITCH_MESSAGE_INDICATE_MEDIA_RENEG; + msg.string_arg = argv[1]; + msg.from = __FILE__; + + if (*uuid == '+') { + msg.numeric_arg++; + uuid++; + } + + if ((lsession = switch_core_session_locate(uuid))) { + status = switch_core_session_receive_message(lsession, &msg); + switch_core_session_rwunlock(lsession); + } + } + + if (status == SWITCH_STATUS_SUCCESS) { + stream->write_function(stream, "+OK Success\n"); + } else { + stream->write_function(stream, "-ERR Operation Failed\n"); + } + + switch_safe_free(mycmd); + return SWITCH_STATUS_SUCCESS; +} + SWITCH_STANDARD_API(uuid_early_ok_function) { char *uuid = (char *) cmd; @@ -5690,6 +5733,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "uuid_limit_release", "Release limit resource", uuid_limit_release_function, LIMIT_RELEASE_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_loglevel", "set loglevel on session", uuid_loglevel, UUID_LOGLEVEL_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_media", "media", uuid_media_function, MEDIA_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "uuid_media_reneg", "media negotiation", uuid_media_neg_function, MEDIA_RENEG_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_park", "Park Channel", park_function, PARK_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_phone_event", "Send and event to the phone", uuid_phone_event_function, PHONE_EVENT_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_pre_answer", "pre_answer", uuid_pre_answer_function, ""); @@ -5841,6 +5885,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add uuid_media ::console::list_uuid"); switch_console_set_complete("add uuid_media off ::console::list_uuid"); switch_console_set_complete("add uuid_park ::console::list_uuid"); + switch_console_set_complete("add uuid_media_reneg ::console::list_uuid"); switch_console_set_complete("add uuid_phone_event ::console::list_uuid talk"); switch_console_set_complete("add uuid_phone_event ::console::list_uuid hold"); switch_console_set_complete("add uuid_preprocess ::console::list_uuid"); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index b1771dd1f2..aa3f3207d5 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1547,6 +1547,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi case SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH: case SWITCH_MESSAGE_INDICATE_APPLICATION_EXEC: break; + case SWITCH_MESSAGE_INDICATE_PROXY_MEDIA: { if (switch_rtp_ready(tech_pvt->rtp_session)) { @@ -1849,6 +1850,43 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } switch (msg->message_id) { + + case SWITCH_MESSAGE_INDICATE_MEDIA_RENEG: + { + switch_core_session_t *nsession; + + if (msg->string_arg) { + switch_channel_set_variable(channel, "absolute_codec_string", NULL); + if (*msg->string_arg == '=') { + switch_channel_set_variable(channel, "codec_string", msg->string_arg); + } else { + switch_channel_set_variable_printf(channel, "codec_string", "=%s%s%s,%s", + tech_pvt->video_rm_encoding ? tech_pvt->video_rm_encoding : "", + tech_pvt->video_rm_encoding ? "," : "", + tech_pvt->rm_encoding, msg->string_arg); + } + + + tech_pvt->num_codecs = 0; + tech_pvt->rm_encoding = NULL; + tech_pvt->video_rm_encoding = NULL; + sofia_clear_flag_locked(tech_pvt, TFLAG_VIDEO); + sofia_glue_tech_prepare_codecs(tech_pvt); + sofia_glue_check_video_codecs(tech_pvt); + sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 1); + sofia_set_pflag(tech_pvt->profile, PFLAG_RENEG_ON_REINVITE); + } + + sofia_glue_do_invite(session); + + if (msg->numeric_arg && switch_core_session_get_partner(session, &nsession) == SWITCH_STATUS_SUCCESS) { + msg->numeric_arg = 0; + switch_core_session_receive_message(nsession, msg); + switch_core_session_rwunlock(nsession); + } + + } + break; case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ: { const char *pl = ""; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index d1e4a09e73..79a925f4f8 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -1209,11 +1209,13 @@ static void our_sofia_event_callback(nua_event_t event, sofia_handle_sip_i_options(status, phrase, nua, profile, nh, sofia_private, sip, de, tags); break; case nua_i_invite: - if (session && sofia_private->is_call > 1) { - sofia_handle_sip_i_reinvite(session, nua, profile, nh, sofia_private, sip, de, tags); - } else { - sofia_private->is_call++; - sofia_handle_sip_i_invite(session, nua, profile, nh, sofia_private, sip, de, tags); + if (session && sofia_private) { + if (sofia_private->is_call > 1) { + sofia_handle_sip_i_reinvite(session, nua, profile, nh, sofia_private, sip, de, tags); + } else { + sofia_private->is_call++; + sofia_handle_sip_i_invite(session, nua, profile, nh, sofia_private, sip, de, tags); + } } break; case nua_i_publish: @@ -1688,6 +1690,14 @@ static void sofia_queue_message(sofia_dispatch_event_t *de) switch_queue_push(mod_sofia_globals.msg_queue, de); } +static void set_call_id(private_object_t *tech_pvt, sip_t const *sip) +{ + if (!tech_pvt->call_id && tech_pvt->session && tech_pvt->channel && sip && sip->sip_call_id && sip->sip_call_id->i_id) { + tech_pvt->call_id = switch_core_session_strdup(tech_pvt->session, sip->sip_call_id->i_id); + switch_channel_set_variable(tech_pvt->channel, "sip_call_id", tech_pvt->call_id); + } +} + void sofia_event_callback(nua_event_t event, int status, @@ -1707,16 +1717,22 @@ void sofia_event_callback(nua_event_t event, if ((session = switch_core_session_locate(sofia_private->uuid))) { private_object_t *tech_pvt = switch_core_session_get_private(session); + switch_channel_t *channel = switch_core_session_get_channel(session); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "detaching session %s\n", sofia_private->uuid); - - tech_pvt->sofia_private = NULL; - tech_pvt->nh = NULL; - sofia_set_flag(tech_pvt, TFLAG_BYE); - switch_mutex_lock(profile->flag_mutex); - switch_core_hash_insert(profile->chat_hash, tech_pvt->call_id, strdup(switch_core_session_get_uuid(session))); - switch_mutex_unlock(profile->flag_mutex); - switch_core_session_rwunlock(session); + set_call_id(tech_pvt, sip); + + if (!zstr(tech_pvt->call_id)) { + tech_pvt->sofia_private = NULL; + tech_pvt->nh = NULL; + sofia_set_flag(tech_pvt, TFLAG_BYE); + switch_mutex_lock(profile->flag_mutex); + switch_core_hash_insert(profile->chat_hash, tech_pvt->call_id, strdup(switch_core_session_get_uuid(session))); + switch_mutex_unlock(profile->flag_mutex); + switch_core_session_rwunlock(session); + } else { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + } } } goto end; @@ -1802,9 +1818,25 @@ void sofia_event_callback(nua_event_t event, } else { free(uuid); uuid = NULL; + sip = NULL; } } } + + if (!sip || !sip->sip_call_id || zstr(sip->sip_call_id->i_id)) { + nua_respond(nh, 503, "INVALID INVITE", TAG_END()); + nua_destroy_event(de->event); + su_free(nh->nh_home, de); + + switch_mutex_lock(profile->flag_mutex); + profile->queued_events--; + switch_mutex_unlock(profile->flag_mutex); + + nua_handle_unref(nh); + nua_stack_unref(nua); + + goto end; + } if (sofia_test_pflag(profile, PFLAG_CALLID_AS_UUID)) { session = switch_core_session_request_uuid(sofia_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL, sip->sip_call_id->i_id); @@ -1827,13 +1859,8 @@ void sofia_event_callback(nua_event_t event, } sofia_glue_attach_private(session, profile, tech_pvt, channel_name); - - if (!tech_pvt->call_id && sip->sip_call_id && sip->sip_call_id->i_id) { - switch_channel_t *channel = switch_core_session_get_channel(session); - tech_pvt->call_id = switch_core_session_strdup(session, sip->sip_call_id->i_id); - switch_channel_set_variable(channel, "sip_call_id", tech_pvt->call_id); - } + set_call_id(tech_pvt, sip); } else { nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END()); nua_destroy_event(de->event); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index c381ead0d4..97d9e06e07 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -833,12 +833,14 @@ void sofia_glue_tech_prepare_codecs(private_object_t *tech_pvt) if (!(codec_string = switch_channel_get_variable(tech_pvt->channel, "codec_string"))) { codec_string = sofia_glue_get_codec_string(tech_pvt); - if (codec_string && *codec_string == '=') { - codec_string++; - goto ready; - } } + if (codec_string && *codec_string == '=') { + codec_string++; + goto ready; + } + + if ((ocodec = switch_channel_get_variable(tech_pvt->channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) { if (!codec_string || sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_TRANSCODING)) { codec_string = ocodec; @@ -871,6 +873,7 @@ void sofia_glue_check_video_codecs(private_object_t *tech_pvt) int i; tech_pvt->video_count = 0; for (i = 0; i < tech_pvt->num_codecs; i++) { + if (tech_pvt->codecs[i]->codec_type == SWITCH_CODEC_TYPE_VIDEO) { tech_pvt->video_count++; } @@ -5135,6 +5138,8 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s if (mimp) { char tmp[50]; + const char *mirror = switch_channel_get_variable(tech_pvt->channel, "sip_mirror_remote_audio_codec_payload"); + tech_pvt->rm_encoding = switch_core_session_strdup(session, (char *) map->rm_encoding); tech_pvt->iananame = switch_core_session_strdup(session, (char *) mimp->iananame); tech_pvt->pt = (switch_payload_t) map->rm_pt; @@ -5152,7 +5157,9 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp); tech_pvt->audio_recv_pt = (switch_payload_t)map->rm_pt; - if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && !sofia_test_flag(tech_pvt, TFLAG_REINVITE)) { + if (!switch_true(mirror) && + switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && + (!sofia_test_flag(tech_pvt, TFLAG_REINVITE) || sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_REINVITE))) { sofia_glue_get_offered_pt(tech_pvt, mimp, &tech_pvt->audio_recv_pt); } @@ -5275,6 +5282,8 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s if (mimp) { if ((tech_pvt->video_rm_encoding = switch_core_session_strdup(session, (char *) rm_encoding))) { char tmp[50]; + const char *mirror = switch_channel_get_variable(tech_pvt->channel, "sip_mirror_remote_video_codec_payload"); + tech_pvt->video_pt = (switch_payload_t) map->rm_pt; tech_pvt->video_rm_rate = map->rm_rate; tech_pvt->video_codec_ms = mimp->microseconds_per_packet / 1000; @@ -5292,7 +5301,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s tech_pvt->video_recv_pt = (switch_payload_t)map->rm_pt; - if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { + if (!switch_true(mirror) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { sofia_glue_get_offered_pt(tech_pvt, mimp, &tech_pvt->video_recv_pt); } diff --git a/src/mod/languages/mod_managed/managed/ManagedSession.cs b/src/mod/languages/mod_managed/managed/ManagedSession.cs index 9629215c70..bed7a03878 100644 --- a/src/mod/languages/mod_managed/managed/ManagedSession.cs +++ b/src/mod/languages/mod_managed/managed/ManagedSession.cs @@ -139,16 +139,13 @@ namespace FreeSWITCH.Native // The delegate needs to be stored so it doesn't get GC'd, so we can't just return GetFunctionPointerForDelegate right away. /// Wraps a nice handler into a delegate suitable for reverse P/Invoke. This only currently works well for hangup/reporting handlers. - public static switch_state_handler_t_delegate CreateStateHandlerDelegate(Action handler) { + public static switch_state_handler_t_delegate CreateStateHandlerDelegate(ManagedSession sess, Action handler) + { // We create a ManagedSession on top of the session so callbacks can use it "nicely" // Then we sort of dispose it. switch_state_handler_t_delegate del = ptr => { - using (var sess = new ManagedSession(new SWIGTYPE_p_switch_core_session(ptr, false))) { handler(sess); - sess.SetAutoHangup(false); - sess.destroy(); return switch_status_t.SWITCH_STATUS_SUCCESS; - } }; return del; } @@ -187,7 +184,7 @@ namespace FreeSWITCH.Native var bleg = new ManagedSession(); bleg.originate_ondestroy_delegate = bleg.originate_ondestroy_method; - bleg.originate_onhangup_delegate = CreateStateHandlerDelegate(sess_b => { + bleg.originate_onhangup_delegate = CreateStateHandlerDelegate(bleg, sess_b => { if (onHangup != null) { onHangup(sess_b); } diff --git a/src/switch_channel.c b/src/switch_channel.c index 38331f0be9..3f767ae21d 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -155,8 +155,13 @@ struct switch_channel { switch_event_t *app_list; switch_event_t *api_list; switch_event_t *var_list; + switch_hold_record_t *hold_record; }; +SWITCH_DECLARE(switch_hold_record_t *) switch_channel_get_hold_record(switch_channel_t *channel) +{ + return channel->hold_record; +} SWITCH_DECLARE(const char *) switch_channel_cause2str(switch_call_cause_t cause) { @@ -1611,9 +1616,24 @@ SWITCH_DECLARE(void) switch_channel_set_flag_value(switch_channel_t *channel, sw switch_mutex_unlock(channel->flag_mutex); if (HELD) { + switch_hold_record_t *hr; + const char *brto = switch_channel_get_partner_uuid(channel); + switch_channel_set_callstate(channel, CCS_HELD); switch_mutex_lock(channel->profile_mutex); channel->caller_profile->times->last_hold = switch_time_now(); + + hr = switch_core_session_alloc(channel->session, sizeof(*hr)); + hr->on = switch_time_now(); + if (brto) { + hr->uuid = switch_core_session_strdup(channel->session, brto); + } + + if (channel->hold_record) { + hr->next = channel->hold_record; + } + channel->hold_record = hr; + switch_mutex_unlock(channel->profile_mutex); } @@ -1763,6 +1783,11 @@ SWITCH_DECLARE(void) switch_channel_clear_flag(switch_channel_t *channel, switch if (channel->caller_profile->times->last_hold) { channel->caller_profile->times->hold_accum += (switch_time_now() - channel->caller_profile->times->last_hold); } + + if (channel->hold_record) { + channel->hold_record->off = switch_time_now(); + } + switch_mutex_unlock(channel->profile_mutex); } @@ -2905,6 +2930,12 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_hangup(switch_chan switch_event_t *event; const char *var; + switch_mutex_lock(channel->profile_mutex); + if (channel->hold_record && !channel->hold_record->off) { + channel->hold_record->off = switch_time_now(); + } + switch_mutex_unlock(channel->profile_mutex); + switch_mutex_lock(channel->state_mutex); last_state = channel->state; channel->state = CS_HANGUP; diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 95f0e901d8..63721e66fd 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -631,8 +631,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_event(switch_core_session_t *se } } - if (!inner || switch_channel_test_flag(channel, CF_STOP_BROADCAST)) { - switch_channel_clear_flag(channel, CF_BROADCAST); + if (!inner) { + switch_channel_clear_flag(channel, CF_BROADCAST); + } + + if (switch_channel_test_flag(channel, CF_STOP_BROADCAST)) { + switch_channel_clear_flag(channel, CF_BROADCAST); switch_channel_set_flag(channel, CF_BREAK); } @@ -2191,11 +2195,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_generate_xml_cdr(switch_core_session_ switch_channel_t *channel = switch_core_session_get_channel(session); switch_caller_profile_t *caller_profile; switch_xml_t variables, cdr, x_main_cp, x_caller_profile, x_caller_extension, x_times, time_tag, - x_application, x_callflow, x_inner_extension, x_apps, x_o, x_channel_data, x_field; + x_application, x_callflow, x_inner_extension, x_apps, x_o, x_channel_data, x_field, xhr, x_hold; switch_app_log_t *app_log; char tmp[512], *f; int cdr_off = 0, v_off = 0, cd_off = 0; - + switch_hold_record_t *hold_record = switch_channel_get_hold_record(channel), *hr; + if (*xml_cdr) { cdr = *xml_cdr; } else { @@ -2262,6 +2267,36 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_generate_xml_cdr(switch_core_session_ } } + if (hold_record) { + int cf_off = 0; + + if (!(xhr = switch_xml_add_child_d(cdr, "hold-record", cdr_off++))) { + goto error; + } + + for (hr = hold_record; hr; hr = hr->next) { + char *t = tmp; + if (!(x_hold = switch_xml_add_child_d(xhr, "hold", cf_off++))) { + goto error; + } + + switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, hr->on); + switch_xml_set_attr_d(x_hold, "on", t); + + switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, hr->off); + switch_xml_set_attr_d(x_hold, "off", t); + + if (hr->uuid) { + switch_xml_set_attr_d(x_hold, "bridged-to", hr->uuid); + } + + + } + + + } + + caller_profile = switch_channel_get_caller_profile(channel); diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index c684c8f14c..4ab523a3a5 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -311,9 +311,18 @@ static dm_match_t switch_ivr_dmachine_check_match(switch_ivr_dmachine_t *dmachin for(bp = dmachine->realm->binding_list; bp; bp = bp->next) { if (bp->is_regex) { - switch_status_t r_status = switch_regex_match(dmachine->digits, bp->digits); - pmatches = 1; + pmatches++; + } else { + if (!strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits))) { + pmatches++; + } + } + } + for(bp = dmachine->realm->binding_list; bp; bp = bp->next) { + if (bp->is_regex) { + switch_status_t r_status = switch_regex_match(dmachine->digits, bp->digits); + if (r_status == SWITCH_STATUS_SUCCESS) { if (is_timeout || (bp == dmachine->realm->binding_list && !bp->next)) { best = DM_MATCH_EXACT; @@ -325,11 +334,7 @@ static dm_match_t switch_ivr_dmachine_check_match(switch_ivr_dmachine_t *dmachin } else { int pmatch = !strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits)); - if (pmatch) { - pmatches++; - } - - if (!exact_bp && pmatch && !strcmp(bp->digits, dmachine->digits)) { + if (!exact_bp && pmatch && (pmatches == 1 || is_timeout) && !strcmp(bp->digits, dmachine->digits)) { best = DM_MATCH_EXACT; exact_bp = bp; if (dmachine->cur_digit_len == dmachine->max_digit_len) break;