owt(open webrtc tookit)sip开发记录

描述

本篇文章主要记录这段时间sip开发过程中遇到的一些问题和解决方法。

s0&s1-混流
s0&s2-混流
s0&s2-混流
s0&s1-混流
s1
s2
s1
s2
client0
sip gateway
client1
client2
  • 参会者三人 client0、client1、client2。
  • 会议发起人为:client0。
  • 会控管理:client0接收所有参会者的实时流,然后为其余client提供混流数据。

sipua 内网穿透问题

owt引用的sipua默认没有开启内网穿透,但是sipua已经具备了内网穿透的功能模块,下面记录如何开启内网穿透功能。

sipua实现内网穿透主要方式有以下几种:

  • comedia
  • stun
  • ice
  • netpmp

owt的sipua编译脚本并没有将stun ice netpmp编译进工程,所以想要启用这些功能首先需要将这些模块编译进工程。

comedia

comedia比较特殊,它的实现思路不需要客户端参与公网地址发现,而是sip 客户端主动向 sip gateway 的udp端口发送rtp和rtcp包以达到sip gateway能够发现客户端公网地址端口的目的。

	snprintf(account_str, sizeof(account_str),
             "%.128s <sip:%.128s:%.64s@%.128s>;regint=%d;regq=0.5;answermode=auto;rtpkeep=zero;",
             disp_name, user_name, password, sip_server, 7200 ) ;

在这里插入图片描述
修改此处代码,sipua会主动向服务器发送空rtp包。
要特别注意的是:若想使用comedia功能,需要服务端支持comedia,所以sip gateway要开启comedia,以asterisk为例修改配置文件/etc/asterisk/sip.conf
在这里插入图片描述

stun

开启stun和ice的流程是一样的,首先修改Makefile将stun和ice模块编译进主工程
在这里插入图片描述

  1. 添加模块初始化函数
    在这里插入图片描述

  2. 调用初始化函数
    在这里插入图片描述

  3. 添加sip连接参数
    在这里插入图片描述
    如果要开启ice,则只需要将medianat=stun 替换成 medianat=ice

修复sipua生成的sdp

sdp中connection信息为网卡ip,即使使用ice和stun也只是修改了m=行的connection。而sip gateway使用的是全局的connection,所以需要将全局connection的ip换成ice和stun获得的ip。
修改后的stun.c代码

/**
 * @file stun.c STUN Module for Media NAT-traversal
 *
 * Copyright (C) 2010 Creytiv.com
 */
#include <re/re.h>
#include <baresip.h>

/**
 * @defgroup stun stun
 *
 * Session Traversal Utilities for NAT (STUN) for media NAT traversal
 */


enum {LAYER = 0, INTERVAL = 30};

struct mnat_sess {
	struct list medial;
	struct sa srv;
	struct stun_dns *dnsq;
	mnat_estab_h *estabh;
	void *arg;
	int mediac;
	struct sdp_session *ss;
};


struct mnat_media {
	struct le le;
	struct sa addr1;
	struct sa addr2;
	struct mnat_sess *sess;
	struct sdp_media *sdpm;
	struct stun_keepalive *ska1;
	struct stun_keepalive *ska2;
	void *sock1;
	void *sock2;
	int proto;
	struct sdp_session *ss;
};


static struct mnat *mnat;


static void session_destructor(void *arg)
{
	struct mnat_sess *sess = arg;

	list_flush(&sess->medial);
	mem_deref(sess->dnsq);
}


static void media_destructor(void *arg)
{
	struct mnat_media *m = arg;

	list_unlink(&m->le);
	mem_deref(m->sdpm);
	mem_deref(m->ska1);
	mem_deref(m->ska2);
	mem_deref(m->sock1);
	mem_deref(m->sock2);
}


static void mapped_handler1(int err, const struct sa *map_addr, void *arg)
{
	struct mnat_media *m = arg;

	if (!err) {

		sdp_session_set_laddr(m->ss, map_addr);
		sdp_media_set_laddr(m->sdpm, map_addr);

		m->addr1 = *map_addr;

		if (m->ska2 && !sa_isset(&m->addr2, SA_ALL))
			return;

		if (--m->sess->mediac)
			return;
	}

	m->sess->estabh(err, 0, NULL, m->sess->arg);
}


