📄 soa_static.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2006 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/string0.h>#include <sofia-sip/bnf.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")#if !HAVE_STRCASESTRchar *strcasestr(const char *haystack, const char *needle);#endiftypedef struct soa_static_session{ soa_session_t sss_session[1]; char *sss_audio_aux; int sss_ordered_user; /**< User SDP is ordered */ int sss_reuse_rejected; /**< Try to reuse rejected media line slots */ /** Mapping from user SDP m= lines to session SDP m= lines */ int *sss_u2s; /** Mapping from session SDP m= lines to user SDP m= lines */ int *sss_s2u;}soa_static_session_t;#define U2S_NOT_USED (-1)#define U2S_SENTINEL (-2)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 *, isize_t);static int soa_static_set_remote_sdp(soa_session_t *ss, int new_version, sdp_session_t *sdp, char const *, isize_t);static int soa_static_set_user_sdp(soa_session_t *ss, sdp_session_t *sdp, char const *, isize_t);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){ soa_static_session_t *sss = (soa_static_session_t *)ss; char const *audio_aux = sss->sss_audio_aux; int ordered_user = sss->sss_ordered_user; int reuse_rejected = sss->sss_reuse_rejected; int n, m; n = tl_gets(tags, SOATAG_AUDIO_AUX_REF(audio_aux), SOATAG_ORDERED_USER_REF(ordered_user), SOATAG_REUSE_REJECTED_REF(reuse_rejected), TAG_END()); if (n > 0 && str0casecmp(audio_aux, sss->sss_audio_aux)) { char *s = su_strdup(ss->ss_home, audio_aux), *tbf = sss->sss_audio_aux; if (s == NULL && audio_aux != NULL) return -1; sss->sss_audio_aux = s; if (tbf) su_free(ss->ss_home, tbf); } sss->sss_ordered_user = ordered_user != 0; sss->sss_reuse_rejected = reuse_rejected != 0; m = soa_base_set_params(ss, tags); if (m < 0) return m; return n + m;}static int soa_static_get_params(soa_session_t const *ss, tagi_t *tags){ soa_static_session_t *sss = (soa_static_session_t *)ss; int n, m; n = tl_tgets(tags, SOATAG_AUDIO_AUX(sss->sss_audio_aux), SOATAG_ORDERED_USER(sss->sss_ordered_user), SOATAG_REUSE_REJECTED(sss->sss_reuse_rejected), TAG_END()); m = soa_base_get_params(ss, tags); if (m < 0) return m; return n + m;}static tagi_t *soa_static_get_paramlist(soa_session_t const *ss, tag_type_t tag, tag_value_t value, ...){ soa_static_session_t *sss = (soa_static_session_t *)ss; ta_list ta; tagi_t *tl; ta_start(ta, tag, value); tl = soa_base_get_paramlist(ss, TAG_IF(sss->sss_audio_aux, SOATAG_AUDIO_AUX(sss->sss_audio_aux)), TAG_IF(sss->sss_ordered_user, SOATAG_ORDERED_USER(1)), TAG_IF(sss->sss_reuse_rejected, SOATAG_REUSE_REJECTED(1)), 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, isize_t 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, isize_t 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, isize_t sdp_len){ return soa_base_set_user_sdp(ss, sdp, sdp_str, sdp_len);}/** Generate a rejected m= line */staticsdp_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. */staticsdp_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;}/** Check if codec is in auxiliary list */staticint soa_sdp_is_auxiliary_codec(sdp_rtpmap_t const *rm, char const *auxiliary){ char const *codec; size_t clen, alen; char const *match; if (!rm || !rm->rm_encoding || !auxiliary) return 0; codec = rm->rm_encoding; clen = strlen(codec), alen = strlen(auxiliary); if (clen > alen) return 0; for (match = auxiliary; (match = strcasestr(match, codec)); match = match + 1) { if (IS_ALPHANUM(match[clen]) || match[clen] == '-') continue; if (match != auxiliary && (IS_ALPHANUM(match[-1]) || match[-1] == '-')) continue; return 1; } return 0;}staticsdp_rtpmap_t *soa_sdp_media_matching_rtpmap(sdp_rtpmap_t const *from, sdp_rtpmap_t const *anylist, char const *auxiliary){ sdp_rtpmap_t const *rm; for (rm = anylist; rm; rm = rm->rm_next) { /* Ignore auxiliary codecs */ if (auxiliary && soa_sdp_is_auxiliary_codec(rm, auxiliary)) continue; if (sdp_rtpmap_find_matching(from, rm)) return (sdp_rtpmap_t *)rm; } return NULL;}#define SDP_MEDIA_NONE ((sdp_media_t *)-1)/** Find first matching media in table @a mm. * * - if allow_rtp_mismatch == 0, search for a matching codec * - if allow_rtp_mismatch == 1, prefer m=line with matching codec * - if allow_rtp_mismatch > 1, ignore codecs */staticint soa_sdp_matching_mindex(soa_session_t *ss, sdp_media_t *mm[], sdp_media_t const *with, int *return_codec_mismatch){ int i, j = -1; soa_static_session_t *sss = (soa_static_session_t *)ss; int rtp = sdp_media_uses_rtp(with), dummy; char const *auxiliary = NULL; if (return_codec_mismatch == NULL) return_codec_mismatch = &dummy; if (with->m_type == sdp_media_audio) { auxiliary = sss->sss_audio_aux; /* Looking for a single codec */ if (with->m_rtpmaps && with->m_rtpmaps->rm_next == NULL) auxiliary = NULL; } for (i = 0; mm[i]; i++) { if (mm[i] == SDP_MEDIA_NONE) continue; if (!sdp_media_match_with(mm[i], with)) continue; if (!rtp) break; if (soa_sdp_media_matching_rtpmap(with->m_rtpmaps, mm[i]->m_rtpmaps, auxiliary)) break; if (j == -1) j = i; } if (mm[i]) return *return_codec_mismatch = 0, i; else return *return_codec_mismatch = 1, j;}/** Set payload types in @a l_m according to the values in @a r_m. * * @retval number of common codecs */staticint 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -