diff --git a/.circleci/config.yml b/.circleci/config.yml index 59be9a326..518e1bb57 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,14 +24,6 @@ jobs: - run: | echo "Build SRS without NASM or SRTP-NASM" && cd trunk && ./configure --nasm=off --srtp-nasm=off && make - build-c7-gb28181: - docker: - - image: ossrs/srs:dev - steps: - - checkout - - run: | - echo "Build SRS with GB28181" && - cd trunk && ./configure --gb28181=on && make build-c7-srt: docker: - image: ossrs/srs:dev @@ -111,7 +103,7 @@ jobs: - checkout - run: | echo "Build and run utest for SRS" && - cd trunk && ./configure --gb28181=on --utest=on --gcov=on && make && + cd trunk && ./configure --utest=on --gcov=on && make && ./objs/srs_utest && bash auto/codecov.sh run-regression-test: docker: @@ -140,7 +132,6 @@ workflows: - run-regression-test - build-c7-nortc - build-c7-noasm - - build-c7-gb28181 - build-c7-srt - build-c8-baseline - build-c8-srt diff --git a/CHANGELOG.md b/CHANGELOG.md index 34d6cc689..e2120c59a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,16 +6,14 @@ The changelog for SRS. ## SRS 4.0 Changelog +* v4.0, 2021-06-16, Change [GB28181](https://github.com/ossrs/srs/issues/1500) to [feature/gb28181](https://github.com/ossrs/srs/tree/feature/gb28181). 4.0.127 * v4.0, 2021-06-01, Support --shared-ffmpeg to link with *.so for LGPL license. 4.0.126 * v4.0, 2021-06-01, Support --shared-srt to link with *.so for MPL license. 4.0.125 * v4.0, 2021-05-31, Use [SPDX-License-Identifier: MIT](https://spdx.dev/ids/). 4.0.124 -* v4.0, 2021-05-28, Fix bugs for GB28181 and RTC. 4.0.123 * v4.0, 2021-05-21, Fix [#2370][bug #2370] bug for Firefox play stream(published by Chrome). 4.0.121 * v4.0, 2021-05-21, RTC: Refine sdk, migrate from onaddstream to ontrack. 4.0.120 * v4.0, 2021-05-21, Tools: Refine configure options. 4.0.119 * v4.0, 2021-05-20, Fix build fail when disable RTC by --rtc=off. 4.0.118 -* v4.0, 2021-05-19, Fix [#2362][bug #2362]: Allow WebRTC to play before publishing, for GB28181 as such. 4.0.117 -* v4.0, 2021-05-18, Fix [#2355][bug #2355]: GB28181: Fix play by RTC bug. 4.0.116 * v4.0, 2021-05-15, SRT: Build SRT from source by SRS. 4.0.115 * v4.0, 2021-05-15, Rename SrsConsumer* to SrsLiveConsumer*. 4.0.114 * v4.0, 2021-05-15, Rename SrsRtcStream* to SrsRtcSource*. 4.0.113 @@ -63,7 +61,6 @@ The changelog for SRS. * v4.0, 2021-01-08, HTML5 video tag resolution adaptive. 4.0.59 * v4.0, 2021-01-08, Fix memory leak and bugs for RTC. 4.0.58 * v4.0, 2021-01-06, Merge #2109, Refine srs_string_split. -* v4.0, 2021-01-06, Merge #2109, Fix bugs for GB28181. * v4.0, 2020-12-24, Support disable CherryPy. 4.0.57 * v4.0, 2020-11-12, For [#1998][bug #1998], Support Firefox, use PT in offer. 4.0.55 * v4.0, 2020-11-11, For [#1508][bug #1508], Transform http header name to upper camel case. 4.0.54 @@ -81,10 +78,8 @@ The changelog for SRS. * v4.0, 2020-07-25, RTC: Support multiple address for client. 4.0.36 * v4.0, 2020-07-11, Refine log context with random string. 4.0.35 * v4.0, 2020-07-04, Fix some bugs for RTC. 4.0.34 -* v4.0, 2020-07-03, Merge [#1830][bug #1830] to fix bugs in GB28181. 4.0.33 * v4.0, 2020-06-24, Support static link c++ libraries. 4.0.32 * v4.0, 2020-06-23, Change log cid from int to string. 4.0.31 -* v4.0, 2020-06-13, GB28181 with JitterBuffer support. 4.0.30 * v4.0, 2020-06-03, Support enable C++11. 4.0.29 * v4.0, 2020-05-31, Remove [srs-librtmp](https://github.com/ossrs/srs/issues/1535#issuecomment-633907655). 4.0.28 * v4.0, 2020-05-21, For [#307][bug #307], disable GSO and sendmmsg. 4.0.27 @@ -93,10 +88,8 @@ The changelog for SRS. * v4.0, 2020-04-30, For [#307][bug #307], support publish RTC with passing opus. 4.0.24 * v4.0, 2020-04-14, For [#307][bug #307], support sendmmsg, GSO and reuseport. 4.0.23 * v4.0, 2020-04-05, For [#307][bug #307], SRTP ASM only works with openssl-1.0, auto detect it. 4.0.22 -* v4.0, 2020-04-04, Merge RTC and GB28181, with bugs fixed. 4.0.21 * v4.0, 2020-04-04, For [#307][bug #307], refine RTC latency from 600ms to 200ms. 4.0.20 * v4.0, 2020-04-03, For [#307][bug #307], build SRTP with openssl to improve performance. 4.0.19 -* v4.0, 2020-03-31, For [#1500][bug #1500], support push stream by GB28181. 4.0.18 * v4.0, 2020-03-31, Play stream by WebRTC on iOS/Android/PC browser. 4.0.17 * v4.0, 2020-03-28, Support multiple OS/Platform build cache. 4.0.16 * v4.0, 2020-03-28, For [#1250][bug #1250], support macOS, OSX, MacbookPro, Apple Darwin. diff --git a/README.md b/README.md index 3b1bc90a9..390cf8b64 100755 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ [![](https://codecov.io/gh/ossrs/srs/branch/4.0release/graph/badge.svg)](https://codecov.io/gh/ossrs/srs/branch/4.0release) [![](https://cloud.githubusercontent.com/assets/2777660/22814959/c51cbe72-ef92-11e6-81cc-32b657b285d5.png)](https://github.com/ossrs/srs/wiki/v4_CN_Contact#wechat) -SRS/4.0,[Leo][release4],是一个简单高效的实时视频服务器,支持RTMP/WebRTC/HLS/HTTP-FLV/SRT/GB28181。 +SRS/4.0,[Leo][release4],是一个简单高效的实时视频服务器,支持RTMP/WebRTC/HLS/HTTP-FLV/SRT。 -SRS is a simple, high efficiency and realtime video server, supports RTMP/WebRTC/HLS/HTTP-FLV/SRT/GB28181. +SRS is a simple, high efficiency and realtime video server, supports RTMP/WebRTC/HLS/HTTP-FLV/SRT. SRS is licenced under [MIT][LICENSE], but some depended libraries are distributed using their [own licenses][LicenseMixing]. @@ -69,7 +69,6 @@ Fast index for Wikis: Other important wiki: -* Usage: How to publish GB28181 to SRS? [#1500](https://github.com/ossrs/srs/issues/1500#issuecomment-606695679) * Usage: How to delivery DASH(Experimental)?([CN][v4_CN_SampleDASH], [EN][v4_EN_SampleDASH]) * Usage: How to transode RTMP stream by FFMPEG?([CN][v4_CN_SampleFFMPEG], [EN][v4_EN_SampleFFMPEG]) * Usage: How to delivery HTTP FLV Live Streaming Cluster?([CN][v4_CN_SampleHttpFlvCluster], [EN][v4_EN_SampleHttpFlvCluster]) @@ -121,9 +120,6 @@ For optional stream caster services, to push streams to SRS: * udp://8935, Stream Caster: [Push MPEGTS over UDP](https://github.com/ossrs/srs/wiki/v4_CN_Streamer#push-mpeg-ts-over-udp) server. * tcp://554, Stream Caster: [Push RTSP](https://github.com/ossrs/srs/wiki/v4_CN_Streamer#push-rtsp-to-srs) server. * tcp://8936, Stream Caster: [Push HTTP-FLV](https://github.com/ossrs/srs/wiki/v4_CN_Streamer#push-http-flv-to-srs) server. -* tcp://5060, Stream Caster: [Push GB28181 SIP](https://github.com/ossrs/srs/issues/1500#issuecomment-606695679) server. -* udp://9000, Stream Caster: [Push GB28181 Media(bundle)](https://github.com/ossrs/srs/issues/1500#issuecomment-606695679) server. -* udp://58200-58300, Stream Caster: [Push GB28181 Media(no-bundle)](https://github.com/ossrs/srs/issues/1500#issuecomment-606695679) server. * udp://10080, Stream Caster: [Push SRT Media](https://github.com/ossrs/srs/issues/1147#issuecomment-577469119) server. For external services to work with SRS: @@ -176,7 +172,7 @@ For external services to work with SRS: - [x] [Experimental] Support transcode RTMP/AAC to WebRTC/Opus, [#307][bug #307]. - [x] [Experimental] Support AV1 codec for WebRTC, [#2324][bug #2324]. - [x] [Experimental] Enhance HTTP Stream Server for HTTP-FLV, HTTPS, HLS etc. [#1657][bug #1657]. -- [x] [Experimental] Support push stream by GB28181, [#1500][bug #1500]. +- [ ] Support push stream by GB28181, [#1500][bug #1500]. - [x] [Experimental] Support DVR in MP4 format, read [#738][bug #738]. - [x] [Experimental] Support MPEG-DASH, the future live streaming protocol, read [#299][bug #299]. - [x] [Experimental] Support pushing MPEG-TS over UDP, please read [bug #250][bug #250]. @@ -306,7 +302,7 @@ The stream architecture of SRS. | MediaSource(2) | | | | (MPEGTSoverUDP | | | | HTTP-FLV, --push-+->- StreamCaster(4) -(rtmp)-+-> SRS | -| GB28181,SRT, | | | +| SRT, | | | | ......) | | | +----------------------+ | | | FFMPEG --push(srt)--+->- SRTModule(5) ---(rtmp)-+-> SRS | diff --git a/trunk/auto/auto_headers.sh b/trunk/auto/auto_headers.sh index fa6a55e58..589861869 100755 --- a/trunk/auto/auto_headers.sh +++ b/trunk/auto/auto_headers.sh @@ -85,12 +85,6 @@ else srs_undefine_macro "SRS_SIMULATOR" $SRS_AUTO_HEADERS_H fi -if [ $SRS_GB28181 = YES ]; then - srs_define_macro "SRS_GB28181" $SRS_AUTO_HEADERS_H -else - srs_undefine_macro "SRS_GB28181" $SRS_AUTO_HEADERS_H -fi - if [ $SRS_HTTPS = YES ]; then srs_define_macro "SRS_HTTPS" $SRS_AUTO_HEADERS_H else diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index 36510a7a1..309f1c66c 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -299,15 +299,6 @@ function OSX_prepare() echo "Please install pkg-config"; exit -1; fi - if [[ $SRS_GB28181 == YES ]]; then - if [[ ! -f /usr/local/opt/libiconv/lib/libiconv.a ]]; then - echo "install libiconv" - echo "brew install libiconv" - brew install libiconv; ret=$?; if [[ 0 -ne $ret ]]; then return $ret; fi - echo "install libiconv success" - fi - fi - if [[ $SRS_SRT == YES ]]; then echo "SRT enable, install depend tools" tclsh <<< "exit" >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh index 2b989c895..574730a0c 100755 --- a/trunk/auto/options.sh +++ b/trunk/auto/options.sh @@ -6,7 +6,6 @@ help=no SRS_HDS=NO SRS_SRT=NO SRS_RTC=RESERVED -SRS_GB28181=NO SRS_CXX11=NO SRS_CXX14=NO SRS_NGINX=NO @@ -115,7 +114,6 @@ Features: --utest=on|off Whether build the utest. Default: $(value2switch $SRS_UTEST) --srt=on|off Whether build the SRT. Default: $(value2switch $SRS_SRT) --rtc=on|off Whether build the WebRTC. Default: $(value2switch $SRS_RTC) - --gb28181=on|off Whether build the GB28181. Default: $(value2switch $SRS_GB28181) --cxx11=on|off Whether enable the C++11. Default: $(value2switch $SRS_CXX11) --cxx14=on|off Whether enable the C++14. Default: $(value2switch $SRS_CXX14) --ffmpeg-fit=on|off Whether enable the FFmpeg fit(source code). Default: $(value2switch $SRS_FFMPEG_FIT) @@ -265,10 +263,6 @@ function parse_user_option() { --simulator) SRS_SIMULATOR=$(switch2value $value) ;; --ffmpeg-fit) SRS_FFMPEG_FIT=$(switch2value $value) ;; - --with-gb28181) SRS_GB28181=YES ;; - --without-gb28181) SRS_GB28181=NO ;; - --gb28181) SRS_GB28181=$(switch2value $value) ;; - --cxx11) SRS_CXX11=$(switch2value $value) ;; --cxx14) SRS_CXX14=$(switch2value $value) ;; @@ -473,7 +467,6 @@ function regenerate_options() { SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --srt=$(value2switch $SRS_SRT)" SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --rtc=$(value2switch $SRS_RTC)" SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --simulator=$(value2switch $SRS_SIMULATOR)" - SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gb28181=$(value2switch $SRS_GB28181)" SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --cxx11=$(value2switch $SRS_CXX11)" SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --cxx14=$(value2switch $SRS_CXX14)" SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --ffmpeg-fit=$(value2switch $SRS_FFMPEG_FIT)" diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 27416b7f2..2a1d76d59 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -366,89 +366,6 @@ stream_caster { listen 8936; } -# GB28181 -stream_caster { - # whether stream caster is enabled. - # default: off - enabled on; - # the caster type of stream, the casters: - # gb28181, Push GB28181 to SRS. - caster gb28181; - # the output rtmp url. - # for gb28181 caster, the typically output url: - # rtmp://127.0.0.1/live/[stream] - # where the [stream] is the VideoChannelCodecID. - output rtmp://127.0.0.1/live/[stream]; - # the listen port for stream caster. - # for gb28181 caster, listen at udp port. for example, 9000. - # @remark We can bundle all gb28181 to this port, to reuse this port. - # User can choose to bundle port in API port_mode or SIP invite_port_fixed. - listen 9000; - # Listen as TCP if on; otherwise, listen as UDP. - # default: off - tcp_enable off; - # If not bundle ports, use specified ports for each stream. - rtp_port_min 58200; - rtp_port_max 58300; - # Whether wait for keyframe then forward to RTMP. - # default: on - wait_keyframe on; - # Max timeout in seconds for RTP stream, if timeout, RTCP bye and close stream. - # default: 30 - rtp_idle_timeout 30; - # Whether has audio. - # @remark Flash/RTMP only supports 11025 22050 44100 sample rate, if not the audio may corrupt. - # default: off - audio_enable off; - # The exposed IP to receive media stream. - # * Retrieve server IP automatically, from all network interfaces. - # eth0 Retrieve server IP by specified network interface name. # TODO: Implements it. - # $CANDIDATE Read the IP from ENV variable $EIP, use * if not set, see https://github.com/ossrs/srs/issues/307#issuecomment-599028124 - # x.x.x.x A specified IP address or DNS name, which can be access by client such as Chrome. - # You can specific more than one interface name: - # eth0 eth1 Use network interface eth0 and eth1. # TODO: Implements it. - # Also by IP or DNS names: - # 192.168.1.3 10.1.2.3 rtc.me # TODO: Implements it. - # And by multiple ENV variables: - # $CANDIDATE $EIP # TODO: Implements it. - # default: * - host *; - #The media channel is automatically created according to the received RTP packet, - # and the channel ID is generated according to the RTP SSRC - # channelid format: 'chid[ssrc]' [ssrc] is rtp's ssrc - auto_create_channel off; - - sip { - # Whether enable embeded SIP server. - # default: on - enabled on; - # The SIP listen port. - # default: 5060 - listen 5060; - # The SIP server ID. - # default: 34020000002000000001 - serial 34020000002000000001; - # The SIP server domain. - # default: 3402000000 - realm 3402000000; - # The SIP ACK response timeout in seconds. - # default: 30 - ack_timeout 30; - # The keepalive timeout in seconds. - # default: 120 - keepalive_timeout 120; - # Whether play immediately after registered. - # default: on - auto_play on; - # Whether bundle media stream port. - # default: on - invite_port_fixed on; - # interval to query equipment list from equipment or subordinate domain, unit(s) - # default: 60 - query_catalog_interval 60; - } -} - ############################################################################################# # SRT server section ############################################################################################# diff --git a/trunk/conf/push.gb28181.conf b/trunk/conf/push.gb28181.conf deleted file mode 100644 index 0890dd94f..000000000 --- a/trunk/conf/push.gb28181.conf +++ /dev/null @@ -1,143 +0,0 @@ -# push gb28181 stream to SRS. - -listen 1935; -max_connections 1000; -daemon off; -srs_log_tank console; - -http_api { - enabled on; - listen 1985; -} - -http_server { - enabled on; - listen 8080; -} - -stats { - network 0; -} - -stream_caster { - enabled on; - caster gb28181; - - # 转发流到rtmp服务器地址与端口 - # TODO: https://github.com/ossrs/srs/pull/1679/files#r400875104 - # [stream] is VideoChannelCodecID(视频通道编码ID) for sip - # 自动创建的道通[stream] 是‘chid[ssrc]’ [ssrc]是rtp的ssrc - # [ssrc] rtp中的ssrc - output rtmp://127.0.0.1:1935/live/[stream]; - - # 接收设备端rtp流的多路复用端口 - listen 9000; - # 多路复用端口类型,on为tcp,off为udp - # 默认:on - tcp_enable on; - - # rtp接收监听端口范围,最小值 - rtp_port_min 58200; - # rtp接收监听端口范围,最大值 - rtp_port_max 58300; - - # 是否等待关键帧之后,再转发, - # off:不需等待,直接转发 - # on:等第一个关键帧后,再转发 - wait_keyframe on; - - # rtp包空闲等待时间,如果指定时间没有收到任何包 - # rtp监听连接自动停止,发送BYE命令 - rtp_idle_timeout 30; - - # 是否转发音频流 - # 目前只支持aac格式,所以需要设备支持aac格式 - # on:转发音频 - # off:不转发音频,只有视频 - # *注意*!!!:flv 只支持11025 22050 44100 三种 - # 如果设备端没有三种中任何一个,转发时为自动选择一种格式 - # 同时也会将adts的头封装在flv aac raw数据中 - # 这样的话播放器为自动通过adts头自动选择采样频率 - # 像ffplay, vlc都可以,但是flash是没有声音, - # 因为flash,只支持11025 22050 44100 - audio_enable off; - - # 是否开启rtp缓冲 - # 开启之后能有效解决rtp乱序等问题 - # tcp模式建议关闭 - jitterbuffer_enable off; - - # 服务器主机号,可以域名或ip地址 - # 也就是设备端将媒体发送的地址,如果是服务器是内外网 - # 需要写外网地址, - # 调用api创建stream session时返回ip地址也是host - # $CANDIDATE 是系统环境变量,从环境变量获取地址,如果没有配置,用* - # *代表指定stats network 的网卡号地址,如果没有配置network,默认则是第0号网卡地址 - # TODO: https://github.com/ossrs/srs/pull/1679/files#r400917594 - host $CANDIDATE; - - #根据收到ps rtp包自带创建rtmp媒体通道,不需要api接口创建 - #rtmp地址参数[stream] 就是通道id 格式chid[ssrc] - auto_create_channel off; - - sip { - # 是否启用srs内部sip信令 - # 为on信令走srs, off 只转发ps流 - enabled on; - - # sip监听udp端口 - listen 5060; - - # SIP server ID(SIP服务器ID). - # 设备端配置编号需要与该值一致,否则无法注册 - serial 34020000002000000001; - - # SIP server domain(SIP服务器域) - realm 3402000000; - - # 服务端发送ack后,接收回应的超时时间,单位为秒 - # 如果指定时间没有回应,认为失败 - ack_timeout 30; - - # 设备心跳维持时间,如果指定时间内(秒)没有接收一个心跳 - # 认为设备离线 - keepalive_timeout 120; - - # 注册之后是否自动给设备端发送invite - # on: 是 off 不是,需要通过api控制 - auto_play on; - # 设备将流发送的端口,是否固定 - # on 发送流到多路复用端口 如9000 - # off 自动从rtp_mix_port - rtp_max_port 之间的值中 - # 选一个可以用的端口 - invite_port_fixed on; - - # 向设备或下级域查询设备列表的间隔,单位(秒) - # 默认60秒 - query_catalog_interval 60; - } -} - -rtc_server { - enabled on; - # Listen at udp://8000 - listen 8000; - # - # The $CANDIDATE means fetch from env, if not configed, use * as default. - # - # The * means retrieving server IP automatically, from all network interfaces, - # @see https://github.com/ossrs/srs/issues/307#issuecomment-599028124 - candidate $CANDIDATE; -} - -vhost __defaultVhost__ { - rtc { - enabled on; - bframe discard; - } - - http_remux { - enabled on; - mount [vhost]/[app]/[stream].flv; - } -} diff --git a/trunk/conf/push.gb28181.tcp.conf b/trunk/conf/push.gb28181.tcp.conf deleted file mode 100644 index 257195afd..000000000 --- a/trunk/conf/push.gb28181.tcp.conf +++ /dev/null @@ -1,143 +0,0 @@ -# push gb28181 stream to SRS. - -listen 1935; -max_connections 1000; -daemon off; -srs_log_tank console; - -http_api { - enabled on; - listen 1985; -} - -http_server { - enabled on; - listen 8080; -} - -stats { - network 0; -} - -stream_caster { - enabled on; - caster gb28181; - - # 转发流到rtmp服务器地址与端口 - # TODO: https://github.com/ossrs/srs/pull/1679/files#r400875104 - # [stream] is VideoChannelCodecID(视频通道编码ID) for sip - # 自动创建的道通[stream] 是‘chid[ssrc]’ [ssrc]是rtp的ssrc - # [ssrc] rtp中的ssrc - output rtmp://127.0.0.1:1935/live/[stream]; - - # 接收设备端rtp流的多路复用端口 - listen 9000; - # 多路复用端口类型,on为tcp,off为udp - # 默认:off - tcp_enable on; - - # rtp接收监听端口范围,最小值 - rtp_port_min 58200; - # rtp接收监听端口范围,最大值 - rtp_port_max 58300; - - # 是否等待关键帧之后,再转发, - # off:不需等待,直接转发 - # on:等第一个关键帧后,再转发 - wait_keyframe on; - - # rtp包空闲等待时间,如果指定时间没有收到任何包 - # rtp监听连接自动停止,发送BYE命令 - rtp_idle_timeout 30; - - # 是否转发音频流 - # 目前只支持aac格式,所以需要设备支持aac格式 - # on:转发音频 - # off:不转发音频,只有视频 - # *注意*!!!:flv 只支持11025 22050 44100 三种 - # 如果设备端没有三种中任何一个,转发时为自动选择一种格式 - # 同时也会将adts的头封装在flv aac raw数据中 - # 这样的话播放器为自动通过adts头自动选择采样频率 - # 像ffplay, vlc都可以,但是flash是没有声音, - # 因为flash,只支持11025 22050 44100 - audio_enable off; - - # 是否开启rtp缓冲 - # 开启之后能有效解决rtp乱序等问题 - # tcp模式建议关闭 - jitterbuffer_enable off; - - # 服务器主机号,可以域名或ip地址 - # 也就是设备端将媒体发送的地址,如果是服务器是内外网 - # 需要写外网地址, - # 调用api创建stream session时返回ip地址也是host - # $CANDIDATE 是系统环境变量,从环境变量获取地址,如果没有配置,用* - # *代表指定stats network 的网卡号地址,如果没有配置network,默认则是第0号网卡地址 - # TODO: https://github.com/ossrs/srs/pull/1679/files#r400917594 - host $CANDIDATE; - - #根据收到ps rtp包自带创建rtmp媒体通道,不需要api接口创建 - #rtmp地址参数[stream] 就是通道id 格式chid[ssrc] - auto_create_channel off; - - sip { - # 是否启用srs内部sip信令 - # 为on信令走srs, off 只转发ps流 - enabled on; - - # sip监听udp端口 - listen 5060; - - # SIP server ID(SIP服务器ID). - # 设备端配置编号需要与该值一致,否则无法注册 - serial 34020000002000000001; - - # SIP server domain(SIP服务器域) - realm 3402000000; - - # 服务端发送ack后,接收回应的超时时间,单位为秒 - # 如果指定时间没有回应,认为失败 - ack_timeout 30; - - # 设备心跳维持时间,如果指定时间内(秒)没有接收一个心跳 - # 认为设备离线 - keepalive_timeout 120; - - # 注册之后是否自动给设备端发送invite - # on: 是 off 不是,需要通过api控制 - auto_play on; - # 设备将流发送的端口,是否固定 - # on 发送流到多路复用端口 如9000 - # off 自动从rtp_mix_port - rtp_max_port 之间的值中 - # 选一个可以用的端口 - invite_port_fixed on; - - # 向设备或下级域查询设备列表的间隔,单位(秒) - # 默认60秒 - query_catalog_interval 60; - } -} - -rtc_server { - enabled on; - # Listen at udp://8000 - listen 8000; - # - # The $CANDIDATE means fetch from env, if not configed, use * as default. - # - # The * means retrieving server IP automatically, from all network interfaces, - # @see https://github.com/ossrs/srs/issues/307#issuecomment-599028124 - candidate $CANDIDATE; -} - -vhost __defaultVhost__ { - rtc { - enabled on; - bframe discard; - } - - http_remux { - enabled on; - mount [vhost]/[app]/[stream].flv; - } -} diff --git a/trunk/configure b/trunk/configure index 20cafeeab..92cf591bb 100755 --- a/trunk/configure +++ b/trunk/configure @@ -171,11 +171,6 @@ if [[ $SRS_SRT == YES ]]; then if [[ $SRS_SHARED_SRT == YES ]]; then LibSRTfile="-L${SRS_OBJS_DIR}/srt/lib -lsrt"; fi fi -# For iconv on macOS only, CentOS seems ok. -if [[ $SRS_GB28181 == YES && $SRS_OSX == YES ]]; then - LibIconvRoot="/usr/local/opt/libiconv/include"; LibIconvfile="/usr/local/opt/libiconv/lib/libiconv.a" -fi - # the link options, always use static link SrsLinkOptions="-ldl -lpthread"; if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == YES ]]; then @@ -287,13 +282,6 @@ fi if [[ $SRS_FFMPEG_FIT == YES ]]; then MODULE_FILES+=("srs_app_rtc_codec") fi -if [[ $SRS_GB28181 == YES ]]; then - MODULE_FILES+=("srs_app_gb28181" "srs_app_gb28181_sip" "srs_app_gb28181_jitter") -fi -if [[ $SRS_GB28181 == YES ]]; then - MODULE_FILES+=("srs_app_gb28181_stack") - ModuleLibIncs+=(${LibIconvRoot}) -fi DEFINES="" # add each modules for app @@ -373,9 +361,6 @@ fi if [[ $SRS_SRT == YES ]]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi -if [[ $SRS_GB28181 == YES ]]; then - ModuleLibFiles+=("${LibIconvfile[*]}") -fi # all depends objects MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]} ${SERVER_OBJS[@]}" ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibGperfRoot} ${LibSSLRoot}) diff --git a/trunk/research/players/rtc_player.html b/trunk/research/players/rtc_player.html index c1e574e23..ab0ad3ea4 100644 --- a/trunk/research/players/rtc_player.html +++ b/trunk/research/players/rtc_player.html @@ -31,7 +31,7 @@ -
  • GB28181
  • +
  • GitHub Repo stars diff --git a/trunk/research/players/rtc_publisher.html b/trunk/research/players/rtc_publisher.html index 3d1681051..6b102a289 100644 --- a/trunk/research/players/rtc_publisher.html +++ b/trunk/research/players/rtc_publisher.html @@ -31,7 +31,7 @@ -
  • GB28181
  • +
  • GitHub Repo stars diff --git a/trunk/research/players/srs_bwt.html b/trunk/research/players/srs_bwt.html index 961609685..a2858241b 100644 --- a/trunk/research/players/srs_bwt.html +++ b/trunk/research/players/srs_bwt.html @@ -29,7 +29,6 @@
  • SRS会议
  • SRS测网速
  • VLC播放器
  • -
  • SRS-GB28181
  • diff --git a/trunk/research/players/srs_chat.html b/trunk/research/players/srs_chat.html index 3ce343549..abed015fc 100644 --- a/trunk/research/players/srs_chat.html +++ b/trunk/research/players/srs_chat.html @@ -28,7 +28,7 @@
  • SRS会议
  • SRS测网速
  • VLC播放器
  • -
  • SRS-GB28181
  • + diff --git a/trunk/research/players/srs_player.html b/trunk/research/players/srs_player.html index 3881f1e9c..62b89489c 100755 --- a/trunk/research/players/srs_player.html +++ b/trunk/research/players/srs_player.html @@ -26,7 +26,7 @@ -
  • GB28181
  • +
  • GitHub Repo stars diff --git a/trunk/research/players/srs_player_deprecated.html b/trunk/research/players/srs_player_deprecated.html index e0e773884..26f21fcfc 100755 --- a/trunk/research/players/srs_player_deprecated.html +++ b/trunk/research/players/srs_player_deprecated.html @@ -40,7 +40,7 @@ -
  • GB28181
  • +
  • GitHub Repo stars diff --git a/trunk/research/players/vlc.html b/trunk/research/players/vlc.html index 893b280a6..4422301ef 100644 --- a/trunk/research/players/vlc.html +++ b/trunk/research/players/vlc.html @@ -25,7 +25,7 @@
  • SRS会议
  • SRS测网速
  • VLC播放器
  • -
  • SRS-GB28181
  • + diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 2558a2796..d6da1a435 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -262,11 +262,6 @@ bool srs_stream_caster_is_flv(string caster) return caster == "flv"; } -bool srs_stream_caster_is_gb28181(string caster) -{ - return caster == "gb28181"; -} - bool srs_config_apply_filter(SrsConfDirective* dvr_apply, SrsRequest* req) { static bool DEFAULT = true; @@ -4590,302 +4585,6 @@ int SrsConfig::get_stream_caster_rtp_port_max(SrsConfDirective* conf) return ::atoi(conf->arg0().c_str()); } -srs_utime_t SrsConfig::get_stream_caster_gb28181_rtp_idle_timeout(SrsConfDirective* conf) -{ - static srs_utime_t DEFAULT = 30 * SRS_UTIME_SECONDS; - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("rtp_idle_timeout"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return (srs_utime_t)(::atoi(conf->arg0().c_str()) * SRS_UTIME_SECONDS); -} - -srs_utime_t SrsConfig::get_stream_caster_gb28181_ack_timeout(SrsConfDirective* conf) -{ - static srs_utime_t DEFAULT = 30 * SRS_UTIME_SECONDS; - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("sip"); - if (!conf) { - return DEFAULT; - } - - conf = conf->get("ack_timeout"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return (srs_utime_t)(::atoi(conf->arg0().c_str()) * SRS_UTIME_SECONDS); -} - -srs_utime_t SrsConfig::get_stream_caster_gb28181_keepalive_timeout(SrsConfDirective* conf) -{ - static srs_utime_t DEFAULT = 120 * SRS_UTIME_SECONDS; - - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("sip"); - if (!conf) { - return DEFAULT; - } - - conf = conf->get("keepalive_timeout"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return (srs_utime_t)(::atoi(conf->arg0().c_str()) * SRS_UTIME_SECONDS); -} - -string SrsConfig::get_stream_caster_gb28181_host(SrsConfDirective* conf) -{ - static string DEFAULT = "*"; - - conf = conf->get("host"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - string eip = srs_getenv(conf->arg0()); - if (!eip.empty()) { - return eip; - } - - // If configed as ENV, but no ENV set, use default value. - if (srs_string_starts_with(conf->arg0(), "$")) { - return DEFAULT; - } - - return conf->arg0(); -} - -string SrsConfig::get_stream_caster_gb28181_serial(SrsConfDirective* conf) -{ - static string DEFAULT = "34020000002000000001"; - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("sip"); - if (!conf) { - return DEFAULT; - } - - conf = conf->get("serial"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return conf->arg0(); -} - -string SrsConfig::get_stream_caster_gb28181_realm(SrsConfDirective* conf) -{ - static string DEFAULT = "3402000000"; - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("sip"); - if (!conf) { - return DEFAULT; - } - - conf = conf->get("realm"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return conf->arg0(); -} - -bool SrsConfig::get_stream_caster_gb28181_audio_enable(SrsConfDirective* conf) -{ - static bool DEFAULT = false; - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("audio_enable"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return SRS_CONF_PERFER_FALSE(conf->arg0()); -} - -bool SrsConfig::get_stream_caster_gb28181_jitterbuffer_enable(SrsConfDirective* conf) -{ - static bool DEFAULT = true; - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("jitterbuffer_enable"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return SRS_CONF_PERFER_FALSE(conf->arg0()); -} - -bool SrsConfig::get_stream_caster_gb28181_wait_keyframe(SrsConfDirective* conf) -{ - static bool DEFAULT = true; - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("wait_keyframe"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return SRS_CONF_PERFER_FALSE(conf->arg0()); -} - -bool SrsConfig::get_stream_caster_gb28181_sip_enable(SrsConfDirective* conf) -{ - static bool DEFAULT = true; - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("sip"); - if (!conf) { - return DEFAULT; - } - - conf = conf->get("enabled"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return SRS_CONF_PERFER_FALSE(conf->arg0()); -} - -bool SrsConfig::get_stream_caster_gb28181_sip_auto_play(SrsConfDirective* conf) -{ - static bool DEFAULT = true; - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("sip"); - if (!conf) { - return DEFAULT; - } - - conf = conf->get("auto_play"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return SRS_CONF_PERFER_FALSE(conf->arg0()); - -} - -int SrsConfig::get_stream_caster_gb28181_sip_listen(SrsConfDirective* conf) -{ - static int DEFAULT = 5060; - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("sip"); - if (!conf) { - return DEFAULT; - } - - conf = conf->get("listen"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return ::atoi(conf->arg0().c_str()); - -} - -bool SrsConfig::get_stream_caster_gb28181_sip_invite_port_fixed(SrsConfDirective* conf) -{ - static bool DEFAULT = true; - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("sip"); - if (!conf) { - return DEFAULT; - } - - conf = conf->get("invite_port_fixed"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return SRS_CONF_PERFER_FALSE(conf->arg0()); - -} - -bool SrsConfig::get_stream_caster_gb28181_auto_create_channel(SrsConfDirective* conf) -{ - static bool DEFAULT = false; - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("auto_create_channel"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return SRS_CONF_PERFER_FALSE(conf->arg0()); -} - -srs_utime_t SrsConfig::get_stream_caster_gb28181_sip_query_catalog_interval(SrsConfDirective* conf) -{ - static srs_utime_t DEFAULT = 60 * SRS_UTIME_SECONDS; - - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("sip"); - if (!conf) { - return DEFAULT; - } - - conf = conf->get("query_catalog_interval"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return (srs_utime_t)(::atoi(conf->arg0().c_str()) * SRS_UTIME_SECONDS); -} - bool SrsConfig::get_rtc_server_enabled() { SrsConfDirective* conf = root->get("rtc_server"); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 0a51183c3..502ce9f65 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -102,7 +102,6 @@ extern bool srs_config_dvr_is_plan_session(std::string plan); extern bool srs_stream_caster_is_udp(std::string caster); extern bool srs_stream_caster_is_rtsp(std::string caster); extern bool srs_stream_caster_is_flv(std::string caster); -extern bool srs_stream_caster_is_gb28181(std::string caster); // Whether the dvr_apply active the stream specified by req. extern bool srs_config_apply_filter(SrsConfDirective* dvr_apply, SrsRequest* req); @@ -502,22 +501,6 @@ class SrsConfig // Get the max udp port for rtp of stream caster rtsp. virtual int get_stream_caster_rtp_port_max(SrsConfDirective* conf); - virtual srs_utime_t get_stream_caster_gb28181_rtp_idle_timeout(SrsConfDirective* conf); - virtual srs_utime_t get_stream_caster_gb28181_ack_timeout(SrsConfDirective* conf); - virtual srs_utime_t get_stream_caster_gb28181_keepalive_timeout(SrsConfDirective* conf); - virtual bool get_stream_caster_gb28181_audio_enable(SrsConfDirective* conf); - virtual bool get_stream_caster_gb28181_jitterbuffer_enable(SrsConfDirective* conf); - virtual std::string get_stream_caster_gb28181_host(SrsConfDirective* conf); - virtual std::string get_stream_caster_gb28181_serial(SrsConfDirective* conf); - virtual std::string get_stream_caster_gb28181_realm(SrsConfDirective* conf); - virtual bool get_stream_caster_gb28181_wait_keyframe(SrsConfDirective* conf); - virtual bool get_stream_caster_gb28181_sip_enable(SrsConfDirective* conf); - virtual bool get_stream_caster_gb28181_sip_auto_play(SrsConfDirective* conf); - virtual int get_stream_caster_gb28181_sip_listen(SrsConfDirective* conf); - virtual bool get_stream_caster_gb28181_sip_invite_port_fixed(SrsConfDirective* conf); - virtual bool get_stream_caster_gb28181_auto_create_channel(SrsConfDirective* conf); - virtual srs_utime_t get_stream_caster_gb28181_sip_query_catalog_interval(SrsConfDirective* conf); - // rtc section public: virtual bool get_rtc_server_enabled(); diff --git a/trunk/src/app/srs_app_gb28181.cpp b/trunk/src/app/srs_app_gb28181.cpp deleted file mode 100644 index 5329db0d9..000000000 --- a/trunk/src/app/srs_app_gb28181.cpp +++ /dev/null @@ -1,2685 +0,0 @@ -// -// Copyright (c) 2013-2021 Lixin -// -// SPDX-License-Identifier: MIT -// - -#include -#include -#include -#include -#include - -using namespace std; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//#define W_PS_FILE -//#define W_VIDEO_FILE -//#define W_AUDIO_FILE -//#define W_UNKONW_FILE - -SrsPsRtpPacket::SrsPsRtpPacket() -{ - isFirstPacket = false; -} - -SrsPsRtpPacket::~SrsPsRtpPacket() -{ -} - -srs_error_t SrsPsRtpPacket::decode(SrsBuffer* stream) -{ - srs_error_t err = srs_success; - - // 12bytes header - if (!stream->require(12)) { - return srs_error_new(ERROR_RTP_HEADER_CORRUPT, "requires 12 only %d bytes", stream->left()); - } - - int8_t vv = stream->read_1bytes(); - version = (vv >> 6) & 0x03; - padding = (vv >> 5) & 0x01; - extension = (vv >> 4) & 0x01; - csrc_count = vv & 0x0f; - - int8_t mv = stream->read_1bytes(); - marker = (mv >> 7) & 0x01; - payload_type = mv & 0x7f; - - sequence_number = stream->read_2bytes(); - timestamp = stream->read_4bytes(); - ssrc = stream->read_4bytes(); - - // TODO: FIXME: check sequence number. - - // video codec. - if (payload_type == 96) { - // ps stream playload atleast 1bytes content. - if (!stream->require(1)) { - return srs_error_new(ERROR_RTP_TYPE96_CORRUPT, "requires 1 only %d bytes", stream->left()); - } - // append left bytes to payload. - payload->append(stream->data() + stream->pos() , stream->size()-stream->pos()); - } - return err; -} - -//SrsPsRtpListener -SrsPsRtpListener::SrsPsRtpListener(SrsGb28181Config* c, int p, std::string s) -{ - rtp_processor = new SrsGb28181PsRtpProcessor(c, s); - _port = p; - // TODO: support listen at <[ip:]port> - listener = new SrsUdpListener(this, srs_any_address_for_listener(), p); -} - -SrsPsRtpListener::~SrsPsRtpListener() -{ - srs_freep(listener); - srs_freep(rtp_processor); -} - -int SrsPsRtpListener::port() -{ - return _port; -} - -srs_error_t SrsPsRtpListener::listen() -{ - return listener->listen(); -} - -srs_error_t SrsPsRtpListener::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf){ - srs_error_t err = srs_success; - if (rtp_processor){ - err = rtp_processor->on_udp_packet(from, fromlen, buf, nb_buf); - } - return err; -} - -//SrsGb28181RtpMuxService -SrsGb28181RtpMuxService::SrsGb28181RtpMuxService(SrsConfDirective* c) -{ - config = new SrsGb28181Config(c); - rtp_processor = new SrsGb28181PsRtpProcessor(config,""); -} - -SrsGb28181RtpMuxService::~SrsGb28181RtpMuxService() -{ - srs_freep(config); - srs_freep(rtp_processor); -} - -srs_error_t SrsGb28181RtpMuxService::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf){ - srs_error_t err = srs_success; - if (rtp_processor){ - err = rtp_processor->on_udp_packet(from, fromlen, buf, nb_buf); - } - return err; -} - -//SrsGb28181PsRtpProcessor -SrsGb28181PsRtpProcessor::SrsGb28181PsRtpProcessor(SrsGb28181Config* c, std::string id) -{ - config = c; - pprint = SrsPithyPrint::create_caster(); - channel_id = id; -} - -SrsGb28181PsRtpProcessor::~SrsGb28181PsRtpProcessor() -{ - dispose(); - srs_freep(pprint); -} - -void SrsGb28181PsRtpProcessor::dispose() -{ - map::iterator it2; - for (it2 = cache_ps_rtp_packet.begin(); it2 != cache_ps_rtp_packet.end(); ++it2) { - srs_freep(it2->second); - } - cache_ps_rtp_packet.clear(); - - clear_pre_packet(); - - return; -} - -void SrsGb28181PsRtpProcessor::clear_pre_packet() -{ - map::iterator it; - for (it = pre_packet.begin(); it != pre_packet.end(); ++it) { - srs_freep(it->second); - } - pre_packet.clear(); -} - -srs_error_t SrsGb28181PsRtpProcessor::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) -{ - if (config->jitterbuffer_enable){ - return on_rtp_packet_jitter(from, fromlen, buf, nb_buf); - }else{ - return on_rtp_packet(from, fromlen, buf, nb_buf); - } -} -srs_error_t SrsGb28181PsRtpProcessor::on_tcp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) -{ - on_udp_packet(from, fromlen, buf, nb_buf); -} - - -srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) -{ - srs_error_t err = srs_success; - bool completed = false; - - pprint->elapse(); - - char address_string[64]; - char port_string[16]; - if (getnameinfo(from, fromlen, - (char*)&address_string, sizeof(address_string), - (char*)&port_string, sizeof(port_string), - NI_NUMERICHOST|NI_NUMERICSERV)){ - // return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address"); - srs_warn("gb28181 ps rtp: bad address"); - return srs_success; - } - - int peer_port = atoi(port_string); - - if (true) { - SrsBuffer stream(buf, nb_buf); - SrsPsRtpPacket pkt; - - if ((err = pkt.decode(&stream)) != srs_success) { - // return srs_error_wrap(err, "ps rtp decode error"); - srs_warn("gb28181 ps rtp: decode error"); - srs_freep(err); - return srs_success; - } - - //TODO: fixme: the same device uses the same SSRC to send with different local ports - std::stringstream ss; - ss << pkt.ssrc << ":" << pkt.timestamp << ":" << port_string; - std::string pkt_key = ss.str(); - - std::stringstream ss2; - ss2 << pkt.ssrc << ":" << port_string; - std::string pre_pkt_key = ss2.str(); - - if (pre_packet.find(pre_pkt_key) == pre_packet.end()){ - pre_packet[pre_pkt_key] = new SrsPsRtpPacket(); - pre_packet[pre_pkt_key]->copy(&pkt); - } - //cache pkt by ssrc and timestamp - if (cache_ps_rtp_packet.find(pkt_key) == cache_ps_rtp_packet.end()) { - cache_ps_rtp_packet[pkt_key] = new SrsPsRtpPacket(); - } - - //get previous timestamp by ssrc - uint32_t pre_timestamp = pre_packet[pre_pkt_key]->timestamp; - uint32_t pre_sequence_number = pre_packet[pre_pkt_key]->sequence_number; - - //TODO: check sequence number out of order - //it may be out of order, or multiple streaming ssrc are the same - if (((pre_sequence_number + 1) % 65536) != pkt.sequence_number && - pre_sequence_number != pkt.sequence_number){ - srs_warn("gb28181: ps sequence_number out of order, ssrc=%#x, pre=%u, cur=%u, peer(%s, %s)", - pkt.ssrc, pre_sequence_number, pkt.sequence_number, address_string, port_string); - //return err; - } - - //copy header to cache - cache_ps_rtp_packet[pkt_key]->copy(&pkt); - //accumulate one frame of data, to payload cache - cache_ps_rtp_packet[pkt_key]->payload->append(pkt.payload); - - //detect whether it is a completed frame - if (pkt.marker) {// rtp maker is true, is a completed frame - completed = true; - }else if (pre_timestamp != pkt.timestamp){ - //current timestamp is different from previous timestamp - //previous timestamp, is a completed frame - std::stringstream ss; - ss << pkt.ssrc << ":" << pre_timestamp << ":" << port_string; - pkt_key = ss.str(); - if (cache_ps_rtp_packet.find(pkt_key) != cache_ps_rtp_packet.end()) { - completed = true; - } - } - - if (pprint->can_print()) { - srs_trace("<- " SRS_CONSTS_LOG_GB28181_CASTER " gb28181: client_id %s, peer(%s, %d) ps rtp packet %dB, age=%d, vt=%d/%u, sts=%u/%u/%#x, paylod=%dB", - channel_id.c_str(), address_string, peer_port, nb_buf, pprint->age(), pkt.version, - pkt.payload_type, pkt.sequence_number, pkt.timestamp, pkt.ssrc, - pkt.payload->length() - ); - } - - //current packet becomes previous packet - srs_freep(pre_packet[pre_pkt_key]); - pre_packet[pre_pkt_key] = new SrsPsRtpPacket(); - pre_packet[pre_pkt_key]->copy(&pkt);; - - if (!completed){ - return err; - } - //process completed frame data - //clear processed one ps frame - //on completed frame data rtp packet in muxer enqueue - map::iterator key = cache_ps_rtp_packet.find(pkt_key); - if(key != cache_ps_rtp_packet.end()) - { - SrsGb28181RtmpMuxer* muxer = NULL; - muxer = fetch_rtmpmuxer(channel_id,pkt.ssrc); - - if (muxer){ - //TODO: fixme: the same device uses the same SSRC to send with different local ports - //record the first peer port - muxer->set_channel_peer_port(peer_port); - muxer->set_channel_peer_ip(address_string); - //not the first peer port's non processing - if (muxer->channel_peer_port() != peer_port){ - srs_warn("<- " SRS_CONSTS_LOG_GB28181_CASTER " gb28181: client_id %s, ssrc=%#x, first peer_port=%d cur peer_port=%d", - muxer->get_channel_id().c_str(), pkt.ssrc, muxer->channel_peer_port(), peer_port); - srs_freep(key->second); - }else { - //put it in queue, wait for consumer to process, and then free - muxer->ps_packet_enqueue(key->second); - } - }else{ - //no consumer process it, discarded - srs_freep(key->second); - } - cache_ps_rtp_packet.erase(pkt_key); - } - } - return err; -} - -SrsGb28181RtmpMuxer* SrsGb28181PsRtpProcessor::fetch_rtmpmuxer(std::string channel_id, uint32_t ssrc) -{ - if(true){ - SrsGb28181RtmpMuxer* muxer = NULL; - //First, search according to the channel_id. Otherwise, search according to the SSRC. - //Some channel_id are created by RTP pool, which are different ports. - //No channel_id are created by multiplexing ports, which are the same port - if (!channel_id.empty()){ - muxer = _srs_gb28181->fetch_rtmpmuxer(channel_id); - }else { - muxer = _srs_gb28181->fetch_rtmpmuxer_by_ssrc(ssrc); - } - - //auto crate channel - if (!muxer && config->auto_create_channel){ - //auto create channel generated id - std::stringstream ss, ss1; - ss << "chid" << ssrc; - std::string tmp_id = ss.str(); - - SrsGb28181StreamChannel channel; - channel.set_channel_id(tmp_id); - // channel.set_port_mode(RTP_PORT_MODE_FIXED); - if (!config->sip_invite_port_fixed) { - channel.set_port_mode(RTP_PORT_MODE_RANDOM); - }else - { - channel.set_port_mode(RTP_PORT_MODE_FIXED); - } - channel.set_ssrc(ssrc); - - srs_error_t err2 = srs_success; - if ((err2 = _srs_gb28181->create_stream_channel(&channel)) != srs_success){ - srs_warn("gb28181: RtpProcessor create stream channel error %s", srs_error_desc(err2).c_str()); - srs_error_reset(err2); - }; - - muxer = _srs_gb28181->fetch_rtmpmuxer(tmp_id); - } - - return muxer; - }//end if FoundFrame -} - -srs_error_t SrsGb28181PsRtpProcessor::rtmpmuxer_enqueue_data(SrsGb28181RtmpMuxer *muxer, uint32_t ssrc, - int peer_port, std::string address_string, SrsPsRtpPacket *pkt) -{ - srs_error_t err = srs_success; - - if (!muxer) - return err; - - if (muxer){ - //TODO: fixme: the same device uses the same SSRC to send with different local ports - //record the first peer port - muxer->set_channel_peer_port(peer_port); - muxer->set_channel_peer_ip(address_string); - //not the first peer port's non processing - if (muxer->channel_peer_port() != peer_port){ - srs_warn("<- " SRS_CONSTS_LOG_GB28181_CASTER " gb28181: client_id %s, ssrc=%#x, first peer_port=%d cur peer_port=%d", - muxer->get_channel_id().c_str(), ssrc, muxer->channel_peer_port(), peer_port); - }else { - //muxer->ps_packet_enqueue(pkt); - muxer->insert_jitterbuffer(pkt); - }//end if (muxer->channel_peer_port() != peer_port) - }//end if (muxer) - - return err; -} - -srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet_jitter(const sockaddr* from, const int fromlen, char* buf, int nb_buf) -{ - srs_error_t err = srs_success; - - pprint->elapse(); - - char address_string[64]; - char port_string[16]; - if (getnameinfo(from, fromlen, - (char*)&address_string, sizeof(address_string), - (char*)&port_string, sizeof(port_string), - NI_NUMERICHOST|NI_NUMERICSERV)){ - // return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address"); - srs_warn("gb28181 ps rtp: bad address"); - return srs_success; - } - - int peer_port = atoi(port_string); - - if (true) { - SrsBuffer stream(buf, nb_buf); - SrsPsRtpPacket *pkt = new SrsPsRtpPacket();; - - if ((err = pkt->decode(&stream)) != srs_success) { - srs_freep(pkt); - // return srs_error_wrap(err, "ps rtp decode error"); - srs_warn("gb28181 ps rtp: decode error"); - srs_freep(err); - return srs_success; - } - - std::stringstream ss3; - ss3 << pkt->ssrc << ":" << port_string; - std::string jitter_key = ss3.str(); - - pkt->completed = pkt->marker; - - - if (pprint->can_print()) { - srs_trace("<- " SRS_CONSTS_LOG_GB28181_CASTER " gb28181: client_id %s, peer(%s, %d) ps rtp packet %dB, age=%d, vt=%d/%u, sts=%u/%u/%#x, paylod=%dB", - channel_id.c_str(), address_string, peer_port, nb_buf, pprint->age(), pkt->version, - pkt->payload_type, pkt->sequence_number, pkt->timestamp, pkt->ssrc, - pkt->payload->length() - ); - } - - SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(channel_id, pkt->ssrc); - if (muxer){ - rtmpmuxer_enqueue_data(muxer, pkt->ssrc, peer_port, address_string, pkt); - } - - SrsAutoFree(SrsPsRtpPacket, pkt); - } - - return err; -} - - -//ISrsPsStreamHander ps stream raw video/audio hander interface -ISrsPsStreamHander::ISrsPsStreamHander() -{ -} - -ISrsPsStreamHander::~ISrsPsStreamHander() -{ -} - -//SrsPsStreamDemixer ps stream parse to h264/aac -SrsPsStreamDemixer::SrsPsStreamDemixer(ISrsPsStreamHander *h, std::string id, bool a, bool k) -{ - hander = h; - audio_enable = a; - wait_first_keyframe = k; - channel_id = id; - first_keyframe_flag = false; - - video_es_id = 0; - video_es_type = 0; - audio_es_id = 0; - audio_es_type = 0; - audio_check_aac_try_count = 0; - - aac = new SrsRawAacStream(); -} - -SrsPsStreamDemixer::~SrsPsStreamDemixer() -{ - srs_freep(aac); -} - -bool SrsPsStreamDemixer::can_send_ps_av_packet(){ - if (!wait_first_keyframe) - return true; - - if (first_keyframe_flag) - return true; - - return false; -} - -std::string SrsPsStreamDemixer::get_ps_map_type_str(uint8_t type) -{ - switch(type){ - case STREAM_TYPE_VIDEO_MPEG1: //0x01 - return "mpeg1"; - case STREAM_TYPE_VIDEO_MPEG2:// 0x02 - return "mpeg2"; - case STREAM_TYPE_AUDIO_MPEG1:// 0x03 - return "mpeg1"; - case STREAM_TYPE_AUDIO_MPEG2:// 0x04 - return "mpeg2"; - case STREAM_TYPE_PRIVATE_SECTION:// 0x05 - return "private_section"; - case STREAM_TYPE_PRIVATE_DATA:// 0x06 - return "private_data"; - case STREAM_TYPE_AUDIO_AAC:// 0x0f - return "aac"; - case STREAM_TYPE_VIDEO_MPEG4:// 0x10 - return "mpeg4"; - case STREAM_TYPE_VIDEO_H264:// 0x1b - return "h264"; - case STREAM_TYPE_VIDEO_HEVC:// 0x24 - return "hevc"; - case STREAM_TYPE_VIDEO_CAVS:// 0x42 - return "cavs"; - case STREAM_TYPE_VIDEO_SAVC:// 0x80 - return "savc"; - - case STREAM_TYPE_AUDIO_AC3:// 0x81 - return "ac3"; - - case STREAM_TYPE_AUDIO_G711:// 0x90 - return "g711"; - case STREAM_TYPE_AUDIO_G711ULAW:// 0x91 - return "g711ulaw"; - case STREAM_TYPE_AUDIO_G722_1:// 0x92 - return "g722_1"; - case STREAM_TYPE_AUDIO_G723_1:// 0x93 - return "g723_1"; - case STREAM_TYPE_AUDIO_G726:// 0x96 - return "g726"; - case STREAM_TYPE_AUDIO_G729_1:// 0x99 - return "g729_1"; - case STREAM_TYPE_AUDIO_SVAC:// 0x9b - return "svac"; - case STREAM_TYPE_AUDIO_PCM:// 0x9c - return "pcm"; - default: - return "unknow"; - } -} - -int64_t SrsPsStreamDemixer::parse_ps_timestamp(const uint8_t* p) -{ - unsigned long b; - //total 33 bits - unsigned long val, val2, val3; - - //1st byte, 5、6、7 bit - b = *p++; - val = (b & 0x0e); - - //2 byte, all bit - b = (*(p++)) << 8; - //3 bytes 1--7 bit - b += *(p++); - val2 = (b & 0xfffe) >> 1; - - //4 byte, all bit - b = (*(p++)) << 8; - //5 byte 1--7 bit - b += *(p++); - val3 = (b & 0xfffe) >> 1; - - //<32--val--30> <29----val2----15> <14----val3----0> - val = (val << 29) | (val2 << 15) | val3; - return val; -} - -srs_error_t SrsPsStreamDemixer::on_ps_stream(char* ps_data, int ps_size, uint32_t timestamp, uint32_t ssrc) -{ - srs_error_t err = srs_success; - int complete_len = 0; - int incomplete_len = ps_size; - char *next_ps_pack = ps_data; - - SrsSimpleStream video_stream; - SrsSimpleStream audio_stream; - uint64_t audio_pts = 0; - uint64_t video_pts = 0; - int pse_index = 0; - -#ifdef W_PS_FILE - if (!ps_fw.is_open()) { - std::string filename = "test_ps_" + channel_id + ".mpg"; - ps_fw.open(filename.c_str()); - } - ps_fw.write(ps_data, ps_size, NULL); -#endif - - while(incomplete_len > 0 - && incomplete_len >= sizeof(SrsPsPacketStartCode)) - { - if (next_ps_pack - && next_ps_pack[0] == (char)0x00 - && next_ps_pack[1] == (char)0x00 - && next_ps_pack[2] == (char)0x01 - && next_ps_pack[3] == (char)0xBA) - { - //ps header - SrsPsPacketHeader *head = (SrsPsPacketHeader *)next_ps_pack; - unsigned char pack_stuffing_length = head->stuffing_length & 0x07; - - next_ps_pack = next_ps_pack + sizeof(SrsPsPacketHeader) + pack_stuffing_length; - complete_len = complete_len + sizeof(SrsPsPacketHeader) + pack_stuffing_length; - incomplete_len = ps_size - complete_len; - } - else if(next_ps_pack - && next_ps_pack[0] == (char)0x00 - && next_ps_pack[1] == (char)0x00 - && next_ps_pack[2] == (char)0x01 - && next_ps_pack[3] == (char)0xBB) - { - //ps system header - SrsPsPacketBBHeader *bbhead=(SrsPsPacketBBHeader *)(next_ps_pack); - int bbheaderlen = htons(bbhead->length); - next_ps_pack = next_ps_pack + sizeof(SrsPsPacketBBHeader) + bbheaderlen; - complete_len = complete_len + sizeof(SrsPsPacketBBHeader) + bbheaderlen; - incomplete_len = ps_size - complete_len; - - first_keyframe_flag = true; - } - else if(next_ps_pack - && next_ps_pack[0] == (char)0x00 - && next_ps_pack[1] == (char)0x00 - && next_ps_pack[2] == (char)0x01 - && next_ps_pack[3] == (char)0xBC) - { - //program stream map - - SrsPsMapPacket* psmap_pack = (SrsPsMapPacket*)next_ps_pack; - psmap_pack->length = htons(psmap_pack->length); - - next_ps_pack = next_ps_pack + psmap_pack->length + sizeof(SrsPsMapPacket); - complete_len = complete_len + psmap_pack->length + sizeof(SrsPsMapPacket); - incomplete_len = ps_size - complete_len; - - //parse ps map - uint16_t psm_length=0, ps_info_length=0, es_map_length=0; - char *p = (char*)psmap_pack + sizeof(SrsPsMapPacket); - - SrsBuffer buf(p, (int)psmap_pack->length); - - psm_length =(int)psmap_pack->length; - buf.read_1bytes(); - buf.read_1bytes(); - - ps_info_length = buf.read_2bytes(); - - /* skip program_stream_info */ - buf.skip(ps_info_length); - /*es_map_length = */buf.read_2bytes(); - /* Ignore es_map_length, trust psm_length */ - es_map_length = psm_length - ps_info_length - 10; - - // /* at least one es available? */ - while (es_map_length >= 4) { - uint8_t type = buf.read_1bytes(); - uint8_t es_id = buf.read_1bytes(); - uint16_t es_info_length = buf.read_2bytes(); - std::string s_type = get_ps_map_type_str(type); - - /* remember mapping from stream id to stream type */ - if (es_id >= PS_AUDIO_ID && es_id <= PS_AUDIO_ID_END){ - if (audio_es_type != type){ - srs_trace("gb28181: ps map audio es_type=%s(%x), es_id=%0x, es_info_length=%d", - s_type.c_str(), type, es_id, es_info_length); - } - - audio_es_id = es_id; - audio_es_type = type; - }else if (es_id >= PS_VIDEO_ID && es_id <= PS_VIDEO_ID_END){ - - if (video_es_type != type){ - srs_trace("gb28181: ps map video es_type=%s(%x), es_id=%0x, es_info_length=%d", - s_type.c_str(), type, es_id, es_info_length); - } - - video_es_id = es_id; - video_es_type = type; - } - - /* skip program_stream_info */ - buf.skip(es_info_length); - es_map_length -= 4 + es_info_length; - } - - } - else if(next_ps_pack - && next_ps_pack[0] == (char)0x00 - && next_ps_pack[1] == (char)0x00 - && next_ps_pack[2] == (char)0x01 - && next_ps_pack[3] == (char)0xE0) - { - //pse video stream - SrsPsePacket* pse_pack = (SrsPsePacket*)next_ps_pack; - - unsigned char pts_dts_flags = (pse_pack->info[0] & 0xF0) >> 6; - //in a frame of data, pts is obtained from the first PSE packet - if (pse_index == 0 && pts_dts_flags > 0) { - video_pts = parse_ps_timestamp((unsigned char*)next_ps_pack + 9); - srs_info("gb28181: ps stream video ts=%u pkt_ts=%u", video_pts, timestamp); - } - pse_index +=1; - - int packlength = htons(pse_pack->length); - int payloadlen = packlength - 2 - 1 - pse_pack->stuffing_length; - - next_ps_pack = next_ps_pack + 9 + pse_pack->stuffing_length; - complete_len = complete_len + 9 + pse_pack->stuffing_length; - - video_stream.append(next_ps_pack, payloadlen); - -#ifdef W_VIDEO_FILE - if (!video_fw.is_open()) { - std::string filename = "test_video_" + channel_id + ".h264"; - video_fw.open(filename.c_str()); - } - video_fw.write(next_ps_pack, payloadlen, NULL); -#endif - - next_ps_pack = next_ps_pack + payloadlen; - complete_len = complete_len + payloadlen; - incomplete_len = ps_size - complete_len; - } - else if (next_ps_pack - && next_ps_pack[0] == (char)0x00 - && next_ps_pack[1] == (char)0x00 - && next_ps_pack[2] == (char)0x01 - && next_ps_pack[3] == (char)0xBD) - { - //private stream - - SrsPsePacket* pse_pack = (SrsPsePacket*)next_ps_pack; - - int packlength = htons(pse_pack->length); - int payload_len = packlength - 2 - 1 - pse_pack->stuffing_length; - - next_ps_pack = next_ps_pack + payload_len + 9 + pse_pack->stuffing_length; - complete_len = complete_len + (payload_len + 9 + pse_pack->stuffing_length); - incomplete_len = ps_size - complete_len; - } - else if (next_ps_pack - && next_ps_pack[0] == (char)0x00 - && next_ps_pack[1] == (char)0x00 - && next_ps_pack[2] == (char)0x01 - && next_ps_pack[3] == (char)0xC0) - { - //audio stream - - SrsPsePacket* pse_pack = (SrsPsePacket*)next_ps_pack; - - unsigned char pts_dts_flags = (pse_pack->info[0] & 0xF0) >> 6; - if (pts_dts_flags > 0 ) { - audio_pts = parse_ps_timestamp((unsigned char*)next_ps_pack + 9); - srs_info("gb28181: ps stream video ts=%u pkt_ts=%u", audio_pts, timestamp); - } - - int packlength = htons(pse_pack->length); - int payload_len = packlength - 2 - 1 - pse_pack->stuffing_length; - next_ps_pack = next_ps_pack + 9 + pse_pack->stuffing_length; - - //if ps map is not aac, but stream many be aac adts , try update type, - //TODO: dahua audio ps map type always is 0x90(g711) - - uint8_t p1 = (uint8_t)(next_ps_pack[0]); - uint8_t p2 = (uint8_t)(next_ps_pack[1]); - //uint8_t p3 = (uint8_t)(next_ps_pack[2]); - //uint8_t p4 = (uint8_t)(next_ps_pack[3]); - - if (audio_enable && audio_es_type != STREAM_TYPE_AUDIO_AAC && - (p1 & 0xFF) == 0xFF && (p2 & 0xF0) == 0xF0) { - - //try update aac type - SrsBuffer avs(next_ps_pack, payload_len); - char* frame = NULL; - int frame_size = 0; - SrsRawAacStreamCodec codec; - - srs_error_t err2 = srs_success; - if ((err2 = aac->adts_demux(&avs, &frame, &frame_size, codec)) != srs_success) { - srs_info("gb28181: client_id %s, audio data not aac adts (%#x/%u) %02x %02x %02x %02x\n", - channel_id.c_str(), ssrc, timestamp, p1, p2, p3, p4); - srs_error_reset(err); - }else{ - srs_warn("gb28181: client_id %s, ps map is not aac (%s) type, but stream many be aac adts, try update type", - channel_id.c_str(), get_ps_map_type_str(audio_es_type).c_str()); - audio_es_type = STREAM_TYPE_AUDIO_AAC; - } - } - - audio_stream.append(next_ps_pack, payload_len); - -#ifdef W_AUDIO_FILE - if (!audio_fw.is_open()) { - std::string filename = "test_audio_" + channel_id + ".aac"; - audio_fw.open(filename.c_str()); - } - audio_fw.write(next_ps_pack, payload_len, NULL); -#endif - - next_ps_pack = next_ps_pack + payload_len; - complete_len = complete_len + (payload_len + 9 + pse_pack->stuffing_length); - incomplete_len = ps_size - complete_len; - - if (hander && audio_enable && audio_stream.length() && can_send_ps_av_packet()) { - if ((err = hander->on_rtp_audio(&audio_stream, audio_pts, audio_es_type)) != srs_success) { - return srs_error_wrap(err, "process ps audio packet"); - } - } - } - else - { - -#ifdef W_UNKONW_FILE - if (!unknow_fw.is_open()) { - std::string filename = "test_unknow_" + channel_id + ".mpg"; - unknow_fw.open(filename.c_str()); - } - unknow_fw.write(next_ps_pack, incomplete_len, NULL); -#endif - //TODO: fixme unkonw ps data parse - if (next_ps_pack - && next_ps_pack[0] == (char)0x00 - && next_ps_pack[1] == (char)0x00 - && next_ps_pack[2] == (char)0x00 - && next_ps_pack[3] == (char)0x01){ - //dahua's PS header may lose packets. It is sent by an RTP packet of Dahua's PS header - //dahua rtp send format: - //ts=1000 seq=1 mark=false payload= ps header - //ts=1000 seq=2 mark=false payload= video - //ts=1000 seq=3 mark=true payload= video - //ts=1000 seq=4 mark=true payload= audio - incomplete_len = ps_size - complete_len; - complete_len = complete_len + incomplete_len; - } - - first_keyframe_flag = false; - srs_trace("gb28181: client_id %s, unkonw ps data (%#x/%u) %02x %02x %02x %02x\n", - channel_id.c_str(), ssrc, timestamp, - next_ps_pack[0]&0xFF, next_ps_pack[1]&0xFF, next_ps_pack[2]&0xFF, next_ps_pack[3]&0xFF); - break; - } - } - - if (complete_len != ps_size){ - srs_trace("gb28181: client_id %s decode ps packet error (%#x/%u)! ps_size=%d complete=%d \n", - channel_id.c_str(), ssrc, timestamp, ps_size, complete_len); - }else if (hander && video_stream.length() && can_send_ps_av_packet() && video_es_type == STREAM_TYPE_VIDEO_H264) { - if ((err = hander->on_rtp_video(&video_stream, video_pts)) != srs_success) { - video_es_type = 0; - return srs_error_wrap(err, "process ps video packet"); - } - } - - return err; -} - -static std::string get_host_candidate_ips(SrsConfDirective* c) -{ - string candidate = _srs_config->get_stream_caster_gb28181_host(c); - if (candidate == "*" || candidate == "0.0.0.0") { - std::vector& ips = srs_get_local_ips(); - int index = _srs_config->get_stats_network(); - SrsIPAddress* ip = ips.at(index); - return ip->ip; - } else { - return candidate; - } -} - -//Gb28181 Config -SrsGb28181Config::SrsGb28181Config(SrsConfDirective* c) -{ - // TODO: FIXME: support reload. - host = get_host_candidate_ips(c); - output = _srs_config->get_stream_caster_output(c); - rtp_mux_port = _srs_config->get_stream_caster_listen(c); - rtp_mux_tcp_enable = _srs_config->get_stream_caster_tcp_enable(c); - rtp_port_min = _srs_config->get_stream_caster_rtp_port_min(c); - rtp_port_max = _srs_config->get_stream_caster_rtp_port_max(c); - rtp_idle_timeout = _srs_config->get_stream_caster_gb28181_rtp_idle_timeout(c); - - wait_keyframe = _srs_config->get_stream_caster_gb28181_wait_keyframe(c); - audio_enable = _srs_config->get_stream_caster_gb28181_audio_enable(c); - auto_create_channel = _srs_config->get_stream_caster_gb28181_auto_create_channel(c); - jitterbuffer_enable = _srs_config->get_stream_caster_gb28181_jitterbuffer_enable(c); - - //sip config - sip_enable = _srs_config->get_stream_caster_gb28181_sip_enable(c); - sip_port = _srs_config->get_stream_caster_gb28181_sip_listen(c); - sip_realm = _srs_config->get_stream_caster_gb28181_realm(c); - sip_serial = _srs_config->get_stream_caster_gb28181_serial(c); - sip_auto_play = _srs_config->get_stream_caster_gb28181_sip_auto_play(c); - sip_ack_timeout = _srs_config->get_stream_caster_gb28181_ack_timeout(c); - sip_keepalive_timeout = _srs_config->get_stream_caster_gb28181_keepalive_timeout(c); - sip_invite_port_fixed = _srs_config->get_stream_caster_gb28181_sip_invite_port_fixed(c); - sip_query_catalog_interval = _srs_config->get_stream_caster_gb28181_sip_query_catalog_interval(c); -} - -SrsGb28181Config::~SrsGb28181Config() -{ - -} - -//SrsGb28181RtmpMuxer gb28181 rtmp muxer, process ps stream to rtmp -SrsGb28181RtmpMuxer::SrsGb28181RtmpMuxer(SrsGb28181Manger* c, std::string id, bool a, bool k) -{ - channel_id = id; - gb28181_manger = c; - channel = new SrsGb28181StreamChannel(); - - pprint = SrsPithyPrint::create_caster(); - trd = new SrsSTCoroutine("gb28181rtmpmuxer", this); - //change stack size to 256K, fix crash when call FFMpeg - ((SrsSTCoroutine*)trd)->set_stack_size(1 << 18); - - sdk = NULL; - vjitter = new SrsRtpTimeJitter(); - ajitter = new SrsRtpTimeJitter(); - - avc = new SrsRawH264Stream(); - aac = new SrsRawAacStream(); - - ps_demixer = new SrsPsStreamDemixer(this, id, a, k); - wait_ps_queue = srs_cond_new(); - - stream_idle_timeout = -1; - recv_rtp_stream_time = 0; - send_rtmp_stream_time = 0; - - _rtmp_url = ""; - - h264_sps = ""; - h264_pps = ""; - aac_specific_config = ""; - - req = NULL; - server = NULL; - source = NULL; - source_publish = true; - - jitter_buffer = new SrsRtpJitterBuffer(id); - jitter_buffer_audio = new SrsRtpJitterBuffer(id); - - ps_buflen = 0; - ps_buffer = NULL; - - ps_buflen_auido = 0; - ps_buffer_audio = NULL; -} - -SrsGb28181RtmpMuxer::~SrsGb28181RtmpMuxer() -{ - - close(); - - srs_cond_destroy(wait_ps_queue); - - srs_freep(jitter_buffer); - srs_freep(jitter_buffer_audio); - srs_freepa(ps_buffer); - srs_freepa(ps_buffer_audio); - - srs_freep(channel); - srs_freep(ps_demixer); - srs_freep(trd); - srs_freep(sdk); - srs_freep(vjitter); - srs_freep(ajitter); - srs_freep(pprint); - - destroy(); -} - -srs_error_t SrsGb28181RtmpMuxer::serve() -{ - srs_error_t err = srs_success; - - if ((err = trd->start()) != srs_success) { - return srs_error_wrap(err, "gb28181rtmpmuxer"); - } - - return err; -} - -std::string SrsGb28181RtmpMuxer::remote_ip() -{ - return ""; -} - -const SrsContextId& SrsGb28181RtmpMuxer::get_id() -{ - return _srs_context->get_id(); -} - -std::string SrsGb28181RtmpMuxer::desc() -{ - return "GBConn"; -} - -std::string SrsGb28181RtmpMuxer::get_channel_id() -{ - return channel_id; -} - -void SrsGb28181RtmpMuxer::copy_channel(SrsGb28181StreamChannel *s) -{ - channel->copy(s); -} - -SrsGb28181StreamChannel SrsGb28181RtmpMuxer::get_channel() -{ - return *channel; -} - -void SrsGb28181RtmpMuxer::set_channel_peer_ip(std::string ip) -{ - if (channel->get_rtp_peer_ip().empty()){ - channel->set_rtp_peer_ip(ip); - } -} - -void SrsGb28181RtmpMuxer::set_channel_peer_port(int port) -{ - if (channel->get_rtp_peer_port() == 0){ - channel->set_recv_time_str(srs_sip_get_utc_date()); - channel->set_recv_time(srs_get_system_time()); - channel->set_rtp_peer_port(port); - } -} - -int SrsGb28181RtmpMuxer::channel_peer_port() -{ - return channel->get_rtp_peer_port(); -} - -std::string SrsGb28181RtmpMuxer::channel_peer_ip() -{ - return channel->get_rtp_peer_ip(); -} - -void SrsGb28181RtmpMuxer::set_rtmp_url(std::string url) -{ - _rtmp_url = url; -} -std::string SrsGb28181RtmpMuxer::rtmp_url() -{ - return _rtmp_url; -} - -srs_utime_t SrsGb28181RtmpMuxer::get_recv_stream_time() -{ - return recv_rtp_stream_time; -} - - -void SrsGb28181RtmpMuxer::destroy() -{ - while(!ps_queue.empty()){ - SrsPsRtpPacket* pkt = ps_queue.front(); - ps_queue.pop(); - //must be free pkt - srs_freep(pkt); - } -} - -srs_error_t SrsGb28181RtmpMuxer::initialize(SrsServer *s, SrsRequest* r) -{ - srs_error_t err = srs_success; - - if (!jitter_buffer) { - jitter_buffer = new SrsRtpJitterBuffer(channel_id); - } - - jitter_buffer->SetDecodeErrorMode(kSelectiveErrors); - jitter_buffer->SetNackMode(kNack, -1, -1); - jitter_buffer->SetNackSettings(250, 450, 0); - - if (!jitter_buffer_audio) { - jitter_buffer_audio = new SrsRtpJitterBuffer(channel_id); - } - - jitter_buffer_audio->SetDecodeErrorMode(kSelectiveErrors); - jitter_buffer_audio->SetNackMode(kNack, -1, -1); - jitter_buffer_audio->SetNackSettings(250, 450, 0); - - if (!source_publish) return err; - - req = r; - server = s; - - if ((err = _srs_sources->fetch_or_create(req, (ISrsLiveSourceHandler*)server, &source)) != srs_success) { - return srs_error_wrap(err, "create source"); - } - - #ifdef SRS_RTC - SrsRtcSource *rtc = NULL; - bool rtc_server_enabled = _srs_config->get_rtc_server_enabled(); - bool rtc_enabled = _srs_config->get_rtc_enabled(req->vhost); - if (rtc_server_enabled && rtc_enabled) { - if ((err = _srs_rtc_sources->fetch_or_create(req, &rtc)) != srs_success) { - return srs_error_wrap(err, "create source"); - } - - if (!rtc->can_publish()) { - return srs_error_new(ERROR_RTC_SOURCE_BUSY, "gb28181 rtc stream %s busy", req->get_stream_url().c_str()); - } - } -#endif - - // Check whether RTMP stream is busy. - if (!source->can_publish(false)) { - return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "gb28181 rtmp: stream %s is busy", req->get_stream_url().c_str()); - } - - // Bridge to RTC streaming. -#if defined(SRS_RTC) && defined(SRS_FFMPEG_FIT) - if (rtc) { - SrsRtcFromRtmpBridger *bridger = new SrsRtcFromRtmpBridger(rtc); - if ((err = bridger->initialize(req)) != srs_success) { - srs_freep(bridger); - return srs_error_wrap(err, "bridger init"); - } - - source->set_bridger(bridger); - } -#endif - - if ((err = source->on_publish()) != srs_success) { - return srs_error_wrap(err, "on publish"); - } - - return err; -} - - -srs_error_t SrsGb28181RtmpMuxer::do_cycle() -{ - srs_error_t err = srs_success; - recv_rtp_stream_time = srs_get_system_time(); - send_rtmp_stream_time = srs_get_system_time(); - uint32_t cur_timestamp = 0; - int buffer_size = 0; - bool keyframe = false; - - //consume ps stream, and check status - while (true) { - - pprint->elapse(); - - if ((err = trd->pull()) != srs_success) { - return srs_error_wrap(err, "gb28181 rtmp muxer cycle"); - } - - SrsGb28181Config config = gb28181_manger->get_gb28181_config(); - - if (config.jitterbuffer_enable){ - if(jitter_buffer->FoundFrame(cur_timestamp)){ - jitter_buffer->GetFrame(&ps_buffer, ps_buflen, buffer_size, keyframe, cur_timestamp); - - if (buffer_size > 0){ - if ((err = ps_demixer->on_ps_stream(ps_buffer, buffer_size, cur_timestamp, 0)) != srs_success){ - srs_warn("gb28181: demix ps stream error:%s", srs_error_desc(err).c_str()); - srs_freep(err); - }; - } - } - - if(jitter_buffer_audio->FoundFrame(cur_timestamp)){ - jitter_buffer_audio->GetFrame(&ps_buffer_audio, ps_buflen_auido, buffer_size, keyframe, cur_timestamp); - - if (buffer_size > 0){ - if ((err = ps_demixer->on_ps_stream(ps_buffer_audio, buffer_size, cur_timestamp, 0)) != srs_success){ - srs_warn("gb28181: demix ps stream error:%s", srs_error_desc(err).c_str()); - srs_freep(err); - }; - } - } - }else { - //demix ps to h264/aac, to rtmp - while(!ps_queue.empty()){ - SrsPsRtpPacket* pkt = ps_queue.front(); - if (pkt){ - if ((err = ps_demixer->on_ps_stream(pkt->payload->bytes(), - pkt->payload->length(), pkt->timestamp, pkt->ssrc)) != srs_success){ - srs_warn("gb28181: demix ps stream error:%s", srs_error_desc(err).c_str()); - srs_freep(err); - }; - } - ps_queue.pop(); - //must be free pkt - srs_freep(pkt); - } - } - - if (pprint->can_print()) { - srs_trace("gb28181: client id=%s, ssrc=%#x, peer(%s, %d), rtmp muxer is alive", - channel_id.c_str(), channel->get_ssrc(), - channel->get_rtp_peer_ip().c_str(), - channel->get_rtp_peer_port()); - } - - srs_utime_t now = srs_get_system_time(); - srs_utime_t duration = now - recv_rtp_stream_time; - - //if no RTP data is received within 2 seconds, - //the peer-port and peer-ip will be cleared and - //other port data will be received again - if (duration > (2 * SRS_UTIME_SECONDS) && channel->get_rtp_peer_port() != 0){ - srs_warn("gb28181: client id=%s ssrc=%#x, peer(%s, %d), no rtp data %d in seconds, clean it, wait other port!", - channel_id.c_str(), channel->get_ssrc(), channel->get_rtp_peer_ip().c_str(), - channel->get_rtp_peer_port(), duration/SRS_UTIME_SECONDS); - channel->set_rtp_peer_port(0); - channel->set_rtp_peer_ip(""); - } - - - if (duration > config.rtp_idle_timeout){ - srs_trace("gb28181: client id=%s, stream idle timeout, stop!!!", channel_id.c_str()); - break; - } - - //RTMP connection is about to timeout without receiving any data., - //waiting for the next time there is data automatically connected - //it is related to the following two parameter settings of the rtmp server - //the publish 1st packet timeout in srs_utime_t - //publish_1stpkt_timeout default 20000ms - //the publish normal packet timeout in srs_utime_t - //publish_normal_timeout default 5000ms - duration = now - send_rtmp_stream_time; - bool will_timeout = duration > (5 * SRS_UTIME_SECONDS); - if (will_timeout && sdk){ - srs_warn("gb28181: client id=%s RTMP connection is about to time out without receiving any data", - channel_id.c_str()); - rtmp_close(); - } - - srs_usleep(30 * SRS_UTIME_MILLISECONDS); - } - - return err; -} - - -void SrsGb28181RtmpMuxer::stop() -{ - if (trd){ - trd->interrupt(); - } - //stop rtmp publish - close(); -} - - -void SrsGb28181RtmpMuxer::insert_jitterbuffer(SrsPsRtpPacket *pkt) -{ - if (!pkt){ - return; - } - - recv_rtp_stream_time = srs_get_system_time(); - - char *payload = pkt->payload->bytes(); - if (!payload) { - return; - } - - uint8_t p1 = (uint8_t)(payload[0]); - uint8_t p2 = (uint8_t)(payload[1]); - uint8_t p3 = (uint8_t)(payload[2]); - uint8_t p4 = (uint8_t)(payload[3]); - - - //check for rtp ps audio streaming - bool av_same_ts = true; - - if (p1 == 0x00 && p2 == 0x00 && p3 == 0x01 && p4 == 0xC0 && - ps_rtp_video_ts != pkt->timestamp) { - av_same_ts = false; - } - - //if audio and video are the same clock, - //if both audio and video use jitter_buffer, - //otherwise audio uses jitter_buffer_audio, and video uses jitter_buffer - if (av_same_ts){ - pkt->marker = false; - jitter_buffer->InsertPacket(pkt->sequence_number, pkt->timestamp, pkt->marker, - pkt->payload->bytes(), pkt->payload->length(), NULL); - ps_rtp_video_ts = pkt->timestamp; - }else { - jitter_buffer_audio->InsertPacket(pkt->sequence_number, pkt->timestamp, pkt->marker, - pkt->payload->bytes(), pkt->payload->length(), NULL); - } - - //srs_cond_signal(wait_ps_queue); -} - -void SrsGb28181RtmpMuxer::ps_packet_enqueue(SrsPsRtpPacket *pkt) -{ - srs_assert(pkt); - - recv_rtp_stream_time = srs_get_system_time(); - - //prevent consumers from being unable to process data - //and accumulating in the queue - uint32_t size = ps_queue.size(); - if (size > 100){ - srs_warn("gb28181: rtmpmuxer too much queue data, need to clear!!!"); - while(!ps_queue.empty()) { - SrsPsRtpPacket* pkt = ps_queue.front(); - ps_queue.pop(); - srs_freep(pkt); - } - } - - ps_queue.push(pkt); - //srs_cond_signal(wait_ps_queue); -} - -srs_error_t SrsGb28181RtmpMuxer::cycle() -{ - // serve the rtmp muxer. - srs_error_t err = do_cycle(); - - gb28181_manger->stop_rtp_listen(channel_id); - - gb28181_manger->remove(this); - srs_trace("gb28181: client id=%s rtmp muxer is remove", channel_id.c_str()); - - if (err == srs_success) { - srs_trace("client finished."); - } else if (srs_is_client_gracefully_close(err)) { - srs_warn("client disconnect peer. code=%d", srs_error_code(err)); - srs_freep(err); - } - - return err; -} - -srs_error_t SrsGb28181RtmpMuxer::on_rtp_video(SrsSimpleStream *stream, int64_t fpts) -{ - srs_error_t err = srs_success; - - if (!source_publish){ - // ensure rtmp connected. - if ((err = connect()) != srs_success) { - //after the connection fails, need to clear flag - //and send the av header again next time - h264_sps = ""; - h264_pps = ""; - aac_specific_config = ""; - return srs_error_wrap(err, "connect"); - } - } - - if ((err = vjitter->correct(fpts)) != srs_success) { - return srs_error_wrap(err, "jitter"); - } - - // ts tbn to flv tbn. - uint32_t dts = (uint32_t)(fpts / 90); - uint32_t pts = (uint32_t)(fpts / 90); - srs_info("gb28181rtmpmuxer: on_rtp_video dts=%u", dts); - - if (true) { - char *data = stream->bytes(); - int length = stream->length(); - - err = replace_startcode_with_nalulen(data, length, dts, pts); - } - - return err; -} - -srs_error_t SrsGb28181RtmpMuxer::write_h264_ipb_frame2(char *frame, int frame_size, uint32_t pts, uint32_t dts) -{ - srs_error_t err = srs_success; - - if (!frame){ - return srs_error_new(ERROR_GB28181_H264_FRAME_FULL, "h264 frame null"); - } - - if (frame_size <= 0){ - return srs_error_new(ERROR_GB28181_H264_FRAMESIZE, "h264 frame size"); - } - - SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(frame[0] & 0x1f); - // ignore the nalu type sei(6) aud(9) - if (nal_unit_type == SrsAvcNaluTypeAccessUnitDelimiter || - nal_unit_type == SrsAvcNaluTypeSEI) { - return err; - } - - // for sps - if (avc->is_sps(frame, frame_size)) { - std::string sps; - if ((err = avc->sps_demux(frame, frame_size, sps)) != srs_success) { - return srs_error_wrap(err, "demux sps"); - } - - if (h264_sps == sps) { - return err; - } - h264_sps = sps; - - if ((err = write_h264_sps_pps(dts, pts)) != srs_success) { - return srs_error_wrap(err, "write sps/pps"); - } - return err; - } - - // for pps - if (avc->is_pps(frame, frame_size)) { - std::string pps; - if ((err = avc->pps_demux(frame, frame_size, pps)) != srs_success) { - return srs_error_wrap(err, "demux pps"); - } - - if (h264_pps == pps) { - return err; - } - h264_pps = pps; - - if ((err = write_h264_sps_pps(dts, pts)) != srs_success) { - return srs_error_wrap(err, "write sps/pps"); - } - return err; - } - - srs_info("gb28181: demux avc ibp frame size=%d, dts=%d", frame_size, dts); - if ((err = write_h264_ipb_frame(frame, frame_size, dts, pts)) != srs_success) { - return srs_error_wrap(err, "write frame"); - } - - return err; -} - - srs_error_t SrsGb28181RtmpMuxer::replace_startcode_with_nalulen(char *video_data, int &size, uint32_t pts, uint32_t dts) - { - srs_error_t err = srs_success; - - int index = 0; - std::list list_index; - - for(; index < size; index++){ - if (index > (size-4)) - break; - if (video_data[index] == 0x00 && video_data[index+1] == 0x00 && - video_data[index+2] == 0x00 && video_data[index+3] == 0x01){ - list_index.push_back(index); - } - } - - if (list_index.size() == 1){ - int cur_pos = list_index.front(); - list_index.pop_front(); - - //0001xxxxxxxxxx - //xxxx0001xxxxxxx - uint32_t naluLen = size - cur_pos - 4; - - char *frame = video_data + cur_pos + 4; - int frame_size = naluLen; - - err = write_h264_ipb_frame2(frame, frame_size, dts, pts); - - }else if (list_index.size() > 1){ - int pre_pos = list_index.front(); - list_index.pop_front(); - int first_pos = pre_pos; - - while(list_index.size() > 0){ - int cur_pos = list_index.front(); - list_index.pop_front(); - - //pre=========cur====================== - //0001xxxxxxxx0001xxxxxxxx0001xxxxxxxxx - //xxxxxxxxxxxx0001xxxxxxxx0001xxxxxxxxx - uint32_t naluLen = cur_pos - pre_pos - 4; - - char *frame = video_data + pre_pos + 4; - int frame_size = naluLen; - - pre_pos = cur_pos; - err = write_h264_ipb_frame2(frame, frame_size, dts, pts); - } - - //========================pre========== - //0001xxxxxxxx0001xxxxxxxx0001xxxxxxxxx - if (first_pos != pre_pos){ - - uint32_t naluLen = size - pre_pos - 4; - - char *frame = video_data + pre_pos + 4; - int frame_size = naluLen; - - err = write_h264_ipb_frame2(frame, frame_size, dts, pts); - } - }else{ - //xxxxxxxxxxxxxxxxxxx - char *frame = video_data; - int frame_size = size; - err = write_h264_ipb_frame2(frame, frame_size, dts, pts); - } - - return err; -} - -srs_error_t SrsGb28181RtmpMuxer::on_rtp_audio(SrsSimpleStream* stream, int64_t fdts, int type) -{ - srs_error_t err = srs_success; - - if (!source_publish){ - // ensure rtmp connected. - if ((err = connect()) != srs_success) { - //after the connection fails, need to clear flag - //and send the av header again next time - h264_sps = ""; - h264_pps = ""; - aac_specific_config = ""; - return srs_error_wrap(err, "connect"); - } - } - - if ((err = ajitter->correct(fdts)) != srs_success) { - return srs_error_wrap(err, "jitter"); - } - - uint32_t dts = (uint32_t)(fdts / 90); - - // send each frame. - SrsBuffer *avs = new SrsBuffer(stream->bytes(), stream->length()); - SrsAutoFree(SrsBuffer, avs); - if (!avs->empty()) { - if (type == STREAM_TYPE_AUDIO_AAC) { - char* frame = NULL; - int frame_size = 0; - SrsRawAacStreamCodec codec; - if ((err = aac->adts_demux(avs, &frame, &frame_size, codec)) != srs_success) { - return srs_error_wrap(err, "demux adts"); - } - - if (frame_size <= 0) { - return err; - } - - bool send_adts = false; - static int srs_aac_srates[] = { - 96000, 88200, 64000, 48000, - 44100, 32000, 24000, 22050, - 16000, 12000, 11025, 8000, - 7350, 0, 0, 0 - }; - switch (srs_aac_srates[codec.sampling_frequency_index]) { - case 11025: - codec.sound_rate = SrsAudioSampleRate11025; - break; - case 22050: - codec.sound_rate = SrsAudioSampleRate22050; - break; - case 44100: - codec.sound_rate = SrsAudioSampleRate44100; - break; - default: - send_adts = true; //raw with adts - break; - }; - - std::string sh; - if ((err = aac->mux_sequence_header(&codec, sh)) != srs_success) { - return srs_error_wrap(err, "mux sequence header"); - } - - if (aac_specific_config != sh){ - std::string sh; - if ((err = aac->mux_sequence_header(&codec, sh)) != srs_success) { - return srs_error_wrap(err, "mux sequence header"); - } - aac_specific_config = sh; - codec.aac_packet_type = 0; - if ((err = write_audio_raw_frame((char*)sh.data(), (int)sh.length(), &codec, dts)) != srs_success) { - return srs_error_wrap(err, "write raw audio frame"); - } - } - - codec.aac_packet_type = 1; - if (send_adts) { // audio raw data. with adts header - if ((err = write_audio_raw_frame(stream->bytes(), stream->length(), &codec, dts)) != srs_success) { - return srs_error_wrap(err, "write audio raw frame"); - } - }else { // audio raw data. without adts header - if ((err = write_audio_raw_frame(frame, frame_size, &codec, dts)) != srs_success) { - return srs_error_wrap(err, "write audio raw frame"); - } - } - }else if (type != 0) { - SrsRawAacStreamCodec codec; - codec.aac_packet_type = 0; - - if (type == STREAM_TYPE_AUDIO_G711){ - codec.sound_format = SrsAudioCodecIdReservedG711AlawLogarithmicPCM; - codec.sound_rate = SrsAudioSampleRate5512; - codec.sound_type = 0; //MONO = 0, STEREO = 1 - codec.sound_size = 0; //0=8K, 1=16K - }else if(type == STREAM_TYPE_AUDIO_G711ULAW){ - codec.sound_format = SrsAudioCodecIdReservedG711MuLawLogarithmicPCM; - codec.sound_rate = SrsAudioSampleRate5512; - codec.sound_type = 0; - codec.sound_size = 0; - }else { - return srs_error_wrap(err, "write audio raw frame, type=%d not suppered", type); - } - - char* frame = stream->bytes(); - int frame_size = stream->length(); - if ((err = write_audio_raw_frame(frame, frame_size, &codec, dts)) != srs_success) { - return srs_error_wrap(err, "write audio raw frame"); - } - } - }//end if (!avs->empty()) - - return err; -} - -srs_error_t SrsGb28181RtmpMuxer::write_h264_sps_pps(uint32_t dts, uint32_t pts) -{ - srs_error_t err = srs_success; - - if (h264_sps == "" || h264_pps == ""){ - return err; - } - - // h264 raw to h264 packet. - std::string sh; - if ((err = avc->mux_sequence_header(h264_sps, h264_pps, dts, pts, sh)) != srs_success) { - return srs_error_wrap(err, "mux sequence header"); - } - - // h264 packet to flv packet. - int8_t frame_type = SrsVideoAvcFrameTypeKeyFrame; - int8_t avc_packet_type = SrsVideoAvcFrameTraitSequenceHeader; - char* flv = NULL; - int nb_flv = 0; - if ((err = avc->mux_avc2flv(sh, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != srs_success) { - return srs_error_wrap(err, "mux avc to flv"); - } - - // the timestamp in rtmp message header is dts. - uint32_t timestamp = dts; - if ((err = rtmp_write_packet(SrsFrameTypeVideo, timestamp, flv, nb_flv)) != srs_success) { - return srs_error_wrap(err, "write packet"); - } - - return err; -} - -srs_error_t SrsGb28181RtmpMuxer::write_h264_ipb_frame(char* frame, int frame_size, uint32_t dts, uint32_t pts, bool writelen) -{ - srs_error_t err = srs_success; - - // 5bits, 7.3.1 NAL unit syntax, - // ISO_IEC_14496-10-AVC-2003.pdf, page 44. - // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame - SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(frame[0] & 0x1f); - - // for IDR frame, the frame is keyframe. - SrsVideoAvcFrameType frame_type = SrsVideoAvcFrameTypeInterFrame; - if (nal_unit_type == SrsAvcNaluTypeIDR) { - frame_type = SrsVideoAvcFrameTypeKeyFrame; - } - - std::string ibp; - - if (writelen){ - if ((err = avc->mux_ipb_frame(frame, frame_size, ibp)) != srs_success) { - return srs_error_wrap(err, "mux ibp frame"); - } - }else{ - ibp = string(frame, frame_size); - } - - int8_t avc_packet_type = SrsVideoAvcFrameTraitNALU; - char* flv = NULL; - int nb_flv = 0; - if ((err = avc->mux_avc2flv(ibp, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != srs_success) { - return srs_error_wrap(err, "mux avc to flv"); - } - - // the timestamp in rtmp message header is dts. - uint32_t timestamp = dts; - return rtmp_write_packet(SrsFrameTypeVideo, timestamp, flv, nb_flv); -} - -srs_error_t SrsGb28181RtmpMuxer::write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, uint32_t dts) -{ - srs_error_t err = srs_success; - - char* data = NULL; - int size = 0; - if ((err = aac->mux_aac2flv(frame, frame_size, codec, dts, &data, &size)) != srs_success) { - return srs_error_wrap(err, "mux aac to flv"); - } - - return rtmp_write_packet(SrsFrameTypeAudio, dts, data, size); -} - -srs_error_t SrsGb28181RtmpMuxer::rtmp_write_packet(char type, uint32_t timestamp, char* data, int size) -{ - srs_error_t err = srs_success; - - if (source_publish){ - return rtmp_write_packet_by_source(type, timestamp, data, size); - } - - if ((err = connect()) != srs_success) { - return srs_error_wrap(err, "connect"); - } - - SrsSharedPtrMessage* msg = NULL; - - send_rtmp_stream_time = srs_get_system_time(); - - if ((err = srs_rtmp_create_msg(type, timestamp, data, size, sdk->sid(), &msg)) != srs_success) { - return srs_error_wrap(err, "create message"); - } - srs_assert(msg); - - // send out encoded msg. - if ((err = sdk->send_and_free_message(msg)) != srs_success) { - close(); - return srs_error_wrap(err, "write message"); - } - return err; -} - -srs_error_t SrsGb28181RtmpMuxer::rtmp_write_packet_by_source(char type, uint32_t timestamp, char* data, int size) -{ - srs_error_t err = srs_success; - - send_rtmp_stream_time = srs_get_system_time(); - - //create a source that will process stream without the need for internal rtmpclient - if (type == SrsFrameTypeAudio) { - SrsMessageHeader header; - header.message_type = RTMP_MSG_AudioMessage; - // TODO: FIXME: Maybe the tbn is not 90k. - header.timestamp = timestamp & 0x3fffffff; - - SrsCommonMessage* shared_video = new SrsCommonMessage(); - SrsAutoFree(SrsCommonMessage, shared_video); - - // TODO: FIXME: Check error. - shared_video->create(&header, data, size); - source->on_audio(shared_video); - }else if(type == SrsFrameTypeVideo) { - SrsMessageHeader header; - header.message_type = RTMP_MSG_VideoMessage; - // TODO: FIXME: Maybe the tbn is not 90k. - header.timestamp = timestamp & 0x3fffffff; - - SrsCommonMessage* shared_video = new SrsCommonMessage(); - SrsAutoFree(SrsCommonMessage, shared_video); - - // TODO: FIXME: Check error. - shared_video->create(&header, data, size); - source->on_video(shared_video); - } - - return err; -} - -srs_error_t SrsGb28181RtmpMuxer::connect() -{ - srs_error_t err = srs_success; - - // Ignore when connected. - if (sdk) { - return err; - } - - // generate rtmp url to connect to. - std::string url = _rtmp_url; - - // connect host. - srs_utime_t cto = SRS_CONSTS_RTMP_TIMEOUT; - srs_utime_t sto = SRS_CONSTS_RTMP_PULSE; - sdk = new SrsSimpleRtmpClient(url, cto, sto); - - srs_trace("gb28181: rtmp connect url=%s", url.c_str()); - - if ((err = sdk->connect()) != srs_success) { - close(); - return srs_error_wrap(err, "connect %s failed, cto=%dms, sto=%dms.", url.c_str(), srsu2msi(cto), srsu2msi(sto)); - } - - // publish. - if ((err = sdk->publish(SRS_CONSTS_RTMP_PROTOCOL_CHUNK_SIZE)) != srs_success) { - close(); - return srs_error_wrap(err, "publish %s failed", url.c_str()); - } - - return err; -} - -void SrsGb28181RtmpMuxer::close() -{ - srs_freep(sdk); - - // cleared and sequence header will be sent again next time. - // RTMP close may stop through API(rtmp_close) - h264_sps = ""; - h264_pps = ""; - aac_specific_config = ""; - - // BUGFIX: if don't unpublish, it will always be in the /api/v1/streams list - //if (source_publish && !source){ - if (source_publish && source){ - source->on_unpublish(); - } -} - -void SrsGb28181RtmpMuxer::rtmp_close(){ - close(); -} - -SrsGb28181StreamChannel::SrsGb28181StreamChannel(){ - channel_id = ""; - port_mode = ""; - app = ""; - stream = ""; - ip = ""; - rtp_port = 0; - rtmp_port = 0; - ssrc = 0; - rtp_peer_port = 0; - rtp_peer_ip = ""; - rtmp_url = ""; - flv_url = ""; - hls_url = ""; - webrtc_url = ""; - recv_time = 0; - recv_time_str = ""; -} - -SrsGb28181StreamChannel::~SrsGb28181StreamChannel() -{ - -} - -void SrsGb28181StreamChannel::copy(const SrsGb28181StreamChannel *s){ - channel_id = s->get_channel_id(); - port_mode = s->get_port_mode(); - app = s->get_app(); - stream = s->get_stream(); - - ip = s->get_ip(); - rtp_port = s->get_rtp_port(); - rtmp_port = s->get_rtmp_port(); - ssrc = s->get_ssrc(); - - rtp_peer_ip = s->get_rtp_peer_ip(); - rtp_peer_port = s->get_rtp_peer_port(); - - rtmp_url = s->get_rtmp_url(); - flv_url = s->get_flv_url(); - hls_url = s->get_hls_url(); - webrtc_url = s->get_webrtc_url(); - - recv_time_str = s->get_recv_time_str(); - recv_time = s->get_recv_time(); - -} - -void SrsGb28181StreamChannel::dumps(SrsJsonObject* obj) -{ - obj->set("id", SrsJsonAny::str(channel_id.c_str())); - obj->set("ip", SrsJsonAny::str(ip.c_str())); - obj->set("rtmp_port", SrsJsonAny::integer(rtmp_port)); - obj->set("app", SrsJsonAny::str(app.c_str())); - obj->set("stream", SrsJsonAny::str(stream.c_str())); - obj->set("rtmp_url", SrsJsonAny::str(rtmp_url.c_str())); - obj->set("flv_url", SrsJsonAny::str(flv_url.c_str())); - obj->set("hls_url", SrsJsonAny::str(hls_url.c_str())); - obj->set("webrtc_url", SrsJsonAny::str(webrtc_url.c_str())); - - obj->set("ssrc", SrsJsonAny::integer(ssrc)); - obj->set("rtp_port", SrsJsonAny::integer(rtp_port)); - obj->set("port_mode", SrsJsonAny::str(port_mode.c_str())); - obj->set("rtp_peer_port", SrsJsonAny::integer(rtp_peer_port)); - obj->set("rtp_peer_ip", SrsJsonAny::str(rtp_peer_ip.c_str())); - obj->set("recv_time", SrsJsonAny::integer(recv_time/SRS_UTIME_SECONDS)); - obj->set("recv_time_str", SrsJsonAny::str(recv_time_str.c_str())); - -} - - -//Global Singleton instance, init in SrsServer -SrsGb28181Manger* _srs_gb28181 = NULL; - -//SrsGb28181Manger -SrsGb28181Manger::SrsGb28181Manger(SrsServer *s, SrsConfDirective* c) -{ - // TODO: FIXME: support reload. - server = s; - config = new SrsGb28181Config(c); - manager = new SrsResourceManager("GB28181"); -} - -SrsGb28181Manger::~SrsGb28181Manger() -{ - used_ports.clear(); - destroy(); - - srs_freep(manager); - srs_freep(config); -} - -srs_error_t SrsGb28181Manger::initialize() -{ - srs_error_t err = srs_success; - if ((err = manager->start()) != srs_success) { - return srs_error_wrap(err, "start manager"); - } - - return err; -} - -SrsGb28181Config SrsGb28181Manger::get_gb28181_config() -{ - return *config; -} - -void SrsGb28181Manger::alloc_port(int* pport) -{ - // use a pair of port. - for (int i = config->rtp_port_min; i < config->rtp_port_max - 1; i += 2) { - if (!used_ports[i]) { - used_ports[i] = true; - used_ports[i + 1] = true; - *pport = i; - break; - } - } - srs_info("gb28181: alloc port=%d-%d", *pport, *pport + 1); -} - -void SrsGb28181Manger::free_port(int lpmin, int lpmax) -{ - for (int i = lpmin; i < lpmax; i++) { - used_ports[i] = false; - } - srs_trace("gb28181: free rtp port=%d-%d", lpmin, lpmax); -} - -uint32_t SrsGb28181Manger::hash_code(std::string str) -{ - uint32_t h = 0; - int len = str.length(); - - if (h == 0) { - int off = 0; - const char *val = str.c_str(); - - for (int i = 0; i < len; i++) { - h = 31 * h + val[off++]; - } - } - return h; -} - -uint32_t SrsGb28181Manger::generate_ssrc(std::string id) -{ - srand(uint(time(0))); - // TODO: SSRC rules can be customized, - //gb28181 live ssrc max value 0999999999(3B9AC9FF) - //gb28181 vod ssrc max value 1999999999(773593FF) - uint8_t index = uint8_t(rand() % (0x0F - 0x01 + 1) + 0x01); - uint32_t ssrc = ((0x2FFFF00) & (hash_code(id) << 8)) | index; - //uint32_t ssrc = 0x00FFFFFF & (hash_code(id)); - srs_trace("gb28181: generate ssrc id=%s, ssrc=%u", id.c_str(), ssrc); - return ssrc; -} - -srs_error_t SrsGb28181Manger::fetch_or_create_rtmpmuxer(std::string id, SrsRequest *req, SrsGb28181RtmpMuxer** gb28181) -{ - srs_error_t err = srs_success; - - SrsGb28181RtmpMuxer* muxer = NULL; - if ((muxer = fetch_rtmpmuxer(id)) != NULL) { - *gb28181 = muxer; - return err; - } - - muxer = new SrsGb28181RtmpMuxer(this, id, config->audio_enable, config->wait_keyframe); - if ((err = muxer->initialize(server, req)) != srs_success) { - return srs_error_wrap(err, "gb28181: rtmp muxer initialize %s", id.c_str()); - } - - if ((err = muxer->serve()) != srs_success) { - return srs_error_wrap(err, "gb28181: rtmp muxer serve %s", id.c_str()); - } - rtmpmuxers[id] = muxer; - *gb28181 = muxer; - - return err; -} - -SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer(std::string id) -{ - SrsGb28181RtmpMuxer* muxer = NULL; - - if (rtmpmuxers.find(id) == rtmpmuxers.end()) { - return NULL; - } - - muxer = rtmpmuxers[id]; - return muxer; -} - -void SrsGb28181Manger::update_rtmpmuxer_to_newssrc_by_id(std::string id, uint32_t ssrc) -{ - SrsGb28181RtmpMuxer* muxer = NULL; - - if (rtmpmuxers.find(id) == rtmpmuxers.end()) { - srs_warn("gb28181: at update_rtmpmuxer_to_newssrc_by_id() client_id not found. client_id=%s",id.c_str()); - return; - } - - muxer = rtmpmuxers[id]; - - SrsGb28181StreamChannel mc = muxer->get_channel(); - uint32_t old_ssrc = mc.get_ssrc(); - if (old_ssrc == ssrc) { - return; - } else { - srs_trace("gb28181: update ssrc of muxer %s from %x to %x", id.c_str(), old_ssrc, ssrc); - } - rtmpmuxer_unmap_by_ssrc(old_ssrc); - mc.set_ssrc(ssrc); - muxer->copy_channel(&mc); - rtmpmuxer_map_by_ssrc(muxer, ssrc); -} - -SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer_by_ssrc(uint32_t ssrc) -{ - SrsGb28181RtmpMuxer* muxer = NULL; - if (rtmpmuxers_ssrc.find(ssrc) == rtmpmuxers_ssrc.end()) { - return NULL; - } - - muxer = rtmpmuxers_ssrc[ssrc]; - return muxer; -} - -void SrsGb28181Manger::rtmpmuxer_map_by_ssrc(SrsGb28181RtmpMuxer*muxer, uint32_t ssrc) -{ - if (rtmpmuxers_ssrc.find(ssrc) == rtmpmuxers_ssrc.end()) { - rtmpmuxers_ssrc[ssrc] = muxer; - } -} - -void SrsGb28181Manger::rtmpmuxer_unmap_by_ssrc(uint32_t ssrc) -{ - std::map::iterator it = rtmpmuxers_ssrc.find(ssrc); - if (it != rtmpmuxers_ssrc.end()) { - rtmpmuxers_ssrc.erase(it); - } -} - -void SrsGb28181Manger::destroy() -{ - if (!config->rtp_mux_tcp_enable) { - //destory ps rtp listen - std::map::iterator it; - for (it = rtp_pool.begin(); it != rtp_pool.end(); ++it) { - SrsPsRtpListener* listener = it->second; - srs_freep(listener); - } - rtp_pool.clear(); - } - - //destory gb28181 muxer - std::map::iterator it; - for (it = rtmpmuxers.begin(); it != rtmpmuxers.end(); ++it) { - SrsGb28181RtmpMuxer* muxer = it->second; - SrsGb28181StreamChannel sess = muxer->get_channel(); - rtmpmuxer_unmap_by_ssrc(sess.get_ssrc()); - manager->remove(muxer); - } - rtmpmuxers.clear(); -} - -void SrsGb28181Manger::remove(SrsGb28181RtmpMuxer* muxer) -{ - std::string id = muxer->get_channel_id(); - - map::iterator it = rtmpmuxers.find(id); - if (it != rtmpmuxers.end()) { - SrsGb28181RtmpMuxer* muxer = it->second; - SrsGb28181StreamChannel sess = muxer->get_channel(); - rtmpmuxer_unmap_by_ssrc(sess.get_ssrc()); - rtmpmuxers.erase(it); - } - manager->remove(muxer); -} - -void SrsGb28181Manger::remove_sip_session(SrsGb28181SipSession* sess) -{ - manager->remove(sess); -} - -srs_error_t SrsGb28181Manger::start_ps_rtp_listen(std::string id, int port) -{ - srs_error_t err = srs_success; - if (port == config->rtp_mux_port) { - return srs_error_wrap(err, "start rtp listen port is mux port"); - } - - /* delete by xbpeng 20201222 should not check rtmpmuxers, becasue it always not find*/ - // map::iterator key = rtmpmuxers.find(id); - // if (key == rtmpmuxers.end()){ - // srs_warn("start rtp listen port rtmp muxer is null. id=%s,port=%d", id.c_str(),port); - // return srs_error_wrap(err, "start rtp listen port rtmp muxer is null"); - // } - - if (!config->rtp_mux_tcp_enable) { - if (rtp_pool.find(port) == rtp_pool.end()) - { - SrsPsRtpListener* rtp = new SrsPsRtpListener(this->config, port, id); - rtp_pool[port] = rtp; - if ((err = rtp_pool[port]->listen()) != srs_success) { - stop_rtp_listen(id); - return srs_error_wrap(err, "rtp listen"); - } - - srs_trace("gb28181: start rtp ps stream over server-port=%d", port); - } - } - - return err; -} - -void SrsGb28181Manger::stop_rtp_listen(std::string id) -{ - map::iterator it = rtmpmuxers.find(id); - if (it == rtmpmuxers.end()){ - return; - } - - SrsGb28181RtmpMuxer* muxer = it->second; - SrsGb28181StreamChannel sess = muxer->get_channel(); - - int port = sess.get_rtp_port(); - if (port == config->rtp_mux_port) { - return; - } - - if (!config->rtp_mux_tcp_enable) { - map::iterator it2 = rtp_pool.find(port); - if (it2 != rtp_pool.end()) { - srs_freep(it2->second); - rtp_pool.erase(it2); - } - } - free_port(port, port+1); -} - -//api -srs_error_t SrsGb28181Manger::create_stream_channel(SrsGb28181StreamChannel *channel) -{ - srs_error_t err = srs_success; - srs_assert(channel); - - std::string id = channel->get_channel_id(); - SrsGb28181RtmpMuxer *muxer = NULL; - - muxer = fetch_rtmpmuxer(id); - if (muxer){ - SrsGb28181StreamChannel s = muxer->get_channel(); - channel->copy(&s); - //return ERROR_GB28181_SESSION_IS_EXIST; - return err; - } - - //Start RTP listening port, receive gb28181 stream, - //fixed is mux port, - //random is random allocation port - int rtp_port = 0; - std::string port_mode = channel->get_port_mode(); - - if (port_mode.empty()){ - port_mode = RTP_PORT_MODE_FIXED; - channel->set_port_mode(port_mode); - } - - if (port_mode == RTP_PORT_MODE_RANDOM){ - alloc_port(&rtp_port); - if (rtp_port <= 0){ - return srs_error_new(ERROR_GB28181_RTP_PORT_FULL, "gb28181: rtp port full"); - } - - if ((err = start_ps_rtp_listen(id, rtp_port)) != srs_success){ - free_port(rtp_port, rtp_port + 1); - return err; - } - } - else if(port_mode == RTP_PORT_MODE_FIXED) { - rtp_port = config->rtp_mux_port; - } - else{ - return srs_error_new(ERROR_GB28181_PORT_MODE_INVALID, "gb28181: port mode invalid"); - } - - uint32_t ssrc = channel->get_ssrc(); - if (ssrc == 0){ - //auto generate SSRC according to the hash code, - //of the string value of the id - ssrc = generate_ssrc(id); - } - - //generate RTMP push stream address, - //if the app and stream in the API are empty, - //RTMP URL is generated using the output template parameter - std::string url = ""; - int rtmp_port; - string app = channel->get_app(); - string stream = channel->get_stream(); - - SrsRequest request; - - if (true) { - string tcUrl, stream_name; - - //get template rtmp url configuration - std::string output = config->output; - srs_parse_rtmp_url(output, tcUrl, stream_name); - - string _schema, _host, _vhost, _param, _app, _stream; - srs_discovery_tc_url(tcUrl, _schema, _host, _vhost, _app, _stream, rtmp_port, _param); - - //if the stream name is not parameterized, - //it needs to be parameterized to ensure that the stream name is different - if (!srs_string_contains(stream_name, "[stream]") && - !srs_string_contains(stream_name, "[timestamp]") && - !srs_string_contains(stream_name, "[ssrc]")){ - stream_name = stream_name + "_[stream]"; - } - - if (app.empty()){ - app = _app; - } - - if (stream.empty()) - { - stream = stream_name; - } - - url = srs_generate_rtmp_url(_host, rtmp_port, "", "", app, stream, ""); - url = srs_string_replace(url, "[app]", "live"); - url = srs_string_replace(url, "[stream]", id); - std::stringstream ss; - ss << ssrc; - url = srs_string_replace(url, "[ssrc]", ss.str()); - url = srs_path_build_timestamp(url); - - //update channel app stream value - srs_parse_rtmp_url(url, tcUrl, stream_name); - srs_discovery_tc_url(tcUrl, _schema, _host, _vhost, _app, _stream, rtmp_port, _param); - - //generate the value returned to the api response - channel->set_rtp_port(rtp_port); - channel->set_ssrc(ssrc); - - channel->set_app(_app); - channel->set_stream(stream_name); - channel->set_rtmp_port(rtmp_port); - channel->set_ip(config->host); - std::string play_url = srs_generate_rtmp_url(config->host, rtmp_port, "", "", app, stream_name, ""); - - std::string flv_url = srs_string_replace(play_url, "rtmp://", "http://"); - std::stringstream port; - port << ":" << rtmp_port; - flv_url = srs_string_replace(flv_url, port.str(), ":"+_srs_config->get_http_stream_listen()); - std::string hls_url = flv_url + ".m3u8"; - flv_url = flv_url + ".flv"; - - std::string webrtc_url = srs_string_replace(play_url, "rtmp://", "webrtc://"); - webrtc_url = srs_string_replace(webrtc_url, port.str(), ":"+_srs_config->get_http_api_listen()); - - channel->set_rtmp_url(play_url); - channel->set_flv_url(flv_url); - channel->set_hls_url(hls_url); - channel->set_webrtc_url(webrtc_url); - - request.app = app; - request.stream = stream_name; - //request.vhost = config->host; - } - - //create on rtmp muxer, gb28181 stream to rtmp - if ((err = fetch_or_create_rtmpmuxer(id, &request, &muxer)) != srs_success){ - srs_warn("gb28181: create rtmp muxer error, %s", srs_error_desc(err).c_str()); - return err; - } - - rtmpmuxer_map_by_ssrc(muxer, ssrc); - muxer->set_rtmp_url(url); - srs_trace("gb28181: create new stream channel id:%s rtmp url=%s", id.c_str(), url.c_str()); - - muxer->copy_channel(channel); - - return err; -} - -srs_error_t SrsGb28181Manger::delete_stream_channel(std::string id, std::string chid) -{ - srs_error_t err = srs_success; - - //notify the device to stop streaming - //if an internal sip service controlled channel - notify_sip_bye(id, chid); - - string channel_id = id + "@" + chid; - - SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(channel_id); - if (muxer){ - stop_rtp_listen(channel_id); - muxer->stop(); - return err; - }else { - return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "stream channel is not exists"); - } -} - - -srs_error_t SrsGb28181Manger::query_stream_channel(std::string id, SrsJsonArray* arr) -{ - srs_error_t err = srs_success; - - if (!id.empty()){ - SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(id); - if (!muxer){ - return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "stream channel not exists"); - } - SrsJsonObject* obj = SrsJsonAny::object(); - arr->append(obj); - muxer->get_channel().dumps(obj); - }else { - std::map::iterator it2; - for (it2 = rtmpmuxers.begin(); it2 != rtmpmuxers.end(); ++it2) { - SrsGb28181RtmpMuxer* muxer = it2->second; - SrsJsonObject* obj = SrsJsonAny::object(); - arr->append(obj); - muxer->get_channel().dumps(obj); - } - } - - return err; -} - -srs_error_t SrsGb28181Manger::notify_sip_invite(std::string id, std::string ip, int port, uint32_t ssrc, std::string chid) -{ - srs_error_t err = srs_success; - - if (!sip_service){ - return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run"); - } - - //if RTMP Muxer does not exist, you need to create - std::string key = id+"@"+chid; - SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(key); - - if (!muxer){ - //if there is an invalid parameter, the channel will be created automatically - if (ip.empty() || port == 0 || ssrc == 0){ - //channel not exist - SrsGb28181StreamChannel channel; - channel.set_channel_id(key); - if (!this->config->sip_invite_port_fixed) { - channel.set_port_mode(RTP_PORT_MODE_RANDOM); - }else - { - channel.set_port_mode(RTP_PORT_MODE_FIXED); - } - err = create_stream_channel(&channel); - if (err != srs_success){ - return err; - } - - ip = channel.get_ip(); - port = channel.get_rtp_port(); - ssrc = channel.get_ssrc(); - } - }else { - //channel exit, use channel config - SrsGb28181StreamChannel channel = muxer->get_channel(); - ip = channel.get_ip(); - port = channel.get_rtp_port(); - ssrc = channel.get_ssrc(); - } - - SrsSipRequest req; - req.sip_auth_id = id; - return sip_service->send_invite(&req, ip, port, ssrc, chid); -} - -srs_error_t SrsGb28181Manger::notify_sip_bye(std::string id, std::string chid) -{ - if (!sip_service){ - return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run"); - } - - SrsSipRequest req; - req.sip_auth_id = id; - return sip_service->send_bye(&req, chid); -} - -srs_error_t SrsGb28181Manger::notify_sip_ptz(std::string id, std::string chid, std::string cmd, - uint8_t speed, int priority) -{ - if (!sip_service){ - return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run"); - } - - SrsSipRequest req; - req.sip_auth_id = id; - return sip_service->send_ptz(&req, chid, cmd, speed, priority); -} - -srs_error_t SrsGb28181Manger::notify_sip_raw_data(std::string id, std::string data) -{ - if (!sip_service){ - return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run"); - } - - SrsSipRequest req; - req.sip_auth_id = id; - return sip_service->send_sip_raw_data(&req, data); - -} - -srs_error_t SrsGb28181Manger::notify_sip_unregister(std::string id) -{ - if (!sip_service){ - return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run"); - } - sip_service->remove_session(id); - return srs_success; - // useless, because - // sip session has been removed - // id is not channel id like id@chid - //return delete_stream_channel(id); -} - -srs_error_t SrsGb28181Manger::notify_sip_query_catalog(std::string id) -{ - if (!sip_service){ - return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run"); - } - - SrsSipRequest req; - req.sip_auth_id = id; - SrsGb28181SipSession *sip_session = sip_service->fetch(req.sip_auth_id); - if (sip_session) { - sip_session->item_list.clear(); - sip_session->clear_device_list(); - srs_trace("notify_sip_query_catalog, clear sip session item and device list"); - } - return sip_service->send_query_catalog(&req); -} - -srs_error_t SrsGb28181Manger::query_sip_session(std::string id, SrsJsonArray* arr) -{ - if (!sip_service){ - return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run"); - } - - return sip_service->query_sip_session(id, arr); -} - -srs_error_t SrsGb28181Manger::query_device_list(std::string id, SrsJsonArray* arr) -{ - if (!sip_service){ - return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run"); - } - - return sip_service->query_device_list(id, arr); -} -#define SRS_RTSP_BUFFER 8192 -#define RTP_TCP_HEADER 2 -#define MAX_PACKAGE_SIZE 1024 * 10 -SrsGb28181Conn::SrsGb28181Conn(SrsGb28181Caster* c, srs_netfd_t fd, SrsGb28181PsRtpProcessor *rtp_processor) -{ - caster = c; - stfd = fd; - skt = new SrsStSocket(); - rtsp = new SrsRtspStack(skt); - trd = new SrsSTCoroutine("rtsp", this); - mbuffer = (char*)malloc(SRS_RTSP_BUFFER); - processor = rtp_processor; -} - -SrsGb28181Conn::~SrsGb28181Conn() -{ - free(mbuffer); - srs_close_stfd(stfd); - - srs_freep(trd); - srs_freep(skt); - srs_freep(rtsp); -} - -srs_error_t SrsGb28181Conn::serve() -{ - srs_error_t err = srs_success; - - if ((err = skt->initialize(stfd)) != srs_success) { - return srs_error_wrap(err, "socket initialize"); - } - - if ((err = trd->start()) != srs_success) { - return srs_error_wrap(err, "rtsp connection"); - } - return err; -} - -std::string SrsGb28181Conn::remote_ip() -{ - // TODO: FIXME: Implement it. - return ""; -} - -srs_error_t SrsGb28181Conn::do_cycle() -{ - srs_error_t err = srs_success; - - // retrieve ip of client. - int fd = srs_netfd_fileno(stfd); - std::string ip = srs_get_peer_ip(fd); - int port = srs_get_peer_port(fd); - int addr_len = sizeof(sockaddr_in); - sockaddr_in *peer_sockaddr = (sockaddr_in*)malloc(addr_len); - peer_sockaddr->sin_family = AF_INET; //设置地址家族 - peer_sockaddr->sin_port = htons(port); //设置端口 - peer_sockaddr->sin_addr.s_addr = inet_addr(ip.c_str()); - - - if (ip.empty() && !_srs_config->empty_ip_ok()) { - srs_warn("empty ip for fd=%d", srs_netfd_fileno(stfd)); - } - srs_trace("gb28181 new connect by rtp-tcp from: %s:%d", ip.c_str(), port); - - uint32_t left_data_len = 0; //缓存剩余数据 - ssize_t nb_read = 0; - uint16_t packet_len = 0; //rtp包长度 - - // consume all rtp data. - while (true) { - if ((err = trd->pull()) != srs_success) { - return srs_error_wrap(err, "rtsp cycle"); - } - nb_read = 0; - if ((err = skt->read(mbuffer + left_data_len, SRS_RTSP_BUFFER - left_data_len, &nb_read)) != srs_success) { - return srs_error_wrap(err, "recv data"); - } - - left_data_len = nb_read + left_data_len; - char * buf = mbuffer; - - uint32_t index = 0; - for( ; index < left_data_len; ){ - if (index + RTP_TCP_HEADER >= left_data_len){ //less rtp package - break; - } - packet_len = (((uint8_t *) buf)[index] << 8) | ((uint8_t *) buf)[index + 1]; - if (packet_len > MAX_PACKAGE_SIZE){ - //FIXME 自动重新invite? - srs_error("abnormal RTP packet length:%d, close the tcp conn:%s", packet_len, remote_ip().c_str()); - return err; - } - if (index + RTP_TCP_HEADER + packet_len >= left_data_len){ - break; - } - processor->on_tcp_packet((sockaddr*)peer_sockaddr, addr_len, buf + index + RTP_TCP_HEADER, packet_len); - index = index + RTP_TCP_HEADER + packet_len; - } - if (index != 0) { //update left data - left_data_len = left_data_len - index; - memmove(mbuffer, buf + index, left_data_len); - } - - } - free(peer_sockaddr); - return err; -} - -srs_error_t SrsGb28181Conn::cycle() -{ - // serve the rtsp client. - srs_error_t err = do_cycle(); - - caster->remove(this); - - if (err == srs_success) { - srs_trace("client finished."); - } - else if (srs_is_client_gracefully_close(err)) { - srs_warn("client disconnect peer. code=%d", srs_error_code(err)); - srs_freep(err); - } - - return err; -} - -std::string SrsGb28181Conn::desc() -{ - return "GB28181TcpConn"; -} - -const SrsContextId& SrsGb28181Conn::get_id() -{ - return trd->cid(); -} - -SrsGb28181Caster::SrsGb28181Caster(SrsConfDirective* c) -{ - // TODO: FIXME: support reload. - output = _srs_config->get_stream_caster_output(c); - config = new SrsGb28181Config(c); - rtp_processor = new SrsGb28181PsRtpProcessor(config, ""); - manager = new SrsResourceManager("GB28181TCP", true); -} - -SrsGb28181Caster::~SrsGb28181Caster() -{ - std::vector::iterator it; - for (it = clients.begin(); it != clients.end(); ++it) { - SrsGb28181Conn* conn = *it; - manager->remove(conn); - } - clients.clear(); - - srs_freep(manager); -} - -srs_error_t SrsGb28181Caster::initialize() -{ - srs_error_t err = srs_success; - if ((err = manager->start()) != srs_success) { - return srs_error_wrap(err, "start manager"); - } - return err; -} - -srs_error_t SrsGb28181Caster::on_tcp_client(srs_netfd_t stfd) -{ - srs_error_t err = srs_success; - - SrsGb28181Conn* conn = new SrsGb28181Conn(this, stfd, rtp_processor); - - if ((err = conn->serve()) != srs_success) { - srs_freep(conn); - return srs_error_wrap(err, "serve conn"); - } - - clients.push_back(conn); - - return err; -} - -void SrsGb28181Caster::remove(SrsGb28181Conn* conn) -{ - std::vector::iterator it = find(clients.begin(), clients.end(), conn); - if (it != clients.end()) { - clients.erase(it); - } - srs_info("rtsp: remove connection from caster."); - - manager->remove(conn); -} - diff --git a/trunk/src/app/srs_app_gb28181.hpp b/trunk/src/app/srs_app_gb28181.hpp deleted file mode 100644 index ba28056a1..000000000 --- a/trunk/src/app/srs_app_gb28181.hpp +++ /dev/null @@ -1,581 +0,0 @@ -// -// Copyright (c) 2013-2021 Lixin -// -// SPDX-License-Identifier: MIT -// - -#ifndef SRS_APP_GB28181_HPP -#define SRS_APP_GB28181_HPP - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define RTP_PORT_MODE_FIXED "fixed" -#define RTP_PORT_MODE_RANDOM "random" - -#define PS_AUDIO_ID 0xc0 -#define PS_AUDIO_ID_END 0xdf -#define PS_VIDEO_ID 0xe0 -#define PS_VIDEO_ID_END 0xef - -#define STREAM_TYPE_VIDEO_MPEG1 0x01 -#define STREAM_TYPE_VIDEO_MPEG2 0x02 -#define STREAM_TYPE_AUDIO_MPEG1 0x03 -#define STREAM_TYPE_AUDIO_MPEG2 0x04 -#define STREAM_TYPE_PRIVATE_SECTION 0x05 -#define STREAM_TYPE_PRIVATE_DATA 0x06 -#define STREAM_TYPE_AUDIO_AAC 0x0f -#define STREAM_TYPE_VIDEO_MPEG4 0x10 -#define STREAM_TYPE_VIDEO_H264 0x1b -#define STREAM_TYPE_VIDEO_HEVC 0x24 -#define STREAM_TYPE_VIDEO_CAVS 0x42 -#define STREAM_TYPE_VIDEO_SAVC 0x80 - -#define STREAM_TYPE_AUDIO_AC3 0x81 - -#define STREAM_TYPE_AUDIO_G711 0x90 -#define STREAM_TYPE_AUDIO_G711ULAW 0x91 -#define STREAM_TYPE_AUDIO_G722_1 0x92 -#define STREAM_TYPE_AUDIO_G723_1 0x93 -#define STREAM_TYPE_AUDIO_G726 0x96 -#define STREAM_TYPE_AUDIO_G729_1 0x99 -#define STREAM_TYPE_AUDIO_SVAC 0x9b -#define STREAM_TYPE_AUDIO_PCM 0x9c - -class SrsConfDirective; -class SrsRtspPacket; -class SrsRtmpClient; -class SrsRawH264Stream; -class SrsRawAacStream; -struct SrsRawAacStreamCodec; -class SrsSharedPtrMessage; -class SrsAudioFrame; -class SrsSimpleStream; -class SrsPithyPrint; -class SrsSimpleRtmpClient; -class SrsSipStack; -class SrsGb28181Manger; -class SrsRtpTimeJitter; -class SrsSipRequest; -class SrsGb28181RtmpMuxer; -class SrsGb28181Config; -class SrsGb28181PsRtpProcessor; -class SrsGb28181SipService; -class SrsGb28181StreamChannel; -class SrsGb28181SipSession; -class SrsRtpJitterBuffer; -class SrsServer; -class SrsLiveSource; -class SrsRequest; -class SrsResourceManager; -class SrsGb28181Conn; -class SrsGb28181Caster; - -//ps rtp header packet parse - -class SrsPsRtpPacket: public SrsRtspPacket -{ -public: - SrsPsRtpPacket(); - virtual ~SrsPsRtpPacket(); - bool isFirstPacket; -public: - virtual srs_error_t decode(SrsBuffer* stream); -}; - -//randomly assigned ports receive gb28181 device streams -class SrsPsRtpListener: public ISrsUdpHandler -{ -private: - SrsUdpListener* listener; - SrsGb28181PsRtpProcessor* rtp_processor; - int _port; -public: - SrsPsRtpListener(SrsGb28181Config* c, int p, std::string s); - virtual ~SrsPsRtpListener(); -public: - virtual int port(); - virtual srs_error_t listen(); -// Interface ISrsUdpHandler -public: - virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); -}; - -//multiplexing service, single port receiving all gb28181 device streams -class SrsGb28181RtpMuxService : public ISrsUdpHandler -{ -private: - SrsGb28181Config *config; - SrsGb28181PsRtpProcessor *rtp_processor; -public: - SrsGb28181RtpMuxService(SrsConfDirective* c); - virtual ~SrsGb28181RtpMuxService(); - - // Interface ISrsUdpHandler -public: - virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); -}; - - -//process gb28181 RTP package, generate a completed PS stream data, -//call the PS stream parser, parse the original video and audio -class SrsGb28181PsRtpProcessor: public ISrsUdpHandler -{ -private: - SrsPithyPrint* pprint; - SrsGb28181Config* config; - std::map cache_ps_rtp_packet; - std::map pre_packet; - std::string channel_id; - bool auto_create_channel; -public: - SrsGb28181PsRtpProcessor(SrsGb28181Config* c, std::string sid); - virtual ~SrsGb28181PsRtpProcessor(); -private: - bool can_send_ps_av_packet(); - void dispose(); - void clear_pre_packet(); - SrsGb28181RtmpMuxer* fetch_rtmpmuxer(std::string channel_id, uint32_t ssrc); - srs_error_t rtmpmuxer_enqueue_data(SrsGb28181RtmpMuxer *muxer, uint32_t ssrc, - int peer_port, std::string address_string, SrsPsRtpPacket *pkt); -// Interface ISrsUdpHandler -public: - virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); - virtual srs_error_t on_tcp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); -public: - virtual srs_error_t on_rtp_packet_jitter(const sockaddr* from, const int fromlen, char* buf, int nb_buf); - virtual srs_error_t on_rtp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); -}; - - -//ps stream processing parsing interface -class ISrsPsStreamHander -{ -public: - ISrsPsStreamHander(); - virtual ~ISrsPsStreamHander(); -public: - virtual srs_error_t on_rtp_video(SrsSimpleStream* stream, int64_t dts)=0; - virtual srs_error_t on_rtp_audio(SrsSimpleStream* stream, int64_t dts, int type)=0; -}; - -//analysis of PS stream and -//extraction of H264 raw data and audio data -//then process the flow through PS stream hander, -//such as RTMP multiplexer, and composited into RTMP av stream -class SrsPsStreamDemixer -{ -public: - // gb28181 program stream struct define - struct SrsPsPacketStartCode - { - uint8_t start_code[3]; - uint8_t stream_id[1]; - }; - - struct SrsPsPacketHeader - { - SrsPsPacketStartCode start;// 4 - uint8_t info[9]; - uint8_t stuffing_length; - }; - - struct SrsPsPacketBBHeader - { - SrsPsPacketStartCode start; - uint16_t length; - }; - - struct SrsPsePacket - { - SrsPsPacketStartCode start; - uint16_t length; - uint8_t info[2]; - uint8_t stuffing_length; - }; - - struct SrsPsMapPacket - { - SrsPsPacketStartCode start; - uint16_t length; - }; - -private: - SrsFileWriter ps_fw; - SrsFileWriter video_fw; - SrsFileWriter audio_fw; - SrsFileWriter unknow_fw; - - bool first_keyframe_flag; - bool wait_first_keyframe; - bool audio_enable; - std::string channel_id; - - uint8_t video_es_id; - uint8_t video_es_type; - uint8_t audio_es_id; - uint8_t audio_es_type; - int audio_check_aac_try_count; - - SrsRawAacStream *aac; - - ISrsPsStreamHander *hander; -public: - SrsPsStreamDemixer(ISrsPsStreamHander *h, std::string sid, bool a, bool k); - virtual ~SrsPsStreamDemixer(); -private: - bool can_send_ps_av_packet(); -public: - int64_t parse_ps_timestamp(const uint8_t* p); - std::string get_ps_map_type_str(uint8_t); - virtual srs_error_t on_ps_stream(char* ps_data, int ps_size, uint32_t timestamp, uint32_t ssrc); -}; - - -//RTMP multiplexer, which processes the raw H264 / AAC, -//then publish it to RTMP server -class SrsGb28181RtmpMuxer : public ISrsCoroutineHandler, - public ISrsConnection, public ISrsPsStreamHander -{ -private: - SrsPithyPrint* pprint; - SrsGb28181StreamChannel *channel; - int stream_idle_timeout; - srs_utime_t recv_rtp_stream_time; - srs_utime_t send_rtmp_stream_time; -private: - std::string channel_id; - std::string _rtmp_url; - std::string video_ssrc; - std::string audio_ssrc; - - SrsGb28181Manger* gb28181_manger; - SrsCoroutine* trd; - SrsPsStreamDemixer* ps_demixer; - srs_cond_t wait_ps_queue; - - SrsSimpleRtmpClient* sdk; - SrsRtpTimeJitter* vjitter; - SrsRtpTimeJitter* ajitter; - - SrsRawH264Stream* avc; - std::string h264_sps; - std::string h264_pps; - - SrsRawAacStream* aac; - std::string aac_specific_config; - - SrsRequest* req; - SrsLiveSource* source; - SrsServer* server; - - SrsRtpJitterBuffer *jitter_buffer; - SrsRtpJitterBuffer *jitter_buffer_audio; - - char *ps_buffer; - char *ps_buffer_audio; - - int ps_buflen; - int ps_buflen_auido; - - uint32_t ps_rtp_video_ts; - - bool source_publish; - -public: - std::queue ps_queue; - -public: - SrsGb28181RtmpMuxer(SrsGb28181Manger* m, std::string id, bool a, bool k); - virtual ~SrsGb28181RtmpMuxer(); - -public: - virtual srs_error_t serve(); - virtual void stop(); - srs_error_t initialize(SrsServer* s, SrsRequest* r); - - virtual std::string get_channel_id(); - virtual void ps_packet_enqueue(SrsPsRtpPacket *pkt); - virtual void copy_channel(SrsGb28181StreamChannel *s); - virtual void set_channel_peer_ip(std::string ip); - virtual void set_channel_peer_port(int port); - virtual int channel_peer_port(); - virtual std::string channel_peer_ip(); - virtual void set_rtmp_url(std::string url); - virtual std::string rtmp_url(); - virtual SrsGb28181StreamChannel get_channel(); - srs_utime_t get_recv_stream_time(); - - void insert_jitterbuffer(SrsPsRtpPacket *pkt); - -private: - virtual srs_error_t do_cycle(); - virtual void destroy(); - -// Interface ISrsOneCycleThreadHandler -public: - virtual srs_error_t cycle(); -// Interface ISrsConnection. -public: - virtual std::string remote_ip(); - virtual const SrsContextId& get_id(); - virtual std::string desc(); -public: - virtual srs_error_t on_rtp_video(SrsSimpleStream* stream, int64_t dts); - virtual srs_error_t on_rtp_audio(SrsSimpleStream* stream, int64_t dts, int type); -private: - - srs_error_t replace_startcode_with_nalulen(char *video_data, int &size, uint32_t pts, uint32_t dts); - srs_error_t write_h264_ipb_frame2(char *frame, int frame_size, uint32_t pts, uint32_t dts); - virtual srs_error_t write_h264_sps_pps(uint32_t dts, uint32_t pts); - virtual srs_error_t write_h264_ipb_frame(char* frame, int frame_size, uint32_t dts, uint32_t pts, bool b = true); - virtual srs_error_t write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, uint32_t dts); - virtual srs_error_t rtmp_write_packet(char type, uint32_t timestamp, char* data, int size); - virtual srs_error_t rtmp_write_packet_by_source(char type, uint32_t timestamp, char* data, int size); -private: - // Connect to RTMP server. - virtual srs_error_t connect(); - // Close the connection to RTMP server. - virtual void close(); -public: - virtual void rtmp_close(); -}; - -//system parameter configuration of gb28181 module, -//read file from configuration file to generate -class SrsGb28181Config -{ -public: - std::string host; - srs_utime_t rtp_idle_timeout; - bool audio_enable; - bool wait_keyframe; - std::string output; - int rtp_port_min; - int rtp_port_max; - int rtp_mux_port; - bool rtp_mux_tcp_enable; - bool auto_create_channel; - bool jitterbuffer_enable; - - //sip config - int sip_port; - std::string sip_serial; - std::string sip_realm; - bool sip_enable; - srs_utime_t sip_ack_timeout; - srs_utime_t sip_keepalive_timeout; - bool sip_auto_play; - bool sip_invite_port_fixed; - srs_utime_t sip_query_catalog_interval; - -public: - SrsGb28181Config(SrsConfDirective* c); - virtual ~SrsGb28181Config(); -}; - -class SrsGb28181StreamChannel -{ -private: - std::string channel_id; - std::string port_mode; - std::string app; - std::string stream; - std::string rtmp_url; - std::string flv_url; - std::string hls_url; - std::string webrtc_url; - - std::string ip; - int rtp_port; - int rtmp_port; - uint32_t ssrc; - srs_utime_t recv_time; - std::string recv_time_str; - - //send rtp stream client local port - int rtp_peer_port; - //send rtp stream client local ip - std::string rtp_peer_ip; - -public: - SrsGb28181StreamChannel(); - virtual ~SrsGb28181StreamChannel(); - - std::string get_channel_id() const { return channel_id; } - std::string get_port_mode() const { return port_mode; } - std::string get_app() const { return app; } - std::string get_stream() const { return stream; } - std::string get_ip() const { return ip; } - int get_rtp_port() const { return rtp_port; } - int get_rtmp_port() const { return rtmp_port; } - uint32_t get_ssrc() const { return ssrc; } - uint32_t get_rtp_peer_port() const { return rtp_peer_port; } - std::string get_rtp_peer_ip() const { return rtp_peer_ip; } - std::string get_rtmp_url() const { return rtmp_url; } - std::string get_flv_url() const { return flv_url; } - std::string get_hls_url() const { return hls_url; } - std::string get_webrtc_url() const { return webrtc_url; } - srs_utime_t get_recv_time() const { return recv_time; } - std::string get_recv_time_str() const { return recv_time_str; } - - void set_channel_id(const std::string &i) { channel_id = i; } - void set_port_mode(const std::string &p) { port_mode = p; } - void set_app(const std::string &a) { app = a; } - void set_stream(const std::string &s) { stream = s; } - void set_ip(const std::string &i) { ip = i; } - void set_rtp_port( const int &p) { rtp_port = p; } - void set_rtmp_port( const int &p) { rtmp_port = p; } - void set_ssrc( const int &s) { ssrc = s;} - void set_rtp_peer_ip( const std::string &p) { rtp_peer_ip = p; } - void set_rtp_peer_port( const int &s) { rtp_peer_port = s;} - void set_rtmp_url( const std::string &u) { rtmp_url = u; } - void set_flv_url( const std::string &u) { flv_url = u; } - void set_hls_url( const std::string &u) { hls_url = u; } - void set_webrtc_url( const std::string &u) { webrtc_url = u; } - void set_recv_time( const srs_utime_t &u) { recv_time = u; } - void set_recv_time_str( const std::string &u) { recv_time_str = u; } - - void copy(const SrsGb28181StreamChannel *s); - void dumps(SrsJsonObject* obj); - -}; - -// Global singleton instance. -extern SrsGb28181Manger* _srs_gb28181; - -//gb28181 module management, management of all RTMP multiplexers, -//random assignment of RTP listeners, and external control interfaces -class SrsGb28181Manger -{ -private: - SrsGb28181Config *config; - // The key: port, value: whether used. - std::map used_ports; - std::map rtp_pool; - std::map rtmpmuxers_ssrc; - std::map rtmpmuxers; - SrsResourceManager* manager; - SrsGb28181SipService* sip_service; - SrsServer* server; -public: - SrsGb28181Manger(SrsServer* s, SrsConfDirective* c); - virtual ~SrsGb28181Manger(); - -public: - srs_error_t fetch_or_create_rtmpmuxer(std::string id, SrsRequest *req, SrsGb28181RtmpMuxer** gb28181); - SrsGb28181RtmpMuxer* fetch_rtmpmuxer(std::string id); - SrsGb28181RtmpMuxer* fetch_rtmpmuxer_by_ssrc(uint32_t ssrc); - void update_rtmpmuxer_to_newssrc_by_id(std::string id, uint32_t ssrc); - void rtmpmuxer_map_by_ssrc(SrsGb28181RtmpMuxer*muxer, uint32_t ssrc); - void rtmpmuxer_unmap_by_ssrc(uint32_t ssrc); - uint32_t generate_ssrc(std::string id); - uint32_t hash_code(std::string str); - - void set_sip_service(SrsGb28181SipService *s) { sip_service = s; } - SrsGb28181SipService* get_sip_service() { return sip_service; } - SrsGb28181Config* get_gb28181_config_ptr() { return config;} - -public: - //stream channel api - srs_error_t create_stream_channel(SrsGb28181StreamChannel *channel); - srs_error_t delete_stream_channel(std::string id, std::string chid); - srs_error_t query_stream_channel(std::string id, SrsJsonArray* arr); - //sip api - srs_error_t notify_sip_invite(std::string id, std::string ip, int port, uint32_t ssrc, std::string chid); - srs_error_t notify_sip_bye(std::string id, std::string chid); - srs_error_t notify_sip_raw_data(std::string id, std::string data); - srs_error_t notify_sip_unregister(std::string id); - srs_error_t notify_sip_query_catalog(std::string id); - srs_error_t notify_sip_ptz(std::string id, std::string chid, std::string cmd, uint8_t speed, int priority); - srs_error_t query_sip_session(std::string id, SrsJsonArray* arr); - srs_error_t query_device_list(std::string id, SrsJsonArray* arr); - -private: - void destroy(); - -public: - // Alloc a rtp port from local ports pool. - // @param pport output the rtp port. - void alloc_port(int* pport); - // Free the alloced rtp port. - void free_port(int lpmin, int lpmax); - srs_error_t initialize(); - - SrsGb28181Config get_gb28181_config(); - srs_error_t start_ps_rtp_listen(std::string id, int port); - void stop_rtp_listen(std::string id); - -public: - void remove(SrsGb28181RtmpMuxer* conn); - void remove_sip_session(SrsGb28181SipSession* sess); -}; - -// The gb28181 tcp connection serve the fd. -class SrsGb28181Conn : public ISrsCoroutineHandler, public ISrsConnection -{ -private: - char* mbuffer; - srs_netfd_t stfd; - SrsStSocket* skt; - SrsRtspStack* rtsp; - SrsGb28181Caster* caster; - SrsCoroutine* trd; - SrsGb28181PsRtpProcessor *processor; -public: - SrsGb28181Conn(SrsGb28181Caster* c, srs_netfd_t fd, SrsGb28181PsRtpProcessor *rtp_processor); - virtual ~SrsGb28181Conn(); -public: - virtual srs_error_t serve(); - virtual std::string remote_ip(); -private: - virtual srs_error_t do_cycle(); - // Interface ISrsOneCycleThreadHandler -public: - virtual srs_error_t cycle(); - virtual std::string desc(); - virtual const SrsContextId& get_id(); -}; - -// The caster for gb28181. -class SrsGb28181Caster : public ISrsTcpHandler -{ -private: - std::string output; - SrsGb28181Config *config; - SrsGb28181PsRtpProcessor *rtp_processor; -private: - std::vector clients; - SrsResourceManager* manager; -public: - SrsGb28181Caster(SrsConfDirective* c); - virtual ~SrsGb28181Caster(); -public: - virtual srs_error_t initialize(); - // Interface ISrsTcpHandler -public: - virtual srs_error_t on_tcp_client(srs_netfd_t stfd); - // internal methods. -public: - virtual void remove(SrsGb28181Conn* conn); -}; - -#endif - diff --git a/trunk/src/app/srs_app_gb28181_jitter.cpp b/trunk/src/app/srs_app_gb28181_jitter.cpp deleted file mode 100644 index 2ced92af4..000000000 --- a/trunk/src/app/srs_app_gb28181_jitter.cpp +++ /dev/null @@ -1,1971 +0,0 @@ -// -// Copyright (c) 2013-2021 Lixin -// -// SPDX-License-Identifier: MIT -// - -#include - -#include -#include -#include -#include -#include -#include - - -using namespace std; - -// Use this rtt if no value has been reported. -static const int64_t kDefaultRtt = 200; - -// Request a keyframe if no continuous frame has been received for this -// number of milliseconds and NACKs are disabled. -//static const int64_t kMaxDiscontinuousFramesTime = 1000; - -typedef std::pair FrameListPair; - -bool IsKeyFrame(FrameListPair pair) -{ - return pair.second->GetFrameType() == kVideoFrameKey; -} - -bool HasNonEmptyState(FrameListPair pair) -{ - return pair.second->GetState() != kStateEmpty; -} - -void FrameList::InsertFrame(SrsRtpFrameBuffer* frame) -{ - insert(rbegin().base(), FrameListPair(frame->GetTimeStamp(), frame)); -} - -SrsRtpFrameBuffer* FrameList::PopFrame(uint32_t timestamp) -{ - FrameList::iterator it = find(timestamp); - - if (it == end()) { - return NULL; - } - - SrsRtpFrameBuffer* frame = it->second; - erase(it); - return frame; -} - -SrsRtpFrameBuffer* FrameList::Front() const -{ - return begin()->second; -} - -SrsRtpFrameBuffer* FrameList::FrontNext() const -{ - FrameList::const_iterator it = begin(); - it++; - - if (it != end()) - { - return it->second; - } - - return NULL; -} - - -SrsRtpFrameBuffer* FrameList::Back() const -{ - return rbegin()->second; -} - -int FrameList::RecycleFramesUntilKeyFrame(FrameList::iterator* key_frame_it, - UnorderedFrameList* free_frames) -{ - int drop_count = 0; - FrameList::iterator it = begin(); - - while (!empty()) { - // Throw at least one frame. - it->second->Reset(); - free_frames->push_back(it->second); - erase(it++); - ++drop_count; - - if (it != end() && it->second->GetFrameType() == kVideoFrameKey) { - *key_frame_it = it; - return drop_count; - } - } - - *key_frame_it = end(); - return drop_count; -} - -void FrameList::CleanUpOldOrEmptyFrames(SrsRtpDecodingState* decoding_state, UnorderedFrameList* free_frames) -{ - while (!empty()) { - SrsRtpFrameBuffer* oldest_frame = Front(); - bool remove_frame = false; - - if (oldest_frame->GetState() == kStateEmpty && size() > 1) { - // This frame is empty, try to update the last decoded state and drop it - // if successful. - remove_frame = decoding_state->UpdateEmptyFrame(oldest_frame); - } else { - remove_frame = decoding_state->IsOldFrame(oldest_frame); - } - - if (!remove_frame) { - break; - } - - free_frames->push_back(oldest_frame); - erase(begin()); - } -} - -void FrameList::Reset(UnorderedFrameList* free_frames) -{ - while (!empty()) { - begin()->second->Reset(); - free_frames->push_back(begin()->second); - erase(begin()); - } -} - - -VCMPacket::VCMPacket() - : - payloadType(0), - timestamp(0), - ntp_time_ms_(0), - seqNum(0), - dataPtr(NULL), - sizeBytes(0), - markerBit(false), - frameType(kEmptyFrame), - codec(kVideoCodecUnknown), - isFirstPacket(false), - completeNALU(kNaluUnset), - insertStartCode(false), - width(0), - height(0) - //codecSpecificHeader() -{ -} - - -VCMPacket::VCMPacket(const uint8_t* ptr, - size_t size, - uint16_t seq, - uint32_t ts, - bool mBit, - H264PacketizationTypes type, - RtpVideoCodecTypes rtpType, - bool singlenual, - bool isfirst, - FrameType ftype) : - payloadType(0), - timestamp(ts), - ntp_time_ms_(0), - seqNum(seq), - dataPtr(ptr), - sizeBytes(size), - markerBit(mBit), - frameType(ftype), - codec(kVideoCodecUnknown), - isFirstPacket(false), - completeNALU(kNaluComplete), - insertStartCode(false), - width(0), - height(0), - h264packetizationType(type) - //codecSpecificHeader() -{ - CopyCodecSpecifics(rtpType, singlenual, isfirst); -} - -void VCMPacket::Reset() -{ - payloadType = 0; - timestamp = 0; - ntp_time_ms_ = 0; - seqNum = 0; - dataPtr = NULL; - sizeBytes = 0; - markerBit = false; - frameType = kEmptyFrame; - codec = kVideoCodecUnknown; - isFirstPacket = false; - completeNALU = kNaluUnset; - insertStartCode = false; - width = 0; - height = 0; - //memset(&codecSpecificHeader, 0, sizeof(RTPVideoHeader)); -} - -void VCMPacket::CopyCodecSpecifics(RtpVideoCodecTypes codecType, bool H264single_nalu, bool firstPacket) -{ - switch (codecType) { - case kRtpVideoVp8: - - // Handle all packets within a frame as depending on the previous packet - // TODO(holmer): This should be changed to make fragments independent - // when the VP8 RTP receiver supports fragments. - if (isFirstPacket && markerBit) { - completeNALU = kNaluComplete; - } else if (isFirstPacket) { - completeNALU = kNaluStart; - } else if (markerBit) { - completeNALU = kNaluEnd; - } else { - completeNALU = kNaluIncomplete; - } - - codec = kVideoCodecVP8; - return; - - case kRtpVideoH264: - isFirstPacket = firstPacket; - - if (isFirstPacket) { - insertStartCode = true; - } - - if (H264single_nalu) { - completeNALU = kNaluComplete; - } else if (isFirstPacket) { - completeNALU = kNaluStart; - } else if (markerBit) { - completeNALU = kNaluEnd; - } else { - completeNALU = kNaluIncomplete; - } - - codec = kVideoCodecH264; - return; - case kRtpVideoPS: - isFirstPacket = firstPacket; - codec = kVideoCodecH264PS; - return; - - case kRtpVideoVp9: - case kRtpVideoGeneric: - case kRtpVideoNone: - codec = kVideoCodecUnknown; - return; - } -} - -uint16_t BufferToUWord16(const uint8_t* dataBuffer) -{ - return (dataBuffer[0] << 8) | dataBuffer[1]; -} - -SrsRtpFrameBuffer::SrsRtpFrameBuffer() -{ - empty_seq_num_low_ = 0; - empty_seq_num_high_ = 0; - first_packet_seq_num_ = 0; - last_packet_seq_num_ = 0; - complete_ = false; - decodable_ = false; - timeStamp_ = 0; - frame_type_ = kEmptyFrame; - decode_error_mode_ = kNoErrors; - _length = 0; - _size = 0; - _buffer = NULL; -} - -SrsRtpFrameBuffer::~SrsRtpFrameBuffer() -{ - srs_freepa(_buffer); -} - -void SrsRtpFrameBuffer::Reset() -{ - //session_nack_ = false; - complete_ = false; - decodable_ = false; - frame_type_ = kVideoFrameDelta; - packets_.clear(); - empty_seq_num_low_ = -1; - empty_seq_num_high_ = -1; - first_packet_seq_num_ = -1; - last_packet_seq_num_ = -1; - _length = 0; -} - -size_t SrsRtpFrameBuffer::Length() const -{ - return _length; -} - -SrsRtpFrameBufferEnum SrsRtpFrameBuffer::InsertPacket(const VCMPacket& packet, const FrameData& frame_data) -{ - if (packets_.size() == kMaxPacketsInSession) { - srs_warn("RTP: jitbuffer Max number of packets per frame has been reached."); - return kSizeError; - } - - if (packets_.size() == 0){ - timeStamp_ = packet.timestamp; - } - - uint32_t requiredSizeBytes = Length() + packet.sizeBytes; - - if (requiredSizeBytes == 0){ - srs_warn("RTP: jitbuffer requiredSizeBytes is zero ts:%u, seq:%u", packet.timestamp, packet.seqNum); - return kSizeError; - } - - if (requiredSizeBytes >= _size) { - const uint8_t* prevBuffer = _buffer; - const uint32_t increments = requiredSizeBytes / - kBufferIncStepSizeBytes + - (requiredSizeBytes % - kBufferIncStepSizeBytes > 0); - const uint32_t newSize = _size + - increments * kBufferIncStepSizeBytes; - - if (newSize > kMaxJBFrameSizeBytes) { - srs_error("RTP: jitbuffer Failed to insert packet due to frame being too big."); - return kSizeError; - } - - VerifyAndAllocate(newSize); - UpdateDataPointers(prevBuffer, _buffer); - - srs_trace("RTP: jitbuffer VerifyAndAllocate:newSize:%d, prevBuffer:%d, _buffer:%d", newSize, prevBuffer, _buffer); - } - - // Find the position of this packet in the packet list in sequence number - // order and insert it. Loop over the list in reverse order. - ReversePacketIterator rit = packets_.rbegin(); - - for (; rit != packets_.rend(); ++rit){ - if (LatestSequenceNumber(packet.seqNum, (*rit).seqNum) == packet.seqNum) { - break; - } - } - - // Check for duplicate packets. - if (rit != packets_.rend() && - (*rit).seqNum == packet.seqNum && (*rit).sizeBytes > 0) { - return kDuplicatePacket; - } - - // if ((packets_.size() == 0)&& - // (first_packet_seq_num_ == -1 || - // IsNewerSequenceNumber(first_packet_seq_num_, packet.seqNum))) { - // first_packet_seq_num_ = packet.seqNum; - // } - - // //TODO: not check marker, check a complete frame with timestamp - // if (packet.markerBit && - // (last_packet_seq_num_ == -1 || - // IsNewerSequenceNumber(packet.seqNum, last_packet_seq_num_))) { - // last_packet_seq_num_ = packet.seqNum; - // } - - if (packet.codec == kVideoCodecH264) { - // frame_type_ = packet.frameType; - if (packet.isFirstPacket && - (first_packet_seq_num_ == -1 || - IsNewerSequenceNumber(first_packet_seq_num_, packet.seqNum))) { - first_packet_seq_num_ = packet.seqNum; - frame_type_ = packet.frameType; - } - - if (packet.markerBit && - (last_packet_seq_num_ == -1 || - IsNewerSequenceNumber(packet.seqNum, last_packet_seq_num_))) { - last_packet_seq_num_ = packet.seqNum; - } - } else if (packet.codec == kVideoCodecH264PS) { - if (packet.isFirstPacket && - (first_packet_seq_num_ == -1 || - IsNewerSequenceNumber(first_packet_seq_num_, packet.seqNum))) { - first_packet_seq_num_ = packet.seqNum; - frame_type_ = packet.frameType; - } - - //TODO: not check marker, check a complete frame with timestamp - if (packet.markerBit && - (last_packet_seq_num_ == -1 || - IsNewerSequenceNumber(packet.seqNum, last_packet_seq_num_))) { - last_packet_seq_num_ = packet.seqNum; - } - }else { - srs_warn("RTP: jitbuffer no support codec type"); - return kFlushIndicator; - } - - // The insert operation invalidates the iterator |rit|. - PacketIterator packet_list_it = packets_.insert(rit.base(), packet); - - //size_t returnLength = (*packet_list_it).sizeBytes; - size_t returnLength = InsertBuffer(_buffer, packet_list_it); - - // update length - _length = Length() + static_cast(returnLength); - UpdateCompleteSession(); - - if (decode_error_mode_ == kWithErrors) { - decodable_ = true; - } else if (decode_error_mode_ == kSelectiveErrors) { - UpdateDecodableSession(frame_data); - } - - if (complete()) { - state_ = kStateComplete; - return kCompleteSession; - } else if (decodable()) { - state_ = kStateDecodable; - return kDecodableSession; - } else if (!complete()) { - state_ = kStateIncomplete; - return kIncomplete; - } - - return kIncomplete; -} - -void SrsRtpFrameBuffer::VerifyAndAllocate(const uint32_t minimumSize) -{ - if (minimumSize > _size) { - // create buffer of sufficient size - uint8_t* newBuffer = new uint8_t[minimumSize]; - - if (_buffer) { - // copy old data - memcpy(newBuffer, _buffer, _size); - delete [] _buffer; - } - - srs_info("RTP: jitbuffer VerifyAndAllocate oldbuffer=%d newbuffer=%d, minimumSize=%d, size=%d", - _buffer, newBuffer, minimumSize, _size); - - _buffer = newBuffer; - _size = minimumSize; - } -} - -void SrsRtpFrameBuffer::UpdateDataPointers(const uint8_t* old_base_ptr, - const uint8_t* new_base_ptr) -{ - for (PacketIterator it = packets_.begin(); it != packets_.end(); ++it) - if ((*it).dataPtr != NULL) { - //assert(old_base_ptr != NULL && new_base_ptr != NULL); - (*it).dataPtr = new_base_ptr + ((*it).dataPtr - old_base_ptr); - } -} - - -size_t SrsRtpFrameBuffer::InsertBuffer(uint8_t* frame_buffer, - PacketIterator packet_it) -{ - VCMPacket& packet = *packet_it; - PacketIterator it; - - // Calculate the offset into the frame buffer for this packet. - size_t offset = 0; - - for (it = packets_.begin(); it != packet_it; ++it) { - offset += (*it).sizeBytes; - } - - // Set the data pointer to pointing to the start of this packet in the - // frame buffer. - const uint8_t* packet_buffer = packet.dataPtr; - packet.dataPtr = frame_buffer + offset; - - // We handle H.264 STAP-A packets in a special way as we need to remove the - // two length bytes between each NAL unit, and potentially add start codes. - const size_t kH264NALHeaderLengthInBytes = 1; - const size_t kLengthFieldLength = 2; - - if (packet.codec == kVideoCodecH264 && - packet.h264packetizationType == kH264StapA - /*packet.codecSpecificHeader.codecHeader.H264.stap_a*/) { - - size_t required_length = 0; - size_t nalu_count = 0; - const uint8_t* nalu_ptr = packet_buffer + kH264NALHeaderLengthInBytes; - - while (nalu_ptr < packet_buffer + packet.sizeBytes) { - size_t length = BufferToUWord16(nalu_ptr); - required_length += length; - nalu_ptr += kLengthFieldLength + length; - nalu_count++; - - srs_info("RTP: jitbuffer H264 stap_a length:%d, nalu_count=%d", length, nalu_count); - } - - size_t total_len = required_length + nalu_count * (kLengthFieldLength) + kH264NALHeaderLengthInBytes; - - if (total_len > packet.sizeBytes) { - srs_error("RTP: jitbuffer H264 required len %d is biger than packet len %d", total_len, packet.sizeBytes); - return -1; - } - - required_length += nalu_count * (packet.insertStartCode ? kH264StartCodeLengthBytes : 0); - - ShiftSubsequentPackets(packet_it, required_length); - nalu_ptr = packet_buffer + kH264NALHeaderLengthInBytes; - uint8_t* frame_buffer_ptr = frame_buffer + offset; - required_length = 0; - - while (nalu_ptr < packet_buffer + packet.sizeBytes) { - size_t length = BufferToUWord16(nalu_ptr); - nalu_ptr += kLengthFieldLength; - size_t naluLen = Insert(nalu_ptr, - length, - packet.insertStartCode, - const_cast(frame_buffer_ptr)); - frame_buffer_ptr += naluLen; - nalu_ptr += length; - required_length += naluLen; - } - - packet.sizeBytes = required_length; - return packet.sizeBytes; - } - - ShiftSubsequentPackets( - packet_it, - packet.sizeBytes + - (packet.insertStartCode ? kH264StartCodeLengthBytes : 0)); - - packet.sizeBytes = Insert(packet_buffer, - packet.sizeBytes, - packet.insertStartCode, - const_cast(packet.dataPtr)); - return packet.sizeBytes; -} - - - -size_t SrsRtpFrameBuffer::Insert(const uint8_t* buffer, - size_t length, - bool insert_start_code, - uint8_t* frame_buffer) -{ - if (insert_start_code) { - const unsigned char startCode[] = {0, 0, 0, 1}; - memcpy(frame_buffer, startCode, kH264StartCodeLengthBytes); - } - - memcpy(frame_buffer + (insert_start_code ? kH264StartCodeLengthBytes : 0), - buffer, - length); - length += (insert_start_code ? kH264StartCodeLengthBytes : 0); - - return length; -} - - -void SrsRtpFrameBuffer::ShiftSubsequentPackets(PacketIterator it, - int steps_to_shift) -{ - ++it; - - if (it == packets_.end()) { - return; - } - - uint8_t* first_packet_ptr = const_cast((*it).dataPtr); - int shift_length = 0; - - // Calculate the total move length and move the data pointers in advance. - for (; it != packets_.end(); ++it) { - shift_length += (*it).sizeBytes; - - if ((*it).dataPtr != NULL) { - (*it).dataPtr += steps_to_shift; - } - } - - memmove(first_packet_ptr + steps_to_shift, first_packet_ptr, shift_length); -} - -void SrsRtpFrameBuffer::UpdateCompleteSession() -{ - if (HaveFirstPacket() && HaveLastPacket()) { - // Do we have all the packets in this session? - bool complete_session = true; - PacketIterator it = packets_.begin(); - PacketIterator prev_it = it; - ++it; - - for (; it != packets_.end(); ++it) { - if (!InSequence(it, prev_it)) { - complete_session = false; - break; - } - - prev_it = it; - } - - complete_ = complete_session; - } -} - -bool SrsRtpFrameBuffer::HaveFirstPacket() const -{ - return !packets_.empty() && (first_packet_seq_num_ != -1); -} - -bool SrsRtpFrameBuffer::HaveLastPacket() const -{ - return !packets_.empty() && (last_packet_seq_num_ != -1); -} - -bool SrsRtpFrameBuffer::InSequence(const PacketIterator& packet_it, - const PacketIterator& prev_packet_it) -{ - // If the two iterators are pointing to the same packet they are considered - // to be in sequence. - return (packet_it == prev_packet_it || - (static_cast((*prev_packet_it).seqNum + 1) == - (*packet_it).seqNum)); -} - -void SrsRtpFrameBuffer::UpdateDecodableSession(const FrameData& frame_data) -{ - // Irrelevant if session is already complete or decodable - if (complete_ || decodable_) { - return; - } - - // TODO(agalusza): Account for bursty loss. - // TODO(agalusza): Refine these values to better approximate optimal ones. - // Do not decode frames if the RTT is lower than this. - const int64_t kRttThreshold = 100; - // Do not decode frames if the number of packets is between these two - // thresholds. - const float kLowPacketPercentageThreshold = 0.2f; - const float kHighPacketPercentageThreshold = 0.8f; - - if (frame_data.rtt_ms < kRttThreshold - || !HaveFirstPacket() - || (NumPackets() <= kHighPacketPercentageThreshold - * frame_data.rolling_average_packets_per_frame - && NumPackets() > kLowPacketPercentageThreshold - * frame_data.rolling_average_packets_per_frame)) { - return; - } - - decodable_ = true; -} - -bool SrsRtpFrameBuffer::complete() const -{ - return complete_; -} - -bool SrsRtpFrameBuffer::decodable() const -{ - return decodable_; -} - -int SrsRtpFrameBuffer::NumPackets() const -{ - return packets_.size(); -} - -uint32_t SrsRtpFrameBuffer::GetTimeStamp() const -{ - return timeStamp_; -} - -FrameType SrsRtpFrameBuffer::GetFrameType() const -{ - return frame_type_; -} - -SrsRtpFrameBufferStateEnum SrsRtpFrameBuffer::GetState() const -{ - return state_; -} - -int32_t SrsRtpFrameBuffer::GetHighSeqNum() const -{ - if (packets_.empty()) { - return empty_seq_num_high_; - } - - if (empty_seq_num_high_ == -1) { - return packets_.back().seqNum; - } - - return LatestSequenceNumber(packets_.back().seqNum, empty_seq_num_high_); - -} - -int32_t SrsRtpFrameBuffer::GetLowSeqNum() const -{ - if (packets_.empty()) { - return empty_seq_num_low_; - } - - return packets_.front().seqNum; -} - -const uint8_t* SrsRtpFrameBuffer::Buffer() const -{ - return _buffer; -} - - -void SrsRtpFrameBuffer::InformOfEmptyPacket(uint16_t seq_num) -{ - // Empty packets may be FEC or filler packets. They are sequential and - // follow the data packets, therefore, we should only keep track of the high - // and low sequence numbers and may assume that the packets in between are - // empty packets belonging to the same frame (timestamp). - if (empty_seq_num_high_ == -1) { - empty_seq_num_high_ = seq_num; - } else { - empty_seq_num_high_ = LatestSequenceNumber(seq_num, empty_seq_num_high_); - } - - if (empty_seq_num_low_ == -1 || IsNewerSequenceNumber(empty_seq_num_low_, - seq_num)) { - empty_seq_num_low_ = seq_num; - } -} - - -size_t SrsRtpFrameBuffer::DeletePacketData(PacketIterator start, PacketIterator end) -{ - size_t bytes_to_delete = 0; // The number of bytes to delete. - PacketIterator packet_after_end = end; - //++packet_after_end; - - // Get the number of bytes to delete. - // Clear the size of these packets. - for (PacketIterator it = start; it != packet_after_end; ++it) { - bytes_to_delete += (*it).sizeBytes; - (*it).sizeBytes = 0; - (*it).dataPtr = NULL; - } - - if (bytes_to_delete > 0) { - ShiftSubsequentPackets(end, -static_cast(bytes_to_delete)); - } - - return bytes_to_delete; -} - -size_t SrsRtpFrameBuffer::MakeDecodable() -{ - size_t return_length = 0; - - if (packets_.empty()) { - return 0; - } - - PacketIterator begin = packets_.begin(); - PacketIterator end = packets_.end(); - return_length += DeletePacketData(begin, end); - - return return_length; -} - -void SrsRtpFrameBuffer::PrepareForDecode(bool continuous) -{ - - size_t bytes_removed = MakeDecodable(); - _length -= bytes_removed; - - // Transfer frame information to EncodedFrame and create any codec - // specific information. - //_frameType = ConvertFrameType(_sessionInfo.FrameType()); - //_completeFrame = _sessionInfo.complete(); - //_missingFrame = !continuous; -} - - - - bool SrsRtpFrameBuffer::DeletePacket(int &count) - { - return true; - } - - -///////////////////////////////////////////////////////////////////////////// - -SrsRtpDecodingState::SrsRtpDecodingState() - : sequence_num_(0), - time_stamp_(0), - //picture_id_(kNoPictureId), - //temporal_id_(kNoTemporalIdx), - //tl0_pic_id_(kNoTl0PicIdx), - full_sync_(true), - in_initial_state_(true), - m_firstPacket(false) {} - -SrsRtpDecodingState::~SrsRtpDecodingState() {} - -void SrsRtpDecodingState::Reset() -{ - // TODO(mikhal): Verify - not always would want to reset the sync - sequence_num_ = 0; - time_stamp_ = 0; - //picture_id_ = kNoPictureId; - //temporal_id_ = kNoTemporalIdx; - //tl0_pic_id_ = kNoTl0PicIdx; - full_sync_ = true; - in_initial_state_ = true; -} - -uint32_t SrsRtpDecodingState::time_stamp() const -{ - return time_stamp_; -} - -uint16_t SrsRtpDecodingState::sequence_num() const -{ - return sequence_num_; -} - -bool SrsRtpDecodingState::IsOldFrame(const SrsRtpFrameBuffer* frame) const -{ - //assert(frame != NULL); - if (frame == NULL) { - return false; - } - - if (in_initial_state_) { - return false; - } - - return !IsNewerTimestamp(frame->GetTimeStamp(), time_stamp_); -} - -bool SrsRtpDecodingState::IsOldPacket(const VCMPacket* packet) -{ - //assert(packet != NULL); - if (packet == NULL) { - return false; - } - - if (in_initial_state_) { - return false; - } - - if (!m_firstPacket) { - m_firstPacket = true; - time_stamp_ = packet->timestamp - 1; - return false; - } - - return !IsNewerTimestamp(packet->timestamp, time_stamp_); -} - -void SrsRtpDecodingState::SetState(const SrsRtpFrameBuffer* frame) -{ - //assert(frame != NULL && frame->GetHighSeqNum() >= 0); - UpdateSyncState(frame); - sequence_num_ = static_cast(frame->GetHighSeqNum()); - time_stamp_ = frame->GetTimeStamp(); - in_initial_state_ = false; -} - -void SrsRtpDecodingState::CopyFrom(const SrsRtpDecodingState& state) -{ - sequence_num_ = state.sequence_num_; - time_stamp_ = state.time_stamp_; - full_sync_ = state.full_sync_; - in_initial_state_ = state.in_initial_state_; -} - -bool SrsRtpDecodingState::UpdateEmptyFrame(const SrsRtpFrameBuffer* frame) -{ - bool empty_packet = frame->GetHighSeqNum() == frame->GetLowSeqNum(); - - if (in_initial_state_ && empty_packet) { - // Drop empty packets as long as we are in the initial state. - return true; - } - - if ((empty_packet && ContinuousSeqNum(frame->GetHighSeqNum())) || - ContinuousFrame(frame)) { - // Continuous empty packets or continuous frames can be dropped if we - // advance the sequence number. - sequence_num_ = frame->GetHighSeqNum(); - time_stamp_ = frame->GetTimeStamp(); - return true; - } - - return false; -} - -void SrsRtpDecodingState::UpdateOldPacket(const VCMPacket* packet) -{ - //assert(packet != NULL); - if (packet == NULL) { - return; - } - - if (packet->timestamp == time_stamp_) { - // Late packet belonging to the last decoded frame - make sure we update the - // last decoded sequence number. - sequence_num_ = LatestSequenceNumber(packet->seqNum, sequence_num_); - } -} - -void SrsRtpDecodingState::SetSeqNum(uint16_t new_seq_num) -{ - sequence_num_ = new_seq_num; -} - -bool SrsRtpDecodingState::in_initial_state() const -{ - return in_initial_state_; -} - -bool SrsRtpDecodingState::full_sync() const -{ - return full_sync_; -} - -void SrsRtpDecodingState::UpdateSyncState(const SrsRtpFrameBuffer* frame) -{ - if (in_initial_state_) { - return; - } -} - -bool SrsRtpDecodingState::ContinuousFrame(const SrsRtpFrameBuffer* frame) const -{ - // Check continuity based on the following hierarchy: - // - Temporal layers (stop here if out of sync). - // - Picture Id when available. - // - Sequence numbers. - // Return true when in initial state. - // Note that when a method is not applicable it will return false. - //assert(frame != NULL); - if (frame == NULL) { - return false; - } - - // A key frame is always considered continuous as it doesn't refer to any - // frames and therefore won't introduce any errors even if prior frames are - // missing. - if (frame->GetFrameType() == kVideoFrameKey) { - return true; - } - - // When in the initial state we always require a key frame to start decoding. - if (in_initial_state_) { - return false; - } - - return ContinuousSeqNum(static_cast(frame->GetLowSeqNum())); -} - -bool SrsRtpDecodingState::ContinuousSeqNum(uint16_t seq_num) const -{ - return seq_num == static_cast(sequence_num_ + 1); -} - -SrsRtpTimeJitter::SrsRtpTimeJitter() -{ - delta = 0; - previous_timestamp = 0; - pts = 0; -} - -SrsRtpTimeJitter::~SrsRtpTimeJitter() -{ -} - -int64_t SrsRtpTimeJitter::timestamp() -{ - return pts; -} - -srs_error_t SrsRtpTimeJitter::correct(int64_t& ts) -{ - srs_error_t err = srs_success; - - if (previous_timestamp == 0) { - previous_timestamp = ts; - } - - delta = srs_max(0, (int)(ts - previous_timestamp)); - if (delta > 90000) { - delta = 0; - } - - previous_timestamp = ts; - - ts = pts + delta; - pts = ts; - - return err; -} - - -void SrsRtpTimeJitter::reset() -{ - delta = 0; - previous_timestamp = 0; - pts = 0; -} - -SrsRtpJitterBuffer::SrsRtpJitterBuffer(std::string key): - key_(key), - running_(false), - max_number_of_frames_(kStartNumberOfFrames), - free_frames_(), - decodable_frames_(), - incomplete_frames_(), - last_decoded_state_(), - first_packet_since_reset_(true), - incoming_frame_rate_(0), - incoming_frame_count_(0), - time_last_incoming_frame_count_(0), - incoming_bit_count_(0), - incoming_bit_rate_(0), - num_consecutive_old_packets_(0), - num_packets_(0), - num_packets_free_(0), - num_duplicated_packets_(0), - num_discarded_packets_(0), - time_first_packet_ms_(0), - //jitter_estimate_(clock), - //inter_frame_delay_(clock_->TimeInMilliseconds()), - rtt_ms_(kDefaultRtt), - nack_mode_(kNoNack), - low_rtt_nack_threshold_ms_(-1), - high_rtt_nack_threshold_ms_(-1), - missing_sequence_numbers_(SequenceNumberLessThan()), - nack_seq_nums_(), - max_nack_list_size_(0), - max_packet_age_to_nack_(0), - max_incomplete_time_ms_(0), - decode_error_mode_(kNoErrors), - average_packets_per_frame_(0.0f), - frame_counter_(0), - last_received_timestamp_(0), - last_received_sequence_number_(0), - first_packet_(0) -{ - for (int i = 0; i < kStartNumberOfFrames; i++) { - free_frames_.push_back(new SrsRtpFrameBuffer()); - } - - wait_cond_t = srs_cond_new(); -} - -SrsRtpJitterBuffer::~SrsRtpJitterBuffer() -{ - for (UnorderedFrameList::iterator it = free_frames_.begin(); - it != free_frames_.end(); ++it) { - delete *it; - } - - for (FrameList::iterator it = incomplete_frames_.begin(); - it != incomplete_frames_.end(); ++it) { - delete it->second; - } - - for (FrameList::iterator it = decodable_frames_.begin(); - it != decodable_frames_.end(); ++it) { - delete it->second; - } - - srs_cond_destroy(wait_cond_t); -} - -void SrsRtpJitterBuffer::SetDecodeErrorMode(SrsRtpDecodeErrorMode error_mode) -{ - decode_error_mode_ = error_mode; -} - -void SrsRtpJitterBuffer::Flush() -{ - //CriticalSectionScoped cs(crit_sect_); - decodable_frames_.Reset(&free_frames_); - incomplete_frames_.Reset(&free_frames_); - last_decoded_state_.Reset(); // TODO(mikhal): sync reset. - //frame_event_->Reset(); - num_consecutive_old_packets_ = 0; - // Also reset the jitter and delay estimates - //jitter_estimate_.Reset(); - //inter_frame_delay_.Reset(clock_->TimeInMilliseconds()); - //waiting_for_completion_.frame_size = 0; - //waiting_for_completion_.timestamp = 0; - //waiting_for_completion_.latest_packet_time = -1; - first_packet_since_reset_ = true; - missing_sequence_numbers_.clear(); -} - -void SrsRtpJitterBuffer::ResetJittter() -{ - Flush(); -} - - -SrsRtpFrameBufferEnum SrsRtpJitterBuffer::InsertPacket(uint16_t seq, uint32_t ts, bool maker, char *buf, int size, - bool* retransmitted) -{ - bool isFirstPacketInFrame = IsFirstPacketInFrame(ts, seq); - - const VCMPacket packet((const uint8_t*)buf, size, - seq, ts, maker, - kH264SingleNalu, kRtpVideoPS, true, isFirstPacketInFrame, kVideoFrameDelta); - - ++num_packets_; - - if (num_packets_ == 1) { - time_first_packet_ms_ = srs_update_system_time(); - } - - //Does this packet belong to an old frame? - // if (last_decoded_state_.IsOldPacket(&packet)) { - - // //return kOldPacket; - // } - - //num_consecutive_old_packets_ = 0; - - SrsRtpFrameBuffer* frame; - FrameList* frame_list; - - const SrsRtpFrameBufferEnum error = GetFrameByRtpPacket(packet, &frame, &frame_list); - - if (error != kNoError) { - return error; - } - - - //srs_utime_t now_ms = srs_update_system_time(); - - FrameData frame_data; - frame_data.rtt_ms = 0; //rtt_ms_; - frame_data.rolling_average_packets_per_frame = 25;//average_packets_per_frame_; - - SrsRtpFrameBufferEnum buffer_state = frame->InsertPacket(packet, frame_data); - - if (buffer_state > 0) { - incoming_bit_count_ += packet.sizeBytes << 3; - - if (first_packet_since_reset_) { - latest_received_sequence_number_ = packet.seqNum; - first_packet_since_reset_ = false; - } else { - // if (IsPacketRetransmitted(packet)) { - // frame->IncrementNackCount(); - // } - - UpdateNackList(packet.seqNum); - - latest_received_sequence_number_ = LatestSequenceNumber( - latest_received_sequence_number_, packet.seqNum); - } - } - - // Is the frame already in the decodable list? - bool continuous = IsContinuous(*frame); - - switch (buffer_state) { - case kGeneralError: - case kTimeStampError: - case kSizeError: { - free_frames_.push_back(frame); - break; - } - - case kCompleteSession: { - //CountFrame(*frame); - // if (previous_state != kStateDecodable && - // previous_state != kStateComplete) { - // /*CountFrame(*frame); - // if (continuous) { - // // Signal that we have a complete session. - // frame_event_->Set(); - // } - // } - } - - // Note: There is no break here - continuing to kDecodableSession. - case kDecodableSession: { - // *retransmitted = (frame->GetNackCount() > 0); - - if (continuous) { - decodable_frames_.InsertFrame(frame); - FindAndInsertContinuousFrames(*frame); - } else { - incomplete_frames_.InsertFrame(frame); - - // If NACKs are enabled, keyframes are triggered by |GetNackList|. - // if (nack_mode_ == kNoNack && NonContinuousOrIncompleteDuration() > - // 90 * kMaxDiscontinuousFramesTime) { - // return kFlushIndicator; - // } - } - - break; - } - - case kIncomplete: { - if (frame->GetState() == kStateEmpty && - last_decoded_state_.UpdateEmptyFrame(frame)) { - free_frames_.push_back(frame); - return kNoError; - } else { - incomplete_frames_.InsertFrame(frame); - - // If NACKs are enabled, keyframes are triggered by |GetNackList|. - // if (nack_mode_ == kNoNack && NonContinuousOrIncompleteDuration() > - // 90 * kMaxDiscontinuousFramesTime) { - // return kFlushIndicator; - // } - } - - break; - } - - case kNoError: - case kOutOfBoundsPacket: - case kDuplicatePacket: { - // Put back the frame where it came from. - if (frame_list != NULL) { - frame_list->InsertFrame(frame); - } else { - free_frames_.push_back(frame); - } - - ++num_duplicated_packets_; - break; - } - - case kFlushIndicator:{ - free_frames_.push_back(frame); - } - return kFlushIndicator; - - default: - assert(false); - } - - return buffer_state; -} - -// Gets frame to use for this timestamp. If no match, get empty frame. -SrsRtpFrameBufferEnum SrsRtpJitterBuffer::GetFrameByRtpPacket(const VCMPacket& packet, - SrsRtpFrameBuffer** frame, - FrameList** frame_list) -{ - *frame = incomplete_frames_.PopFrame(packet.timestamp); - - if (*frame != NULL) { - *frame_list = &incomplete_frames_; - return kNoError; - } - - *frame = decodable_frames_.PopFrame(packet.timestamp); - - if (*frame != NULL) { - *frame_list = &decodable_frames_; - return kNoError; - } - - *frame_list = NULL; - // No match, return empty frame. - *frame = GetEmptyFrame(); - - if (*frame == NULL) { - // No free frame! Try to reclaim some... - bool found_key_frame = RecycleFramesUntilKeyFrame(); - *frame = GetEmptyFrame(); - assert(*frame); - - if (!found_key_frame) { - free_frames_.push_back(*frame); - return kFlushIndicator; - } - } - - (*frame)->Reset(); - return kNoError; -} - -SrsRtpFrameBuffer* SrsRtpJitterBuffer::GetEmptyFrame() -{ - if (free_frames_.empty()) { - if (!TryToIncreaseJitterBufferSize()) { - return NULL; - } - } - - SrsRtpFrameBuffer* frame = free_frames_.front(); - free_frames_.pop_front(); - return frame; -} - -bool SrsRtpJitterBuffer::TryToIncreaseJitterBufferSize() -{ - if (max_number_of_frames_ >= kMaxNumberOfFrames) { - return false; - } - - free_frames_.push_back(new SrsRtpFrameBuffer()); - ++max_number_of_frames_; - return true; -} - -// Recycle oldest frames up to a key frame, used if jitter buffer is completely -// full. -bool SrsRtpJitterBuffer::RecycleFramesUntilKeyFrame() -{ - // First release incomplete frames, and only release decodable frames if there - // are no incomplete ones. - FrameList::iterator key_frame_it; - bool key_frame_found = false; - int dropped_frames = 0; - dropped_frames += incomplete_frames_.RecycleFramesUntilKeyFrame( - &key_frame_it, &free_frames_); - key_frame_found = key_frame_it != incomplete_frames_.end(); - - if (dropped_frames == 0) { - dropped_frames += decodable_frames_.RecycleFramesUntilKeyFrame( - &key_frame_it, &free_frames_); - key_frame_found = key_frame_it != decodable_frames_.end(); - } - - if (key_frame_found) { - //LOG(LS_INFO) << "Found key frame while dropping frames."; - // Reset last decoded state to make sure the next frame decoded is a key - // frame, and start NACKing from here. - last_decoded_state_.Reset(); - DropPacketsFromNackList(EstimatedLowSequenceNumber(*key_frame_it->second)); - } else if (decodable_frames_.empty()) { - // All frames dropped. Reset the decoding state and clear missing sequence - // numbers as we're starting fresh. - last_decoded_state_.Reset(); - missing_sequence_numbers_.clear(); - } - - return key_frame_found; -} - -bool SrsRtpJitterBuffer::IsContinuousInState(const SrsRtpFrameBuffer& frame, - const SrsRtpDecodingState& decoding_state) const -{ - if (decode_error_mode_ == kWithErrors) { - return true; - } - - // Is this frame (complete or decodable) and continuous? - // kStateDecodable will never be set when decode_error_mode_ is false - // as SessionInfo determines this state based on the error mode (and frame - // completeness). - return (frame.GetState() == kStateComplete || - frame.GetState() == kStateDecodable) && - decoding_state.ContinuousFrame(&frame); -} - -bool SrsRtpJitterBuffer::IsContinuous(const SrsRtpFrameBuffer& frame) const -{ - if (IsContinuousInState(frame, last_decoded_state_)) { - return true; - } - - SrsRtpDecodingState decoding_state; - decoding_state.CopyFrom(last_decoded_state_); - - for (FrameList::const_iterator it = decodable_frames_.begin(); - it != decodable_frames_.end(); ++it) { - SrsRtpFrameBuffer* decodable_frame = it->second; - - if (IsNewerTimestamp(decodable_frame->GetTimeStamp(), frame.GetTimeStamp())) { - break; - } - - decoding_state.SetState(decodable_frame); - - if (IsContinuousInState(frame, decoding_state)) { - return true; - } - } - - return false; -} - -void SrsRtpJitterBuffer::FindAndInsertContinuousFrames(const SrsRtpFrameBuffer& new_frame) -{ - SrsRtpDecodingState decoding_state; - decoding_state.CopyFrom(last_decoded_state_); - decoding_state.SetState(&new_frame); - - // When temporal layers are available, we search for a complete or decodable - // frame until we hit one of the following: - // 1. Continuous base or sync layer. - // 2. The end of the list was reached. - for (FrameList::iterator it = incomplete_frames_.begin(); - it != incomplete_frames_.end();) { - SrsRtpFrameBuffer* frame = it->second; - - if (IsNewerTimestamp(new_frame.GetTimeStamp(), frame->GetTimeStamp())) { - ++it; - continue; - } - - if (IsContinuousInState(*frame, decoding_state)) { - decodable_frames_.InsertFrame(frame); - incomplete_frames_.erase(it++); - decoding_state.SetState(frame); - } else { - ++it; - } - } -} - -// Must be called under the critical section |crit_sect_|. -void SrsRtpJitterBuffer::CleanUpOldOrEmptyFrames() -{ - decodable_frames_.CleanUpOldOrEmptyFrames(&last_decoded_state_, - &free_frames_); - incomplete_frames_.CleanUpOldOrEmptyFrames(&last_decoded_state_, - &free_frames_); - - if (!last_decoded_state_.in_initial_state()) { - DropPacketsFromNackList(last_decoded_state_.sequence_num()); - } -} - -// Returns immediately or a |max_wait_time_ms| ms event hang waiting for a -// complete frame, |max_wait_time_ms| decided by caller. -bool SrsRtpJitterBuffer::NextCompleteTimestamp(uint32_t max_wait_time_ms, uint32_t* timestamp) -{ - // crit_sect_->Enter(); - - // if (!running_) { - // crit_sect_->Leave(); - // return false; - // } - - CleanUpOldOrEmptyFrames(); - - if (decodable_frames_.empty() || - decodable_frames_.Front()->GetState() != kStateComplete) { - const int64_t end_wait_time_ms = srs_update_system_time() + - max_wait_time_ms * SRS_UTIME_MILLISECONDS; - int64_t wait_time_ms = max_wait_time_ms * SRS_UTIME_MILLISECONDS; - - while (wait_time_ms > 0) { - int ret = srs_cond_timedwait(wait_cond_t, wait_time_ms); - if (ret == 0) { - // Finding oldest frame ready for decoder. - CleanUpOldOrEmptyFrames(); - - if (decodable_frames_.empty() || - decodable_frames_.Front()->GetState() != kStateComplete) { - wait_time_ms = end_wait_time_ms - srs_update_system_time(); - } else { - break; - } - } else { - break; - } - } - - // Inside |crit_sect_|. - } else { - // We already have a frame, reset the event. - //frame_event_->Reset(); - } - - if (decodable_frames_.empty() || - decodable_frames_.Front()->GetState() != kStateComplete) { - //crit_sect_->Leave(); - return false; - } - - *timestamp = decodable_frames_.Front()->GetTimeStamp(); - //crit_sect_->Leave(); - return true; -} - -bool SrsRtpJitterBuffer::NextMaybeIncompleteTimestamp(uint32_t* timestamp) -{ - if (decode_error_mode_ == kNoErrors) { - srs_warn("RTP jitbuffer NextMaybeIncompleteTimestamp decode_error_mode_ %d", decode_error_mode_); - // No point to continue, as we are not decoding with errors. - return false; - } - - CleanUpOldOrEmptyFrames(); - - SrsRtpFrameBuffer* oldest_frame; - - if (decodable_frames_.empty()) { - //in order to solve the problem of bad network, we can wait for more incomplete frames - //ex fps=15 - if (incomplete_frames_.size() < 15) { - return false; - } - - oldest_frame = incomplete_frames_.Front(); - SrsRtpFrameBufferStateEnum oldest_frame_state = oldest_frame->GetState(); - - SrsRtpFrameBuffer* next_frame; - next_frame = incomplete_frames_.FrontNext(); - - if (oldest_frame_state != kStateComplete && next_frame && - IsNewerSequenceNumber(next_frame->GetLowSeqNum(), oldest_frame->GetHighSeqNum()) && - next_frame->NumPackets() > 0 ) { - oldest_frame_state = kStateComplete; - } - - // Frame will only be removed from buffer if it is complete (or decodable). - if (oldest_frame_state < kStateComplete) { - int oldest_frame_hight_seq = oldest_frame->GetHighSeqNum(); - int next_frame_low_seq = next_frame->GetLowSeqNum(); - - srs_warn("RTP: jitbuffer NextMaybeIncompleteTimestamp key(%s) incomplete oldest_frame (%u,%d)->(%u,%d)", - key_.c_str(), oldest_frame->GetTimeStamp(), oldest_frame_hight_seq, - next_frame->GetTimeStamp(), next_frame_low_seq); - return false; - } - } else { - oldest_frame = decodable_frames_.Front(); - - // If we have exactly one frame in the buffer, release it only if it is - // complete. We know decodable_frames_ is not empty due to the previous - // check. - if (decodable_frames_.size() == 1 && incomplete_frames_.empty() - && oldest_frame->GetState() != kStateComplete) { - return false; - } - } - - *timestamp = oldest_frame->GetTimeStamp(); - return true; -} - -SrsRtpFrameBuffer* SrsRtpJitterBuffer::ExtractAndSetDecode(uint32_t timestamp) -{ - // Extract the frame with the desired timestamp. - SrsRtpFrameBuffer* frame = decodable_frames_.PopFrame(timestamp); - bool continuous = true; - - if (!frame) { - frame = incomplete_frames_.PopFrame(timestamp); - - if (frame) { - continuous = last_decoded_state_.ContinuousFrame(frame); - } else { - return NULL; - } - } - - // Fix build warnings: variable ‘continuous’ set but not used - (void)continuous; - - // The state must be changed to decoding before cleaning up zero sized - // frames to avoid empty frames being cleaned up and then given to the - // decoder. Propagates the missing_frame bit. - //frame->PrepareForDecode(continuous); - - // We have a frame - update the last decoded state and nack list. - last_decoded_state_.SetState(frame); - //DropPacketsFromNackList(last_decoded_state_.sequence_num()); - - // if ((*frame).IsSessionComplete()) { - // //UpdateAveragePacketsPerFrame(frame->NumPackets()); - // } - - return frame; -} - -// Release frame when done with decoding. Should never be used to release -// frames from within the jitter buffer. -void SrsRtpJitterBuffer::ReleaseFrame(SrsRtpFrameBuffer* frame) -{ - //CriticalSectionScoped cs(crit_sect_); - //VCMFrameBuffer* frame_buffer = static_cast(frame); - - if (frame) { - free_frames_.push_back(frame); - } -} - -bool SrsRtpJitterBuffer::FoundFrame(uint32_t& time_stamp) -{ - - bool found_frame = NextCompleteTimestamp(0, &time_stamp); - - if (!found_frame) { - found_frame = NextMaybeIncompleteTimestamp(&time_stamp); - } - - return found_frame; -} - -bool SrsRtpJitterBuffer::GetFrame(char **buffer, int &buf_len, int &size, bool &keyframe, const uint32_t time_stamp) -{ - SrsRtpFrameBuffer* frame = ExtractAndSetDecode(time_stamp); - - if (frame == NULL) { - return false; - } - - size = frame->Length(); - if (size <= 0){ - return false; - } - - if (buffer == NULL){ - return false; - } - - //verify and allocate a frame buffer, used to completed frame data - if (buf_len < size || *buffer == NULL) { - srs_freepa(*buffer); - - int resize = size + kBufferIncStepSizeBytes; - *buffer = new char[resize]; - - srs_trace("RTP: jitbuffer key=%s reallocate a frame buffer size(%d>%d) resize(%d)", - key_.c_str(), size, buf_len, resize); - - buf_len = resize; - } - - const uint8_t *frame_buffer = frame->Buffer(); - memcpy(*buffer, frame_buffer, size); - if (frame->GetFrameType() == kVideoFrameKey){ - keyframe = true; - } - - frame->PrepareForDecode(false); - ReleaseFrame(frame); - return true; -} - - -SrsRtpFrameBuffer* SrsRtpJitterBuffer::NextFrame() const -{ - if (!decodable_frames_.empty()) { - return decodable_frames_.Front(); - } - - if (!incomplete_frames_.empty()) { - return incomplete_frames_.Front(); - } - - return NULL; -} - -bool SrsRtpJitterBuffer::UpdateNackList(uint16_t sequence_number) -{ - if (nack_mode_ == kNoNack) { - return true; - } - - // Make sure we don't add packets which are already too old to be decoded. - if (!last_decoded_state_.in_initial_state()) { - latest_received_sequence_number_ = LatestSequenceNumber( - latest_received_sequence_number_, - last_decoded_state_.sequence_num()); - } - - if (IsNewerSequenceNumber(sequence_number, - latest_received_sequence_number_)) { - // Push any missing sequence numbers to the NACK list. - for (uint16_t i = latest_received_sequence_number_ + 1; - IsNewerSequenceNumber(sequence_number, i); ++i) { - missing_sequence_numbers_.insert(missing_sequence_numbers_.end(), i); - } - - if (TooLargeNackList() && !HandleTooLargeNackList()) { - srs_warn("RTP: jitbuffer key(%s) requesting key frame due to too large NACK list.", key_.c_str()); - return false; - } - - if (MissingTooOldPacket(sequence_number) && - !HandleTooOldPackets(sequence_number)) { - srs_warn("RTP: jitbuffer key(%s) requesting key frame due to missing too old packets", key_.c_str()); - return false; - } - - } else { - missing_sequence_numbers_.erase(sequence_number); - } - - return true; -} - -bool SrsRtpJitterBuffer::TooLargeNackList() const -{ - return missing_sequence_numbers_.size() > max_nack_list_size_; -} - -bool SrsRtpJitterBuffer::HandleTooLargeNackList() -{ - // Recycle frames until the NACK list is small enough. It is likely cheaper to - // request a key frame than to retransmit this many missing packets. - srs_warn("RTP: jitbuffer NACK list has grown too large: %d > %d", - missing_sequence_numbers_.size(), max_nack_list_size_); - bool key_frame_found = false; - - while (TooLargeNackList()) { - key_frame_found = RecycleFramesUntilKeyFrame(); - } - - return key_frame_found; -} - -bool SrsRtpJitterBuffer::MissingTooOldPacket(uint16_t latest_sequence_number) const -{ - if (missing_sequence_numbers_.empty()) { - return false; - } - - const uint16_t age_of_oldest_missing_packet = latest_sequence_number - - *missing_sequence_numbers_.begin(); - // Recycle frames if the NACK list contains too old sequence numbers as - // the packets may have already been dropped by the sender. - return age_of_oldest_missing_packet > max_packet_age_to_nack_; -} - -bool SrsRtpJitterBuffer::HandleTooOldPackets(uint16_t latest_sequence_number) -{ - bool key_frame_found = false; - const uint16_t age_of_oldest_missing_packet = latest_sequence_number - - *missing_sequence_numbers_.begin(); - srs_warn("RTP: jitbuffer NACK list contains too old sequence numbers: %d > %d", - age_of_oldest_missing_packet, - max_packet_age_to_nack_); - - while (MissingTooOldPacket(latest_sequence_number)) { - key_frame_found = RecycleFramesUntilKeyFrame(); - } - - return key_frame_found; -} - -void SrsRtpJitterBuffer::DropPacketsFromNackList(uint16_t last_decoded_sequence_number) -{ - // Erase all sequence numbers from the NACK list which we won't need any - // longer. - missing_sequence_numbers_.erase(missing_sequence_numbers_.begin(), - missing_sequence_numbers_.upper_bound( - last_decoded_sequence_number)); -} - -void SrsRtpJitterBuffer::SetNackMode(SrsRtpNackMode mode, - int64_t low_rtt_nack_threshold_ms, - int64_t high_rtt_nack_threshold_ms) -{ - nack_mode_ = mode; - - if (mode == kNoNack) { - missing_sequence_numbers_.clear(); - } - - assert(low_rtt_nack_threshold_ms >= -1 && high_rtt_nack_threshold_ms >= -1); - assert(high_rtt_nack_threshold_ms == -1 || - low_rtt_nack_threshold_ms <= high_rtt_nack_threshold_ms); - assert(low_rtt_nack_threshold_ms > -1 || high_rtt_nack_threshold_ms == -1); - low_rtt_nack_threshold_ms_ = low_rtt_nack_threshold_ms; - high_rtt_nack_threshold_ms_ = high_rtt_nack_threshold_ms; - - // Don't set a high start rtt if high_rtt_nack_threshold_ms_ is used, to not - // disable NACK in hybrid mode. - if (rtt_ms_ == kDefaultRtt && high_rtt_nack_threshold_ms_ != -1) { - rtt_ms_ = 0; - } - - // if (!WaitForRetransmissions()) { - // jitter_estimate_.ResetNackCount(); - // } -} - -void SrsRtpJitterBuffer::SetNackSettings(size_t max_nack_list_size, - int max_packet_age_to_nack, - int max_incomplete_time_ms) -{ - assert(max_packet_age_to_nack >= 0); - assert(max_incomplete_time_ms_ >= 0); - max_nack_list_size_ = max_nack_list_size; - max_packet_age_to_nack_ = max_packet_age_to_nack; - max_incomplete_time_ms_ = max_incomplete_time_ms; - nack_seq_nums_.resize(max_nack_list_size_); -} - -SrsRtpNackMode SrsRtpJitterBuffer::nack_mode() const -{ - return nack_mode_; -} - - -int SrsRtpJitterBuffer::NonContinuousOrIncompleteDuration() -{ - if (incomplete_frames_.empty()) { - return 0; - } - - uint32_t start_timestamp = incomplete_frames_.Front()->GetTimeStamp(); - - if (!decodable_frames_.empty()) { - start_timestamp = decodable_frames_.Back()->GetTimeStamp(); - } - - return incomplete_frames_.Back()->GetTimeStamp() - start_timestamp; -} - -uint16_t SrsRtpJitterBuffer::EstimatedLowSequenceNumber(const SrsRtpFrameBuffer& frame) const -{ - assert(frame.GetLowSeqNum() >= 0); - - if (frame.HaveFirstPacket()) { - return frame.GetLowSeqNum(); - } - - // This estimate is not accurate if more than one packet with lower sequence - // number is lost. - return frame.GetLowSeqNum() - 1; -} - -uint16_t* SrsRtpJitterBuffer::GetNackList(uint16_t* nack_list_size, - bool* request_key_frame) -{ - //CriticalSectionScoped cs(crit_sect_); - *request_key_frame = false; - - if (nack_mode_ == kNoNack) { - *nack_list_size = 0; - return NULL; - } - - if (last_decoded_state_.in_initial_state()) { - SrsRtpFrameBuffer* next_frame = NextFrame(); - const bool first_frame_is_key = next_frame && - next_frame->GetFrameType() == kVideoFrameKey && - next_frame->HaveFirstPacket(); - - if (!first_frame_is_key) { - bool have_non_empty_frame = decodable_frames_.end() != find_if( - decodable_frames_.begin(), decodable_frames_.end(), - HasNonEmptyState); - - if (!have_non_empty_frame) { - have_non_empty_frame = incomplete_frames_.end() != find_if( - incomplete_frames_.begin(), incomplete_frames_.end(), - HasNonEmptyState); - } - - bool found_key_frame = RecycleFramesUntilKeyFrame(); - - if (!found_key_frame) { - *request_key_frame = have_non_empty_frame; - *nack_list_size = 0; - return NULL; - } - } - } - - if (TooLargeNackList()) { - *request_key_frame = !HandleTooLargeNackList(); - } - - if (max_incomplete_time_ms_ > 0) { - int non_continuous_incomplete_duration = - NonContinuousOrIncompleteDuration(); - - if (non_continuous_incomplete_duration > 90 * max_incomplete_time_ms_) { - // LOG_F(LS_WARNING) << "Too long non-decodable duration: " - // << non_continuous_incomplete_duration << " > " - // << 90 * max_incomplete_time_ms_; - FrameList::reverse_iterator rit = find_if(incomplete_frames_.rbegin(), - incomplete_frames_.rend(), IsKeyFrame); - - if (rit == incomplete_frames_.rend()) { - // Request a key frame if we don't have one already. - *request_key_frame = true; - *nack_list_size = 0; - return NULL; - } else { - // Skip to the last key frame. If it's incomplete we will start - // NACKing it. - // Note that the estimated low sequence number is correct for VP8 - // streams because only the first packet of a key frame is marked. - last_decoded_state_.Reset(); - DropPacketsFromNackList(EstimatedLowSequenceNumber(*rit->second)); - } - } - } - - unsigned int i = 0; - SequenceNumberSet::iterator it = missing_sequence_numbers_.begin(); - - for (; it != missing_sequence_numbers_.end(); ++it, ++i) { - nack_seq_nums_[i] = *it; - } - - *nack_list_size = i; - return &nack_seq_nums_[0]; -} - -bool SrsRtpJitterBuffer::WaitForRetransmissions() -{ - if (nack_mode_ == kNoNack) { - // NACK disabled -> don't wait for retransmissions. - return false; - } - - // Evaluate if the RTT is higher than |high_rtt_nack_threshold_ms_|, and in - // that case we don't wait for retransmissions. - if (high_rtt_nack_threshold_ms_ >= 0 && - rtt_ms_ >= high_rtt_nack_threshold_ms_) { - return false; - } - - return true; -} - -bool SrsRtpJitterBuffer::IsPacketInOrder(uint16_t sequence_number) -{ - if (!first_packet_) { - return true; - } - - if (IsNewerSequenceNumber(sequence_number, last_received_sequence_number_)) { - return true; - } - - return false; -} - -bool SrsRtpJitterBuffer::IsFirstPacketInFrame(uint32_t ts, uint16_t seq) -{ - bool is_first_packet_in_frame = false; - bool in_order = IsPacketInOrder(seq); - - if (first_packet_){ - is_first_packet_in_frame = - last_received_sequence_number_ + 1 == seq && - last_received_timestamp_ != ts; - }else{ - is_first_packet_in_frame = true; - } - - if (in_order) { - first_packet_ = true; - - if (last_received_timestamp_ != ts) { - last_received_timestamp_ = ts; - } - - last_received_sequence_number_ = seq; - } - - return is_first_packet_in_frame; -} diff --git a/trunk/src/app/srs_app_gb28181_jitter.hpp b/trunk/src/app/srs_app_gb28181_jitter.hpp deleted file mode 100644 index a2d93d8bf..000000000 --- a/trunk/src/app/srs_app_gb28181_jitter.hpp +++ /dev/null @@ -1,530 +0,0 @@ -// -// Copyright (c) 2013-2021 Lixin -// -// SPDX-License-Identifier: MIT -// - -#ifndef SRS_APP_GB28181_RTP_JITBUFFER_HPP -#define SRS_APP_GB28181_RTP_JITBUFFER_HPP - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -class SrsPsRtpPacket; -class SrsRtpFrameBuffer; -class SrsRtpDecodingState; -class SrsGb28181RtmpMuxer; -class VCMPacket; -class SrsRtpPacket; - -///jittbuffer - -enum FrameType { - kEmptyFrame = 0, - kAudioFrameSpeech = 1, - kAudioFrameCN = 2, - kVideoFrameKey = 3, // independent frame - kVideoFrameDelta = 4, // depends on the previus frame - kVideoFrameGolden = 5, // depends on a old known previus frame - kVideoFrameAltRef = 6 -}; - -// Used to indicate which decode with errors mode should be used. -enum SrsRtpDecodeErrorMode { - kNoErrors, // Never decode with errors. Video will freeze - // if nack is disabled. - kSelectiveErrors, // Frames that are determined decodable in - // VCMSessionInfo may be decoded with missing - // packets. As not all incomplete frames will be - // decodable, video will freeze if nack is disabled. - kWithErrors // Release frames as needed. Errors may be - // introduced as some encoded frames may not be - // complete. -}; - -// Used to estimate rolling average of packets per frame. -static const float kFastConvergeMultiplier = 0.4f; -static const float kNormalConvergeMultiplier = 0.2f; - -enum { kMaxNumberOfFrames = 300 }; -enum { kStartNumberOfFrames = 6 }; -enum { kMaxVideoDelayMs = 10000 }; -enum { kPacketsPerFrameMultiplier = 5 }; -enum { kFastConvergeThreshold = 5}; - -enum SrsRtpJitterBufferEnum { - kMaxConsecutiveOldFrames = 60, - kMaxConsecutiveOldPackets = 300, - kMaxPacketsInSession = 800, - kBufferIncStepSizeBytes = 30000, // >20 packets. - kMaxJBFrameSizeBytes = 4000000 // sanity don't go above 4Mbyte. -}; - -enum SrsRtpFrameBufferEnum { - kOutOfBoundsPacket = -7, - kNotInitialized = -6, - kOldPacket = -5, - kGeneralError = -4, - kFlushIndicator = -3, // Indicator that a flush has occurred. - kTimeStampError = -2, - kSizeError = -1, - kNoError = 0, - kIncomplete = 1, // Frame incomplete. - kCompleteSession = 3, // at least one layer in the frame complete. - kDecodableSession = 4, // Frame incomplete, but ready to be decoded - kDuplicatePacket = 5 // We're receiving a duplicate packet. -}; - -enum SrsRtpFrameBufferStateEnum { - kStateEmpty, // frame popped by the RTP receiver - kStateIncomplete, // frame that have one or more packet(s) stored - kStateComplete, // frame that have all packets - kStateDecodable // Hybrid mode - frame can be decoded -}; - -enum SrsRtpNackMode { - kNack, - kNoNack -}; - -// Used to indicate if a received packet contain a complete NALU (or equivalent) -enum VCMNaluCompleteness { - kNaluUnset = 0, // Packet has not been filled. - kNaluComplete = 1, // Packet can be decoded as is. - kNaluStart, // Packet contain beginning of NALU - kNaluIncomplete, // Packet is not beginning or end of NALU - kNaluEnd, // Packet is the end of a NALU -}; - -enum RtpVideoCodecTypes { - kRtpVideoNone, - kRtpVideoGeneric, - kRtpVideoVp8, - kRtpVideoVp9, - kRtpVideoH264, - kRtpVideoPS -}; - - -// Video codec types -enum VideoCodecType { - kVideoCodecVP8, - kVideoCodecVP9, - kVideoCodecH264, - kVideoCodecH264SVC, - kVideoCodecI420, - kVideoCodecRED, - kVideoCodecULPFEC, - kVideoCodecGeneric, - kVideoCodecH264PS, - kVideoCodecUnknown -}; - -// The packetization types that we support: single, aggregated, and fragmented. -enum H264PacketizationTypes { - kH264SingleNalu, // This packet contains a single NAL unit. - kH264StapA, // This packet contains STAP-A (single time - // aggregation) packets. If this packet has an - // associated NAL unit type, it'll be for the - // first such aggregated packet. - kH264FuA, // This packet contains a FU-A (fragmentation - // unit) packet, meaning it is a part of a frame - // that was too large to fit into a single packet. -}; - -enum { kH264StartCodeLengthBytes = 4}; - -// Used to pass data from jitter buffer to session info. -// This data is then used in determining whether a frame is decodable. -struct FrameData { - int64_t rtt_ms; - float rolling_average_packets_per_frame; -}; - -inline bool IsNewerSequenceNumber(uint16_t sequence_number, - uint16_t prev_sequence_number) -{ - return sequence_number != prev_sequence_number && - static_cast(sequence_number - prev_sequence_number) < 0x8000; -} - -inline bool IsNewerTimestamp(uint32_t timestamp, uint32_t prev_timestamp) -{ - return timestamp != prev_timestamp && - static_cast(timestamp - prev_timestamp) < 0x80000000; -} - -inline uint16_t LatestSequenceNumber(uint16_t sequence_number1, - uint16_t sequence_number2) -{ - return IsNewerSequenceNumber(sequence_number1, sequence_number2) - ? sequence_number1 - : sequence_number2; -} - -inline uint32_t LatestTimestamp(uint32_t timestamp1, uint32_t timestamp2) -{ - return IsNewerTimestamp(timestamp1, timestamp2) ? timestamp1 : timestamp2; -} - -typedef std::list UnorderedFrameList; - -class TimestampLessThan { -public: - bool operator() (const uint32_t& timestamp1, - const uint32_t& timestamp2) const - { - return IsNewerTimestamp(timestamp2, timestamp1); - } -}; - -class FrameList - : public std::map { -public: - void InsertFrame(SrsRtpFrameBuffer* frame); - SrsRtpFrameBuffer* PopFrame(uint32_t timestamp); - SrsRtpFrameBuffer* Front() const; - SrsRtpFrameBuffer* FrontNext() const; - SrsRtpFrameBuffer* Back() const; - int RecycleFramesUntilKeyFrame(FrameList::iterator* key_frame_it, - UnorderedFrameList* free_frames); - void CleanUpOldOrEmptyFrames(SrsRtpDecodingState* decoding_state, UnorderedFrameList* free_frames); - void Reset(UnorderedFrameList* free_frames); -}; - - -class VCMPacket { -public: - VCMPacket(); - VCMPacket(const uint8_t* ptr, - size_t size, - uint16_t seqNum, - uint32_t timestamp, - bool markerBit, - H264PacketizationTypes type, - RtpVideoCodecTypes rtpType, - bool singlenual, - bool isfirst, - FrameType ftype - ); - - void Reset(); - - uint8_t payloadType; - uint32_t timestamp; - // NTP time of the capture time in local timebase in milliseconds. - int64_t ntp_time_ms_; - uint16_t seqNum; - const uint8_t* dataPtr; - size_t sizeBytes; - bool markerBit; - - FrameType frameType; - VideoCodecType codec; - - bool isFirstPacket; // Is this first packet in a frame. - VCMNaluCompleteness completeNALU; // Default is kNaluIncomplete. - bool insertStartCode; // True if a start code should be inserted before this - // packet. - int width; - int height; - //RTPVideoHeader codecSpecificHeader; - - - //H264 header - H264PacketizationTypes h264packetizationType; - bool h264singleNalu; - -public: - void CopyCodecSpecifics(RtpVideoCodecTypes codecType, bool H264single_nalu, bool firstPacket); -}; - -class SrsRtpFrameBuffer { -public: - SrsRtpFrameBuffer(); - virtual ~SrsRtpFrameBuffer(); - -public: - SrsRtpFrameBufferEnum InsertPacket(const VCMPacket& packet, const FrameData& frame_data); - void UpdateCompleteSession(); - void UpdateDecodableSession(const FrameData& frame_data); - bool HaveFirstPacket() const; - bool HaveLastPacket() const; - void Reset(); - - uint32_t GetTimeStamp() const; - FrameType GetFrameType() const; - SrsRtpFrameBufferStateEnum GetState() const; - - int32_t GetHighSeqNum() const; - int32_t GetLowSeqNum() const; - size_t Length() const; - const uint8_t* Buffer() const; - - int NumPackets() const; - void InformOfEmptyPacket(uint16_t seq_num); - - bool complete() const; - bool decodable() const; - - bool DeletePacket(int &count); - void PrepareForDecode(bool continuous); - -private: - - typedef std::list PacketList; - typedef PacketList::iterator PacketIterator; - typedef PacketList::const_iterator PacketIteratorConst; - typedef PacketList::reverse_iterator ReversePacketIterator; - - bool InSequence(const PacketIterator& packet_it, - const PacketIterator& prev_packet_it); - - size_t InsertBuffer(uint8_t* frame_buffer, PacketIterator packet_it); - size_t Insert(const uint8_t* buffer, size_t length, bool insert_start_code, uint8_t* frame_buffer); - void ShiftSubsequentPackets(PacketIterator it, int steps_to_shift); - void VerifyAndAllocate(const uint32_t minimumSize); - void UpdateDataPointers(const uint8_t* old_base_ptr, const uint8_t* new_base_ptr); - size_t DeletePacketData(PacketIterator start, PacketIterator end); - size_t MakeDecodable(); - - - PacketList packets_; - int empty_seq_num_low_; - int empty_seq_num_high_; - - int first_packet_seq_num_; - int last_packet_seq_num_; - - bool complete_; - bool decodable_; - - uint32_t timeStamp_; - FrameType frame_type_; - - SrsRtpDecodeErrorMode decode_error_mode_; - SrsRtpFrameBufferStateEnum state_; - - //uint16_t nackCount_; - //int64_t latestPacketTimeMs_; - - // The payload. - uint8_t* _buffer; - size_t _size; - size_t _length; -}; - -class SrsRtpDecodingState { -public: - SrsRtpDecodingState(); - ~SrsRtpDecodingState(); - // Check for old frame - bool IsOldFrame(const SrsRtpFrameBuffer* frame) const; - // Check for old packet - bool IsOldPacket(const VCMPacket* packet); - // Check for frame continuity based on current decoded state. Use best method - // possible, i.e. temporal info, picture ID or sequence number. - bool ContinuousFrame(const SrsRtpFrameBuffer* frame) const; - void SetState(const SrsRtpFrameBuffer* frame); - void CopyFrom(const SrsRtpDecodingState& state); - bool UpdateEmptyFrame(const SrsRtpFrameBuffer* frame); - // Update the sequence number if the timestamp matches current state and the - // sequence number is higher than the current one. This accounts for packets - // arriving late. - void UpdateOldPacket(const VCMPacket* packet); - void SetSeqNum(uint16_t new_seq_num); - void Reset(); - uint32_t time_stamp() const; - uint16_t sequence_num() const; - // Return true if at initial state. - bool in_initial_state() const; - // Return true when sync is on - decode all layers. - bool full_sync() const; - -private: - void UpdateSyncState(const SrsRtpFrameBuffer* frame); - // Designated continuity functions - //bool ContinuousPictureId(int picture_id) const; - bool ContinuousSeqNum(uint16_t seq_num) const; - //bool ContinuousLayer(int temporal_id, int tl0_pic_id) const; - //bool UsingPictureId(const SrsRtpFrameBuffer* frame) const; - - // Keep state of last decoded frame. - // TODO(mikhal/stefan): create designated classes to handle these types. - uint16_t sequence_num_; - uint32_t time_stamp_; - bool full_sync_; // Sync flag when temporal layers are used. - bool in_initial_state_; - - bool m_firstPacket; -}; - -// The time jitter correct for rtp. -class SrsRtpTimeJitter -{ -private: - int64_t previous_timestamp; - int64_t pts; - int delta; -public: - SrsRtpTimeJitter(); - virtual ~SrsRtpTimeJitter(); -public: - int64_t timestamp(); - srs_error_t correct(int64_t& ts); - void reset(); -}; - -class SrsRtpJitterBuffer -{ -public: - SrsRtpJitterBuffer(std::string key); - virtual ~SrsRtpJitterBuffer(); - -public: - srs_error_t start(); - void Reset(); - SrsRtpFrameBufferEnum InsertPacket(uint16_t seq, uint32_t ts, bool maker, char *buf, int size, - bool* retransmitted); - void ReleaseFrame(SrsRtpFrameBuffer* frame); - bool FoundFrame(uint32_t& time_stamp); - bool GetFrame(char **buffer, int &buf_len, int &size, bool &keyframe, const uint32_t time_stamp); - void SetDecodeErrorMode(SrsRtpDecodeErrorMode error_mode); - void SetNackMode(SrsRtpNackMode mode,int64_t low_rtt_nack_threshold_ms, - int64_t high_rtt_nack_threshold_ms); - void SetNackSettings(size_t max_nack_list_size,int max_packet_age_to_nack, - int max_incomplete_time_ms); - uint16_t* GetNackList(uint16_t* nack_list_size, bool* request_key_frame); - void Flush(); - void ResetJittter(); - - bool isFirstKeyFrame; -private: - - SrsRtpFrameBufferEnum GetFrameByRtpPacket(const VCMPacket& packet, SrsRtpFrameBuffer** frame, - FrameList** frame_list); - SrsRtpFrameBuffer* GetEmptyFrame(); - bool NextCompleteTimestamp(uint32_t max_wait_time_ms, uint32_t* timestamp); - bool NextMaybeIncompleteTimestamp(uint32_t* timestamp); - SrsRtpFrameBuffer* ExtractAndSetDecode(uint32_t timestamp); - SrsRtpFrameBuffer* NextFrame() const; - - - bool TryToIncreaseJitterBufferSize(); - bool RecycleFramesUntilKeyFrame(); - bool IsContinuous(const SrsRtpFrameBuffer& frame) const; - bool IsContinuousInState(const SrsRtpFrameBuffer& frame, - const SrsRtpDecodingState& decoding_state) const; - void FindAndInsertContinuousFrames(const SrsRtpFrameBuffer& new_frame); - void CleanUpOldOrEmptyFrames(); - - //nack - bool UpdateNackList(uint16_t sequence_number); - bool TooLargeNackList() const; - bool HandleTooLargeNackList(); - bool MissingTooOldPacket(uint16_t latest_sequence_number) const; - bool HandleTooOldPackets(uint16_t latest_sequence_number); - void DropPacketsFromNackList(uint16_t last_decoded_sequence_number); - SrsRtpNackMode nack_mode() const; - int NonContinuousOrIncompleteDuration(); - uint16_t EstimatedLowSequenceNumber(const SrsRtpFrameBuffer& frame) const; - bool WaitForRetransmissions(); - - bool IsPacketInOrder(uint16_t sequence_number); - bool IsFirstPacketInFrame(uint32_t ts, uint16_t seq); - -private: - class SequenceNumberLessThan { - public: - bool operator() (const uint16_t& sequence_number1, - const uint16_t& sequence_number2) const - { - return IsNewerSequenceNumber(sequence_number2, sequence_number1); - } - }; - typedef std::set SequenceNumberSet; - - std::string key_; - - srs_cond_t wait_cond_t; - // If we are running (have started) or not. - bool running_; - // Number of allocated frames. - int max_number_of_frames_; - UnorderedFrameList free_frames_; - FrameList decodable_frames_; - FrameList incomplete_frames_; - SrsRtpDecodingState last_decoded_state_; - bool first_packet_since_reset_; - - // Statistics. - //VCMReceiveStatisticsCallback* stats_callback_ GUARDED_BY(crit_sect_); - // Frame counts for each type (key, delta, ...) - //FrameCounts receive_statistics_; - // Latest calculated frame rates of incoming stream. - unsigned int incoming_frame_rate_; - unsigned int incoming_frame_count_; - int64_t time_last_incoming_frame_count_; - unsigned int incoming_bit_count_; - unsigned int incoming_bit_rate_; - // Number of frames in a row that have been too old. - int num_consecutive_old_frames_; - // Number of packets in a row that have been too old. - int num_consecutive_old_packets_; - // Number of packets received. - int num_packets_; - int num_packets_free_; - // Number of duplicated packets received. - int num_duplicated_packets_; - // Number of packets discarded by the jitter buffer. - int num_discarded_packets_; - // Time when first packet is received. - int64_t time_first_packet_ms_; - - // Jitter estimation. - // Filter for estimating jitter. - //VCMJitterEstimator jitter_estimate_; - // Calculates network delays used for jitter calculations. - //VCMInterFrameDelay inter_frame_delay_; - //VCMJitterSample waiting_for_completion_; - int64_t rtt_ms_; - - // NACK and retransmissions. - SrsRtpNackMode nack_mode_; - int64_t low_rtt_nack_threshold_ms_; - int64_t high_rtt_nack_threshold_ms_; - // Holds the internal NACK list (the missing sequence numbers). - SequenceNumberSet missing_sequence_numbers_; - uint16_t latest_received_sequence_number_; - std::vector nack_seq_nums_; - size_t max_nack_list_size_; - int max_packet_age_to_nack_; // Measured in sequence numbers. - int max_incomplete_time_ms_; - - SrsRtpDecodeErrorMode decode_error_mode_; - // Estimated rolling average of packets per frame - float average_packets_per_frame_; - // average_packets_per_frame converges fast if we have fewer than this many - // frames. - int frame_counter_; - - uint32_t last_received_timestamp_; - uint16_t last_received_sequence_number_; - bool first_packet_; - -}; - -#endif - diff --git a/trunk/src/app/srs_app_gb28181_sip.cpp b/trunk/src/app/srs_app_gb28181_sip.cpp deleted file mode 100644 index 6da31fab3..000000000 --- a/trunk/src/app/srs_app_gb28181_sip.cpp +++ /dev/null @@ -1,1093 +0,0 @@ -// -// Copyright (c) 2013-2021 Lixin -// -// SPDX-License-Identifier: MIT -// - -#include - -#include -#include -#include -#include -#include - -using namespace std; - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -std::string srs_get_sip_session_status_str(SrsGb28181SipSessionStatusType status) -{ - switch(status){ - case SrsGb28181SipSessionRegisterOk: - return "RegisterOk"; - case SrsGb28181SipSessionAliveOk: - return "AliveOk"; - case SrsGb28181SipSessionInviteOk: - return "InviteOk"; - case SrsGb28181SipSessionTrying: - return "InviteTrying"; - case SrsGb28181SipSessionBye: - return "InviteBye"; - default: - return "Unknow"; - } -} - -SrsGb28181Device::SrsGb28181Device() -{ - device_id = ""; - device_name = ""; - invite_status = SrsGb28181SipSessionUnkonw; - invite_time = 0; - device_status = ""; - -} - -SrsGb28181Device::~SrsGb28181Device() -{} - -SrsGb28181SipSession::SrsGb28181SipSession(SrsGb28181SipService *c, SrsSipRequest* r) -{ - servcie = c; - req = new SrsSipRequest(); - req->copy(r); - _session_id = req->sip_auth_id; - _reg_expires = 3600 * SRS_UTIME_SECONDS; - - trd = new SrsSTCoroutine("gb28181sip", this); - pprint = SrsPithyPrint::create_caster(); - - _register_status = SrsGb28181SipSessionUnkonw; - _alive_status = SrsGb28181SipSessionUnkonw; - _invite_status = SrsGb28181SipSessionUnkonw; - _register_time = 0; - _alive_time = 0; - _invite_time = 0; - _query_catalog_time = 0; - - _peer_ip = ""; - _peer_port = 0; - - _fromlen = 0; - _sip_cseq = 100; - - item_list_sumnum = 0; - -} - -SrsGb28181SipSession::~SrsGb28181SipSession() -{ - destroy(); - - srs_freep(req); - srs_freep(trd); - srs_freep(pprint); -} - -srs_error_t SrsGb28181SipSession::serve() -{ - srs_error_t err = srs_success; - - if ((err = trd->start()) != srs_success) { - return srs_error_wrap(err, "gb28181sip"); - } - - return err; -} - -void SrsGb28181SipSession::destroy() -{ - //destory all device - std::map::iterator it; - for (it = _device_list.begin(); it != _device_list.end(); ++it) { - srs_freep(it->second); - } - - _device_list.clear(); -} - -srs_error_t SrsGb28181SipSession::do_cycle() -{ - srs_error_t err = srs_success; - _register_time = srs_get_system_time(); - _alive_time = srs_get_system_time(); - _invite_time = srs_get_system_time(); - //call it immediately after alive ok; - _query_catalog_time = 0; - - while (true) { - - pprint->elapse(); - - if ((err = trd->pull()) != srs_success) { - return srs_error_wrap(err, "gb28181 sip session cycle"); - } - - SrsGb28181Config *config = servcie->get_config(); - srs_utime_t now = srs_get_system_time(); - srs_utime_t reg_duration = now - _register_time; - srs_utime_t alive_duration = now - _alive_time; - srs_utime_t query_duration = now - _query_catalog_time; - - //send invite, play client av - //start ps rtp listen, recv ps stream - if (_register_status == SrsGb28181SipSessionRegisterOk && - _alive_status == SrsGb28181SipSessionAliveOk) - { - std::list auto_play_list; - - std::map::iterator it; - for (it = _device_list.begin(); it != _device_list.end(); it++) { - SrsGb28181Device *device = it->second; - std::string chid = it->first; - - //update device invite time - srs_utime_t invite_duration = 0; - if (device->invite_time != 0){ - invite_duration = srs_get_system_time() - device->invite_time; - } - - //It is possible that the camera head keeps pushing and opening, - //and the duration will be very large. It will take 1 day to update - if (invite_duration > 24 * SRS_UTIME_HOURS){ - device->invite_time = srs_get_system_time(); - } - - if (device->invite_status == SrsGb28181SipSessionTrying && - invite_duration > config->sip_ack_timeout){ - device->invite_status = SrsGb28181SipSessionUnkonw; - } - - if (!config->sip_auto_play) continue; - - //offline or already invite device does not need to send invite - if (device->device_status != "ON" || - device->invite_status != SrsGb28181SipSessionUnkonw) continue; - - auto_play_list.push_back(chid); - }//end for (it) - - //auto send sip invite and create stream chennal - while(auto_play_list.size() > 0){ - std::string chid = auto_play_list.front(); - auto_play_list.pop_front(); - - SrsGb28181StreamChannel ch; - - ch.set_channel_id(_session_id + "@" + chid); - ch.set_ip(config->host); - - if (config->sip_invite_port_fixed){ - ch.set_port_mode(RTP_PORT_MODE_FIXED); - }else { - ch.set_port_mode(RTP_PORT_MODE_RANDOM); - } - - //create stream channel, ready for recv device av stream - srs_error_t err = _srs_gb28181->create_stream_channel(&ch); - - if ((err = _srs_gb28181->create_stream_channel(&ch)) == srs_success){ - SrsSipRequest req; - req.sip_auth_id = _session_id; - - //send invite to device, req push av stream - err = servcie->send_invite(&req, ch.get_ip(), - ch.get_rtp_port(), ch.get_ssrc(), chid); - } - - int code = srs_error_code(err); - if (err != srs_success){ - srs_error_reset(err); - } - - //the same device can't be sent too fast. the device can't handle it - srs_usleep(1*SRS_UTIME_SECONDS); - - srs_trace("gb28181: %s clients device=%s send invite code=%d", - _session_id.c_str(), chid.c_str(), code); - }//end while (auto_play_list.size()) - }//end if (config) - - if (_register_status == SrsGb28181SipSessionRegisterOk && - reg_duration > _reg_expires){ - srs_trace("gb28181: sip session=%s register expire", _session_id.c_str()); - break; - } - - if (_register_status == SrsGb28181SipSessionRegisterOk && - _alive_status == SrsGb28181SipSessionAliveOk && - alive_duration > config->sip_keepalive_timeout){ - srs_trace("gb28181: sip session=%s keepalive timeout", _session_id.c_str()); - break; - } - - //query device channel - if (_alive_status == SrsGb28181SipSessionAliveOk && - query_duration >= config->sip_query_catalog_interval) { - SrsSipRequest req; - req.sip_auth_id = _session_id; - _query_catalog_time = srs_get_system_time(); - - srs_error_t err = servcie->send_query_catalog(&req); - if (err != srs_success){ - srs_trace("gb28181: sip query catalog error %s",srs_error_desc(err).c_str()); - srs_error_reset(err); - } - - //print device status - srs_trace("gb28181: sip session=%s peer(%s, %d) status(%s,%s) duration(%u,%u)", - _session_id.c_str(), _peer_ip.c_str(), _peer_port, - srs_get_sip_session_status_str(_register_status).c_str(), - srs_get_sip_session_status_str(_alive_status).c_str(), - (reg_duration / SRS_UTIME_SECONDS), - (alive_duration / SRS_UTIME_SECONDS)); - - std::map::iterator it; - for (it = _device_list.begin(); it != _device_list.end(); it++) { - SrsGb28181Device *device = it->second; - std::string chid = it->first; - - srs_utime_t invite_duration = srs_get_system_time() - device->invite_time; - - if (device->invite_status != SrsGb28181SipSessionTrying && - device->invite_status != SrsGb28181SipSessionInviteOk){ - invite_duration = 0; - } - - srs_info("gb28181: sip session=%s device=%s status(%s, %s), duration(%u)", - _session_id.c_str(), chid.c_str(), device->device_status.c_str(), - srs_get_sip_session_status_str(device->invite_status).c_str(), - (invite_duration / SRS_UTIME_SECONDS)); - } - } - - srs_usleep(1 * SRS_UTIME_SECONDS); - }//end while - - return err; -} - -std::string SrsGb28181SipSession::remote_ip() -{ - return _peer_ip; -} - -const SrsContextId& SrsGb28181SipSession::get_id() -{ - return _srs_context->get_id(); -} - -std::string SrsGb28181SipSession::desc() -{ - return "SipConn"; -} - -srs_error_t SrsGb28181SipSession::cycle() -{ - srs_error_t err = do_cycle(); - - servcie->remove_session(_session_id); - srs_trace("gb28181: client id=%s sip session is remove", _session_id.c_str()); - - if (err == srs_success) { - srs_trace("gb28181: sip client finished."); - } else if (srs_is_client_gracefully_close(err)) { - srs_warn("gb28181: sip client disconnect code=%d", srs_error_code(err)); - srs_freep(err); - } - - return err; -} - -void SrsGb28181SipSession::update_device_list(std::map lst) -{ - std::map::iterator it; - for (it = lst.begin(); it != lst.end(); ++it) { - std::string id = it->first; - std::string status = it->second; - - if (_device_list.find(id) == _device_list.end()){ - SrsGb28181Device *device = new SrsGb28181Device(); - device->device_id = id; - if (status.find(",") != std::string::npos) { - device->device_status = status.substr(0,status.find(",")); - device->device_name = status.substr(status.find(",")+1); - } else { - device->device_status = status; - device->device_name = "NONAME"; - } - device->invite_status = SrsGb28181SipSessionUnkonw; - device->invite_time = 0; - _device_list[id] = device; - - }else { - SrsGb28181Device *device = _device_list[id]; - if (status.find(",") != std::string::npos) { - device->device_status = status.substr(0,status.find(",")); - device->device_name = status.substr(status.find(",")+1); - } else { - device->device_status = status; - device->device_name = "NONAME"; - } - } - - } -} - -void SrsGb28181SipSession::clear_device_list() -{ - //destory all device - std::map::iterator it; - for (it = _device_list.begin(); it != _device_list.end(); ++it) { - srs_freep(it->second); - } - - _device_list.clear(); -} - -SrsGb28181Device* SrsGb28181SipSession::get_device_info(std::string chid) -{ - if (_device_list.find(chid) != _device_list.end()){ - return _device_list[chid]; - } - return NULL; -} - -void SrsGb28181SipSession::dumps(SrsJsonObject* obj) -{ - obj->set("id", SrsJsonAny::str(_session_id.c_str())); - obj->set("device_sumnum", SrsJsonAny::integer(_device_list.size())); - - SrsJsonArray* arr = SrsJsonAny::array(); - obj->set("devices", arr); - std::map::iterator it; - for (it = _device_list.begin(); it != _device_list.end(); ++it) { - SrsGb28181Device *device = it->second; - SrsJsonObject* obj = SrsJsonAny::object(); - arr->append(obj); - obj->set("device_id", SrsJsonAny::str(device->device_id.c_str())); - obj->set("device_name", SrsJsonAny::str(device->device_name.c_str())); - obj->set("device_status", SrsJsonAny::str(device->device_status.c_str())); - obj->set("invite_status", SrsJsonAny::str(srs_get_sip_session_status_str(device->invite_status).c_str())); - obj->set("invite_time", SrsJsonAny::integer(device->invite_time/SRS_UTIME_SECONDS)); - } -} - -void SrsGb28181SipSession::dumpItemList(SrsJsonObject* obj) -{ - obj->set("TopDeviceID", SrsJsonAny::str(_session_id.c_str())); - obj->set("SumNum", SrsJsonAny::integer(item_list_sumnum)); - obj->set("RealSumNum", SrsJsonAny::integer(item_list.size())); - - SrsJsonArray* arr = SrsJsonAny::array(); - obj->set("ItemList", arr); - std::map >::iterator it; - for (it = item_list.begin(); it != item_list.end(); ++it) { - std::map device = it->second; - SrsJsonObject* obj2 = SrsJsonAny::object(); - arr->append(obj2); - std::map::iterator it2; - for (it2 = device.begin(); it2 != device.end(); ++it2) { - obj2->set(it2->first, SrsJsonAny::str(it2->second.c_str())); - } - } -} - -//gb28181 sip Service -SrsGb28181SipService::SrsGb28181SipService(SrsConfDirective* c) -{ - // TODO: FIXME: support reload. - config = new SrsGb28181Config(c); - sip = new SrsSipStack(); - - lock_session = srs_mutex_new(); - - if (_srs_gb28181){ - _srs_gb28181->set_sip_service(this); - } -} - -SrsGb28181SipService::~SrsGb28181SipService() -{ - destroy(); - srs_mutex_destroy(lock_session); - - srs_freep(sip); - srs_freep(config); -} - -SrsGb28181Config* SrsGb28181SipService::get_config() -{ - return config; -} - -void SrsGb28181SipService::set_stfd(srs_netfd_t fd) -{ - lfd = fd; -} - -srs_error_t SrsGb28181SipService::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) -{ - char address_string[64]; - char port_string[16]; - if(getnameinfo(from, fromlen, - (char*)&address_string, sizeof(address_string), - (char*)&port_string, sizeof(port_string), - NI_NUMERICHOST|NI_NUMERICSERV)) { - // return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address"); - srs_warn("gb28181: bad address"); - return srs_success; - } - std::string peer_ip = std::string(address_string); - int peer_port = atoi(port_string); - - std::string recv_msg(buf, nb_buf); - srs_error_t err = on_udp_sip(peer_ip, peer_port, recv_msg, (sockaddr*)from, fromlen); - if (err != srs_success) { - // return srs_error_wrap(err, "process udp"); - srs_warn("gb28181: process udp"); - srs_freep(err); - return srs_success; - } - return err; -} - -srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port, - std::string recv_msg, sockaddr* from, const int fromlen) -{ - srs_error_t err = srs_success; - - int recv_len = recv_msg.size(); - char* recv_data = (char*)recv_msg.c_str(); - - srs_info("gb28181: request peer(%s, %d) nbbuf=%d", peer_ip.c_str(), peer_port, recv_len); - srs_info("gb28181: request recv message=%s", recv_data); - - if (recv_len < 10) { - return err; - } - - SrsSipRequest* req = NULL; - - if ((err = sip->parse_request(&req, recv_data, recv_len)) != srs_success) { - return srs_error_wrap(err, "parse sip request"); - } - - req->peer_ip = peer_ip; - req->peer_port = peer_port; - SrsAutoFree(SrsSipRequest, req); - - std::string session_id = req->sip_auth_id; - - if (req->is_register()) { - std::vector serial = srs_string_split(srs_string_replace(req->uri,"sip:", ""), "@"); - if (serial.empty()){ - return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "register string split"); - } - - //if (serial.at(0) != config->sip_serial){ - // srs_warn("gb28181: client:%s request serial and server serial inconformity(%s:%s)", - // req->sip_auth_id.c_str(), serial.at(0).c_str(), config->sip_serial.c_str()); - // return err; - //} - - srs_trace("gb28181: request client id=%s peer(%s, %d)", req->sip_auth_id.c_str(), peer_ip.c_str(), peer_port); - srs_trace("gb28181: %s method=%s, uri=%s, version=%s expires=%d", - req->get_cmdtype_str().c_str(), req->method.c_str(), - req->uri.c_str(), req->version.c_str(), req->expires); - - SrsGb28181SipSession* sip_session = NULL; - if ((err = fetch_or_create_sip_session(req, &sip_session)) != srs_success) { - srs_error_wrap(err, "create sip session error!"); - return err; - } - srs_assert(sip_session); - sip_session->set_request(req); - - send_status(req, from, fromlen); - sip_session->set_register_status(SrsGb28181SipSessionRegisterOk); - sip_session->set_register_time(srs_get_system_time()); - sip_session->set_reg_expires(req->expires); - sip_session->set_sockaddr((sockaddr)*from); - sip_session->set_sockaddr_len(fromlen); - sip_session->set_peer_ip(peer_ip); - sip_session->set_peer_port(peer_port); - - }else if (req->is_message()) { - SrsGb28181SipSession* sip_session = fetch(session_id); - - if (!sip_session){ - sip_session = fetch_session_by_callid(req->call_id); - } - - if (!sip_session || sip_session->register_status() == SrsGb28181SipSessionUnkonw){ - srs_trace("gb28181: %s client not registered", req->sip_auth_id.c_str()); - return err; - } - - //reponse status - if (req->cmdtype == SrsSipCmdRequest){ - send_status(req, from, fromlen); - sip_session->set_alive_status(SrsGb28181SipSessionAliveOk); - sip_session->set_alive_time(srs_get_system_time()); - sip_session->set_sockaddr((sockaddr)*from); - sip_session->set_sockaddr_len(fromlen); - sip_session->set_peer_port(peer_port); - sip_session->set_peer_ip(peer_ip); - - //update device list - if (req->device_list_map.size() > 0){ - sip_session->update_device_list(req->device_list_map); - } - if (!strcasecmp(req->content_type.c_str(),"application/manscdp+xml") - && req->xml_body_map.find("Response@CmdType") != req->xml_body_map.end() - && req->xml_body_map["Response@CmdType"] == "Catalog") { - if (req->xml_body_map.find("Response@SumNum") != req->xml_body_map.end()) { - sip_session->item_list_sumnum = atoi(req->xml_body_map["Response@SumNum"].c_str()); - } - std::vector >::iterator it; - for (it = req->item_list.begin(); it != req->item_list.end(); ++it) { - std::map device = *it; - std::map >::iterator it2 = sip_session->item_list.find(device["DeviceID"]); - if (it2 != sip_session->item_list.end()) { - sip_session->item_list.erase(it2); - sip_session->item_list[device["DeviceID"]] = device; - } else { - sip_session->item_list[device["DeviceID"]] = device; - } - } - } - } - - }else if (req->is_invite()) { - SrsGb28181SipSession* sip_session = fetch_session_by_callid(req->call_id); - - srs_trace("gb28181: request client id=%s, peer(%s, %d)", req->sip_auth_id.c_str(), - peer_ip.c_str(), peer_port); - srs_trace("gb28181: %s method=%s, uri=%s, version=%s ", - req->get_cmdtype_str().c_str(), req->method.c_str(), req->uri.c_str(), req->version.c_str()); - - if (!sip_session){ - srs_trace("gb28181: call_id %s not map %s client ", req->call_id.c_str(), req->sip_auth_id.c_str()); - return err; - } - - // sip_session->set_sockaddr((sockaddr)*from); - // sip_session->set_sockaddr_len(fromlen); - - if (sip_session->register_status() == SrsGb28181SipSessionUnkonw || - sip_session->alive_status() == SrsGb28181SipSessionUnkonw) { - srs_trace("gb28181: %s client not registered or not alive", req->sip_auth_id.c_str()); - return err; - } - - if (req->cmdtype == SrsSipCmdRespone){ - srs_trace("gb28181: INVITE response %s client status=%s", req->sip_auth_id.c_str(), req->status.c_str()); - - if (req->status == "200") { - srs_trace("gb28181: device unique id is %s@%s", sip_session->session_id().c_str(), req->sip_auth_id.c_str()); - // if srs is external realm, ssrc is generated by source realm rather than srs - // so update ssrc to the y line in source realm '200 OK' response - // actually, we should do this all the time - if (req->y_ssrc != 0) { - _srs_gb28181->update_rtmpmuxer_to_newssrc_by_id(sip_session->session_id()+"@"+req->sip_auth_id, req->y_ssrc); - req->y_ssrc = 0; - } - send_ack(req, from, fromlen); - SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id); - if (device){ - device->invite_status = SrsGb28181SipSessionInviteOk; - device->req_inivate.copy(req); - device->invite_time = srs_get_system_time(); - } - }else if (req->status == "100") { - //send_ack(req, from, fromlen); - SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id); - if (device){ - device->req_inivate.copy(req); - device->invite_status = SrsGb28181SipSessionTrying; - device->invite_time = srs_get_system_time(); - } - }else{ - SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id); - if (device){ - device->req_inivate.copy(req); - device->invite_status = SrsGb28181SipSessionUnkonw; - device->invite_time = srs_get_system_time(); - } - } - } - - }else if (req->is_bye()) { - srs_trace("gb28181: request client id=%s, peer(%s, %d)", req->sip_auth_id.c_str(), - peer_ip.c_str(), peer_port); - srs_trace("gb28181: %s method=%s, uri=%s, version=%s ", - req->get_cmdtype_str().c_str(), req->method.c_str(), req->uri.c_str(), req->version.c_str()); - - send_status(req, from, fromlen); - - SrsGb28181SipSession* sip_session = fetch_session_by_callid(req->call_id); - srs_trace("gb28181: request client id=%s, peer(%s, %d)", req->sip_auth_id.c_str(), - peer_ip.c_str(), peer_port); - srs_trace("gb28181: %s method=%s, uri=%s, version=%s ", - req->get_cmdtype_str().c_str(), req->method.c_str(), req->uri.c_str(), req->version.c_str()); - - if (!sip_session){ - srs_trace("gb28181: call_id %s not map %s client ", req->call_id.c_str(), req->sip_auth_id.c_str()); - return err; - } - - if (req->cmdtype == SrsSipCmdRespone){ - srs_trace("gb28181: BYE %s client status=%s", req->sip_auth_id.c_str(), req->status.c_str()); - - if (req->status == "200") { - SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id); - if (device){ - device->invite_status = SrsGb28181SipSessionBye; - device->invite_time = srs_get_system_time(); - } - }else { - //TODO:fixme - SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id); - if (device){ - device->invite_status = SrsGb28181SipSessionBye; - device->invite_time = srs_get_system_time(); - } - } - } - }else{ - srs_trace("gb28181: ingor request method=%s", req->method.c_str()); - } - - return err; -} - -int SrsGb28181SipService::send_message(sockaddr* from, int fromlen, std::stringstream& ss) -{ - std::string str = ss.str(); - srs_info("gb28181: send_message:%s", str.c_str()); - srs_assert(!str.empty()); - - int ret = srs_sendto(lfd, (char*)str.c_str(), (int)str.length(), from, fromlen, SRS_UTIME_NO_TIMEOUT); - if (ret <= 0){ - srs_trace("gb28181: send_message falid (%d)", ret); - } - - return ret; -} - - -int SrsGb28181SipService::send_ack(SrsSipRequest *req, sockaddr *f, int l) -{ - srs_assert(req); - - std::stringstream ss; - - req->host = config->host; - req->host_port = config->sip_port; - req->realm = config->sip_realm; - req->serial = config->sip_serial; - req->chid = req->sip_auth_id; - - sip->req_ack(ss, req); - return send_message(f, l, ss); -} - -int SrsGb28181SipService::send_status(SrsSipRequest *req, sockaddr *f, int l) -{ - srs_assert(req); - - std::stringstream ss; - - req->host = config->host; - req->host_port = config->sip_port; - req->realm = config->sip_realm; - req->serial = config->sip_serial; - - sip->resp_status(ss, req); - return send_message(f, l, ss); -} - - -srs_error_t SrsGb28181SipService::send_invite(SrsSipRequest *req, string ip, int port, uint32_t ssrc, std::string chid) -{ - srs_error_t err = srs_success; - - srs_assert(req); - - SrsGb28181SipSession *sip_session = fetch(req->sip_auth_id); - - if (!sip_session){ - return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist"); - } - - //if you are inviting or succeed in invite, - //you cannot invite again. you need to 'bye' and try again - SrsGb28181Device *device = sip_session->get_device_info(chid); - if (!device || device->device_status != "ON"){ - return srs_error_new(ERROR_GB28181_SIP_CH_OFFLINE, "sip device channel offline"); - } - - if (device->invite_status == SrsGb28181SipSessionTrying || - device->invite_status == SrsGb28181SipSessionInviteOk){ - return srs_error_new(ERROR_GB28181_SIP_IS_INVITING, "sip device channel inviting"); - } - - req->host = config->host; - req->host_port = config->sip_port; - req->realm = config->sip_realm; - req->serial = config->sip_serial; - req->chid = chid; - req->seq = sip_session->sip_cseq(); - - SrsSipRequest register_req = sip_session->request(); - req->to_realm = register_req.to_realm; - req->from_realm = config->sip_realm; - - std::stringstream ss; - sip->req_invite(ss, req, ip, port, ssrc, config->rtp_mux_tcp_enable); - - sockaddr addr = sip_session->sockaddr_from(); - - if (send_message(&addr, sip_session->sockaddr_fromlen(), ss) <= 0) - { - return srs_error_new(ERROR_GB28181_SIP_INVITE_FAILED, "sip device invite failed"); - } - - //prame branch, from_tag, to_tag, call_id, - //The parameter of 'bye' must be the same as 'invite' - device->req_inivate.copy(req); - device->invite_time = srs_get_system_time(); - device->invite_status = SrsGb28181SipSessionTrying; - - //call_id map sip_session - sip_session_map_by_callid(sip_session, req->call_id); - - return err; -} - -srs_error_t SrsGb28181SipService::send_bye(SrsSipRequest *req, std::string chid) -{ - srs_error_t err = srs_success; - - srs_assert(req); - - SrsGb28181SipSession *sip_session = fetch(req->sip_auth_id); - - if (!sip_session){ - return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist"); - } - - SrsGb28181Device *device = sip_session->get_device_info(chid); - if (!device){ - return srs_error_new(ERROR_GB28181_SIP_CH_NOTEXIST, "sip device channel not exist"); - } - - //prame branch, from_tag, to_tag, call_id, - //The parameter of 'bye' must be the same as 'invite' - //SrsSipRequest r = sip_session->request(); - - req->copy(&device->req_inivate); - - req->host = config->host; - req->host_port = config->sip_port; - req->realm = config->sip_realm; - req->serial = config->sip_serial; - req->chid = chid; - req->seq = sip_session->sip_cseq(); - - SrsSipRequest register_req = sip_session->request(); - req->to_realm = register_req.to_realm; - req->from_realm = config->sip_realm; - - //get protocol stack - std::stringstream ss; - sip->req_bye(ss, req); - - sockaddr addr = sip_session->sockaddr_from(); - if (send_message(&addr, sip_session->sockaddr_fromlen(), ss) <= 0) - { - return srs_error_new(ERROR_GB28181_SIP_BYE_FAILED, "sip bye failed"); - } - - return err; -} - -srs_error_t SrsGb28181SipService::send_sip_raw_data(SrsSipRequest *req, std::string data) -{ - srs_error_t err = srs_success; - - srs_assert(req); - - SrsGb28181SipSession *sip_session = fetch(req->sip_auth_id); - - if (!sip_session){ - return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session no exist"); - } - - std::stringstream ss; - ss << data; - - sockaddr addr = sip_session->sockaddr_from(); - if (send_message(&addr, sip_session->sockaddr_fromlen(), ss) <= 0) - { - return srs_error_new(ERROR_GB28181_SIP_RAW_DATA_FAILED, "sip raw data failed"); - } - - return err; -} - -srs_error_t SrsGb28181SipService::send_query_catalog(SrsSipRequest *req) -{ - srs_assert(req); - - SrsGb28181SipSession *sip_session = fetch(req->sip_auth_id); - - if (!sip_session){ - return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist"); - } - - req->host = config->host; - req->host_port = config->sip_port; - req->realm = config->sip_realm; - req->serial = config->sip_serial; - req->chid = req->sip_auth_id; - req->seq = sip_session->sip_cseq(); - - //get protocol stack - std::stringstream ss; - sip->req_query_catalog(ss, req); - - return send_sip_raw_data(req, ss.str()); -} - -srs_error_t SrsGb28181SipService::send_ptz(SrsSipRequest *req, std::string chid, std::string cmd, - uint8_t speed, int priority) -{ - srs_error_t err = srs_success; - - srs_assert(req); - - SrsGb28181SipSession *sip_session = fetch(req->sip_auth_id); - - if (!sip_session){ - return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist"); - } - - SrsGb28181Device *device = sip_session->get_device_info(chid); - if (!device){ - return srs_error_new(ERROR_GB28181_SIP_CH_NOTEXIST, "sip device channel not exist"); - } - - if (device->invite_status != SrsGb28181SipSessionInviteOk){ - return srs_error_new(ERROR_GB28181_SIP_NOT_INVITE, "sip device channel not inviting"); - } - - //prame branch, from_tag, to_tag, call_id, - //The parameter of 'bye' must be the same as 'invite' - //SrsSipRequest r = sip_session->request(); - req->copy(&device->req_inivate); - - req->host = config->host; - req->host_port = config->sip_port; - req->realm = config->sip_realm; - req->serial = config->sip_serial; - req->chid = chid; - req->seq = sip_session->sip_cseq(); - - SrsSipPtzCmdType ptzcmd = SrsSipPtzCmdRight; - const char *ss_cmd = cmd.c_str(); - if (!strcasecmp(ss_cmd, "stop")){ - ptzcmd = SrsSipPtzCmdStop; - }else if (!strcasecmp(ss_cmd, "right")){ - ptzcmd = SrsSipPtzCmdRight; - }else if (!strcasecmp(ss_cmd, "left")){ - ptzcmd = SrsSipPtzCmdLeft; - }else if (!strcasecmp(ss_cmd, "down")){ - ptzcmd = SrsSipPtzCmdDown; - }else if (!strcasecmp(ss_cmd, "up")){ - ptzcmd = SrsSipPtzCmdUp; - }else if (!strcasecmp(ss_cmd, "zoomout")){ - ptzcmd = SrsSipPtzCmdZoomOut; - }else if (!strcasecmp(ss_cmd, "zoomin")){ - ptzcmd = SrsSipPtzCmdZoomIn; - }else{ - return srs_error_new(ERROR_GB28181_SIP_PTZ_CMD_INVALID, "sip ptz cmd no support"); - } - - if (speed < 0 || speed > 0xFF){ - return srs_error_new(ERROR_GB28181_SIP_PTZ_CMD_INVALID, "sip ptz cmd speed out of range"); - } - - if (priority <= 0 ){ - priority = 5; - } - - //get protocol stack - std::stringstream ss; - sip->req_ptz(ss, req, ptzcmd, speed, priority); - - sockaddr addr = sip_session->sockaddr_from(); - if (send_message(&addr, sip_session->sockaddr_fromlen(), ss) <= 0) - { - return srs_error_new(ERROR_GB28181_SIP_PTZ_FAILED, "sip ptz failed"); - } - - //call_id map sip_session - sip_session_map_by_callid(sip_session, req->call_id); - - return err; - -} - -srs_error_t SrsGb28181SipService::query_sip_session(std::string sid, SrsJsonArray* arr) -{ - srs_error_t err = srs_success; - - if (!sid.empty()){ - SrsGb28181SipSession* sess = fetch(sid); - if (!sess){ - return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist"); - } - SrsJsonObject* obj = SrsJsonAny::object(); - arr->append(obj); - sess->dumps(obj); - }else { - std::map::iterator it; - for (it = sessions.begin(); it != sessions.end(); ++it) { - SrsGb28181SipSession* sess = it->second; - SrsJsonObject* obj = SrsJsonAny::object(); - arr->append(obj); - sess->dumps(obj); - } - } - - return err; -} - -srs_error_t SrsGb28181SipService::query_device_list(std::string sid, SrsJsonArray* arr) -{ - srs_error_t err = srs_success; - - if (!sid.empty()){ - SrsGb28181SipSession* sess = fetch(sid); - if (!sess){ - return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist"); - } - SrsJsonObject* obj = SrsJsonAny::object(); - arr->append(obj); - sess->dumpItemList(obj); - }else { - std::map::iterator it; - for (it = sessions.begin(); it != sessions.end(); ++it) { - SrsGb28181SipSession* sess = it->second; - SrsJsonObject* obj = SrsJsonAny::object(); - arr->append(obj); - sess->dumpItemList(obj); - } - } - - return err; -} - -srs_error_t SrsGb28181SipService::fetch_or_create_sip_session(SrsSipRequest *req, SrsGb28181SipSession** sip_session) -{ - srs_error_t err = srs_success; - - SrsGb28181SipSession* sess = NULL; - if ((sess = fetch(req->sip_auth_id)) != NULL) { - *sip_session = sess; - return err; - } - - sess = new SrsGb28181SipSession(this, req);; - if ((err = sess->serve()) != srs_success) { - return srs_error_wrap(err, "gb28181: sip serssion serve %s", req->sip_auth_id.c_str()); - } - - sessions[req->sip_auth_id] = sess; - *sip_session = sess; - - return err; -} - -SrsGb28181SipSession* SrsGb28181SipService::fetch(std::string sid) -{ - SrsLocker(lock_session); - - std::map::iterator it = sessions.find(sid); - if (it == sessions.end()){ - return NULL; - }else{ - return it->second; - } -} - -void SrsGb28181SipService::remove_session(std::string sid) -{ - SrsLocker(lock_session); - - std::map::iterator it = sessions.find(sid); - if (it != sessions.end()){ - //srs_freep(it->second); - //thread exit management by gb28181 manger - _srs_gb28181->remove_sip_session(it->second); - sessions.erase(it); - } -} - - -void SrsGb28181SipService::destroy() -{ - //destory all sip session - std::map::iterator it; - for (it = sessions.begin(); it != sessions.end(); ++it) { - //srs_freep(it->second); - //thread exit management by gb28181 manger - _srs_gb28181->remove_sip_session(it->second); - } - sessions.clear(); -} - -void SrsGb28181SipService::sip_session_map_by_callid(SrsGb28181SipSession *sess, std::string call_id) -{ - if (sessions_by_callid.find(call_id) == sessions_by_callid.end()) { - sessions_by_callid[call_id] = sess; - } -} - -void SrsGb28181SipService::sip_session_unmap_by_callid(std::string call_id) -{ - std::map::iterator it = sessions_by_callid.find(call_id); - if (it != sessions_by_callid.end()) { - sessions_by_callid.erase(it); - } -} - -SrsGb28181SipSession* SrsGb28181SipService::fetch_session_by_callid(std::string call_id) -{ - SrsGb28181SipSession* session = NULL; - if (sessions_by_callid.find(call_id) == sessions_by_callid.end()) { - return NULL; - } - - session = sessions_by_callid[call_id]; - return session; -} - - diff --git a/trunk/src/app/srs_app_gb28181_sip.hpp b/trunk/src/app/srs_app_gb28181_sip.hpp deleted file mode 100644 index ed8370f30..000000000 --- a/trunk/src/app/srs_app_gb28181_sip.hpp +++ /dev/null @@ -1,206 +0,0 @@ -// -// Copyright (c) 2013-2021 Lixin -// -// SPDX-License-Identifier: MIT -// - -#ifndef SRS_APP_GB28181_SIP_HPP -#define SRS_APP_GB28181_SIP_HPP - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -class SrsConfDirective; -class SrsSipRequest; -class SrsGb28181Config; -class SrsSipStack; -class SrsGb28181SipService; -class SrsGb28181Device; - -enum SrsGb28181SipSessionStatusType{ - SrsGb28181SipSessionUnkonw = 0, - SrsGb28181SipSessionRegisterOk = 1, - SrsGb28181SipSessionAliveOk = 2, - SrsGb28181SipSessionInviteOk = 3, - SrsGb28181SipSessionTrying = 4, - SrsGb28181SipSessionBye = 5, -}; - -class SrsGb28181Device -{ -public: - SrsGb28181Device(); - virtual ~SrsGb28181Device(); -public: - std::string device_id; - std::string device_name; - std::string device_status; - SrsGb28181SipSessionStatusType invite_status; - srs_utime_t invite_time; - SrsSipRequest req_inivate; -}; - -class SrsGb28181SipSession: public ISrsCoroutineHandler, public ISrsConnection -{ -private: - //SrsSipRequest *req; - SrsGb28181SipService *servcie; - std::string _session_id; - SrsCoroutine* trd; - SrsPithyPrint* pprint; -private: - SrsGb28181SipSessionStatusType _register_status; - SrsGb28181SipSessionStatusType _alive_status; - SrsGb28181SipSessionStatusType _invite_status; - srs_utime_t _register_time; - srs_utime_t _alive_time; - srs_utime_t _invite_time; - srs_utime_t _reg_expires; - srs_utime_t _query_catalog_time; - - std::string _peer_ip; - int _peer_port; - - sockaddr _from; - int _fromlen; - SrsSipRequest *req; - - std::map _device_list; - //std::map _device_status; - int _sip_cseq; - -public: - SrsGb28181SipSession(SrsGb28181SipService *c, SrsSipRequest* r); - virtual ~SrsGb28181SipSession(); - -private: - void destroy(); - -public: - void set_register_status(SrsGb28181SipSessionStatusType s) { _register_status = s;} - void set_alive_status(SrsGb28181SipSessionStatusType s) { _alive_status = s;} - void set_invite_status(SrsGb28181SipSessionStatusType s) { _invite_status = s;} - void set_register_time(srs_utime_t t) { _register_time = t;} - void set_alive_time(srs_utime_t t) { _alive_time = t;} - void set_invite_time(srs_utime_t t) { _invite_time = t;} - //void set_recv_rtp_time(srs_utime_t t) { _recv_rtp_time = t;} - void set_reg_expires(int e) { _reg_expires = e*SRS_UTIME_SECONDS;} - void set_peer_ip(std::string i) { _peer_ip = i;} - void set_peer_port(int o) { _peer_port = o;} - void set_sockaddr(sockaddr f) { _from = f;} - void set_sockaddr_len(int l) { _fromlen = l;} - void set_request(SrsSipRequest *r) { req->copy(r);} - - SrsGb28181SipSessionStatusType register_status() { return _register_status;} - SrsGb28181SipSessionStatusType alive_status() { return _alive_status;} - SrsGb28181SipSessionStatusType invite_status() { return _invite_status;} - srs_utime_t register_time() { return _register_time;} - srs_utime_t alive_time() { return _alive_time;} - srs_utime_t invite_time() { return _invite_time;} - //srs_utime_t recv_rtp_time() { return _recv_rtp_time;} - int reg_expires() { return _reg_expires;} - std::string peer_ip() { return _peer_ip;} - int peer_port() { return _peer_port;} - sockaddr sockaddr_from() { return _from;} - int sockaddr_fromlen() { return _fromlen;} - SrsSipRequest request() { return *req;} - int sip_cseq(){ return _sip_cseq++;} - - std::string session_id() { return _session_id;} - std::map > item_list; - int item_list_sumnum; -public: - void update_device_list(std::map devlist); - void clear_device_list(); - SrsGb28181Device *get_device_info(std::string chid); - void dumps(SrsJsonObject* obj); - void dumpItemList(SrsJsonObject* obj); - -public: - virtual srs_error_t serve(); - -// Interface ISrsOneCycleThreadHandler -public: - virtual srs_error_t cycle(); -// Interface ISrsConnection. -public: - virtual std::string remote_ip(); - virtual const SrsContextId& get_id(); - virtual std::string desc(); -private: - virtual srs_error_t do_cycle(); -}; - -class SrsGb28181SipService : public ISrsUdpHandler -{ -private: - SrsSipStack *sip; - SrsGb28181Config *config; - srs_netfd_t lfd; - - std::map sessions; - std::map sessions_by_callid; - - srs_mutex_t lock_session; -public: - SrsGb28181SipService(SrsConfDirective* c); - virtual ~SrsGb28181SipService(); - - // Interface ISrsUdpHandler -public: - virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); - virtual void set_stfd(srs_netfd_t fd); -private: - void destroy(); - srs_error_t on_udp_sip(std::string host, int port, std::string recv_msg, sockaddr* from, int fromlen); -public: - int send_message(sockaddr* f, int l, std::stringstream& ss); - - int send_ack(SrsSipRequest *req, sockaddr *f, int l); - int send_status(SrsSipRequest *req, sockaddr *f, int l); - - srs_error_t send_invite(SrsSipRequest *req, std::string ip, int port, uint32_t ssrc, std::string chid); - srs_error_t send_bye(SrsSipRequest *req, std::string chid); - srs_error_t send_query_catalog(SrsSipRequest *req); - srs_error_t send_ptz(SrsSipRequest *req, std::string chid, std::string cmd, uint8_t speed, int priority); - - // The SIP command is transmitted through HTTP API, - // and the body content is transmitted to the device, - // mainly for testing and debugging, For example, here is HTTP body: - // BYE sip:34020000001320000003@3402000000 SIP/2.0 - // Via: SIP/2.0/UDP 39.100.155.146:15063;rport;branch=z9hG4bK34205410 - // From: ;tag=512355410 - // To: ;tag=680367414 - // Call-ID: 200003304 - // CSeq: 21 BYE - // Max-Forwards: 70 - // User-Agent: SRS/4.0.4(Leo) - // Content-Length: 0 - // - // - srs_error_t send_sip_raw_data(SrsSipRequest *req, std::string data); - srs_error_t query_sip_session(std::string sid, SrsJsonArray* arr); - srs_error_t query_device_list(std::string sid, SrsJsonArray* arr); - -public: - srs_error_t fetch_or_create_sip_session(SrsSipRequest *req, SrsGb28181SipSession** sess); - SrsGb28181SipSession* fetch(std::string id); - void remove_session(std::string id); - SrsGb28181Config* get_config(); - - void sip_session_map_by_callid(SrsGb28181SipSession *sess, std::string call_id); - void sip_session_unmap_by_callid(std::string call_id); - SrsGb28181SipSession* fetch_session_by_callid(std::string call_id); -}; - -#endif - diff --git a/trunk/src/app/srs_app_gb28181_stack.cpp b/trunk/src/app/srs_app_gb28181_stack.cpp deleted file mode 100644 index e3c1a1d5e..000000000 --- a/trunk/src/app/srs_app_gb28181_stack.cpp +++ /dev/null @@ -1,1442 +0,0 @@ -// -// Copyright (c) 2013-2021 Lixin -// -// SPDX-License-Identifier: MIT -// - -#include - -#include -#include -#include -#include - -using namespace std; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* Code (GB2312 <--> UTF-8) Convert Class */ -class CodeConverter -{ -private: - iconv_t cd; -public: - CodeConverter(const char *pFromCharset, const char *pToCharset) - { - cd = iconv_open(pToCharset, pFromCharset); - if ((iconv_t)(-1) == cd) - srs_warn("CodeConverter: iconv_open failed <%s --> %s>", pFromCharset, pToCharset); - } - ~CodeConverter() - { - if ((iconv_t)(-1) != cd) - iconv_close(cd); - } - int Convert(char *pInBuf, size_t InLen, char *pOutBuf, size_t OutLen) - { - return iconv(cd, &pInBuf, (size_t *)&InLen, &pOutBuf, (size_t *)&OutLen); - } - static bool IsUTF8(const char *pInBuf, int InLen) - { - if (InLen < 0) { - return false; - } - - int i = 0; - int nBytes = 0; - unsigned char chr = 0; - - while (i < InLen) { - chr = *(pInBuf + i); - if (nBytes == 0) { - if ((chr & 0x80) != 0) { - while ((chr & 0x80) != 0) { - chr <<= 1; - nBytes++; - } - if (nBytes < 2 || nBytes > 6) { - return false; - } - nBytes--; - } - } else { - if ((chr & 0xc0) != 0x80) { - return false; - } - nBytes--; - } - ++i; - } - - return nBytes == 0; - } -}; - -unsigned int srs_sip_random(int min,int max) -{ - //it is possible to duplicate data with time(0) - srand(unsigned(srs_update_system_time())); - return rand() % (max - min + 1) + min; -} - -std::string srs_sip_generate_branch() -{ - int rand = srs_sip_random(10000000, 99999999); - std::stringstream branch; - branch << "SrsGbB" << rand; - return branch.str(); -} - -std::string srs_sip_generate_to_tag() -{ - uint32_t rand = srs_sip_random(10000000, 99999999); - std::stringstream branch; - branch << "SrsGbT" << rand; - return branch.str(); -} - -std::string srs_sip_generate_from_tag() -{ - uint32_t rand = srs_sip_random(10000000, 99999999); - std::stringstream branch; - branch << "SrsGbF" << rand; - return branch.str(); -} - -std::string srs_sip_generate_call_id() -{ - uint32_t rand = srs_sip_random(10000000, 99999999); - std::stringstream branch; - branch << "2020" << rand; - return branch.str(); -} - -std::string srs_sip_generate_sn() -{ - uint32_t rand = srs_sip_random(10000000, 99999999); - std::stringstream sn; - sn << rand; - return sn.str(); -} - -std::string srs_sip_get_form_to_uri(std::string msg) -{ - //;tag=536961166 - //sip:34020000002000000001@3402000000 - - size_t pos = msg.find("<"); - if (pos == string::npos) { - return msg; - } - - msg = msg.substr(pos+1); - - size_t pos2 = msg.find(">"); - if (pos2 == string::npos) { - return msg; - } - - msg = msg.substr(0, pos2); - return msg; -} - -std::string srs_sip_get_utc_date() -{ - // clock time - timeval tv; - if (gettimeofday(&tv, NULL) == -1) { - return ""; - } - - // to calendar time - struct tm* tm; - if ((tm = gmtime(&tv.tv_sec)) == NULL) { - return ""; - } - - //Date: 2020-03-21T14:20:57.638 - std::string utc_date = ""; - char buffer[25] = {0}; - snprintf(buffer, 25, - "%d-%02d-%02dT%02d:%02d:%02d.%03d", - 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 1000)); - utc_date = buffer; - return utc_date; -} - - -std::string srs_sip_get_param(std::string msg, std::string param) -{ - std::vector vec_params = srs_string_split(msg, ";"); - - for (vector::iterator it = vec_params.begin(); it != vec_params.end(); ++it) { - string value = *it; - - size_t pos = value.find(param); - if (pos == string::npos) { - continue; - } - - std::vector v_pram = srs_string_split(value, "="); - - if (v_pram.size() > 1) { - return v_pram.at(1); - } - } - return ""; -} - -SrsSipRequest::SrsSipRequest() -{ - seq = 0; - content_length = 0; - sdp = NULL; - transport = NULL; - - method = ""; - uri = "";; - version = "";; - seq = 0; - content_type = ""; - content_length = 0; - call_id = ""; - from = ""; - to = ""; - via = ""; - from_tag = ""; - to_tag = ""; - contact = ""; - user_agent = ""; - branch = ""; - status = ""; - expires = 3600; - max_forwards = 70; - www_authenticate = ""; - authorization = ""; - cmdtype = SrsSipCmdRequest; - - host = "127.0.0.1";; - host_port = 5060; - - serial = "";; - realm = "";; - - sip_auth_id = ""; - sip_auth_pwd = ""; - sip_username = ""; - peer_ip = ""; - peer_port = 0; - - chid = ""; - - from_realm = ""; - to_realm = ""; - y_ssrc = 0; -} - -SrsSipRequest::~SrsSipRequest() -{ - srs_freep(sdp); - srs_freep(transport); -} - -bool SrsSipRequest::is_register() -{ - return method == SRS_SIP_METHOD_REGISTER; -} - -bool SrsSipRequest::is_invite() -{ - return method == SRS_SIP_METHOD_INVITE; -} - -bool SrsSipRequest::is_ack() -{ - return method == SRS_SIP_METHOD_ACK; -} - -bool SrsSipRequest::is_message() -{ - return method == SRS_SIP_METHOD_MESSAGE; -} - -bool SrsSipRequest::is_bye() -{ - return method == SRS_SIP_METHOD_BYE; -} - -std::string SrsSipRequest::get_cmdtype_str() -{ - switch(cmdtype) { - case SrsSipCmdRequest: - return "request"; - case SrsSipCmdRespone: - return "respone"; - } - - return ""; -} - -void SrsSipRequest::copy(SrsSipRequest* src) -{ - if (!src){ - return; - } - - method = src->method; - uri = src->uri; - version = src->version; - seq = src->seq; - content_type = src->content_type; - content_length = src->content_length; - call_id = src->call_id; - from = src->from; - to = src->to; - via = src->via; - from_tag = src->from_tag; - to_tag = src->to_tag; - contact = src->contact; - user_agent = src->user_agent; - branch = src->branch; - status = src->status; - expires = src->expires; - max_forwards = src->max_forwards; - www_authenticate = src->www_authenticate; - authorization = src->authorization; - cmdtype = src->cmdtype; - - host = src->host; - host_port = src->host_port; - - serial = src->serial; - realm = src->realm; - - sip_auth_id = src->sip_auth_id; - sip_auth_pwd = src->sip_auth_pwd; - sip_username = src->sip_username; - peer_ip = src->peer_ip; - peer_port = src->peer_port; - - chid = src->chid; - - xml_body_map = src->xml_body_map; - device_list_map = src->device_list_map; - - from_realm = src->from_realm; - to_realm = src->to_realm; -} - -SrsSipStack::SrsSipStack() -{ - buf = new SrsSimpleStream(); -} - -SrsSipStack::~SrsSipStack() -{ - srs_freep(buf); -} - -srs_error_t SrsSipStack::parse_request(SrsSipRequest** preq, const char* recv_msg, int nb_len) -{ - srs_error_t err = srs_success; - - SrsSipRequest* req = new SrsSipRequest(); - if ((err = do_parse_request(req, recv_msg)) != srs_success) { - srs_freep(req); - return srs_error_wrap(err, "recv message"); - } - - *preq = req; - - return err; -} - -srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map &json_map, std::vector > &item_list) -{ - /* - - - Keepalive - 2034 - 34020000001110000001 - OK - - 34020000001320000002 - 34020000001320000003 - 34020000001320000005 - 34020000001320000006 - 34020000001320000007 - 34020000001320000008 - - - */ - - if (CodeConverter::IsUTF8(xml_msg.c_str(), xml_msg.size()) == false) { - char *outBuf = (char *)calloc(1, xml_msg.size() * 2); - CodeConverter cc("gb2312", "utf-8"); - if (cc.Convert((char *)xml_msg.c_str(), xml_msg.size(), (char *)outBuf, xml_msg.size() * 2 - 1) != -1) - xml_msg = string(outBuf); - if (outBuf) - free(outBuf); - } - - const char* start = xml_msg.c_str(); - const char* end = start + xml_msg.size(); - char* p = (char*)start; - - char* value_start = NULL; - - std::string xml_header; - int xml_layer = 0; - int in_item_tag = 0; - - //std::map json_map; - std::map json_key; - std::map one_item; - while (p < end) { - if (p[0] == '\n'){ - p +=1; - value_start = NULL; - } else if (p[0] == '\r' && p[1] == '\n') { - p +=2; - value_start = NULL; - } else if (p[0] == '<' && p[1] == '/') { // xml item end flag - std::string value = ""; - if (value_start) { - value = std::string(value_start, p-value_start); - } - - //skip get Notify - char *s = p; - while (p[0] != '>') {p++;} - std::string key(s, p-s); - - // get DeviceList - std::vector vec = srs_string_split(key, " "); - if (vec.empty()){ - return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "prase xml"); - } - - key = vec.at(0); - - /*xml element to map - - - 34020000001320000001 - 34020000001320000002 - - - to map is: Notify@Info@DeviceID:34020000001320000001,34020000001320000002 - */ - - //get map key - std::string mkey = ""; - for (int i = 0; i < xml_layer ; i++){ - if (mkey.empty()) { - mkey = json_key[i]; - }else{ - mkey = mkey + "@" + json_key[i]; - } - } - - //set map value - if (!mkey.empty()){ - if (json_map.find(mkey) == json_map.end()){ - json_map[mkey] = value; - }else{ - json_map[mkey] = json_map[mkey] + ","+ value; - } - } - - if (in_item_tag && value != "" && (xml_layer - in_item_tag) == 2) { - // (xml_layer - in_item_tag) == 2, this condition filters all deeper tags under tag "Item" - one_item[key] = value; - } - - value_start = NULL; - xml_layer--; - - if (json_key[xml_layer] == "Item") { - in_item_tag = 0; - // all items (DeviceList, Alarmstatus, RecordList) have "DeviceID" - if (one_item.find("DeviceID") != one_item.end()) - item_list.push_back(one_item); - } - } else if (p[0] == '<') { // xml item begin flag - //skip < - p +=1; - - // get Notify - char *s = p; - while (p[0] != '>') {p++;} - std::string key(s, p-s); - - if (srs_string_contains(key, "?xml")){ - //xml header - xml_header = key; - json_map["XmlHeader"] = xml_header; - }else { - // get DeviceList - std::vector vec = srs_string_split(key, " "); - if (vec.empty()){ - return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "prase xml"); - } - - key = vec.at(0); - - //key to map by xml_layer - // - // - // - // - //json_key[0] = "Notify" - //json_key[1] = "info" - json_key[xml_layer] = key; - if (json_key[xml_layer] == "Item") { - // "Item" won't be the first layer (xml_layer is 0) - in_item_tag = xml_layer; - one_item.clear(); - } - xml_layer++; - } - - p +=1; - value_start = p; - } else { - p++; - } - } - - // std::map::iterator it2; - // for (it2 = json_map.begin(); it2 != json_map.end(); ++it2) { - // srs_trace("========%s:%s", it2->first.c_str(), it2->second.c_str()); - // } - - return srs_success; -} - -srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_msg) -{ - srs_error_t err = srs_success; - - std::vector header_body = srs_string_split(recv_msg, SRS_RTSP_CRLFCRLF); - if (header_body.empty()){ - return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "parse reques message"); - } - - std::string header = header_body.at(0); - //Must be added SRS_RTSP_CRLFCRLF in order to handle the last line header - header += SRS_RTSP_CRLFCRLF; - std::string body = ""; - - if (header_body.size() > 1){ - // SRS_RTSP_CRLFCRLF may exist in content body (h3c) - string recv_str(recv_msg); - body = recv_str.substr(recv_str.find(SRS_RTSP_CRLFCRLF) + strlen(SRS_RTSP_CRLFCRLF)); - //body = header_body.at(1); - } - - srs_info("sip: header=%s\n", header.c_str()); - srs_info("sip: body=%s\n", body.c_str()); - - // parse one by one. - char* start = (char*)header.c_str(); - char* end = start + header.size(); - char* p = start; - char* newline_start = start; - std::string firstline = ""; - while (p < end) { - if (p[0] == '\r' && p[1] == '\n'){ - p +=2; - int linelen = (int)(p - newline_start); - std::string oneline(newline_start, linelen); - newline_start = p; - - if (firstline == ""){ - firstline = srs_string_replace(oneline, "\r\n", ""); - srs_info("sip: first line=%s", firstline.c_str()); - }else{ - size_t pos = oneline.find(":"); - if (pos != string::npos){ - if (pos != 0) { - //ex: CSeq: 100 MESSAGE header is 'CSeq:',content is '100 MESSAGE' - std::string head = oneline.substr(0, pos+1); - std::string content = oneline.substr(pos+1, oneline.length()-pos-1); - content = srs_string_replace(content, "\r\n", ""); - content = srs_string_trim_start(content, " "); - char *phead = (char*)head.c_str(); - - if (!strcasecmp(phead, "call-id:")) { - std::vector vec_callid = srs_string_split(content, " "); - req->call_id = vec_callid.empty() ? "" : vec_callid.at(0); - } - else if (!strcasecmp(phead, "contact:")) { - req->contact = content; - } - else if (!strcasecmp(phead, "content-encoding:")) { - srs_trace("sip: message head %s content=%s", phead, content.c_str()); - } - else if (!strcasecmp(phead, "content-length:")) { - req->content_length = strtoul(content.c_str(), NULL, 10); - } - else if (!strcasecmp(phead, "content-type:")) { - req->content_type = content; - } - else if (!strcasecmp(phead, "cseq:")) { - std::vector vec_seq = srs_string_split(content, " "); - std::string seq = vec_seq.empty() ? "" : vec_seq.at(0); - req->seq = strtoul(seq.c_str(), NULL, 10); - req->method = vec_seq.size() > 0 ? vec_seq.at(1) : ""; - } - else if (!strcasecmp(phead, "from:")) { - content = srs_string_replace(content, "sip:", ""); - req->from = srs_sip_get_form_to_uri(content.c_str()); - if (srs_string_contains(content, "tag")) { - req->from_tag = srs_sip_get_param(content.c_str(), "tag"); - } - - std::vector vec = srs_string_split(req->from, "@"); - if (vec.size() > 1){ - req->from_realm = vec.at(1); - } - } - else if (!strcasecmp(phead, "to:")) { - content = srs_string_replace(content, "sip:", ""); - req->to = srs_sip_get_form_to_uri(content.c_str()); - if (srs_string_contains(content, "tag")) { - req->to_tag = srs_sip_get_param(content.c_str(), "tag"); - } - - std::vector vec = srs_string_split(req->to, "@"); - if (vec.size() > 1){ - req->to_realm = vec.at(1); - } - } - else if (!strcasecmp(phead, "via:")) { - req->via = content; - req->branch = srs_sip_get_param(content.c_str(), "branch"); - } - else if (!strcasecmp(phead, "expires:")){ - req->expires = strtoul(content.c_str(), NULL, 10); - } - else if (!strcasecmp(phead, "user-agent:")){ - req->user_agent = content; - } - else if (!strcasecmp(phead, "max-forwards:")){ - req->max_forwards = strtoul(content.c_str(), NULL, 10); - } - else if (!strcasecmp(phead, "www-authenticate:")){ - req->www_authenticate = content; - } - else if (!strcasecmp(phead, "authorization:")){ - req->authorization = content; - } - else { - //TODO: fixme - srs_trace("sip: unkonw message head %s content=%s", phead, content.c_str()); - } - } - } - } - }else{ - p++; - } - } - - std::vector method_uri_ver = srs_string_split(firstline, " "); - - if (method_uri_ver.empty() || method_uri_ver.size() < 3) { - return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "parse request firstline is empty or less than 3 fields"); - } - - //respone first line text:SIP/2.0 200 OK - if (!strcasecmp(method_uri_ver.at(0).c_str(), "sip/2.0")) { - req->cmdtype = SrsSipCmdRespone; - //req->method= vec_seq.at(1); - req->status = method_uri_ver.size() > 1 ? method_uri_ver.at(1) : ""; - req->version = method_uri_ver.at(0); - req->uri = req->from; - - vector str = srs_string_split(req->to, "@"); - std::string ss = str.empty() ? "" : str.at(0); - req->sip_auth_id = srs_string_replace(ss, "sip:", ""); - - }else {//request first line text :MESSAGE sip:34020000002000000001@3402000000 SIP/2.0 - req->cmdtype = SrsSipCmdRequest; - req->method= method_uri_ver.at(0); - req->uri = method_uri_ver.size() > 1 ? method_uri_ver.at(1) : ""; - req->version = method_uri_ver.size() > 2 ? method_uri_ver.at(2) : ""; - - vector str = srs_string_split(req->from, "@"); - std::string ss = str.empty() ? "" : str.at(0); - req->sip_auth_id = srs_string_replace(ss, "sip:", ""); - } - - req->sip_username = req->sip_auth_id; - - //Content-Type: Application/MANSCDP+xml - if (!strcasecmp(req->content_type.c_str(),"application/manscdp+xml")){ - //xml to map - if ((err = parse_xml(body, req->xml_body_map, req->item_list)) != srs_success) { - return srs_error_wrap(err, "sip parse xml"); - }; - - //Response Cmd - if (req->xml_body_map.find("Response") != req->xml_body_map.end()){ - std::string cmdtype = req->xml_body_map["Response@CmdType"]; - if (cmdtype == "Catalog"){ - #if 0 - //Response@DeviceList@Item@DeviceID:3000001,3000002 - std::vector vec_device_id = srs_string_split(req->xml_body_map["Response@DeviceList@Item@DeviceID"], ","); - //Response@DeviceList@Item@Status:ON,OFF - std::vector vec_device_status = srs_string_split(req->xml_body_map["Response@DeviceList@Item@Status"], ","); - - //map key:devicd_id value:status - for(int i=0 ; i< (int)vec_device_id.size(); i++){ - std::string status = ""; - if ((int)vec_device_status.size() > i) { - status = vec_device_status.at(i); - } - - req->device_list_map[vec_device_id.at(i)] = status; - } - #endif - for(int i=0 ; i< (int)req->item_list.size(); i++){ - std::map one_item = req->item_list.at(i); - std::string status; - if (one_item.find("Status") != one_item.end() && one_item.find("Name") != one_item.end()) { - status = one_item["Status"] + "," + one_item["Name"]; - } else { - // if no Status, it's not a camera but a group - continue; - } - req->device_list_map[one_item["DeviceID"]] = status; - } - }else{ - //TODO: fixme - srs_trace("sip: Response cmdtype=%s not processed", cmdtype.c_str()); - } - } //Notify Cmd - else if (req->xml_body_map.find("Notify") != req->xml_body_map.end()){ - std::string cmdtype = req->xml_body_map["Notify@CmdType"]; - if (cmdtype == "Keepalive"){ - //TODO: ???? - std::vector vec_device_id = srs_string_split(req->xml_body_map["Notify@Info@DeviceID"], ","); - for(int i=0; i< (int)vec_device_id.size(); i++){ - //req->device_list_map[vec_device_id.at(i)] = "OFF"; - } - }else{ - //TODO: fixme - srs_trace("sip: Notify cmdtype=%s not processed", cmdtype.c_str()); - } - }// end if(req->xml_body_map) - }//end if (!strcasecmp) - else if (!strcasecmp(req->content_type.c_str(),"application/sdp")) { - std::vector sdp_lines = srs_string_split(body.c_str(), SRS_RTSP_CRLF); - for(int i=0 ; i< (int)sdp_lines.size(); i++){ - if (!strncasecmp(sdp_lines.at(i).c_str(), "y=", 2)) { - string yline = sdp_lines.at(i); - string ssrc = yline.substr(2); - req->y_ssrc = strtoul(ssrc.c_str(), NULL, 10); - srs_trace("gb28181: ssrc in y line is %u:%x", req->y_ssrc, req->y_ssrc); - break; - } - } - } - - srs_info("sip: method=%s uri=%s version=%s cmdtype=%s", - req->method.c_str(), req->uri.c_str(), req->version.c_str(), req->get_cmdtype_str().c_str()); - srs_info("via=%s", req->via.c_str()); - srs_info("via_branch=%s", req->branch.c_str()); - srs_info("cseq=%d", req->seq); - srs_info("contact=%s", req->contact.c_str()); - srs_info("from=%s", req->from.c_str()); - srs_info("to=%s", req->to.c_str()); - srs_info("callid=%s", req->call_id.c_str()); - srs_info("status=%s", req->status.c_str()); - srs_info("from_tag=%s", req->from_tag.c_str()); - srs_info("to_tag=%s", req->to_tag.c_str()); - srs_info("sip_auth_id=%s", req->sip_auth_id.c_str()); - - return err; -} - -std::string SrsSipStack::get_sip_from(SrsSipRequest const *req) -{ - std::string from_tag; - if (req->from_tag.empty()){ - from_tag = ""; - }else { - from_tag = ";tag=" + req->from_tag; - } - - return "from + ">" + from_tag; -} - -std::string SrsSipStack::get_sip_to(SrsSipRequest const *req) -{ - std::string to_tag; - if (req->to_tag.empty()){ - to_tag = ""; - }else { - to_tag = ";tag=" + req->to_tag; - } - - return "to + ">" + to_tag; -} - -std::string SrsSipStack::get_sip_via(SrsSipRequest const *req) -{ - std::string via = srs_string_replace(req->via, SRS_SIP_VERSION"/UDP ", ""); - std::vector vec_via = srs_string_split(via, ";"); - - std::string ip_port = vec_via.empty() ? "" : vec_via.at(0); - std::vector vec_ip_port = srs_string_split(ip_port, ":"); - - std::string ip = vec_ip_port.empty() ? "" : vec_ip_port.at(0); - std::string port = vec_ip_port.size() > 1 ? vec_ip_port.at(1) : ""; - - std::string branch, rport, received; - if (req->branch.empty()){ - branch = ""; - }else { - branch = ";branch=" + req->branch; - } - - if (!req->peer_ip.empty()){ - ip = req->peer_ip; - - std::stringstream ss; - ss << req->peer_port; - port = ss.str(); - } - - received = ";received=" + ip; - rport = ";rport=" + port; - - return SRS_SIP_VERSION"/UDP " + ip_port + rport + received + branch; -} - -void SrsSipStack::resp_keepalive(std::stringstream& ss, SrsSipRequest *req) -{ - ss << SRS_SIP_VERSION <<" 200 OK" << SRS_RTSP_CRLF - << "Via: " << SRS_SIP_VERSION << "/UDP " << req->host << ":" << req->host_port << ";branch=" << req->branch << SRS_RTSP_CRLF - << "From: from.c_str() << ">;tag=" << req->from_tag << SRS_RTSP_CRLF - << "To: to.c_str() << ">\r\n" - << "Call-ID: " << req->call_id << SRS_RTSP_CRLF - << "CSeq: " << req->seq << " " << req->method << SRS_RTSP_CRLF - << "Contact: "<< req->contact << SRS_RTSP_CRLF - << "Max-Forwards: 70" << SRS_RTSP_CRLF - << "User-Agent: "<< SRS_SIP_USER_AGENT << SRS_RTSP_CRLF - << "Content-Length: 0" << SRS_RTSP_CRLFCRLF; -} - -void SrsSipStack::resp_status(stringstream& ss, SrsSipRequest *req) -{ - if (req->method == "REGISTER"){ - /* - //request: sip-agent-----REGISTER------->sip-server - REGISTER sip:34020000002000000001@3402000000 SIP/2.0 - Via: SIP/2.0/UDP 192.168.137.11:5060;rport;branch=z9hG4bK1371463273 - From: ;tag=2043466181 - To: - Call-ID: 1011047669 - CSeq: 1 REGISTER - Contact: - Max-Forwards: 70 - User-Agent: IP Camera - Expires: 3600 - Content-Length: 0 - - //response: sip-agent<-----200 OK--------sip-server - SIP/2.0 200 OK - Via: SIP/2.0/UDP 192.168.137.11:5060;rport;branch=z9hG4bK1371463273 - From: - To: - CSeq: 1 REGISTER - Call-ID: 1011047669 - Contact: - User-Agent: SRS/4.0.4(Leo) - Expires: 3600 - Content-Length: 0 - - */ - if (req->authorization.empty()){ - //TODO: fixme supoort 401 - //return req_401_unauthorized(ss, req); - } - - ss << SRS_SIP_VERSION <<" 200 OK" << SRS_RTSP_CRLF - << "Via: " << get_sip_via(req) << SRS_RTSP_CRLF - << "From: "<< get_sip_from(req) << SRS_RTSP_CRLF - << "To: "<< get_sip_to(req) << SRS_RTSP_CRLF - << "CSeq: "<< req->seq << " " << req->method << SRS_RTSP_CRLF - << "Call-ID: " << req->call_id << SRS_RTSP_CRLF - << "Contact: " << req->contact << SRS_RTSP_CRLF - << "User-Agent: " << SRS_SIP_USER_AGENT << SRS_RTSP_CRLF - << "Expires: " << req->expires << SRS_RTSP_CRLF - << "Content-Length: 0" << SRS_RTSP_CRLFCRLF; - }else{ - /* - //request: sip-agnet-------MESSAGE------->sip-server - MESSAGE sip:34020000002000000001@3402000000 SIP/2.0 - Via: SIP/2.0/UDP 192.168.137.11:5060;rport;branch=z9hG4bK1066375804 - From: ;tag=1925919231 - To: - Call-ID: 1185236415 - CSeq: 20 MESSAGE - Content-Type: Application/MANSCDP+xml - Max-Forwards: 70 - User-Agent: IP Camera - Content-Length: 175 - - - - Keepalive - 1 - 34020000001320000003 - OK - - - - //response: sip-agent------200 OK --------> sip-server - SIP/2.0 200 OK - Via: SIP/2.0/UDP 192.168.137.11:5060;rport;branch=z9hG4bK1066375804 - From: - To: - CSeq: 20 MESSAGE - Call-ID: 1185236415 - User-Agent: SRS/4.0.4(Leo) - Content-Length: 0 - - */ - - ss << SRS_SIP_VERSION <<" 200 OK" << SRS_RTSP_CRLF - << "Via: " << get_sip_via(req) << SRS_RTSP_CRLF - << "From: " << get_sip_from(req) << SRS_RTSP_CRLF - << "To: "<< get_sip_to(req) << SRS_RTSP_CRLF - << "CSeq: "<< req->seq << " " << req->method << SRS_RTSP_CRLF - << "Call-ID: " << req->call_id << SRS_RTSP_CRLF - << "User-Agent: " << SRS_SIP_USER_AGENT << SRS_RTSP_CRLF - << "Content-Length: 0" << SRS_RTSP_CRLFCRLF; - } - -} - -void SrsSipStack::req_invite(stringstream& ss, SrsSipRequest *req, string ip, int port, uint32_t ssrc, bool tcpFlag) -{ - /* - //request: sip-agent <-------INVITE------ sip-server - INVITE sip:34020000001320000003@3402000000 SIP/2.0 - Via: SIP/2.0/UDP 39.100.155.146:15063;rport;branch=z9hG4bK34208805 - From: ;tag=512358805 - To: - Call-ID: 200008805 - CSeq: 20 INVITE - Content-Type: Application/SDP - Contact: - Max-Forwards: 70 - User-Agent: SRS/4.0.4(Leo) - Subject: 34020000001320000003:630886,34020000002000000001:0 - Content-Length: 164 - - v=0 - o=34020000001320000003 0 0 IN IP4 39.100.155.146 - s=Play - c=IN IP4 39.100.155.146 - t=0 0 - m=video 9000 RTP/AVP 96 - a=recvonly - a=rtpmap:96 PS/90000 - y=630886 - //response: sip-agent --------100 Trying--------> sip-server - SIP/2.0 100 Trying - Via: SIP/2.0/UDP 39.100.155.146:15063;rport=15063;branch=z9hG4bK34208805 - From: ;tag=512358805 - To: - Call-ID: 200008805 - CSeq: 20 INVITE - User-Agent: IP Camera - Content-Length: 0 - - //response: sip-agent -------200 OK--------> sip-server - SIP/2.0 200 OK - Via: SIP/2.0/UDP 39.100.155.146:15063;rport=15063;branch=z9hG4bK34208805 - From: ;tag=512358805 - To: ;tag=1083111311 - Call-ID: 200008805 - CSeq: 20 INVITE - Contact: - Content-Type: application/sdp - User-Agent: IP Camera - Content-Length: 263 - - v=0 - o=34020000001320000003 1073 1073 IN IP4 192.168.137.11 - s=Play - c=IN IP4 192.168.137.11 - t=0 0 - m=video 15060 RTP/AVP 96 - a=setup:active - a=sendonly - a=rtpmap:96 PS/90000 - a=username:34020000001320000003 - a=password:12345678 - a=filesize:0 - y=0000630886 - f= - //request: sip-agent <------ ACK ------- sip-server - ACK sip:34020000001320000003@3402000000 SIP/2.0 - Via: SIP/2.0/UDP 39.100.155.146:15063;rport;branch=z9hG4bK34208805 - From: ;tag=512358805 - To: - Call-ID: 200008805 - CSeq: 20 ACK - Max-Forwards: 70 - User-Agent: SRS/4.0.4(Leo) - Content-Length: 0 - */ - char _ssrc[11]; - sprintf(_ssrc, "%010d", ssrc); - - std::stringstream sdp; - if (!tcpFlag){ - sdp << "v=0" << SRS_RTSP_CRLF - << "o=" << req->serial << " 0 0 IN IP4 " << ip << SRS_RTSP_CRLF - << "s=Play" << SRS_RTSP_CRLF - << "c=IN IP4 " << ip << SRS_RTSP_CRLF - << "t=0 0" << SRS_RTSP_CRLF - //TODO 97 98 99 current no support - //<< "m=video " << port <<" RTP/AVP 96 97 98 99" << SRS_RTSP_CRLF - << "m=video " << port <<" RTP/AVP 96" << SRS_RTSP_CRLF - << "a=recvonly" << SRS_RTSP_CRLF - << "a=rtpmap:96 PS/90000" << SRS_RTSP_CRLF - //TODO: current no support - //<< "a=rtpmap:97 MPEG4/90000" << SRS_RTSP_CRLF - //<< "a=rtpmap:98 H264/90000" << SRS_RTSP_CRLF - //<< "a=rtpmap:99 H265/90000" << SRS_RTSP_CRLF - //<< "a=streamMode:MAIN\r\n" - //<< "a=filesize:0\r\n" - << "y=" << _ssrc << SRS_RTSP_CRLF; - } else { - sdp << "v=0" << SRS_RTSP_CRLF - << "o=" << req->serial << " 0 0 IN IP4 " << ip << SRS_RTSP_CRLF - << "s=Play" << SRS_RTSP_CRLF - << "c=IN IP4 " << ip << SRS_RTSP_CRLF - << "t=0 0" << SRS_RTSP_CRLF - //TODO 97 98 99 current no support - //<< "m=video " << port <<" RTP/AVP 96 97 98 99" << SRS_RTSP_CRLF - //<< "m=video " << port <<" RTP/AVP 96" << SRS_RTSP_CRLF - << "m=video " << port << " TCP/RTP/AVP 96" << SRS_RTSP_CRLF - //<< "m=video " << port << " TCP/RTP/AVP 98" << SRS_RTSP_CRLF - << "a=recvonly" << SRS_RTSP_CRLF - << "a=rtpmap:96 PS/90000" << SRS_RTSP_CRLF - << "a=setup:passive" << SRS_RTSP_CRLF - << "a=connection:new" << SRS_RTSP_CRLF - //TODO: current no support - //<< "a=rtpmap:97 MPEG4/90000" << SRS_RTSP_CRLF - //<< "a=rtpmap:98 H264/90000" << SRS_RTSP_CRLF - //<< "a=rtpmap:99 H265/90000" << SRS_RTSP_CRLF - //<< "a=streamMode:MAIN\r\n" - //<< "a=filesize:0\r\n" - << "y=" << _ssrc << SRS_RTSP_CRLF; - } - - - std::stringstream from, to, uri; - //"INVITE sip:34020000001320000001@3402000000 SIP/2.0\r\n - uri << "sip:" << req->chid << "@" << req->realm; - //From: ;tag=500485%d\r\n - from << req->serial << "@" << req->realm; - to << req->chid << "@" << req->realm; - - req->from = from.str(); - req->to = to.str(); - - if (!req->to_realm.empty()){ - req->to = req->chid + "@" + req->to_realm; - } - - if (!req->from_realm.empty()){ - req->from = req->serial + "@" + req->from_realm; - } - - req->uri = uri.str(); - - req->call_id = srs_sip_generate_call_id(); - req->branch = srs_sip_generate_branch(); - req->from_tag = srs_sip_generate_from_tag(); - - ss << "INVITE " << req->uri << " " << SRS_SIP_VERSION << SRS_RTSP_CRLF - << "Via: " << SRS_SIP_VERSION << "/UDP "<< req->host << ":" << req->host_port << ";rport;branch=" << req->branch << SRS_RTSP_CRLF - << "From: " << get_sip_from(req) << SRS_RTSP_CRLF - << "To: " << get_sip_to(req) << SRS_RTSP_CRLF - << "Call-ID: " << req->call_id <seq << " INVITE" << SRS_RTSP_CRLF - << "Content-Type: Application/SDP" << SRS_RTSP_CRLF - << "Contact: to << ">" << SRS_RTSP_CRLF - << "Max-Forwards: 70" << SRS_RTSP_CRLF - << "User-Agent: " << SRS_SIP_USER_AGENT <chid << ":" << _ssrc << "," << req->serial << ":0" << SRS_RTSP_CRLF - << "Content-Length: " << sdp.str().length() << SRS_RTSP_CRLFCRLF - << sdp.str(); -} - - -void SrsSipStack::req_401_unauthorized(std::stringstream& ss, SrsSipRequest *req) -{ - /* sip-agent <-----401 Unauthorized ------ sip-server - SIP/2.0 401 Unauthorized - Via: SIP/2.0/UDP 192.168.137.92:5061;rport=61378;received=192.168.1.13;branch=z9hG4bK802519080 - From: ;tag=611442989 - To: ;tag=102092689 - CSeq: 1 REGISTER - Call-ID: 1650345118 - User-Agent: SRS/4.0.4(Leo) - Contact: - Content-Length: 0 - WWW-Authenticate: Digest realm="3402000000",qop="auth",nonce="f1da98bd160f3e2efe954c6eedf5f75a" - */ - - ss << SRS_SIP_VERSION <<" 401 Unauthorized" << SRS_RTSP_CRLF - //<< "Via: " << req->via << SRS_RTSP_CRLF - << "Via: " << get_sip_via(req) << SRS_RTSP_CRLF - << "From: " << get_sip_from(req) << SRS_RTSP_CRLF - << "To: " << get_sip_to(req) << SRS_RTSP_CRLF - << "CSeq: "<< req->seq << " " << req->method << SRS_RTSP_CRLF - << "Call-ID: " << req->call_id << SRS_RTSP_CRLF - << "Contact: " << req->contact << SRS_RTSP_CRLF - << "User-Agent: " << SRS_SIP_USER_AGENT << SRS_RTSP_CRLF - << "Content-Length: 0" << SRS_RTSP_CRLF - << "WWW-Authenticate: Digest realm=\"3402000000\",qop=\"auth\",nonce=\"f1da98bd160f3e2efe954c6eedf5f75a\"" << SRS_RTSP_CRLFCRLF; - return; -} - -void SrsSipStack::req_ack(std::stringstream& ss, SrsSipRequest *req){ - /* - //request: sip-agent <------ ACK ------- sip-server - ACK sip:34020000001320000003@3402000000 SIP/2.0 - Via: SIP/2.0/UDP 39.100.155.146:15063;rport;branch=z9hG4bK34208805 - From: ;tag=512358805 - To: - Call-ID: 200008805 - CSeq: 20 ACK - Max-Forwards: 70 - User-Agent: SRS/4.0.4(Leo) - Content-Length: 0 - */ - - ss << "ACK " << "sip:" << req->chid << "@" << req->realm << " "<< SRS_SIP_VERSION << SRS_RTSP_CRLF - << "Via: " << SRS_SIP_VERSION << "/UDP " << req->host << ":" << req->host_port << ";rport;branch=" << req->branch << SRS_RTSP_CRLF - << "From: " << get_sip_from(req) << SRS_RTSP_CRLF - << "To: "<< get_sip_to(req) << SRS_RTSP_CRLF - << "Call-ID: " << req->call_id << SRS_RTSP_CRLF - << "CSeq: " << req->seq << " ACK"<< SRS_RTSP_CRLF - << "Max-Forwards: 70" << SRS_RTSP_CRLF - << "User-Agent: "<< SRS_SIP_USER_AGENT << SRS_RTSP_CRLF - << "Content-Length: 0" << SRS_RTSP_CRLFCRLF; -} - -void SrsSipStack::req_bye(std::stringstream& ss, SrsSipRequest *req) -{ - /* - //request: sip-agent <------BYE------ sip-server - BYE sip:34020000001320000003@3402000000 SIP/2.0 - Via: SIP/2.0/UDP 39.100.155.146:15063;rport;branch=z9hG4bK34208805 - From: ;tag=512358805 - To: ;tag=1083111311 - Call-ID: 200008805 - CSeq: 79 BYE - Max-Forwards: 70 - User-Agent: SRS/4.0.4(Leo) - Content-Length: 0 - - //response: sip-agent ------200 OK ------> sip-server - SIP/2.0 200 OK - Via: SIP/2.0/UDP 39.100.155.146:15063;rport=15063;branch=z9hG4bK34208805 - From: ;tag=512358805 - To: ;tag=1083111311 - Call-ID: 200008805 - CSeq: 79 BYE - User-Agent: IP Camera - Content-Length: 0 - - */ - - std::stringstream from, to, uri; - uri << "sip:" << req->chid << "@" << req->realm; - from << req->serial << "@" << req->realm; - to << req->chid << "@" << req->realm; - - req->from = from.str(); - req->to = to.str(); - - if (!req->to_realm.empty()){ - req->to = req->chid + "@" + req->to_realm; - } - - if (!req->from_realm.empty()){ - req->from = req->serial + "@" + req->from_realm; - } - - req->uri = uri.str(); - - ss << "BYE " << req->uri << " "<< SRS_SIP_VERSION << SRS_RTSP_CRLF - //<< "Via: "<< SRS_SIP_VERSION << "/UDP "<< req->host << ":" << req->host_port << ";rport" << branch << SRS_RTSP_CRLF - << "Via: " << SRS_SIP_VERSION << "/UDP " << req->host << ":" << req->host_port << ";rport;branch=" << req->branch << SRS_RTSP_CRLF - << "From: " << get_sip_from(req) << SRS_RTSP_CRLF - << "To: " << get_sip_to(req) << SRS_RTSP_CRLF - //bye callid is inivte callid - << "Call-ID: " << req->call_id << SRS_RTSP_CRLF - << "CSeq: "<< req->seq <<" BYE" << SRS_RTSP_CRLF - << "Max-Forwards: 70" << SRS_RTSP_CRLF - << "User-Agent: " << SRS_SIP_USER_AGENT << SRS_RTSP_CRLF - << "Content-Length: 0" << SRS_RTSP_CRLFCRLF; - -} - -void SrsSipStack::req_query_catalog(std::stringstream& ss, SrsSipRequest *req) -{ - /* - //request: sip-agent <----MESSAGE Query Catalog--- sip-server - MESSAGE sip:34020000001110000001@192.168.1.21:5060 SIP/2.0 - Via: SIP/2.0/UDP 192.168.1.17:5060;rport;branch=z9hG4bK563315752 - From: ;tag=387315752 - To: - Call-ID: 728315752 - CSeq: 32 MESSAGE - Content-Type: Application/MANSCDP+xml - Max-Forwards: 70 - User-Agent: SRS/4.0.20(Leo) - Content-Length: 162 - - - - Catalog - 419315752 - 34020000001110000001 - - SIP/2.0 200 OK - Via: SIP/2.0/UDP 192.168.1.17:5060;rport=5060;branch=z9hG4bK563315752 - From: ;tag=387315752 - To: ;tag=1420696981 - Call-ID: 728315752 - CSeq: 32 MESSAGE - User-Agent: Embedded Net DVR/NVR/DVS - Content-Length: 0 - - //response: sip-agent ----MESSAGE Query Catalog---> sip-server - SIP/2.0 200 OK - Via: SIP/2.0/UDP 192.168.1.17:5060;rport=5060;received=192.168.1.17;branch=z9hG4bK563315752 - From: ;tag=387315752 - To: ;tag=1420696981 - CSeq: 32 MESSAGE - Call-ID: 728315752 - User-Agent: SRS/4.0.20(Leo) - Content-Length: 0 - - //request: sip-agent ----MESSAGE Response Catalog---> sip-server - MESSAGE sip:34020000001110000001@3402000000.spvmn.cn SIP/2.0 - Via: SIP/2.0/UDP 192.168.1.21:5060;rport;branch=z9hG4bK1681502633 - From: ;tag=1194168247 - To: - Call-ID: 685380150 - CSeq: 20 MESSAGE - Content-Type: Application/MANSCDP+xml - Max-Forwards: 70 - User-Agent: Embedded Net DVR/NVR/DVS - Content-Length: 909 - - - - Catalog - 419315752 - 34020000001110000001 - 8 - - - 34020000001320000001 - Camera 01 - Manufacturer - Camera - Owner - CivilCode -
    192.168.254.18
    - 0 - 0 - 1 - 0 - ON -
    - - 34020000001320000002 - IPCamera 02 - Manufacturer - Camera - Owner - CivilCode -
    192.168.254.14
    - 0 - 0 - 1 - 0 - OFF -
    -
    -
    - - */ - - std::stringstream xml; - std::string xmlbody; - - xml << "" << SRS_RTSP_CRLF - << "" << SRS_RTSP_CRLF - << "Catalog" << SRS_RTSP_CRLF - << "" << srs_sip_generate_sn() << "" << SRS_RTSP_CRLF - << "" << req->sip_auth_id << "" << SRS_RTSP_CRLF - << "" << SRS_RTSP_CRLF; - xmlbody = xml.str(); - - std::stringstream from, to, uri; - //"INVITE sip:34020000001320000001@3402000000 SIP/2.0\r\n - uri << "sip:" << req->sip_auth_id << "@" << req->realm; - //From: ;tag=500485%d\r\n - from << req->serial << "@" << req->host << ":" << req->host_port; - to << req->sip_auth_id << "@" << req->realm; - - req->from = from.str(); - req->to = to.str(); - req->uri = uri.str(); - - req->call_id = srs_sip_generate_call_id(); - req->branch = srs_sip_generate_branch(); - req->from_tag = srs_sip_generate_from_tag(); - - ss << "MESSAGE " << req->uri << " " << SRS_SIP_VERSION << SRS_RTSP_CRLF - << "Via: " << SRS_SIP_VERSION << "/UDP "<< req->host << ":" << req->host_port << ";rport;branch=" << req->branch << SRS_RTSP_CRLF - << "From: " << get_sip_from(req) << SRS_RTSP_CRLF - << "To: " << get_sip_to(req) << SRS_RTSP_CRLF - << "Call-ID: " << req->call_id << SRS_RTSP_CRLF - << "CSeq: " << req->seq << " MESSAGE" << SRS_RTSP_CRLF - << "Content-Type: Application/MANSCDP+xml" << SRS_RTSP_CRLF - << "Max-Forwards: 70" << SRS_RTSP_CRLF - << "User-Agent: " << SRS_SIP_USER_AGENT << SRS_RTSP_CRLF - << "Content-Length: " << xmlbody.length() << SRS_RTSP_CRLFCRLF - << xmlbody; - -} - -void SrsSipStack::req_ptz(std::stringstream& ss, SrsSipRequest *req, uint8_t cmd, uint8_t speed, int priority) -{ - - /* - - - DeviceControl - 11 - 34020000001310000053 - A50F01021F0000D6 - - */ - - uint8_t ptz_cmd[8] = {0}; - ptz_cmd[0] = SRS_SIP_PTZ_START; - ptz_cmd[1] = 0x0F; - ptz_cmd[2] = 0x01; - ptz_cmd[3] = cmd; - switch(cmd){ - case SrsSipPtzCmdStop: // = 0x00 - ptz_cmd[4] = 0; - ptz_cmd[5] = 0; - ptz_cmd[6] = 0; - break; - case SrsSipPtzCmdRight: // = 0x01, - case SrsSipPtzCmdLeft: // = 0x02, - ptz_cmd[4] = speed; - break; - case SrsSipPtzCmdDown: // = 0x04, - case SrsSipPtzCmdUp: // = 0x08, - ptz_cmd[5] = speed; - break; - case SrsSipPtzCmdZoomOut: // = 0x10, - case SrsSipPtzCmdZoomIn: // = 0x20 - ptz_cmd[6] = (speed & 0x0F) << 4; - break; - default: - return; - } - - uint32_t check = 0; - for (int i = 0; i < 7; i++){ - check += ptz_cmd[i]; - } - - ptz_cmd[7] = (uint8_t)(check % 256); - - std::stringstream ss_ptzcmd; - for (int i = 0; i < 8; i++){ - char hex_cmd[3] = {0}; - sprintf(hex_cmd, "%02X", ptz_cmd[i]); - ss_ptzcmd << hex_cmd; - } - - std::stringstream xml; - std::string xmlbody; - - xml << "" << SRS_RTSP_CRLF - << "" << SRS_RTSP_CRLF - << "DeviceControl" << SRS_RTSP_CRLF - << "" << srs_sip_generate_sn() << "" << SRS_RTSP_CRLF - << "" << req->sip_auth_id << "" << SRS_RTSP_CRLF - << "" << ss_ptzcmd.str() << "" << SRS_RTSP_CRLF - << "" << SRS_RTSP_CRLF - << "" << priority << "" << SRS_RTSP_CRLF - << "" << SRS_RTSP_CRLF - << "" << SRS_RTSP_CRLF; - xmlbody = xml.str(); - - std::stringstream from, to, uri, call_id; - //"INVITE sip:34020000001320000001@3402000000 SIP/2.0\r\n - uri << "sip:" << req->sip_auth_id << "@" << req->realm; - //From: ;tag=500485%d\r\n - from << req->serial << "@" << req->host << ":" << req->host_port; - to << req->sip_auth_id << "@" << req->realm; - - req->from = from.str(); - req->to = to.str(); - req->uri = uri.str(); - - req->call_id = srs_sip_generate_call_id(); - req->branch = srs_sip_generate_branch(); - req->from_tag = srs_sip_generate_from_tag(); - - ss << "MESSAGE " << req->uri << " "<< SRS_SIP_VERSION << SRS_RTSP_CRLF - //<< "Via: "<< SRS_SIP_VERSION << "/UDP "<< req->host << ":" << req->host_port << ";rport" << branch << SRS_RTSP_CRLF - << "Via: " << SRS_SIP_VERSION << "/UDP " << req->host << ":" << req->host_port << ";rport;branch=" << req->branch << SRS_RTSP_CRLF - << "From: " << get_sip_from(req) << SRS_RTSP_CRLF - << "To: " << get_sip_to(req) << SRS_RTSP_CRLF - << "Call-ID: " << req->call_id << SRS_RTSP_CRLF - << "CSeq: "<< req->seq <<" MESSAGE" << SRS_RTSP_CRLF - << "Content-Type: Application/MANSCDP+xml" << SRS_RTSP_CRLF - << "Max-Forwards: 70" << SRS_RTSP_CRLF - << "User-Agent: " << SRS_SIP_USER_AGENT << SRS_RTSP_CRLF - << "Content-Length: " << xmlbody.length() << SRS_RTSP_CRLFCRLF - << xmlbody; - -} - diff --git a/trunk/src/app/srs_app_gb28181_stack.hpp b/trunk/src/app/srs_app_gb28181_stack.hpp deleted file mode 100644 index e461115ef..000000000 --- a/trunk/src/app/srs_app_gb28181_stack.hpp +++ /dev/null @@ -1,168 +0,0 @@ -// -// Copyright (c) 2013-2021 Lixin -// -// SPDX-License-Identifier: MIT -// - -#ifndef SRS_APP_GB28181_STACK_HPP -#define SRS_APP_GB28181_STACK_HPP - -#include - -#include -#include -#include -#include - -#include -#include - -class SrsBuffer; -class SrsSimpleStream; -class SrsAudioFrame; - -// SIP methods -#define SRS_SIP_METHOD_REGISTER "REGISTER" -#define SRS_SIP_METHOD_MESSAGE "MESSAGE" -#define SRS_SIP_METHOD_INVITE "INVITE" -#define SRS_SIP_METHOD_ACK "ACK" -#define SRS_SIP_METHOD_BYE "BYE" - -// SIP-Version -#define SRS_SIP_VERSION "SIP/2.0" -#define SRS_SIP_USER_AGENT RTMP_SIG_SRS_SERVER - -#define SRS_SIP_PTZ_START 0xA5 - - -enum SrsSipCmdType{ - SrsSipCmdRequest=0, - SrsSipCmdRespone=1 -}; - -enum SrsSipPtzCmdType{ - SrsSipPtzCmdStop = 0x00, - SrsSipPtzCmdRight = 0x01, - SrsSipPtzCmdLeft = 0x02, - SrsSipPtzCmdDown = 0x04, - SrsSipPtzCmdUp = 0x08, - SrsSipPtzCmdZoomIn = 0x10, - SrsSipPtzCmdZoomOut = 0x20 -}; - -std::string srs_sip_get_utc_date(); - -class SrsSipRequest -{ -public: - //sip header member - std::string method; - std::string uri; - std::string version; - std::string status; - - std::string via; - std::string from; - std::string to; - std::string from_tag; - std::string to_tag; - std::string branch; - - std::string call_id; - long seq; - - std::string contact; - std::string user_agent; - - std::string content_type; - long content_length; - - long expires; - int max_forwards; - - std::string www_authenticate; - std::string authorization; - - std::string chid; - - std::map xml_body_map; - std::map device_list_map; - // add an item_list, you can do a lot of other things - // used by DeviceList, Alarmstatus, RecordList in "GB/T 28181—2016" - std::vector > item_list; - -public: - std::string serial; - std::string realm; - std::string sip_auth_id; - std::string sip_auth_pwd; - std::string sip_username; - std::string peer_ip; - int peer_port; - std::string host; - int host_port; - SrsSipCmdType cmdtype; - - std::string from_realm; - std::string to_realm; - uint32_t y_ssrc; - -public: - SrsRtspSdp* sdp; - SrsRtspTransport* transport; -public: - SrsSipRequest(); - virtual ~SrsSipRequest(); -public: - virtual bool is_register(); - virtual bool is_invite(); - virtual bool is_message(); - virtual bool is_ack(); - virtual bool is_bye(); - - virtual void copy(SrsSipRequest* src); -public: - virtual std::string get_cmdtype_str(); -}; - -// The gb28181 sip protocol stack. -class SrsSipStack -{ -private: - // The cached bytes buffer. - SrsSimpleStream* buf; -public: - SrsSipStack(); - virtual ~SrsSipStack(); -public: - virtual srs_error_t parse_request(SrsSipRequest** preq, const char *recv_msg, int nb_buf); -protected: - virtual srs_error_t do_parse_request(SrsSipRequest* req, const char *recv_msg); - virtual srs_error_t parse_xml(std::string xml_msg, std::map &json_map, std::vector > &item_list); - -private: - //response from - virtual std::string get_sip_from(SrsSipRequest const *req); - //response to - virtual std::string get_sip_to(SrsSipRequest const *req); - //response via - virtual std::string get_sip_via(SrsSipRequest const *req); - -public: - //response: request sent by the sip-agent, wait for sip-server response - virtual void resp_status(std::stringstream& ss, SrsSipRequest *req); - virtual void resp_keepalive(std::stringstream& ss, SrsSipRequest *req); - - //request: request sent by the sip-server, wait for sip-agent response - virtual void req_invite(std::stringstream& ss, SrsSipRequest *req, std::string ip, - int port, uint32_t ssrc, bool tcpFlag); - virtual void req_ack(std::stringstream& ss, SrsSipRequest *req); - virtual void req_bye(std::stringstream& ss, SrsSipRequest *req); - virtual void req_401_unauthorized(std::stringstream& ss, SrsSipRequest *req); - virtual void req_query_catalog(std::stringstream& ss, SrsSipRequest *req); - virtual void req_ptz(std::stringstream& ss, SrsSipRequest *req, uint8_t cmd, uint8_t speed, int priority); - -}; - -#endif - diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 7fe24d5ca..5087a825e 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1299,200 +1299,6 @@ srs_error_t SrsGoApiError::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage return srs_api_response_code(w, r, 100); } -#ifdef SRS_GB28181 -SrsGoApiGb28181::SrsGoApiGb28181() -{ -} - -SrsGoApiGb28181::~SrsGoApiGb28181() -{ -} - -srs_error_t SrsGoApiGb28181::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) -{ - srs_error_t err = srs_success; - - if ((err = do_serve_http(w, r)) != srs_success) { - srs_warn("Server GB28181 err %s", srs_error_desc(err).c_str()); - int code = srs_error_code(err); srs_error_reset(err); - return srs_api_response_code(w, r, code); - } - - return err; -} - -srs_error_t SrsGoApiGb28181::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) -{ - srs_error_t err = srs_success; - - SrsJsonObject* obj = SrsJsonAny::object(); - SrsAutoFree(SrsJsonObject, obj); - - obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); - SrsJsonObject* data = SrsJsonAny::object(); - obj->set("data", data); - - string id = r->query_get("id"); - string action = r->query_get("action"); - string vhost = r->query_get("vhost"); - string app = r->query_get("app"); - string stream = r->query_get("stream"); - //fixed, random - string port_mode = r->query_get("port_mode"); - - if (!_srs_gb28181) { - return srs_error_new(ERROR_GB28181_SERVER_NOT_RUN, "no gb28181 engine"); - } - - if(action == "create_channel"){ - if (id.empty()){ - return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id"); - } - - SrsGb28181StreamChannel channel; - channel.set_channel_id(id); - channel.set_app(app); - channel.set_stream(stream); - channel.set_port_mode(port_mode); - - if ((err = _srs_gb28181->create_stream_channel(&channel)) != srs_success) { - return srs_error_wrap(err, "create stream channel"); - } - - data->set("query", SrsJsonAny::object() - ->set("id", SrsJsonAny::str(channel.get_channel_id().c_str())) - ->set("ip", SrsJsonAny::str(channel.get_ip().c_str())) - ->set("rtmp_port", SrsJsonAny::integer(channel.get_rtmp_port())) - ->set("app", SrsJsonAny::str(channel.get_app().c_str())) - ->set("stream", SrsJsonAny::str(channel.get_stream().c_str())) - ->set("rtp_port", SrsJsonAny::integer(channel.get_rtp_port())) - ->set("ssrc", SrsJsonAny::integer(channel.get_ssrc()))); - return srs_api_response(w, r, obj->dumps()); - - } else if(action == "delete_channel"){ - string chid = r->query_get("chid"); - if (id.empty() || chid.empty()){ - return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id or chid"); - } - - if ((err = _srs_gb28181->delete_stream_channel(id, chid)) != srs_success) { - return srs_error_wrap(err, "delete stream channel"); - } - - return srs_api_response_code(w, r, 0); - } else if(action == "query_channel") { - SrsJsonArray* arr = SrsJsonAny::array(); - data->set("channels", arr); - - if ((err = _srs_gb28181->query_stream_channel(id, arr)) != srs_success) { - return srs_error_wrap(err, "query stream channel"); - } - - return srs_api_response(w, r, obj->dumps()); - } else if(action == "sip_invite"){ - string chid = r->query_get("chid"); - if (id.empty() || chid.empty()){ - return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id or chid"); - } - - string ssrc = r->query_get("ssrc"); - string rtp_port = r->query_get("rtp_port"); - string ip = r->query_get("ip"); - - int _port = strtoul(rtp_port.c_str(), NULL, 10); - uint32_t _ssrc = (uint32_t)(strtoul(ssrc.c_str(), NULL, 10)); - - if ((err = _srs_gb28181->notify_sip_invite(id, ip, _port, _ssrc, chid)) != srs_success) { - return srs_error_wrap(err, "notify sip invite"); - } - - return srs_api_response_code(w, r, 0); - } else if(action == "sip_bye"){ - string chid = r->query_get("chid"); - if (id.empty() || chid.empty()){ - return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id or chid"); - } - - if ((err = _srs_gb28181->notify_sip_bye(id, chid)) != srs_success) { - return srs_error_wrap(err, "notify sip bye"); - } - - return srs_api_response_code(w, r, 0); - } else if(action == "sip_ptz"){ - string chid = r->query_get("chid"); - string ptzcmd = r->query_get("ptzcmd"); - string speed = r->query_get("speed"); - string priority = r->query_get("priority"); - if (id.empty() || chid.empty() || ptzcmd.empty() || speed.empty()){ - return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id or chid or ptzcmd or speed"); - } - - uint8_t _speed = (uint8_t)(strtoul(speed.c_str(), NULL, 10)); - int _priority = (int)(strtoul(priority.c_str(), NULL, 10)); - - if ((err = _srs_gb28181->notify_sip_ptz(id, chid, ptzcmd, _speed, _priority)) != srs_success) { - return srs_error_wrap(err, "notify sip ptz"); - } - - return srs_api_response_code(w, r, 0); - } else if(action == "sip_raw_data"){ - if (id.empty()){ - return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id"); - } - - std::string body; - r->body_read_all(body); - - if ((err = _srs_gb28181->notify_sip_raw_data(id, body)) != srs_success) { - return srs_error_wrap(err, "notify sip raw data"); - } - - return srs_api_response_code(w, r, 0); - } else if(action == "sip_unregister"){ - if (id.empty()){ - return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id"); - } - - if ((err = _srs_gb28181->notify_sip_unregister(id)) != srs_success) { - return srs_error_wrap(err, "notify sip unregister"); - } - - return srs_api_response_code(w, r, 0); - } else if(action == "sip_query_catalog"){ - if (id.empty()){ - return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id"); - } - - if ((err = _srs_gb28181->notify_sip_query_catalog(id)) != srs_success) { - return srs_error_wrap(err, "notify sip query catelog"); - } - - return srs_api_response_code(w, r, 0); - } else if(action == "sip_query_devicelist"){ - SrsJsonArray* arr = SrsJsonAny::array(); - data->set("PlatformID", SrsJsonAny::str(_srs_gb28181->get_gb28181_config_ptr()->sip_serial.c_str())); - data->set("DeviceList", arr); - - if ((err = _srs_gb28181->query_device_list("", arr)) != srs_success) { - return srs_error_wrap(err, "query device list"); - } - - return srs_api_response(w, r, obj->dumps()); - } else if(action == "sip_query_session"){ - SrsJsonArray* arr = SrsJsonAny::array(); - data->set("sessions", arr); - - if ((err = _srs_gb28181->query_sip_session(id, arr)) != srs_success) { - return srs_error_wrap(err, "notify sip session"); - } - - return srs_api_response(w, r, obj->dumps()); - } else { - return srs_error_new(ERROR_GB28181_ACTION_INVALID, "action %s", action.c_str()); - } -} -#endif - #ifdef SRS_GPERF #include diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 0815cd8cc..50079b673 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -205,19 +205,6 @@ class SrsGoApiError : public ISrsHttpHandler virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); }; -#ifdef SRS_GB28181 -class SrsGoApiGb28181 : public ISrsHttpHandler -{ -public: - SrsGoApiGb28181(); - virtual ~SrsGoApiGb28181(); -public: - virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); -private: - virtual srs_error_t do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); -}; -#endif - #ifdef SRS_GPERF class SrsGoApiTcmalloc : public ISrsHttpHandler { diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index 5c18ae24c..78ce829f8 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -943,17 +943,6 @@ srs_error_t SrsRtmpConn::acquire_publish(SrsLiveSource* source) srs_error_t err = srs_success; SrsRequest* req = info->req; - - // @see https://github.com/ossrs/srs/issues/2364 - // Check whether GB28181 stream is busy. -#if defined(SRS_GB28181) - if (_srs_gb28181 != NULL) { - SrsGb28181RtmpMuxer* gb28181 = _srs_gb28181->fetch_rtmpmuxer(req->stream); - if (gb28181 != NULL) { - return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "gb28181 stream %s busy", req->get_stream_url().c_str()); - } - } -#endif // Check whether RTC stream is busy. #ifdef SRS_RTC diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 7d559cc63..554a61219 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -35,8 +35,6 @@ using namespace std; #include #include #include -#include -#include std::string srs_listener_type2string(SrsListenerType type) { @@ -57,10 +55,6 @@ std::string srs_listener_type2string(SrsListenerType type) return "RTSP"; case SrsListenerFlv: return "HTTP-FLV"; - case SrsListenerGb28181Sip: - return "GB28181-SIP over UDP"; - case SrsListenerGb28181RtpMux: - return "GB28181-Stream over RTP"; default: return "UNKONWN"; } @@ -253,9 +247,7 @@ srs_error_t SrsUdpStreamListener::listen(string i, int p) // the caller already ensure the type is ok, // we just assert here for unknown stream caster. - srs_assert(type == SrsListenerMpegTsOverUdp - || type == SrsListenerGb28181Sip - || type == SrsListenerGb28181RtpMux); + srs_assert(type == SrsListenerMpegTsOverUdp); ip = i; port = p; @@ -293,85 +285,6 @@ SrsUdpCasterListener::~SrsUdpCasterListener() srs_freep(caster); } -#ifdef SRS_GB28181 - -SrsGb28181Listener::SrsGb28181Listener(SrsServer* svr, SrsListenerType t, SrsConfDirective* c) : SrsUdpStreamListener(svr, t, NULL) -{ - // the caller already ensure the type is ok, - // we just assert here for unknown stream caster. - srs_assert(type == SrsListenerGb28181Sip - ||type == SrsListenerGb28181RtpMux); - - if (type == SrsListenerGb28181Sip) { - caster = new SrsGb28181SipService(c); - }else if(type == SrsListenerGb28181RtpMux){ - caster = new SrsGb28181RtpMuxService(c); - } -} - -SrsGb28181Listener::~SrsGb28181Listener() -{ - srs_freep(caster); -} - -SrsGb28181TcpListener::SrsGb28181TcpListener(SrsServer* svr, SrsListenerType t, SrsConfDirective* c) : SrsListener(svr, t) -{ - // the caller already ensure the type is ok, - // we just assert here for unknown stream caster. - srs_assert(type == SrsListenerGb28181RtpMux); - - caster = new SrsGb28181Caster(c); - listener = NULL; -} - -SrsGb28181TcpListener::~SrsGb28181TcpListener() -{ - srs_freep(caster); - srs_freep(listener); -} - -srs_error_t SrsGb28181TcpListener::listen(std::string i, int p) -{ - srs_error_t err = srs_success; - - // the caller already ensure the type is ok, - // we just assert here for unknown stream caster. - srs_assert(type == SrsListenerGb28181RtpMux); - - ip = i; - port = p; - - if ((err = caster->initialize()) != srs_success) { - return srs_error_wrap(err, "init caster"); - } - - srs_freep(listener); - listener = new SrsTcpListener(this, ip, port); - - if ((err = listener->listen()) != srs_success) { - return srs_error_wrap(err, "rtsp listen %s:%d", ip.c_str(), port); - } - - string v = srs_listener_type2string(type); - - return err; -} - -srs_error_t SrsGb28181TcpListener::on_tcp_client(srs_netfd_t stfd) -{ - int fd = srs_netfd_fileno(stfd); - string ip = srs_get_peer_ip(fd); - - srs_error_t err = caster->on_tcp_client(stfd); - if (err != srs_success) { - srs_warn("accept client failed, err is %s", srs_error_desc(err).c_str()); - srs_freep(err); - } - return srs_success; -} - -#endif - SrsSignalManager* SrsSignalManager::instance = NULL; SrsSignalManager::SrsSignalManager(SrsServer* s) @@ -699,11 +612,6 @@ void SrsServer::destroy() srs_freep(signal_manager); srs_freep(conn_manager); - -#ifdef SRS_GB28181 - //free global gb28181 manager - srs_freep(_srs_gb28181); -#endif } void SrsServer::dispose() @@ -980,11 +888,6 @@ srs_error_t SrsServer::http_handle() if ((err = http_api_mux->handle("/api/v1/clusters", new SrsGoApiClusters())) != srs_success) { return srs_error_wrap(err, "handle clusters"); } -#ifdef SRS_GB28181 - if ((err = http_api_mux->handle("/api/v1/gb28181", new SrsGoApiGb28181())) != srs_success) { - return srs_error_wrap(err, "handle raw"); - } -#endif // test the request info. if ((err = http_api_mux->handle("/api/v1/tests/requests", new SrsGoApiRequests())) != srs_success) { @@ -1411,32 +1314,6 @@ srs_error_t SrsServer::listen_https_stream() return err; } -#ifdef SRS_GB28181 -srs_error_t SrsServer::listen_gb28181_sip(SrsConfDirective* stream_caster) -{ - srs_error_t err = srs_success; - - SrsListener* sip_listener = NULL; - sip_listener = new SrsGb28181Listener(this, SrsListenerGb28181Sip, stream_caster); - - int port = _srs_config->get_stream_caster_gb28181_sip_listen(stream_caster); - if (port <= 0) { - return srs_error_new(ERROR_STREAM_CASTER_PORT, "invalid sip port=%d", port); - } - - srs_assert(sip_listener != NULL); - - listeners.push_back(sip_listener); - - // TODO: support listen at <[ip:]port> - if ((err = sip_listener->listen(srs_any_address_for_listener(), port)) != srs_success) { - return srs_error_wrap(err, "listen at %d", port); - } - - return err; -} -#endif - srs_error_t SrsServer::listen_stream_caster() { srs_error_t err = srs_success; @@ -1462,33 +1339,6 @@ srs_error_t SrsServer::listen_stream_caster() listener = new SrsRtspListener(this, SrsListenerRtsp, stream_caster); } else if (srs_stream_caster_is_flv(caster)) { listener = new SrsHttpFlvListener(this, SrsListenerFlv, stream_caster); -#ifdef SRS_GB28181 - } else if (srs_stream_caster_is_gb28181(caster)) { - //init global gb28181 manger - if (_srs_gb28181 == NULL){ - _srs_gb28181 = new SrsGb28181Manger(this, stream_caster); - if ((err = _srs_gb28181->initialize()) != srs_success){ - return err; - } - } - - //sip listener - if (_srs_config->get_stream_caster_gb28181_sip_enable(stream_caster)){ - if ((err = listen_gb28181_sip(stream_caster)) != srs_success){ - return err; - } - } - - //gb28181 stream listener - if (!_srs_config->get_stream_caster_tcp_enable(stream_caster)) { - listener = new SrsGb28181Listener(this, SrsListenerGb28181RtpMux, stream_caster); - } else { - listener = new SrsGb28181TcpListener(this, SrsListenerGb28181RtpMux, stream_caster); - } -#else - srs_warn("gb28181 is disabled, please enable it by: ./configure --with-gb28181"); - continue; -#endif } else { return srs_error_new(ERROR_STREAM_CASTER_ENGINE, "invalid caster %s", caster.c_str()); } diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 70d9a72ba..467df4503 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -19,8 +19,6 @@ #include #include #include -#include -#include #include class SrsServer; @@ -37,8 +35,6 @@ class SrsTcpListener; class SrsAppCasterFlv; class SrsRtspCaster; class SrsResourceManager; -class SrsGb28181Caster; - // The listener type for server to identify the connection, // that is, use different type to process the connection. @@ -56,10 +52,6 @@ enum SrsListenerType SrsListenerRtsp = 4, // TCP stream, FLV stream over HTTP. SrsListenerFlv = 5, - // UDP stream, gb28181 ps stream over rtp, - SrsListenerGb28181RtpMux = 6, - // UDP gb28181 sip server - SrsListenerGb28181Sip = 7, // HTTPS api, SrsListenerHttpsApi = 8, // HTTPS stream, @@ -151,33 +143,6 @@ class SrsUdpCasterListener : public SrsUdpStreamListener virtual ~SrsUdpCasterListener(); }; -#ifdef SRS_GB28181 - -// A UDP gb28181 listener, for sip and rtp stream mux server. -class SrsGb28181Listener : public SrsUdpStreamListener -{ -public: - SrsGb28181Listener(SrsServer* svr, SrsListenerType t, SrsConfDirective* c); - virtual ~SrsGb28181Listener(); -}; - -class SrsGb28181TcpListener : public SrsListener, public ISrsTcpHandler -{ -private: - SrsTcpListener* listener; - SrsGb28181Caster* caster; -public: - SrsGb28181TcpListener(SrsServer* svr, SrsListenerType t, SrsConfDirective* c); - virtual ~SrsGb28181TcpListener(); -public: - virtual srs_error_t listen(std::string i, int p); -// Interface ISrsTcpHandler -public: - virtual srs_error_t on_tcp_client(srs_netfd_t stfd); -}; - -#endif - // Convert signal to io, // @see: st-1.9/docs/notes.html class SrsSignalManager : public ISrsCoroutineHandler @@ -340,9 +305,6 @@ class SrsServer : public ISrsReloadHandler, public ISrsLiveSourceHandler virtual srs_error_t listen_http_stream(); virtual srs_error_t listen_https_stream(); virtual srs_error_t listen_stream_caster(); -#ifdef SRS_GB28181 - virtual srs_error_t listen_gb28181_sip(SrsConfDirective* c); -#endif // Close the listeners for specified type, // Remove the listen object from manager. virtual void close_listeners(SrsListenerType type); diff --git a/trunk/src/core/srs_core_version4.hpp b/trunk/src/core/srs_core_version4.hpp index 927b5994b..655c070f9 100644 --- a/trunk/src/core/srs_core_version4.hpp +++ b/trunk/src/core/srs_core_version4.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 4 #define VERSION_MINOR 0 -#define VERSION_REVISION 126 +#define VERSION_REVISION 127 #endif diff --git a/trunk/src/kernel/srs_kernel_consts.hpp b/trunk/src/kernel/srs_kernel_consts.hpp index 71060dc5f..bde0761bf 100644 --- a/trunk/src/kernel/srs_kernel_consts.hpp +++ b/trunk/src/kernel/srs_kernel_consts.hpp @@ -171,8 +171,6 @@ #define SRS_CONSTS_LOG_EXEC "EXE" // The rtc. #define SRS_CONSTS_LOG_RTC "RTC" -// The gb28181 stream log id. -#define SRS_CONSTS_LOG_GB28181_CASTER "GBS" /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index b9fca34ee..8b68bccde 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -351,31 +351,6 @@ #define ERROR_RTC_NO_TRACK 5030 #define ERROR_RTC_RTCP_EMPTY_RR 5031 -/////////////////////////////////////////////////////// -// GB28181 API error. -/////////////////////////////////////////////////////// -#define ERROR_GB28181_SERVER_NOT_RUN 6000 -#define ERROR_GB28181_SESSION_IS_EXIST 6001 -#define ERROR_GB28181_SESSION_IS_NOTEXIST 6002 -#define ERROR_GB28181_RTP_PORT_FULL 6003 -#define ERROR_GB28181_PORT_MODE_INVALID 6004 -#define ERROR_GB28181_VALUE_EMPTY 6005 -#define ERROR_GB28181_ACTION_INVALID 6006 -#define ERROR_GB28181_SIP_NOT_RUN 6007 -#define ERROR_GB28181_SIP_INVITE_FAILED 6008 -#define ERROR_GB28181_SIP_BYE_FAILED 6009 -#define ERROR_GB28181_SIP_IS_INVITING 6010 -#define ERROR_GB28181_CREATER_RTMPMUXER_FAILED 6011 -#define ERROR_GB28181_SIP_CH_OFFLINE 6012 -#define ERROR_GB28181_SIP_CH_NOTEXIST 6013 -#define ERROR_GB28181_SIP_RAW_DATA_FAILED 6014 -#define ERROR_GB28181_SIP_PRASE_FAILED 6015 -#define ERROR_GB28181_SIP_PTZ_FAILED 6016 -#define ERROR_GB28181_SIP_NOT_INVITE 6017 -#define ERROR_GB28181_SIP_PTZ_CMD_INVALID 6018 -#define ERROR_GB28181_H264_FRAMESIZE 6019 -#define ERROR_GB28181_H264_FRAME_FULL 6020 - /////////////////////////////////////////////////////// // HTTP API error. ///////////////////////////////////////////////////////