static void mapped_handler2(int err, const struct sa *map_addr, void *arg)
{
	struct mnat_media *m = arg;

	if (!err) {

		sdp_media_set_laddr_rtcp(m->sdpm, map_addr);

		m->addr2 = *map_addr;

		if (m->ska1 && !sa_isset(&m->addr1, SA_ALL))
			return;

		if (--m->sess->mediac)
			return;
	}

	m->sess->estabh(err, 0, NULL, m->sess->arg);
}


static int media_start(struct mnat_sess *sess, struct mnat_media *m)
{
	int err = 0;

	if (m->sock1) {
		err |= stun_keepalive_alloc(&m->ska1, m->proto,
					    m->sock1, LAYER, &sess->srv, NULL,
					    mapped_handler1, m);
	}
	if (m->sock2) {
		err |= stun_keepalive_alloc(&m->ska2, m->proto,
					    m->sock2, LAYER, &sess->srv, NULL,
					    mapped_handler2, m);
	}
	if (err)
		return err;

	stun_keepalive_enable(m->ska1, INTERVAL);
	stun_keepalive_enable(m->ska2, INTERVAL);

	return 0;
}


static void dns_handler(int err, const struct sa *srv, void *arg)
{
	struct mnat_sess *sess = arg;
	struct le *le;

	if (err)
		goto out;

	sess->srv = *srv;

	for (le=sess->medial.head; le; le=le->next) {

		struct mnat_media *m = le->data;

		m->ss = sess->ss;
		err = media_start(sess, m);
		if (err)
			goto out;
	}

	return;

 out:
	sess->estabh(err, 0, NULL, sess->arg);
}


static int session_alloc(struct mnat_sess **sessp, struct dnsc *dnsc,
			 int af, const char *srv, uint16_t port,
			 const char *user, const char *pass,
			 struct sdp_session *ss, bool offerer,
			 mnat_estab_h *estabh, void *arg)
{
	struct mnat_sess *sess;
	int err;
	(void)user;
	(void)pass;
//	(void)ss;
	(void)offerer;

	if (!sessp || !dnsc || !srv || !ss || !estabh)
		return EINVAL;

	sess = mem_zalloc(sizeof(*sess), session_destructor);
	if (!sess)
		return ENOMEM;

	sess->estabh = estabh;
	sess->arg    = arg;
	sess->ss = ss;

	err = stun_server_discover(&sess->dnsq, dnsc,
				   stun_usage_binding, stun_proto_udp,
				   af, srv, port, dns_handler, sess);

	if (err)
		mem_deref(sess);
	else
		*sessp = sess;

	return err;
}


static int media_alloc(struct mnat_media **mp, struct mnat_sess *sess,
		       int proto, void *sock1, void *sock2,
		       struct sdp_media *sdpm)
{
	struct mnat_media *m;
	int err = 0;

	if (!mp || !sess || !sdpm)
		return EINVAL;

	m = mem_zalloc(sizeof(*m), media_destructor);
	if (!m)
		return ENOMEM;

	list_append(&sess->medial, &m->le, m);
	m->sdpm  = mem_ref(sdpm);
	m->sess  = sess;
	m->sock1 = mem_ref(sock1);
	m->sock2 = mem_ref(sock2);
	m->proto = proto;
	m->ss = sess->ss;

	if (sa_isset(&sess->srv, SA_ALL))
		err = media_start(sess, m);

	if (err)
		mem_deref(m);
	else {
		*mp = m;
		++sess->mediac;
	}

	return err;
}


static int module_init(void)
{
	return mnat_register(&mnat, "stun", NULL, session_alloc, media_alloc,
			     NULL);
}

int stun_module_init(void)
{
	return mnat_register(&mnat, "stun", NULL, session_alloc, media_alloc,
			     NULL);
}

static int module_close(void)
{
	mnat = mem_deref(mnat);

	return 0;
}


EXPORT_SYM const struct mod_export DECL_EXPORTS(stun) = {
	"stun",
	"mnat",
	module_init,
	module_close,
};

netpmp

关于netpmp,这里就不过多讨论了,因为使用上述三种方案已经能够实现内网穿透。有不明白的可以进群交流。

QQ交流群:697773082

QQ交流群:697773082

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值