📄 soa_static.c
字号:
* * @retval 1 if session was changed (or to be changed, if @a dryrun is nonzero) */ staticint soa_sdp_mode_set(sdp_session_t const *user, int const *s2u, sdp_session_t *session, sdp_session_t const *remote, char const *hold, int dryrun){ sdp_media_t *sm; sdp_media_t const *rm, *rm_next, *um; int retval = 0, i, j; int hold_all; int inactive_all; int inactive = 0; char const *hold_media = NULL; sdp_mode_t send_mode, recv_mode; SU_DEBUG_7(("soa_sdp_mode_set(%p, %p, \"%s\"): called\n", (void *)session, (void *)remote, hold ? hold : "")); if (!session || !session->sdp_media) return 0; rm = remote ? remote->sdp_media : NULL, rm_next = NULL; hold_all = str0cmp(hold, "*") == 0; inactive_all = str0cmp(hold, "#") == 0; i = 0; for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next, i++) { rm_next = rm ? rm->m_next : NULL; inactive = 0; if (sm->m_rejected) continue; assert(s2u); for (j = 0, um = user->sdp_media; j != s2u[i]; um = um->m_next, j++) assert(um); if (um == NULL) { if (dryrun) return 1; else retval = 1; sm->m_rejected = 1; sm->m_mode = sdp_inactive; sm->m_port = 0; continue; } send_mode = um->m_mode & sdp_sendonly; if (rm) send_mode = (rm->m_mode & sdp_recvonly) ? sdp_sendonly : 0; recv_mode = um->m_mode & sdp_recvonly; if (rm && rm->m_mode == sdp_inactive) { send_mode = recv_mode = 0; } else if (inactive_all) { send_mode = recv_mode = 0; } else if (hold_all) { recv_mode = 0; } else if (hold && (hold_media = strcasestr(hold, sm->m_type_name))) { recv_mode = 0; hold_media += strlen(sm->m_type_name); hold_media += strspn(hold_media, " \t"); if (hold_media[0] == '=') { hold_media += strspn(hold, " \t"); if (strncasecmp(hold_media, "inactive", strlen("inactive")) == 0) recv_mode = send_mode = 0; } } if (sm->m_mode != (unsigned)(recv_mode | send_mode)) { if (dryrun) return 1; else retval = 1; sm->m_mode = recv_mode | send_mode; } } return retval;}enum offer_answer_action { generate_offer, generate_answer, process_answer};/** * Updates the modified copy of local SDP based * on application provided local SDP and remote SDP. */static int offer_answer_step(soa_session_t *ss, enum offer_answer_action action, char const *by){ soa_static_session_t *sss = (soa_static_session_t *)ss; char c_address[64]; sdp_session_t *local = ss->ss_local->ssd_sdp; sdp_session_t local0[1]; sdp_session_t *user = ss->ss_user->ssd_sdp; unsigned user_version = ss->ss_user_version; sdp_session_t *remote = ss->ss_remote->ssd_sdp; unsigned remote_version = ss->ss_remote_version; sdp_origin_t o[1] = {{ sizeof(o) }}; sdp_connection_t *c, c0[1] = {{ sizeof(c0) }}; sdp_time_t t[1] = {{ sizeof(t) }}; int *u2s = NULL, *s2u = NULL, *tbf; char const *phrase = "Internal Media Error"; su_home_t tmphome[SU_HOME_AUTO_SIZE(8192)]; su_home_auto(tmphome, sizeof tmphome); SU_DEBUG_7(("soa_static_offer_answer_action(%p, %s): called\n", (void *)ss, by)); if (user == NULL) return soa_set_status(ss, 500, "No session set by user"); if (action == generate_offer) remote = NULL; else if (remote == NULL) return soa_set_status(ss, 500, "No remote SDP"); /* Pre-negotiation Step: Expand truncated remote SDP */ if (local && remote) switch (action) { case generate_answer: case process_answer: if (sdp_media_count(remote, sdp_media_any, "*", 0, 0) < sdp_media_count(local, sdp_media_any, "*", 0, 0)) { SU_DEBUG_5(("%s: remote %s is truncated: expanding\n", by, action == generate_answer ? "offer" : "answer")); remote = soa_sdp_expand_media(tmphome, remote, local); if (remote == NULL) return soa_set_status(ss, 500, "Cannot expand remote session"); } default: break; } /* Step A: Create local SDP session (based on user-supplied SDP) */ if (local == NULL) switch (action) { case generate_offer: case generate_answer: SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by, "generating local description")); local = local0; *local = *user, local->sdp_media = NULL; if (local->sdp_origin) { o->o_username = local->sdp_origin->o_username; /* o->o_address = local->sdp_origin->o_address; */ } if (!o->o_address) o->o_address = c0; local->sdp_origin = o; if (soa_init_sdp_origin(ss, o, c_address) < 0) { phrase = "Cannot Get IP Address for Media"; goto internal_error; } break; case process_answer: default: goto internal_error; } /* Step B: upgrade local SDP (add m= lines to it) */ switch (action) { case generate_offer: /* Upgrade local SDP based on user SDP */ if (local != local0 && ss->ss_local_user_version == user_version) break; if (local != local0) *local0 = *local, local = local0; SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by, "upgrade with local description")); if (soa_sdp_upgrade(ss, tmphome, local, user, NULL, &u2s, &s2u) < 0) goto internal_error; break; case generate_answer: /* Upgrade local SDP based on remote SDP */ if (ss->ss_local_user_version == user_version && ss->ss_local_remote_version == remote_version) break; if (1) { if (local != local0) *local0 = *local, local = local0; SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by, "upgrade with remote description")); if (soa_sdp_upgrade(ss, tmphome, local, user, remote, &u2s, &s2u) < 0) goto internal_error; } break; case process_answer: default: break; } /* Step C: reject media */ switch (action) { case generate_offer: /* Local media is marked as rejected already in upgrade phase */ break; case generate_answer: case process_answer: if (ss->ss_local_remote_version == remote_version) break; if (soa_sdp_reject_is_needed(local, remote)) { if (local != local0) { *local0 = *local, local = local0;#define DUP_LOCAL(local) \ do { \ if (!local->sdp_media) break; \ local->sdp_media = \ sdp_media_dup_all(tmphome, local->sdp_media, local); \ if (!local->sdp_media) \ goto internal_error; \ } while (0) DUP_LOCAL(local); } SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by, "marking rejected media")); soa_sdp_reject(tmphome, local, remote); } break; default: break; } /* Step D: Set media mode bits */ switch (action) { int const *s2u_; case generate_offer: case generate_answer: case process_answer: s2u_ = s2u; if (!s2u_) s2u_ = sss->sss_s2u; if (soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 1)) { if (local != local0) { *local0 = *local, local = local0; DUP_LOCAL(local); } soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 0); } break; default: break; } /* Step E: Upgrade codecs by answer. */ switch (action) { case process_answer: /* Upgrade local SDP based on remote SDP */ if (ss->ss_local_remote_version == remote_version) break; if (1 /* We don't have good test for codecs */) { SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by, "upgrade codecs with remote description")); if (local != local0) { *local0 = *local, local = local0; DUP_LOCAL(local); } soa_sdp_session_upgrade_rtpmaps(ss, local, remote); } break; case generate_offer: case generate_answer: default: break; } /* Step F: Update c= line */ switch (action) { case generate_offer: case generate_answer: /* Upgrade local SDP based of user SDP */ if (ss->ss_local_user_version == user_version && local->sdp_connection) break; if (local->sdp_connection == NULL || (user->sdp_connection != NULL && sdp_connection_cmp(local->sdp_connection, user->sdp_connection))) { sdp_media_t *m; /* Every m= line (even rejected one) must have a c= line * or there must be a c= line at session level */ if (user->sdp_connection) c = user->sdp_connection; else c = local->sdp_origin->o_address; for (m = local->sdp_media; m; m = m->m_next) if (m->m_connections == NULL) break; if (m) { if (local != local0) { *local0 = *local, local = local0; DUP_LOCAL(local); } local->sdp_connection = c; } } break; default: break; } soa_description_free(ss, ss->ss_previous); if (u2s) { u2s = u2s_alloc(ss->ss_home, u2s); s2u = u2s_alloc(ss->ss_home, s2u); if (!u2s || !s2u) goto internal_error; } if (ss->ss_local->ssd_sdp != local && sdp_session_cmp(ss->ss_local->ssd_sdp, local)) { /* We have modified local session: update origin-line */ if (local->sdp_origin != o) *o = *local->sdp_origin, local->sdp_origin = o; o->o_version++; /* Do sanity checks for the created SDP */ if (!local->sdp_subject) /* s= is mandatory */ local->sdp_subject = "-"; if (!local->sdp_time) /* t= is mandatory */ local->sdp_time = t; if (action == generate_offer) { /* Keep a copy of previous session state */ *ss->ss_previous = *ss->ss_local; memset(ss->ss_local, 0, (sizeof *ss->ss_local)); ss->ss_previous_user_version = ss->ss_local_user_version; ss->ss_previous_remote_version = ss->ss_local_remote_version; } SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by, "storing local description")); /* Update the unparsed and pretty-printed descriptions */ if (soa_description_set(ss, ss->ss_local, local, NULL, 0) < 0) { if (action == generate_offer) { /* Remove 2nd reference to local session state */ memset(ss->ss_previous, 0, (sizeof *ss->ss_previous)); ss->ss_previous_user_version = 0; ss->ss_previous_remote_version = 0; } su_free(ss->ss_home, u2s), su_free(ss->ss_home, s2u); goto internal_error; } } if (u2s) { tbf = sss->sss_u2s, sss->sss_u2s = u2s, su_free(ss->ss_home, tbf); tbf = sss->sss_s2u, sss->sss_s2u = s2u, su_free(ss->ss_home, tbf); } /* Update version numbers */ switch (action) { case generate_offer: ss->ss_local_user_version = user_version; break; case generate_answer: ss->ss_local_user_version = user_version; ss->ss_local_remote_version = remote_version; break; case process_answer: ss->ss_local_remote_version = remote_version; default: break; } su_home_deinit(tmphome); return 0; internal_error: su_home_deinit(tmphome); return soa_set_status(ss, 500, phrase);}/** * Generates offer based on local SDP. */static int soa_static_generate_offer(soa_session_t *ss, soa_callback_f *completed){ if (!ss->ss_user->ssd_sdp) return soa_set_status(ss, 500, "No session set by user"); if (offer_answer_step(ss, generate_offer, "soa_generate_offer") < 0) return -1; return soa_base_generate_offer(ss, NULL);}static int soa_static_generate_answer(soa_session_t *ss, soa_callback_f *completed){ /* NOTE: * - local SDP might have changed * - remote SDP might have been updated */ if (offer_answer_step(ss, generate_answer, "soa_generate_answer") < 0) return -1; return soa_base_generate_answer(ss, NULL);}static int soa_static_process_answer(soa_session_t *ss, soa_callback_f *completed){ /* NOTE: * - both local and remote information is available * - local SDP might have changed * - remote SDP might have been updated */ if (offer_answer_step(ss, process_answer, "soa_process_answer") < 0) return -1; return soa_base_process_answer(ss, NULL);}/** Process rejected offer */static int soa_static_process_reject(soa_session_t *ss, soa_callback_f *completed){ struct soa_description d[1]; *d = *ss->ss_local; *ss->ss_local = *ss->ss_previous; ss->ss_local_user_version = ss->ss_previous_user_version; ss->ss_local_remote_version = ss->ss_previous_remote_version; memset(ss->ss_previous, 0, (sizeof *ss->ss_previous)); soa_description_free(ss, d); return soa_base_process_reject(ss, NULL);}static int soa_static_activate(soa_session_t *ss, char const *option){ return soa_base_activate(ss, option);}static int soa_static_deactivate(soa_session_t *ss, char const *option){ return soa_base_deactivate(ss, option);}static void soa_static_terminate(soa_session_t *ss, char const *option){ soa_description_free(ss, ss->ss_user); soa_base_terminate(ss, option);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -