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 int sipsess_offer_handler(struct mbuf **descp, const struct sip_msg *msg, void *arg) { const bool got_offer = mbuf_get_left(msg->mb); struct call *call = arg; int err; MAGIC_CHECK(call); info("call: got re-INVITE%s\n", got_offer ? " (SDP Offer)" : ""); if (got_offer) { /* Decode SDP Offer */ err = sdp_decode(call->sdp, msg->mb, true); if (err) return err; err = update_media(call); if (err) return err; } /* Encode SDP Answer */ return sdp_encode(descp, call->sdp, !got_offer); }
/* * called when an SDP offer is received (got offer: true) or * when an offer is to be sent (got_offer: false) */ static int offer_handler(struct mbuf **mbp, const struct sip_msg *msg, void *arg) { const bool got_offer = mbuf_get_left(msg->mb); int err; (void)arg; if (got_offer) { err = sdp_decode(sdp, msg->mb, true); if (err) { re_fprintf(stderr, "unable to decode SDP offer: %s\n", strerror(err)); return err; } re_printf("SDP offer received\n"); update_media(); } else { re_printf("sending SDP offer\n"); } return sdp_encode(mbp, sdp, !got_offer); }
/* called upon incoming calls */ static void connect_handler(const struct sip_msg *msg, void *arg) { struct mbuf *mb; bool got_offer; int err; (void)arg; if (sess) { /* Already in a call */ (void)sip_treply(NULL, sip, msg, 486, "Busy Here"); return; } got_offer = (mbuf_get_left(msg->mb) > 0); /* Decode SDP offer if incoming INVITE contains SDP */ if (got_offer) { err = sdp_decode(sdp, msg->mb, true); if (err) { re_fprintf(stderr, "unable to decode SDP offer: %s\n", strerror(err)); goto out; } update_media(); } /* Encode SDP */ err = sdp_encode(&mb, sdp, !got_offer); if (err) { re_fprintf(stderr, "unable to encode SDP: %s\n", strerror(err)); goto out; } /* Answer incoming call */ err = sipsess_accept(&sess, sess_sock, msg, 200, "OK", name, "application/sdp", mb, auth_handler, NULL, false, offer_handler, answer_handler, establish_handler, NULL, NULL, close_handler, NULL, NULL); mem_deref(mb); /* free SDP buffer */ if (err) { re_fprintf(stderr, "session accept error: %s\n", strerror(err)); goto out; } out: if (err) { (void)sip_treply(NULL, sip, msg, 500, strerror(err)); } else { re_printf("accepting incoming call from <%r>\n", &msg->from.auri); } }
/** * Test parsing of various SDP messages from various vendors */ int test_sdp_parse(void) { struct sdp_session *sess = NULL; struct sdp_media *audio; struct mbuf *mb; struct sa laddr; uint32_t i; int err; mb = mbuf_alloc(2048); if (!mb) return ENOMEM; sa_init(&laddr, AF_INET); for (i=0; i<ARRAY_SIZE(msgs); i++) { sess = mem_deref(sess); err = sdp_session_alloc(&sess, &laddr); if (err) goto out; err = sdp_media_add(&audio, sess, sdp_media_audio, 5004, sdp_proto_rtpavp); if (err) goto out; err = sdp_format_add(NULL, audio, false, ref_pt, ref_cname, ref_srate, 1, NULL, NULL, NULL, false, NULL); if (err) goto out; err = sdp_format_add(NULL, audio, false, "8", "PCMA", 8000, 1, NULL, NULL, NULL, false, NULL); if (err) goto out; mbuf_rewind(mb); (void)mbuf_write_str(mb, msgs[i]); mb->pos = 0; err = sdp_decode(sess, mb, true); if (err) goto out; } out: mem_deref(sess); mem_deref(mb); return err; }
static int oa_offeranswer(struct oa *oa, const char *offer, const char *answer) { struct mbuf *mbo = NULL, *mba = NULL; int err = 0; /* create and send offer, compare offer */ err = sdp_encode(&mbo, oa->alice, true); if (err) goto out; if (!sdp_cmp(mbo, offer)) { DEBUG_WARNING("offer failed:\n%b", mbo->buf, mbo->end); err = EBADMSG; goto out; } /* bob decodes offer */ err = sdp_decode(oa->bob, mbo, true); if (err) goto out; /* create and send answer, compare answer */ err = sdp_encode(&mba, oa->bob, false); if (err) goto out; if (!sdp_cmp(mba, answer)) { DEBUG_WARNING("answer failed:\n%b", mba->buf, mba->end); err = EBADMSG; goto out; } err = sdp_decode(oa->alice, mba, false); out: oa_reset(oa); mem_deref(mbo); mem_deref(mba); return err; }
static session_desc_t *find_sdp_for_program (const char *cm, const char *loc, char *errmsg, uint32_t errlen, uint64_t prog) { char buffer[1024]; http_client_t *http_client; http_resp_t *http_resp; sdp_decode_info_t *sdp_info; session_desc_t *sdp, *ptr, *sdp_ret; int translated; int ret, ix; snprintf(buffer, sizeof(buffer), "http://%s/%s", cm, loc); http_resp = NULL; http_client = http_init_connection(buffer); if (http_client == NULL) { snprintf(errmsg, errlen, "Cannot create http client with %s\n", cm); return NULL; } ret = http_get(http_client, NULL, &http_resp); sdp_ret = NULL; if (ret > 0) { sdp_info = set_sdp_decode_from_memory(http_resp->body); if ((sdp_decode(sdp_info, &sdp, &translated) == 0) && (translated > 0)) { for (ix = 0; ix < translated && sdp_ret == NULL; ix++) { if (sdp->session_id == prog) { sdp_ret = sdp; sdp = sdp->next; sdp_ret->next = NULL; } else { ptr = sdp->next; sdp->next = NULL; sdp_free_session_desc(sdp); sdp = ptr; } } sdp_decode_info_free(sdp_info); if (sdp != NULL) sdp_free_session_desc(sdp); } } http_resp_free(http_resp); http_free_connection(http_client); return sdp_ret; }
static int create_from_sdp (CPlayerSession *psptr, const char *name, char *errmsg, uint32_t errlen, sdp_decode_info_t *sdp_info, int have_audio_driver, control_callback_vft_t *cc_vft) { session_desc_t *sdp; int translated; if (sdp_info == NULL) { strcpy(errmsg, "SDP error"); return (-1); } if (sdp_decode(sdp_info, &sdp, &translated) != 0) { snprintf(errmsg, errlen, "Invalid SDP file"); sdp_decode_info_free(sdp_info); return (-1); } if (translated != 1) { snprintf(errmsg, errlen, "More than 1 program described in SDP"); sdp_decode_info_free(sdp_info); return (-1); } int err; if (sdp->control_string != NULL) { // An on demand file... Just use the URL... err = create_media_for_streaming_ondemand(psptr, sdp->control_string, errmsg, errlen, cc_vft); sdp_free_session_desc(sdp); sdp_decode_info_free(sdp_info); return (err); } sdp_decode_info_free(sdp_info); return (create_media_for_streaming_broadcast(psptr, sdp, errmsg, errlen, have_audio_driver, cc_vft)); }
/* called when an SDP answer is received */ static int answer_handler(const struct sip_msg *msg, void *arg) { int err; (void)arg; re_printf("SDP answer received\n"); err = sdp_decode(sdp, msg->mb, false); if (err) { re_fprintf(stderr, "unable to decode SDP answer: %s\n", strerror(err)); return err; } update_media(); return 0; }
int main (int argc, char **argv) { sdp_decode_info_t *sdpd; session_desc_t *session; int err; int num_translated; char *formatted; argc--; argv++; if (argc == 0) { printf("No arguments specified\n"); exit(1); } sdp_set_loglevel(LOG_DEBUG); sdp_set_error_func(library_message); sdpd = set_sdp_decode_from_filename(*argv); if (sdpd == NULL) { printf("Didn't find file %s\n", *argv); exit(1); } err = sdp_decode(sdpd, &session, &num_translated); if (err != 0) { printf("couldn't decode it - error code is %d - number %d\n", err, num_translated + 1); } if (num_translated != 0) { session_dump_list(session); err = sdp_encode_list_to_memory(session, &formatted, NULL); if (err == 0) { printf("%s\n", formatted); } else { printf("Error formating session %d\n", err); } free(formatted); sdp_free_session_desc(session); } sdp_decode_info_free(sdpd); return (0); }
static int sipsess_answer_handler(const struct sip_msg *msg, void *arg) { struct call *call = arg; int err; MAGIC_CHECK(call); if (msg_ctype_cmp(&msg->ctyp, "multipart", "mixed")) (void)sdp_decode_multipart(&msg->ctyp.params, msg->mb); err = sdp_decode(call->sdp, msg->mb, false); if (err) { warning("call: could not decode SDP answer: %m\n", err); return err; } err = update_media(call); if (err) return err; return 0; }
int check_name_for_network (const char *name, int &isOnDemand, int &isRtpOverRtsp) { sdp_decode_info_t *sdp_info; session_desc_t *sdp; int translated; http_resp_t *http_resp; int do_sdp = 0; http_resp = NULL; isOnDemand = 0; isRtpOverRtsp = 0; sdp_info = NULL; if (strncmp(name, "mpeg2t://", strlen("mpeg2t://")) == 0) { return 1; } if (strncmp(name, "iptv://", strlen("iptv://")) == 0) { // more later to handle the on demand/streaming case return 1; } if (strncmp(name, "rtsp://", strlen("rtsp://")) == 0) { isOnDemand = 1; isRtpOverRtsp = config.get_config_value(CONFIG_USE_RTP_OVER_RTSP); return 1; } // handle http, .sdp case if (strncmp(name, "http://", strlen("http://")) == 0) { http_client_t *http_client; int ret; http_client = http_init_connection(name); if (http_client == NULL) { return -1; } ret = http_get(http_client, NULL, &http_resp); if (ret > 0) { sdp_decode_info_t *sdp_info; sdp_info = set_sdp_decode_from_memory(http_resp->body); do_sdp = 1; http_free_connection(http_client); } else return -1; do_sdp = 1; } else { const char *suffix = strrchr(name, '.'); if (suffix == NULL) { return -1; } if (strcasecmp(suffix, ".sdp") == 0) { sdp_info = set_sdp_decode_from_filename(name); do_sdp = 1; } else return 0; } if (do_sdp != 0) { if ((sdp_decode(sdp_info, &sdp, &translated) != 0) || translated != 1) { sdp_decode_info_free(sdp_info); return (-1); } if (sdp->control_string != NULL) { isOnDemand = 1; isRtpOverRtsp = config.get_config_value(CONFIG_USE_RTP_OVER_RTSP); } sdp_free_session_desc(sdp); if (http_resp != NULL) http_resp_free(http_resp); sdp_decode_info_free(sdp_info); return 1; } return 0; }
/* * create_streaming - create a session for streaming. Create an * RTSP session with the server, get the SDP information from it. */ int CPlayerSession::create_streaming_ondemand (const char *url, char *errmsg, uint32_t errlen, int use_tcp) { rtsp_command_t cmd; rtsp_decode_t *decode; sdp_decode_info_t *sdpdecode; int dummy; int err; // streaming has seek capability (at least on demand) session_set_seekable(1); player_debug_message("Creating streaming %s", url); memset(&cmd, 0, sizeof(rtsp_command_t)); /* * create RTSP session */ if (use_tcp != 0) { m_rtsp_client = rtsp_create_client_for_rtp_tcp(url, &err); } else { m_rtsp_client = rtsp_create_client(url, &err); } if (m_rtsp_client == NULL) { snprintf(errmsg, errlen, "Failed to create RTSP client"); player_error_message("Failed to create rtsp client - error %d", err); return (err); } m_rtp_over_rtsp = use_tcp; cmd.accept = "application/sdp"; /* * Send the RTSP describe. This should return SDP information about * the session. */ int rtsp_resp; rtsp_resp = rtsp_send_describe(m_rtsp_client, &cmd, &decode); if (rtsp_resp != RTSP_RESPONSE_GOOD) { int retval; if (decode != NULL) { retval = (((decode->retcode[0] - '0') * 100) + ((decode->retcode[1] - '0') * 10) + (decode->retcode[2] - '0')); snprintf(errmsg, errlen, "RTSP describe error %d %s", retval, decode->retresp != NULL ? decode->retresp : ""); free_decode_response(decode); } else { retval = -1; snprintf(errmsg, errlen, "RTSP return invalid %d", rtsp_resp); } player_error_message("Describe response not good\n"); return (retval); } sdpdecode = set_sdp_decode_from_memory(decode->body); if (sdpdecode == NULL) { snprintf(errmsg, errlen, "Memory failure"); player_error_message("Couldn't get sdp decode\n"); free_decode_response(decode); return (-1); } /* * Decode the SDP information into structures we can use. */ err = sdp_decode(sdpdecode, &m_sdp_info, &dummy); free(sdpdecode); if (err != 0) { snprintf(errmsg, errlen, "Couldn't decode session description %s", decode->body); player_error_message("Couldn't decode sdp %s", decode->body); free_decode_response(decode); return (-1); } if (dummy != 1) { snprintf(errmsg, errlen, "Incorrect number of sessions in sdp decode %d", dummy); player_error_message("%s", errmsg); free_decode_response(decode); return (-1); } /* * Make sure we can use the urls in the sdp info */ if (decode->content_location != NULL) { // Note - we may have problems if the content location is not absolute. m_content_base = strdup(decode->content_location); } else if (decode->content_base != NULL) { m_content_base = strdup(decode->content_base); } else { int urllen = strlen(url); if (url[urllen] != '/') { char *temp; temp = (char *)malloc(urllen + 2); strcpy(temp, url); strcat(temp, "/"); m_content_base = temp; } else { m_content_base = strdup(url); } } convert_relative_urls_to_absolute(m_sdp_info, m_content_base); if (m_sdp_info->control_string != NULL) { player_debug_message("setting control url to %s", m_sdp_info->control_string); set_session_control_url(m_sdp_info->control_string); } free_decode_response(decode); m_streaming = 1; m_streaming_ondemand = (get_range_from_sdp(m_sdp_info) != NULL); return (0); }
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 main (int argc, char **argv) { rtsp_client_t *rtsp_client; int ret; rtsp_command_t cmd; rtsp_decode_t *decode; session_desc_t *sdp; media_desc_t *media; sdp_decode_info_t *sdpdecode; rtsp_session_t *session; int dummy; rtsp_set_error_func(local_error_msg); rtsp_set_loglevel(LOG_DEBUG); memset(&cmd, 0, sizeof(rtsp_command_t)); argv++; rtsp_client = rtsp_create_client(*argv, &ret, NULL, 0); if (rtsp_client == NULL) { printf("No client created - error %d\n", ret); return (1); } if (rtsp_send_describe(rtsp_client, &cmd, &decode) != RTSP_RESPONSE_GOOD) { printf("Describe response not good\n"); free_decode_response(decode); free_rtsp_client(rtsp_client); return(1); } sdpdecode = set_sdp_decode_from_memory(decode->body); if (sdpdecode == NULL) { printf("Couldn't get sdp decode\n"); free_decode_response(decode); free_rtsp_client(rtsp_client); return(1); } if (sdp_decode(sdpdecode, &sdp, &dummy) != 0) { printf("Couldn't decode sdp\n"); free_decode_response(decode); free_rtsp_client(rtsp_client); return (1); } free(sdpdecode); if (decode->content_base == NULL) { convert_relative_urls_to_absolute (sdp, *argv); } else { convert_relative_urls_to_absolute(sdp, decode->content_base); } free_decode_response(decode); decode = NULL; #if 1 cmd.transport = "RTP/AVP;unicast;client_port=4588-4589"; #else cmd.transport = "RTP/AVP/TCP;interleaved=0-1"; #endif media = sdp->media; dummy = rtsp_send_setup(rtsp_client, media->control_string, &cmd, &session, &decode, 0); if (dummy != RTSP_RESPONSE_GOOD) { printf("Response to setup is %d\n", dummy); sdp_free_session_desc(sdp); free_decode_response(decode); free_rtsp_client(rtsp_client); return (1); } free_decode_response(decode); cmd.range = "npt=0.0-30.0"; cmd.transport = NULL; if (sdp->control_string != NULL) dummy = rtsp_send_aggregate_play(rtsp_client, sdp->control_string, &cmd, &decode); else dummy = rtsp_send_play(session, &cmd, &decode); if (dummy != RTSP_RESPONSE_GOOD) { printf("response to play is %d\n", dummy); } else { sleep(10); } free_decode_response(decode); cmd.transport = NULL; if (sdp->control_string != NULL) dummy = rtsp_send_aggregate_teardown(rtsp_client, sdp->control_string, &cmd, &decode); else dummy = rtsp_send_teardown(session, NULL, &decode); printf("Teardown response %d\n", dummy); sdp_free_session_desc(sdp); free_decode_response(decode); free_rtsp_client(rtsp_client); return (0); }
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; }
int test_sdp_all(void) { struct sdp_session *sess = NULL; struct sdp_media *audio = NULL; struct mbuf *desc = NULL; struct sa ref; const struct sdp_format *rc = NULL, *sc; struct sa laddr; int err; (void)sa_set_str(&laddr, ref_host, 0); err = sdp_session_alloc(&sess, &laddr); if (err) goto out; err = sdp_media_add(&audio, sess, sdp_media_audio, 5004, sdp_proto_rtpavp); if (err) goto out; err = sdp_format_add(NULL, audio, false, ref_pt, ref_cname, ref_srate, 1, NULL, NULL, NULL, false, NULL); err |= sdp_format_add(NULL, audio, false, "110", cname_speex, 16000, 2, NULL, NULL, NULL, false, NULL); if (err) goto out; /* find codec - expected */ sc = sdp_media_format(audio, true, NULL, 0, "PCMU", 8000, 1); if (!sc) { DEBUG_WARNING("codec not found\n"); err = ENOENT; goto out; } sc = sdp_media_format(audio, true, NULL, 110, "Speex", 16000, 2); if (!sc) { DEBUG_WARNING("codec not found: speex\n"); err = ENOENT; goto out; } /* find codec - not expected */ sc = sdp_media_format(audio, true, NULL, -1, "Speex", 8000, 1); if (sc) { DEBUG_WARNING("unexpected codec found\n"); err = EINVAL; goto out; } err = sdp_encode(&desc, sess, true); if (err) goto out; if (!sdp_cmp(desc, ref_msg)) { DEBUG_WARNING("ref: %s\n", ref_msg); DEBUG_WARNING("sdp: %b\n", desc->buf, desc->end); err = EBADMSG; goto out; } err = sdp_decode(sess, desc, false); if (err) goto out; rc = sdp_media_rformat(audio, NULL); if (!rc) { err = ENOENT; goto out; } err = sa_set_str(&ref, ref_host, ref_port); if (err) goto out; err = EINVAL; if (!sa_cmp(sdp_media_raddr(audio), &ref, SA_ALL)) goto out; if (!rc) goto out; if (0 != strcmp(rc->id, ref_pt)) goto out; if (0 != strcmp(ref_cname, rc->name)) goto out; if (rc->srate != ref_srate) goto out; err = 0; out: mem_deref(audio); mem_deref(sess); mem_deref(desc); return err; }