Skip to content

Commit

Permalink
chore: Add a section for an external SIP signaling server to the GB28…
Browse files Browse the repository at this point in the history
…181 document. (#67)

* chore: Add a section for an external SIP signaling server to the GB28181 document.

* chore: Update GB28181 document with improved wording and formatting

* chore: Update GB28181 document with repository link

* chore: update register

* Update README for GB SIP.

* Update

---------

Co-authored-by: winlin <[email protected]>
  • Loading branch information
duiniuluantanqin and winlinvip authored Jul 27, 2024
1 parent 0466579 commit 6e08afa
Showing 1 changed file with 49 additions and 96 deletions.
145 changes: 49 additions & 96 deletions i18n/zh-cn/docusaurus-plugin-content-docs/current/doc/gb28181.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,57 @@ GB相关的协议如下:
* [GB28181-2016: 公共安全视频监控联网系统信息传输、交换、控制技术要求](https://openstd.samr.gov.cn/bzgk/gb/newGbInfo?hcno=469659DC56B9B8187671FF08748CEC89)
* [ISO13818-1-2000](https://ossrs.net/lts/zh-cn/assets/files/hls-mpeg-ts-iso13818-1-d21d1e9765012a327f03b43ce460079a.pdf): MPEGPS(Program Stream), PS媒体流规范。

## External Sip

> Note: SRS 6.0.135+支持外部SIP,若需要使用这个功能,请升级到这个版本。
目前SRS内置的SIP服务器仅实现了简单的`Register``Invite`指令,而要实现GB/T-28181的全部功能,势必会引入复杂的上层业务逻辑。
因此,我们开发了一个独立的外置的SIP服务器。而SRS,只需开放几个简单的API接口,这样既保证了其媒体转发服务器的单一属性,
又兼顾了与第三方SIP信令服务器对接的需求。

播放器请求SRS-SIP,SRS-SIP向SRS Server申请媒体端口,然后邀请GB28181 Device设备推流。设备推流到SRS后,播放器直接从SRS播放流。
下面是几个组件的关系图,详细的交互时序图参考[srs-sip](https://github.com/ossrs/srs-sip#sequence)

```text
+-------------API/Media--------------------+
| |
+----------+ +------------+ +------+------+ +----------------+
| Player +--API--+ SRS-SIP +---API--+ SRS Server +----Media----+ GB28181 Device +
+----------+ +-----+------+ +-------------+ +-------+--------+
| |
+------------------SIP-------------------------+
```

> Note: 暂时没有实现鉴权功能,敬请期待。
摄像头上面的配置方法同上,仅需将SIP服务器地址从SRS改成SRS-SIP。

首先启动SRS,请确认版本为`6.0.135+`,使用配置`conf/gb28181-without-sip.conf`,参考[Usage](#usage)

```bash
./objs/srs -c conf/gb28181-without-sip.conf
```

然后启动SRS-SIP,参考[srs-sip](https://github.com/ossrs/srs-sip#usage)

```bash
./bin/srs-sip -sip-port 5060 -media-addr 127.0.0.1:1985 -api-port 2020 -http-server-port 8888
```

* `-sip-port`是SIP服务器的端口,默认是5060。GB摄像头和这个SIP服务器通信,完成设备注册等能力。
* `-media-addr`是SRS的媒体服务器地址,SIP服务器返回这个地址给GB摄像头,GB摄像头推流到这个地址。
* `-api-port`是SIP服务器的API端口,默认是2020。这个API是给Player和用户使用的,比如查询设备列表、要求摄像头推流等。
* `-http-server-port`是SIP服务器的Web端口,默认是8888。这个HTTP服务器是提供网页的web服务器,用户通过网页访问摄像头。

启动GB28181设备,将SIP服务器地址改成SRS-SIP的地址,端口为5060。

现在,可以通过SRS-SIP内置的网页播放器测试 [http://localhost:8888](http://localhost:8888)

## SIP Parser

C++没有特别好的SIP库,这也是SIP处理不稳定的一个原因
SRS本身也内嵌了一个简单的SIP服务器,支持部分SIP协议的解析;不过C++没有特别好的SIP库,这也是之前SIP处理不稳定的一个原因

不过发现SIP协议和HTTP协议结构非常一致,因此SRS采用[http-parser](https://github.com/ossrs/http-parser)解析SIP,这个库是nodejs维护的,之前好像是NGINX中扒出来的,所以稳定性还是非常高的。
调研发现,SIP协议和HTTP协议结构非常一致,因此SRS采用[http-parser](https://github.com/ossrs/http-parser)解析SIP,这个库是nodejs维护的,之前好像是NGINX中扒出来的,所以稳定性还是非常高的。

当然用HTTP解析SIP,需要有些修改,主要是以下修改:

Expand Down Expand Up @@ -324,100 +370,7 @@ GB存在和[Source清理](https://github.com/ossrs/srs/issues/413#issuecomment-1

Source清理的问题,本质上是多个协程之间生命周期不同步,所以如果释放Source后可能有些协程活得比Source更久,就可能出现野指针引用。详细请查看[#413](https://github.com/ossrs/srs/issues/413)的描述。

而这些问题的解决方案都是Lazy Sweep,也就是互相持有的不是裸指针,而是Wrapper指针(有点像C++ 11的智能指针只是没有什么智能可言),因为Wrapper释放后Resource还是可用的,其他Wrapper对象还是可以使用Resource,我们在释放Resource时,等所有Wrapper都释放后再安全释放,也就是Lazy Sweep。

先在SRS 5.0 GB上实现这个机制,估计在6.0就可以比较容易实现Source的释放了。

比如有两个资源,互相依赖,定义如下:

```cpp
class SrsLazyGbSipTcpConn : public ISrsLazyResource {
private:
SrsLazyGbSessionWrapper* session_;
};

class SrsLazyGbSession : public ISrsLazyResource {
private:
SrsLazyGbSipTcpConnWrapper* sip_;
};
```
它们对应的Wrapper定义如下,使用宏定义会很简单:
```cpp
class SrsLazyGbSipTcpConnWrapper : public ISrsResource, public ISrsGbSipConnWrapper {
SRS_LAZY_WRAPPER_GENERATOR(SrsLazyGbSipTcpConn, SrsLazyGbSipTcpConnWrapper, SrsLazyGbSipTcpConn);
};
class SrsLazyGbSessionWrapper : public ISrsResource {
SRS_LAZY_WRAPPER_GENERATOR(SrsLazyGbSession, SrsLazyGbSessionWrapper, SrsLazyGbSession);
};
```

比如sip对象创建Session,放到全局对象管理manager里面,然后自己拷贝一份引用:

```cpp
SrsLazyGbSessionWrapper* session = new SrsLazyGbSessionWrapper();
_srs_gb_manager->add_with_id(device, session);
session_ = session->copy();
```
这样在释放sip对象时,是直接释放的session的wrapper,而在sip对象生命周期中,session一直是可用的:
```cpp
SrsLazyGbMediaTcpConn::~SrsLazyGbMediaTcpConn() {
srs_freep(session_);
}
srs_error_t SrsLazyGbSipTcpConn::cycle() {
session_->resource()->on_sip_dispose();
```

同样,session对象拥有的是sip对象的wrapper,是sip自己传过来的,session会持有一份拷贝:

```cpp
void SrsLazyGbSession::on_sip_transport(SrsLazyGbSipTcpConnWrapper* sip) {
srs_freep(sip_);
sip_ = sip->copy();
}
```
这样在session释放时,也是直接释放sip的wrapper,在session生命周期中,sip一直都是可用的:
```cpp
SrsLazyGbSession::~SrsLazyGbSession() {
srs_freep(sip_);
}
srs_error_t SrsLazyGbSession::cycle() {
sip_->resource()->interrupt();
srs_error_t SrsLazyGbSession::do_cycle() {
while (true) {
if (sip_->resource()->is_bye()) {
srs_error_t SrsLazyGbSession::drive_state() {
if (state_ == SrsGbSessionStateInit) {
if (sip_->resource()->is_registered()) {
```

而sip和session在释放自己的wrapper时,也不用关注谁在使用,只需要根据自己的创建选择对应的释放即可,比如一般使用manager管理对象,那么就应该使用manager释放对象:

```cpp
srs_error_t SrsLazyGbSipTcpConn::cycle() {
// Note that we added wrapper to manager, so we must free the wrapper, not this connection.
SrsLazyGbSipTcpConnWrapper* wrapper = dynamic_cast<SrsLazyGbSipTcpConnWrapper*>(gc_creator_wrapper());
_srs_gb_manager->remove(wrapper);

srs_error_t SrsLazyGbSession::cycle() {
// Note that we added wrapper to manager, so we must free the wrapper, not this connection.
SrsLazyGbSessionWrapper* wrapper = dynamic_cast<SrsLazyGbSessionWrapper*>(gc_creator_wrapper());
_srs_gb_manager->remove(wrapper);
```
此外,wrapper对象就是普通的对象,可以直接被释放,也可以用manager释放,都是可以的。
这个方案和直接裸指针引用的差别,在于增加了一个wrapper对象,没有任何其他特别的地方,看起来只是加了一层函数而已,是最简单的方案。
SRS 6.0引入了Smart Pointer,解决了Source清理的问题,具体参考[SmartPtr for GB](https://github.com/ossrs/srs/commit/6834ec208d67fa47c21536d1f1041bb6d60c1834)的修改。

## Benchmark

Expand Down

0 comments on commit 6e08afa

Please sign in to comment.