Author: brian Date: Fri Dec 14 19:39:53 2007 New Revision: 6802 Modified: freeswitch/trunk/conf/directory/default.xml freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_presence.c freeswitch/trunk/src/switch_channel.c Log: wip Modified: freeswitch/trunk/conf/directory/default.xml ============================================================================== --- freeswitch/trunk/conf/directory/default.xml (original) +++ freeswitch/trunk/conf/directory/default.xml Fri Dec 14 19:39:53 2007 @@ -2,7 +2,7 @@ <!--the domain or ip (the right hand side of the @ in the addr--> <domain name="$${domain}"> <params> - <param name="dial-string" value="sofia/${dialed_domain}/${dialed_user}"/> + <param name="dial-string" value="{presence_id=${dialed_user}@${dialed_domain}}sofia/${dialed_domain}/${dialed_user}"/> </params> <X-PRE-PROCESS cmd="include" data="default/*.xml"/> Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c Fri Dec 14 19:39:53 2007 @@ -2125,7 +2125,7 @@ } if (du->du_cr && cr != du->du_cr) { - assert(!nua_client_is_queued(du->du_cr)); + if (nua_client_is_queued(du->du_cr)) return -1; if (nua_client_is_reporting(du->du_cr)) { Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c ============================================================================== --- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c (original) +++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c Fri Dec 14 19:39:53 2007 @@ -998,9 +998,13 @@ "Call-ID \t%s\n" "User \t%s@%s\n" "Contact \t%s\n" + "Agent \t%s\n" "Status \t%s(%s) EXP(%s)\n\n", switch_str_nil(argv[0]), switch_str_nil(argv[1]), switch_str_nil(argv[2]), switch_str_nil(argv[3]), - switch_str_nil(argv[4]), switch_str_nil(argv[5]), exp_buf); + switch_str_nil(argv[7]), + switch_str_nil(argv[4]), + switch_str_nil(argv[5]), + exp_buf); return 0; } Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c ============================================================================== --- freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c (original) +++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c Fri Dec 14 19:39:53 2007 @@ -58,6 +58,17 @@ char const *phrase, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[]) { + if (status == 481 && sip) { + const char *call_id = sip->sip_call_id->i_id; + char *sql; + switch_core_hash_delete(profile->sub_hash, call_id); + + sql = switch_mprintf("delete from sip_subscriptions where call_id='%q'", call_id); + switch_assert(sql != NULL); + sofia_glue_execute_sql(profile, SWITCH_FALSE, sql, profile->ireg_mutex); + free(sql); + nua_handle_destroy(nh); + } } void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, @@ -318,7 +329,7 @@ sofia_glue_execute_sql(profile, SWITCH_FALSE, sql, NULL); switch_safe_free(sql); - sql = switch_mprintf("insert into sip_registrations values ('%q', '%q','%q','%q','Regestered', '%q', %ld, '%q')", + sql = switch_mprintf("insert into sip_registrations values ('%q', '%q','%q','%q','Registered', '%q', %ld, '%q')", call_id, from_user, from_host, contact_str, rpid, expires, user_agent); if (sql) { @@ -398,6 +409,7 @@ TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)), TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("presence")), TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("dialog")), + TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("call-info")), TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("presence.winfo")), TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("message-summary")), SIPTAG_SUPPORTED_STR("100rel, precondition, timer"), SIPTAG_USER_AGENT_STR(profile->user_agent), TAG_END()); Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c ============================================================================== --- freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c (original) +++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c Fri Dec 14 19:39:53 2007 @@ -1233,6 +1233,7 @@ if (!switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { const char *stream; switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + switch_channel_presence(tech_pvt->channel, "unknown", "hold"); if (tech_pvt->max_missed_packets) { switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets * 10); } @@ -1251,6 +1252,7 @@ } switch_channel_set_flag_partner(tech_pvt->channel, CF_BREAK); switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + switch_channel_presence(tech_pvt->channel, "unknown", "unhold"); } } Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_presence.c ============================================================================== --- freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_presence.c (original) +++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_presence.c Fri Dec 14 19:39:53 2007 @@ -40,6 +40,11 @@ static int sofia_presence_resub_callback(void *pArg, int argc, char **argv, char **columnNames); static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char **columnNames); +struct presence_helper { + sofia_profile_t *profile; + switch_event_t *event; +}; + switch_status_t sofia_presence_chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint) { char buf[256]; @@ -117,7 +122,8 @@ sofia_profile_t *profile; switch_hash_index_t *hi; void *val; - + struct presence_helper helper; + if ((sql = switch_mprintf("select *,-1,'unavailable','unavailable' from sip_subscriptions where event='presence'"))) { switch_mutex_lock(mod_sofia_globals.hash_mutex); for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) { @@ -126,8 +132,9 @@ if (!(profile->pflags & PFLAG_PRESENCE)) { continue; } - - if (sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, sofia_presence_sub_callback, profile) != SWITCH_TRUE) { + helper.profile = profile; + helper.event = NULL; + if (sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, sofia_presence_sub_callback, &helper) != SWITCH_TRUE) { continue; } } @@ -275,6 +282,7 @@ char *rpid = switch_event_get_header(event, "rpid"); char *status = switch_event_get_header(event, "status"); char *event_type = switch_event_get_header(event, "event_type"); + char *alt_event_type = switch_event_get_header(event, "alt_event_type"); char *sql = NULL; char *euser = NULL, *user = NULL, *host = NULL; @@ -309,7 +317,8 @@ } if (event->event_id == SWITCH_EVENT_ROSTER) { - + struct presence_helper helper; + if (from) { sql = switch_mprintf("select *,1,'%q','%q' from sip_subscriptions where event='presence' and full_from like '%%%q%%'", status, rpid, from); } else { @@ -324,13 +333,14 @@ if (!(profile->pflags & PFLAG_PRESENCE)) { continue; } - + helper.profile = profile; + helper.event = NULL; sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, sofia_presence_sub_callback, - profile); + &helper); } switch_mutex_unlock(mod_sofia_globals.hash_mutex); free(sql); @@ -341,6 +351,10 @@ event_type = "presence"; } + if (switch_strlen_zero(alt_event_type)) { + alt_event_type = "presence"; + } + if ((user = strdup(from))) { if ((host = strchr(user, '@'))) { char *p; @@ -399,14 +413,14 @@ case SWITCH_EVENT_PRESENCE_IN: sql = switch_mprintf - ("select *,1,'%q','%q' from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'", - status, rpid, proto, event_type, euser, host); + ("select *,1,'%q','%q' from sip_subscriptions where proto='%q' and (event='%q' or event='%q') and sub_to_user='%q' and sub_to_host='%q'", + status, rpid, proto, event_type, alt_event_type, euser, host); break; case SWITCH_EVENT_PRESENCE_OUT: sql = switch_mprintf - ("select *,0,'%q','%q' from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'", - status, rpid, proto, event_type, euser, host); + ("select *,0,'%q','%q' from sip_subscriptions where proto='%q' and (event='%q' or event='%q') and sub_to_user='%q' and sub_to_host='%q'", + status, rpid, proto, event_type, alt_event_type, euser, host); break; default: break; @@ -421,12 +435,15 @@ } if (sql) { + struct presence_helper helper; + helper.profile = profile; + helper.event = event; sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, sofia_presence_sub_callback, - profile); + &helper); } } switch_mutex_unlock(mod_sofia_globals.hash_mutex); @@ -455,13 +472,14 @@ if (switch_strlen_zero(status)) { status = "Available"; } - if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { + if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", status); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_subtype", "probe"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto-specific-event-name", "%s", event_name); switch_event_fire(&event); } @@ -529,7 +547,8 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char **columnNames) { - sofia_profile_t *profile = (sofia_profile_t *) pArg; + struct presence_helper *helper = (struct presence_helper *) pArg; + sofia_profile_t *profile = helper->profile; char *pl; char *id, *note; uint32_t in = atoi(argv[13]); @@ -584,34 +603,68 @@ } to = switch_mprintf("sip:%s@%s", user, host); - pl = switch_mprintf("<?xml version='1.0' encoding='UTF-8'?>\r\n" - "<presence xmlns='urn:ietf:params:xml:ns:pidf'\r\n" - "xmlns:dm='urn:ietf:params:xml:ns:pidf:data-model'\r\n" - "xmlns:rpid='urn:ietf:params:xml:ns:pidf:rpid'\r\n" - "xmlns:c='urn:ietf:params:xml:ns:pidf:cipid'\r\n" - "entity='pres:%s'>\r\n" - "<presentity uri=\"%s;method=SUBSCRIBE\"/>\r\n" - "<atom id=\"1002\">\r\n" - "<address uri=\"%s\" priority=\"0.800000\">\r\n" - "<status status=\"%s\">\r\n" - "<note>%s</note>\r\n" - "</status>\r\n" - "<msnsubstatus substatus=\"%s\"/>\r\n" - "</address>\r\n" - "</atom>\r\n" - "<tuple id='t6a5ed77e'>\r\n" - "<status>\r\n" - "<basic>%s</basic>\r\n" - "</status>\r\n" - "</tuple>\r\n" - "<dm:person id='p06360c4a'>\r\n" - "<rpid:activities>\r\n" "<rpid:%s/>\r\n" - "</rpid:activities>%s</dm:person>\r\n" - "</presence>", id, - id, profile->url, open, status, prpid, - open, rpid, note); + + if (!strcmp(event, "dialog") && helper->event) { + switch_stream_handle_t stream = { 0 }; + //const char *direction = switch_str_nil(switch_event_get_header(helper->event, "call-direction")); + const char *uuid = switch_str_nil(switch_event_get_header(helper->event, "unique-id")); + const char *state = switch_str_nil(switch_event_get_header(helper->event, "channel-state")); + const char *status = switch_str_nil(switch_event_get_header(helper->event, "status")); + + SWITCH_STANDARD_STREAM(stream); + + + stream.write_function(&stream, + "<?xml version=\"1.0\"?>\n" + "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" " + "version=\"%s\" state=\"full\" entity=\"%s\">\n", + switch_str_nil(switch_event_get_header(helper->event, "event_count")), to); + + if (!strcasecmp(state, "RING")) { + stream.write_function(&stream, "<dialog id=\"%s\" direction=\"recipient\">\n", uuid); + } else { + stream.write_function(&stream, "<dialog id=\"%s\">\n", uuid); + } + + stream.write_function(&stream, "<state>%s</state>\n", switch_str_nil(switch_event_get_header(helper->event, "answer-state"))); + if (!strcasecmp(status, "hold")) { + stream.write_function(&stream, "<local>\n<target uri=\"%s\">\n" + "<param pname=\"+sip.rendering\" pvalue=\"no\">\n" + "</target>\n</local>\n", to); + } + stream.write_function(&stream, "</dialog>\n</dialog-info>\n"); + pl = stream.data; + } else { + pl = switch_mprintf("<?xml version='1.0' encoding='UTF-8'?>\r\n" + "<presence xmlns='urn:ietf:params:xml:ns:pidf'\r\n" + "xmlns:dm='urn:ietf:params:xml:ns:pidf:data-model'\r\n" + "xmlns:rpid='urn:ietf:params:xml:ns:pidf:rpid'\r\n" + "xmlns:c='urn:ietf:params:xml:ns:pidf:cipid'\r\n" + "entity='pres:%s'>\r\n" + "<presentity uri=\"%s;method=SUBSCRIBE\"/>\r\n" + "<atom id=\"1002\">\r\n" + "<address uri=\"%s\" priority=\"0.800000\">\r\n" + "<status status=\"%s\">\r\n" + "<note>%s</note>\r\n" + "</status>\r\n" + "<msnsubstatus substatus=\"%s\"/>\r\n" + "</address>\r\n" + "</atom>\r\n" + "<tuple id='t6a5ed77e'>\r\n" + "<status>\r\n" + "<basic>%s</basic>\r\n" + "</status>\r\n" + "</tuple>\r\n" + "<dm:person id='p06360c4a'>\r\n" + "<rpid:activities>\r\n" "<rpid:%s/>\r\n" + "</rpid:activities>%s</dm:person>\r\n" + "</presence>", id, + id, profile->url, open, status, prpid, + open, rpid, note); + } nua_notify(nh, + NUTAG_NEWSUB(1), SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=3600"), SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"), SIPTAG_PAYLOAD_STR(pl), TAG_END()); @@ -666,6 +719,7 @@ exp = switch_mprintf("active;expires=%ld", expire_sec); nua_notify(nh, + NUTAG_NEWSUB(1), SIPTAG_SUBSCRIPTION_STATE_STR(exp), SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"), SIPTAG_PAYLOAD_STR(body), TAG_END()); @@ -745,10 +799,13 @@ const char *display = "\"user\""; switch_event_t *sevent; int sub_state; + int sent_reply = 0; tl_gets(tags, NUTAG_SUBSTATE_REF(sub_state), TAG_END()); + event = sip_header_as_string(profile->home, (void *) sip->sip_event); + if (contact) { char *port = (char *) contact->m_url->url_port; @@ -818,7 +875,7 @@ switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "login", "%s", profile->name); switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host); switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "to", "%s@%s", to_user, to_host); - + switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "proto-specific-event-name", "%s", event); switch_event_fire(&sevent); } } @@ -843,7 +900,6 @@ } call_id = sip->sip_call_id->i_id; - event = sip_header_as_string(profile->home, (void *) sip->sip_event); full_from = sip_header_as_string(profile->home, (void *) sip->sip_from); full_via = sip_header_as_string(profile->home, (void *) sip->sip_via); @@ -881,20 +937,31 @@ switch_mutex_unlock(profile->ireg_mutex); sstr = switch_mprintf("active;expires=%ld", exp_raw); - switch_core_hash_insert(profile->sub_hash, call_id, nh); + if (status < 200) { + switch_core_hash_insert(profile->sub_hash, call_id, nh); + } } + + if (status < 200) { + nua_respond(nh, SIP_202_ACCEPTED, + NUTAG_WITH_THIS(nua), + SIPTAG_SUBSCRIPTION_STATE_STR(sstr), + SIPTAG_FROM(sip->sip_to), + SIPTAG_TO(sip->sip_from), + SIPTAG_CONTACT_STR(contact_str), + TAG_END()); + } + + sent_reply++; - nua_respond(nh, SIP_202_ACCEPTED, - NUTAG_WITH_THIS(nua), - SIPTAG_SUBSCRIPTION_STATE_STR(sstr), - SIPTAG_FROM(sip->sip_to), - SIPTAG_TO(sip->sip_from), - SIPTAG_CONTACT_STR(contact_str), - TAG_END()); - - nua_notify(nh, SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR("application/octet-stream"), - SIPTAG_PAYLOAD_STR("Come to ClueCon http://www.cluecon.com\n\n"), +#if 0 + nua_notify(nh, + NUTAG_NEWSUB(1), + SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EVENT_STR(event), + SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"), + SIPTAG_PAYLOAD_STR("Note: Come to ClueCon http://www.cluecon.com\n\n"), TAG_END()); +#endif switch_safe_free(sstr); @@ -930,7 +997,12 @@ switch_safe_free(d_user); switch_safe_free(to_str); switch_safe_free(contact_str); + + if (!sent_reply) { + nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END()); + } } + } void sofia_presence_handle_sip_r_subscribe(int status, Modified: freeswitch/trunk/src/switch_channel.c ============================================================================== --- freeswitch/trunk/src/switch_channel.c (original) +++ freeswitch/trunk/src/switch_channel.c Fri Dec 14 19:39:53 2007 @@ -120,6 +120,7 @@ switch_hash_t *private_hash; switch_call_cause_t hangup_cause; int vi; + int event_count; }; @@ -305,6 +306,7 @@ } if (switch_event_create(&event, type) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(channel, event); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "%s", __FILE__); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", __FILE__); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s", id); @@ -316,6 +318,8 @@ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", status); } switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", channel->event_count++); switch_event_fire(&event); } @@ -587,8 +591,11 @@ switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG, "%s Running State Change %s\n", channel->name, state_names[channel->state]); channel->running_state = channel->state; - + if (channel->state >= CS_RING) { + switch_channel_presence(channel, "unknown", (char *) state_names[channel->state]); + } + if (channel->state < CS_HANGUP) { switch_event_t *event; if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_STATE) == SWITCH_STATUS_SUCCESS) { @@ -601,6 +608,14 @@ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-State-Number", "%s", (char *) state_num); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Name", "%s", channel->name); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Unique-ID", "%s", switch_core_session_get_uuid(channel->session)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Call-Direction", "%s", switch_channel_test_flag(channel, CF_OUTBOUND) ? "outbound" : "inbound"); + if (switch_channel_test_flag(channel, CF_ANSWERED)) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Answer-State", "confirmed"); + } else if (switch_channel_test_flag(channel, CF_EARLY_MEDIA)) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Answer-State", "early"); + } else { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Answer-State", "ringing"); + } } switch_event_fire(&event); } @@ -799,9 +814,6 @@ if (ok) { - if (state > CS_RING) { - switch_channel_presence(channel, "unknown", (char *) state_names[state]); - } switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG, "%s State Change %s -> %s\n", channel->name, state_names[last_state], state_names[state]); switch_mutex_lock(channel->flag_mutex); @@ -858,6 +870,15 @@ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Name", "%s", switch_channel_get_name(channel)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Unique-ID", "%s", switch_core_session_get_uuid(channel->session)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Call-Direction", "%s", switch_channel_test_flag(channel, CF_OUTBOUND) ? "outbound" : "inbound"); + if (switch_channel_test_flag(channel, CF_ANSWERED)) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Answer-State", "answered"); + } else if (switch_channel_test_flag(channel, CF_EARLY_MEDIA)) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Answer-State", "early"); + } else { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Answer-State", "ringing"); + } + if ((codec = switch_core_session_get_read_codec(channel->session)) && codec->implementation) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Read-Codec-Name", "%s", switch_str_nil(codec->implementation->iananame)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Read-Codec-Rate", "%u", codec->implementation->actual_samples_per_second);