static void sipsub_notify_handler(struct sip *sip, const struct sip_msg *msg, void *arg) { struct call *call = arg; struct pl scode, reason; uint32_t sc; if (re_regex((char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb), "SIP/2.0 [0-9]+ [^\r\n]+", &scode, &reason)) { (void)sip_reply(sip, msg, 400, "Bad sipfrag"); return; } (void)sip_reply(sip, msg, 200, "OK"); sc = pl_u32(&scode); if (sc >= 300) { warning("call: transfer failed: %u %r\n", sc, &reason); call_event_handler(call, CALL_EVENT_TRANSFER_FAILED, "%u %r", sc, &reason); } else if (sc >= 200) { call_event_handler(call, CALL_EVENT_CLOSED, "Call transfered"); } }
static void sipsess_progr_handler(const struct sip_msg *msg, void *arg) { struct call *call = arg; bool media; MAGIC_CHECK(call); info("call: SIP Progress: %u %r (%r/%r)\n", msg->scode, &msg->reason, &msg->ctyp.type, &msg->ctyp.subtype); if (msg->scode <= 100) return; /* check for 18x and content-type * * 1. start media-stream if application/sdp * 2. play local ringback tone if not * * we must also handle changes to/from 180 and 183, * so we reset the media-stream/ringback each time. */ if (msg_ctype_cmp(&msg->ctyp, "application", "sdp") && mbuf_get_left(msg->mb) && !sdp_decode(call->sdp, msg->mb, false)) { media = true; } else if (msg_ctype_cmp(&msg->ctyp, "multipart", "mixed") && !sdp_decode_multipart(&msg->ctyp.params, msg->mb) && !sdp_decode(call->sdp, msg->mb, false)) { media = true; } else media = false; switch (msg->scode) { case 180: set_state(call, STATE_RINGING); break; case 183: set_state(call, STATE_EARLY); break; } if (media) call_event_handler(call, CALL_EVENT_PROGRESS, call->peer_uri); else call_event_handler(call, CALL_EVENT_RINGING, call->peer_uri); call_stream_stop(call); if (media) call_stream_start(call, false); }
static void sipsess_refer_handler(struct sip *sip, const struct sip_msg *msg, void *arg) { struct call *call = arg; const struct sip_hdr *hdr; int err; /* get the transfer target */ hdr = sip_msg_hdr(msg, SIP_HDR_REFER_TO); if (!hdr) { warning("call: bad REFER request from %r\n", &msg->from.auri); (void)sip_reply(sip, msg, 400, "Missing Refer-To header"); return; } /* The REFER creates an implicit subscription. * Reply 202 to the REFER request */ call->not = mem_deref(call->not); err = sipevent_accept(&call->not, uag_sipevent_sock(), msg, sipsess_dialog(call->sess), NULL, 202, "Accepted", 60, 60, 60, ua_cuser(call->ua), "message/sipfrag", auth_handler, call->acc, true, sipnot_close_handler, call, "Allow: %s\r\n", uag_allowed_methods()); if (err) { warning("call: refer: sipevent_accept failed: %m\n", err); return; } (void)call_notify_sipfrag(call, 100, "Trying"); call_event_handler(call, CALL_EVENT_TRANSFER, "%r", &hdr->val); }
BOOL FooControl::handle_message(Rollout *ro, UINT message, WPARAM wParam, LPARAM lParam) { if (message == CC_SPINNER_CHANGE) { one_value_local(arg); /* handle CC_SPINNER_CHANGE message received for this control - call my _T('changed') event handler with * with the current spinner value as the argument */ if (spin_type == EDITTYPE_INT) { value = (float)((ISpinnerControl *)lParam)->GetIVal(); vl.arg = Integer::intern((int)value); } else vl.arg = Float::intern(value = ((ISpinnerControl *)lParam)->GetFVal()); try { call_event_handler(ro, n_changed, &vl.arg, 1); } catch (...) { SendMessage(GetDlgItem(ro->page, control_ID), WM_LBUTTONUP, 0, 0); // on error, force a buttonup to release the spinner throw; } pop_value_locals(); return TRUE; } return FALSE; }
static void invite_timeout(void *arg) { struct call *call = arg; info("%s: Local timeout after %u seconds\n", call->peer_uri, LOCAL_TIMEOUT); call_event_handler(call, CALL_EVENT_CLOSED, "Local timeout"); }
static void menc_error_handler(int err, void *arg) { struct call *call = arg; MAGIC_CHECK(call); warning("call: mediaenc '%s' error: %m\n", call->acc->mencid, err); call_stream_stop(call); call_event_handler(call, CALL_EVENT_CLOSED, "mediaenc failed"); }
static void video_error_handler(int err, const char *str, void *arg) { struct call *call = arg; MAGIC_CHECK(call); warning("call: video device error: %m (%s)\n", err, str); call_stream_stop(call); call_event_handler(call, CALL_EVENT_CLOSED, str); }
/** Called when all media streams are established */ static void mnat_handler(int err, uint16_t scode, const char *reason, void *arg) { struct call *call = arg; MAGIC_CHECK(call); if (err) { warning("call: medianat '%s' failed: %m\n", call->acc->mnatid, err); call_event_handler(call, CALL_EVENT_CLOSED, "%m", err); return; } else if (scode) { warning("call: medianat failed: %u %s\n", scode, reason); call_event_handler(call, CALL_EVENT_CLOSED, "%u %s", scode, reason); return; } /* Re-INVITE */ if (!call->mnat_wait) { info("call: medianat established -- sending Re-INVITE\n"); (void)call_modify(call); return; } call->mnat_wait = false; switch (call->state) { case STATE_OUTGOING: (void)send_invite(call); break; case STATE_INCOMING: call_event_handler(call, CALL_EVENT_INCOMING, call->peer_uri); break; default: break; } }
static void sipsub_close_handler(int err, const struct sip_msg *msg, const struct sipevent_substate *substate, void *arg) { struct call *call = arg; (void)substate; call->sub = mem_deref(call->sub); if (err) { info("call: subscription closed: %m\n", err); } else if (msg && msg->scode >= 300) { info("call: transfer failed: %u %r\n", msg->scode, &msg->reason); call_event_handler(call, CALL_EVENT_TRANSFER_FAILED, "%u %r", msg->scode, &msg->reason); } }
static void sipsess_estab_handler(const struct sip_msg *msg, void *arg) { struct call *call = arg; MAGIC_CHECK(call); (void)msg; if (call->state == STATE_ESTABLISHED) return; set_state(call, STATE_ESTABLISHED); call_event_handler(call, CALL_EVENT_ESTABLISHED, call->peer_uri); call_stream_start(call, true); /* the transferor will hangup this call */ if (call->not) { (void)call_notify_sipfrag(call, 200, "OK"); } }
static void sipsess_close_handler(int err, const struct sip_msg *msg, void *arg) { struct call *call = arg; char reason[128] = ""; MAGIC_CHECK(call); if (err) { info("%s: session closed: %m\n", call->peer_uri, err); if (call->not) { (void)call_notify_sipfrag(call, 500, "%m", err); } } else if (msg) { call->scode = msg->scode; (void)re_snprintf(reason, sizeof(reason), "%u %r", msg->scode, &msg->reason); info("%s: session closed: %u %r\n", call->peer_uri, msg->scode, &msg->reason); if (call->not) { (void)call_notify_sipfrag(call, msg->scode, "%r", &msg->reason); } } else { info("%s: session closed\n", call->peer_uri); } call_stream_stop(call); call_event_handler(call, CALL_EVENT_CLOSED, reason); }
int call_accept(struct call *call, struct sipsess_sock *sess_sock, const struct sip_msg *msg) { bool got_offer; int err; if (!call || !msg) return EINVAL; call->outgoing = false; got_offer = (mbuf_get_left(msg->mb) > 0); err = pl_strdup(&call->peer_uri, &msg->from.auri); if (err) return err; if (pl_isset(&msg->from.dname)) { err = pl_strdup(&call->peer_name, &msg->from.dname); if (err) return err; } if (got_offer) { struct sdp_media *m; const struct sa *raddr; err = sdp_decode(call->sdp, msg->mb, true); if (err) return err; call->got_offer = true; /* * Each media description in the SDP answer MUST * use the same network type as the corresponding * media description in the offer. * * See RFC 6157 */ m = stream_sdpmedia(audio_strm(call->audio)); raddr = sdp_media_raddr(m); if (sa_af(raddr) != call->af) { info("call: incompatible address-family" " (local=%s, remote=%s)\n", net_af2name(call->af), net_af2name(sa_af(raddr))); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "Wrong address family"); return 0; } /* Check if we have any common audio codecs, after * the SDP offer has been parsed */ if (!have_common_audio_codecs(call)) { info("call: no common audio codecs - rejected\n"); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "No audio codecs"); return 0; } } err = sipsess_accept(&call->sess, sess_sock, msg, 180, "Ringing", ua_cuser(call->ua), "application/sdp", NULL, auth_handler, call->acc, true, sipsess_offer_handler, sipsess_answer_handler, sipsess_estab_handler, sipsess_info_handler, sipsess_refer_handler, sipsess_close_handler, call, "Allow: %s\r\n", uag_allowed_methods()); if (err) { warning("call: sipsess_accept: %m\n", err); return err; } set_state(call, STATE_INCOMING); /* New call */ tmr_start(&call->tmr_inv, LOCAL_TIMEOUT*1000, invite_timeout, call); if (!call->acc->mnat) call_event_handler(call, CALL_EVENT_INCOMING, call->peer_uri); return err; }
int call_accept(struct call *call, struct sipsess_sock *sess_sock, const struct sip_msg *msg) { bool got_offer; int err; if (!call || !msg) return EINVAL; got_offer = (mbuf_get_left(msg->mb) > 0); err = pl_strdup(&call->peer_uri, &msg->from.auri); if (err) return err; if (pl_isset(&msg->from.dname)) { err = pl_strdup(&call->peer_name, &msg->from.dname); if (err) return err; } if (got_offer) { err = sdp_decode(call->sdp, msg->mb, true); if (err) return err; call->got_offer = true; /* Check if we have any common audio codecs, after * the SDP offer has been parsed */ if (!have_common_audio_codecs(call)) { info("call: no common audio codecs - rejected\n"); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "No audio codecs"); return 0; } } err = sipsess_accept(&call->sess, sess_sock, msg, 180, "Ringing", ua_cuser(call->ua), "application/sdp", NULL, auth_handler, call->acc, true, sipsess_offer_handler, sipsess_answer_handler, sipsess_estab_handler, sipsess_info_handler, sipsess_refer_handler, sipsess_close_handler, call, "Allow: %s\r\n", uag_allowed_methods()); if (err) { warning("call: sipsess_accept: %m\n", err); return err; } set_state(call, STATE_INCOMING); /* New call */ tmr_start(&call->tmr_inv, LOCAL_TIMEOUT*1000, invite_timeout, call); if (!call->acc->mnat) call_event_handler(call, CALL_EVENT_INCOMING, call->peer_uri); return err; }