📄 soa_static.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE soa_static.c * * @brief Static implementation of Sofia SDP Offer/Answer Engine * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Tue Aug 16 17:06:06 EEST 2005 * * @par Use-cases * 1. no existing session * a) generating offer (upgrade with user-SDP) * b) generating answer (upgrade with remote-SDP, rejects with user-SDP) * 2. session exists * a) generating offer: * upgrades with user-SDP * b) generating answer: * upgrades with remote-SDP, rejects with user-SDP * c) processing answer: * rejects with user-SDP, no upgrades * * Upgrading session with user SDP: */#include "config.h"#include <stddef.h>#include <stdlib.h>#include <string.h>#include <assert.h>struct soa_static_complete;#define SU_MSG_ARG_T struct soa_static_completed#include <sofia-sip/su_wait.h>#include <sofia-sip/su_tag_class.h>#include <sofia-sip/su_tag_class.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/su_strlst.h>#include "sofia-sip/soa.h"#include <sofia-sip/sdp.h>#include "sofia-sip/soa_session.h"#define NONE ((void *)-1)#define XXX assert(!"implemented")#define str0cmp(a, b) strcmp(a ? a : "", b ? b : "")#if !HAVE_STRCASESTRchar *strcasestr(const char *haystack, const char *needle);#endiftypedef struct soa_static_session{ soa_session_t sss_session[1];}soa_static_session_t;static int soa_static_init(char const *, soa_session_t *, soa_session_t *);static void soa_static_deinit(soa_session_t *);static int soa_static_set_params(soa_session_t *ss, tagi_t const *tags);static int soa_static_get_params(soa_session_t const *ss, tagi_t *tags);static tagi_t *soa_static_get_paramlist(soa_session_t const *ss, tag_type_t tag, tag_value_t value, ...);static int soa_static_set_capability_sdp(soa_session_t *ss, sdp_session_t *sdp, char const *, int);static int soa_static_set_remote_sdp(soa_session_t *ss, int new_version, sdp_session_t *sdp, char const *, int);static int soa_static_set_user_sdp(soa_session_t *ss, sdp_session_t *sdp, char const *, int);static int soa_static_generate_offer(soa_session_t *ss, soa_callback_f *);static int soa_static_generate_answer(soa_session_t *ss, soa_callback_f *);static int soa_static_process_answer(soa_session_t *ss, soa_callback_f *);static int soa_static_process_reject(soa_session_t *ss, soa_callback_f *);static int soa_static_activate(soa_session_t *ss, char const *option);static int soa_static_deactivate(soa_session_t *ss, char const *option);static void soa_static_terminate(soa_session_t *ss, char const *option);struct soa_session_actions const soa_default_actions = { (sizeof soa_default_actions), sizeof (struct soa_static_session), "static", soa_static_init, soa_static_deinit, soa_static_set_params, soa_static_get_params, soa_static_get_paramlist, soa_base_media_features, soa_base_sip_require, soa_base_sip_supported, soa_base_remote_sip_features, soa_static_set_capability_sdp, soa_static_set_remote_sdp, soa_static_set_user_sdp, soa_static_generate_offer, soa_static_generate_answer, soa_static_process_answer, soa_static_process_reject, soa_static_activate, soa_static_deactivate, soa_static_terminate };/* Initialize session */static int soa_static_init(char const *name, soa_session_t *ss, soa_session_t *parent){ return soa_base_init(name, ss, parent);}static void soa_static_deinit(soa_session_t *ss){ soa_base_deinit(ss);}static int soa_static_set_params(soa_session_t *ss, tagi_t const *tags){ return soa_base_set_params(ss, tags);}static int soa_static_get_params(soa_session_t const *ss, tagi_t *tags){ return soa_base_get_params(ss, tags);}static tagi_t *soa_static_get_paramlist(soa_session_t const *ss, tag_type_t tag, tag_value_t value, ...){ ta_list ta; tagi_t *tl; ta_start(ta, tag, value); tl = soa_base_get_paramlist(ss, TAG_NEXT(ta_args(ta))); ta_end(ta); return tl;}static int soa_static_set_capability_sdp(soa_session_t *ss, sdp_session_t *sdp, char const *sdp_str, int sdp_len){ return soa_base_set_capability_sdp(ss, sdp, sdp_str, sdp_len);}static int soa_static_set_remote_sdp(soa_session_t *ss, int new_version, sdp_session_t *sdp, char const *sdp_str, int sdp_len){ return soa_base_set_remote_sdp(ss, new_version, sdp, sdp_str, sdp_len);}static int soa_static_set_user_sdp(soa_session_t *ss, sdp_session_t *sdp, char const *sdp_str, int sdp_len){ return soa_base_set_user_sdp(ss, sdp, sdp_str, sdp_len);}/** Generate a rejected m= line */sdp_media_t *soa_sdp_make_rejected_media(su_home_t *home, sdp_media_t const *m, sdp_session_t *sdp, int include_all_codecs){ sdp_media_t rejected[1] = {{ sizeof (rejected) }}; rejected->m_type = m->m_type; rejected->m_type_name = m->m_type_name; rejected->m_port = 0; rejected->m_proto = m->m_proto; rejected->m_proto_name = m->m_proto_name; if (include_all_codecs) { rejected->m_rtpmaps = m->m_rtpmaps; } rejected->m_rejected = 1; return sdp_media_dup(home, rejected, sdp);}/** Expand a @a truncated SDP. */sdp_session_t *soa_sdp_expand_media(su_home_t *home, sdp_session_t const *truncated, sdp_session_t const *complete){ sdp_session_t *expanded; sdp_media_t **m0; sdp_media_t * const *m1; expanded = sdp_session_dup(home, truncated); if (expanded) { for (m0 = &expanded->sdp_media, m1 = &complete->sdp_media; *m1; m1 = &(*m1)->m_next) { if (!*m0) { *m0 = soa_sdp_make_rejected_media(home, *m1, expanded, 0); if (!*m0) return NULL; } m0 = &(*m0)->m_next; } } return expanded;}/** Check if @a session should be upgraded with @a remote */ int soa_sdp_upgrade_is_needed(sdp_session_t const *session, sdp_session_t const *remote){ sdp_media_t const *rm, *lm; if (!remote) return 0; if (!session) return 1; for (rm = remote->sdp_media, lm = session->sdp_media; rm && lm ; rm = rm->m_next, lm = lm->m_next) { if (rm->m_rejected) continue; if (lm->m_rejected) break; } return rm != NULL;}/** Find first matching media in table. */sdp_media_t *soa_sdp_matching(soa_session_t *ss, sdp_media_t *mm[], sdp_media_t const *with, int *return_common_codecs){ int i, j = -1; sdp_media_t *m; sdp_rtpmap_t const *rm; for (i = 0; mm[i]; i++) { if (!sdp_media_match_with(mm[i], with)) continue; if (!sdp_media_uses_rtp(with)) break; if (!return_common_codecs) break; /* Check also rtpmaps */ for (rm = mm[i]->m_rtpmaps; rm; rm = rm->rm_next) { if (sdp_rtpmap_find_matching(with->m_rtpmaps, rm)) break; } if (rm) break; if (j == -1) j = i; } if (return_common_codecs) *return_common_codecs = mm[i] != NULL; if (mm[i] == NULL && j != -1) i = j; /* return m= line without common codecs */ m = mm[i]; for (; mm[i]; i++) mm[i] = mm[i + 1]; return m;}/** Set payload types in @a l_m according to the values in @a r_m. * * @retval number of common codecs */int soa_sdp_set_rtpmap_pt(sdp_media_t *l_m, sdp_media_t const *r_m){ sdp_rtpmap_t *lrm, **next_lrm; sdp_rtpmap_t const *rrm; int local_codecs = 0, common_codecs = 0; unsigned char dynamic_pt[128]; unsigned pt; for (next_lrm = &l_m->m_rtpmaps; (lrm = *next_lrm); ) { if (lrm->rm_any) { /* Remove codecs known only by pt number */ *next_lrm = lrm->rm_next; continue; } else { next_lrm = &lrm->rm_next; } local_codecs++; rrm = sdp_rtpmap_find_matching(r_m->m_rtpmaps, lrm); /* XXX - do fmtp comparison */ if (rrm) { /* Use same payload type as remote */ if (lrm->rm_pt != rrm->rm_pt) { lrm->rm_predef = 0; lrm->rm_pt = rrm->rm_pt; } common_codecs++; } else { /* Determine payload type later */ lrm->rm_any = 1; } } if (local_codecs == common_codecs) return common_codecs; /* Select unique dynamic payload type for each payload */ memset(dynamic_pt, 0, sizeof dynamic_pt); for (lrm = l_m->m_rtpmaps; lrm; lrm = lrm->rm_next) { if (!lrm->rm_any) dynamic_pt[lrm->rm_pt] = 1; } for (rrm = r_m->m_rtpmaps; rrm; rrm = rrm->rm_next) { dynamic_pt[rrm->rm_pt] = 1; } for (next_lrm = &l_m->m_rtpmaps; (lrm = *next_lrm); ) { if (!lrm->rm_any) { next_lrm = &lrm->rm_next; continue; } lrm->rm_any = 0; pt = lrm->rm_pt; if (dynamic_pt[pt]) { for (pt = 96; pt < 128; pt++) if (!dynamic_pt[pt]) break; if (pt == 128) { for (pt = 0; pt < 128; pt++) if (!sdp_rtpmap_well_known[pt] && !dynamic_pt[pt]) break; } if (pt == 128) { for (pt = 0; pt < 128; pt++) if (!dynamic_pt[pt]) break; } if (pt == 128) { /* Too many payload types */ *next_lrm = lrm->rm_next; continue; } lrm->rm_pt = pt; lrm->rm_predef = 0; } dynamic_pt[pt] = 1; next_lrm = &lrm->rm_next; } return common_codecs;}/** Sort rtpmaps in @a l_m according to the values in @a r_m. * * @return Number of common codecs */int soa_sdp_sort_rtpmap(sdp_rtpmap_t **inout_list, sdp_rtpmap_t const *rrm){ sdp_rtpmap_t *sorted = NULL, **next = &sorted, **left; int common_codecs = 0; assert(inout_list); if (!inout_list) return 0; /* Insertion sort from *inout_list to sorted */ for (; rrm && *inout_list; rrm = rrm->rm_next) { for (left = inout_list; *left; left = &(*left)->rm_next) { if (sdp_rtpmap_match(rrm, (*left))) break; } if (!*left) continue; common_codecs++; *next = *left; next = &(*next)->rm_next; *left = (*left)->rm_next; } /* Append leftover codecs */ *next = *inout_list; *inout_list = sorted; return common_codecs;}/** Select rtpmaps in @a l_m according to the values in @a r_m. * * @return Number of common codecs */int soa_sdp_select_rtpmap(sdp_rtpmap_t **inout_list, sdp_rtpmap_t const *rrm){ sdp_rtpmap_t **left; int common_codecs = 0; assert(inout_list); if (!inout_list) return 0; for (left = inout_list; *left; ) { if (sdp_rtpmap_find_matching(rrm, (*left))) /* Select */ left = &(*left)->rm_next, common_codecs++; else /* Remove */ *left = (*left)->rm_next; } return common_codecs;}/** Sort and select rtpmaps within session */ int soa_sdp_upgrade_rtpmaps(soa_session_t *ss, sdp_session_t *session, sdp_session_t const *remote){ sdp_media_t *sm; sdp_media_t const *rm; for (sm = session->sdp_media, rm = remote->sdp_media; sm && rm; sm = sm->m_next, rm = rm->m_next) { if (sm->m_rejected) continue; if (sdp_media_uses_rtp(sm)) { int common_codecs = soa_sdp_set_rtpmap_pt(sm, rm); if (ss->ss_rtp_sort == SOA_RTP_SORT_REMOTE || (ss->ss_rtp_sort == SOA_RTP_SORT_DEFAULT && rm->m_mode == sdp_recvonly)) { soa_sdp_sort_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps); } if (common_codecs == 0) ; else if (ss->ss_rtp_select == SOA_RTP_SELECT_SINGLE) { if (sm->m_rtpmaps) sm->m_rtpmaps->rm_next = NULL; } else if (ss->ss_rtp_select == SOA_RTP_SELECT_COMMON) { soa_sdp_select_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps); } } } return 0;}/** Upgrade m= lines within session */ int soa_sdp_upgrade(soa_session_t *ss, su_home_t *home, sdp_session_t *session, sdp_session_t const *caps, sdp_session_t const *upgrader){ int Ns, Nc, Nu, size, i, j; sdp_media_t *m, **mm, *cm; sdp_media_t **s_media, **o_media, **c_media; sdp_media_t const **u_media; Ns = sdp_media_count(session, sdp_media_any, 0, 0, 0); Nc = sdp_media_count(caps, sdp_media_any, 0, 0, 0); Nu = sdp_media_count(upgrader, sdp_media_any, 0, 0, 0); if (caps == upgrader) size = Ns + Nc + 1; else if (Ns < Nu) size = Nu + 1; else size = Ns + 1; s_media = su_zalloc(home, size * (sizeof *s_media)); o_media = su_zalloc(home, (Ns + 1) * (sizeof *o_media)); c_media = su_zalloc(home, (Nc + 1) * (sizeof *c_media)); u_media = su_zalloc(home, (Nu + 1) * (sizeof *u_media));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -