From c99fb99ab6e39634e035a30180c75a8a00aeb4c8 Mon Sep 17 00:00:00 2001 From: xialixin Date: Tue, 31 Mar 2020 00:39:10 +0800 Subject: [PATCH] refactor gb28181, supporting SIP server enable, multiplex, API interface --- trunk/conf/push.gb28181.conf | 99 +- trunk/configure | 2 +- trunk/src/app/srs_app_config.cpp | 144 ++- trunk/src/app/srs_app_config.hpp | 7 +- trunk/src/app/srs_app_gb28181.cpp | 1358 ++++++++++++++----------- trunk/src/app/srs_app_gb28181.hpp | 438 +++++--- trunk/src/app/srs_app_gb28181_sip.cpp | 471 +++++++++ trunk/src/app/srs_app_gb28181_sip.hpp | 161 +++ trunk/src/app/srs_app_http_api.cpp | 125 +++ trunk/src/app/srs_app_http_api.hpp | 10 + trunk/src/app/srs_app_server.cpp | 70 +- trunk/src/app/srs_app_server.hpp | 13 +- trunk/src/kernel/srs_kernel_error.hpp | 16 + trunk/src/protocol/srs_sip_stack.cpp | 406 ++++++-- trunk/src/protocol/srs_sip_stack.hpp | 14 +- 15 files changed, 2439 insertions(+), 895 deletions(-) create mode 100644 trunk/src/app/srs_app_gb28181_sip.cpp create mode 100644 trunk/src/app/srs_app_gb28181_sip.hpp diff --git a/trunk/conf/push.gb28181.conf b/trunk/conf/push.gb28181.conf index cb2f848b2b..f7a3779b6b 100644 --- a/trunk/conf/push.gb28181.conf +++ b/trunk/conf/push.gb28181.conf @@ -6,28 +6,35 @@ daemon off; pid ./objs/srs28181.pid; srs_log_file ./objs/srs28181.log; srs_log_tank console; + +http_api { + enabled on; + listen 1985; +} + stream_caster { enabled on; caster gb28181; - #rtmp输出地址,可以参数化 - #[stream] 代表客户端sip设备编号 - #[timestamp] 时间戳 - output rtmp://127.0.0.1/live/[stream]; - #sip监听udp端口 - listen 15060; + #转发流到rtmp服务器地址与端口 + output 127.0.0.1:1935; - #服务器主机号,可以域名或ip地址 - #也就是设备端将媒体发送的地址,如果是服务器是内外网 - #需要写外网地址 - host 192.168.1.27; + #接收设备端rtp流的多路复用端口 + listen 9000; - #服务器端编号 - #设备端配置编号需要与该值一致,否则无法注册 - serial 34020000002000000001; + #rtp接收监听端口范围,最小值 + rtp_port_min 58200; + #rtp接收监听端口范围,最大值 + rtp_port_max 58300; - #服务器端域 - realm 3402000000; + #是否等待关键帧之后,再转发, + #off:不需等待,直接转发 + #on:等第一个关键帧后,再转发 + wait_keyframe off; + + #rtp包空闲等待时间,如果指定时间没有收到任何包 + #rtp监听连接自动停止,发送BYE命令 + rtp_idle_timeout 30; #是否转发音频流 #目前只支持aac格式,所以需要设备支持aac格式 @@ -41,32 +48,50 @@ stream_caster { #因为flash,只支持11025 22050 44100 audio_enable on; - #服务端发送ack后,接收回应的超时时间,单位为秒 - #如果指定时间没有回应,认为失败 - ack_timeout 30; + #服务器主机号,可以域名或ip地址 + #也就是设备端将媒体发送的地址,如果是服务器是内外网 + #需要写外网地址, + #调用api创建stream session时返回ip地址也是host + host 192.168.1.27; - #设备心跳维持时间,如果指定时间内(秒)没有接收一个心跳 - #认为设备离线 - keepalive_timeout 30; + sip { + #是否启用srs内部sip信令 + #为on信令走srs, off 只转发ps流 + enabled on; + + #sip监听udp端口 + listen 15060; + + #服务器端编号 + #设备端配置编号需要与该值一致,否则无法注册 + serial 34020000002000000001; - #是否等待关键帧之后,再转发, - #off:不需等待,直接转发 - #on:等第一个关键帧后,再转发 - wait_keyframe off; + #服务器端域 + realm 3402000000; - #日志打印是否打印sip信息 - #off:不打印 - #on:打印接收或发送sip命令信息 - print_sip_message off; - - #rtp包空闲等待时间,如果指定时间没有收到任何包 - #rtp监听连接自动停止,发送BYE命令 - rtp_idle_timeout 30; + #服务端发送ack后,接收回应的超时时间,单位为秒 + #如果指定时间没有回应,认为失败 + ack_timeout 30; - #rtp接收监听端口范围,最小值 - rtp_port_min 58200; - #rtp接收监听端口范围,最大值 - rtp_port_max 58300; + #设备心跳维持时间,如果指定时间内(秒)没有接收一个心跳 + #认为设备离线 + keepalive_timeout 30; + + #日志打印是否打印sip信息 + #off:不打印 + #on:打印接收或发送sip命令信息 + print_sip_message off; + + #注册之后是否自动给设备端发送invite + #on: 是 off 不是,需要通过api控制 + auto_play on; + + #设备将流发送的端口,是否固定 + #on 发送流到多路复用端口 如9000 + #off 自动从rtp_mix_port - rtp_max_port 之间的值中 + #选一个可以用的端口 + invite_port_fixed on; + } } vhost __defaultVhost__ { } diff --git a/trunk/configure b/trunk/configure index 0b50507e7f..d4369ef303 100755 --- a/trunk/configure +++ b/trunk/configure @@ -257,7 +257,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then "srs_app_mpegts_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" - "srs_app_coworkers" "srs_app_hybrid" "srs_app_gb28181") + "srs_app_coworkers" "srs_app_hybrid" "srs_app_gb28181" "srs_app_gb28181_sip") DEFINES="" # add each modules for app for SRS_MODULE in ${SRS_MODULES[*]}; do diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index bb4fc793a6..d7ca83ace7 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -2160,6 +2160,10 @@ srs_error_t SrsConfig::global_to_json(SrsJsonObject* obj) sobj->set(sdir->name, sdir->dumps_arg0_to_str()); } else if (sdir->name == "print_sip_message") { sobj->set(sdir->name, sdir->dumps_arg0_to_str()); + } else if (sdir->name == "invite_port_fixed") { + sobj->set(sdir->name, sdir->dumps_arg0_to_str()); + } else if (sdir->name == "auto_play") { + sobj->set(sdir->name, sdir->dumps_arg0_to_str()); } } @@ -3672,12 +3676,24 @@ srs_error_t SrsConfig::check_normal_config() string n = conf->name; if (n != "enabled" && n != "caster" && n != "output" && n != "listen" && n != "rtp_port_min" && n != "rtp_port_max" - && n != "rtp_idle_timeout" && n != "ack_timeout" && n != "keepalive_timeout" - && n != "host" && n != "serial" && n != "realm" + && n != "rtp_idle_timeout" && n != "sip" && n != "audio_enable" && n != "wait_keyframe" - && n != "print_sip_message") { + && n != "host") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal stream_caster.%s", n.c_str()); } + + if (n == "sip") { + for (int j = 0; j < (int)conf->directives.size(); j++) { + string m = conf->at(j)->name; + if (m != "enabled" && m != "listen" + && m != "ack_timeout" && m != "keepalive_timeout" + && m != "host" && m != "serial" && m != "realm" + && m != "print_sip_message" && m != "auto_play" + && m != "invite_port_fixed") { + return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal stream_caster.%s", m.c_str()); + } + } + } } } @@ -4207,7 +4223,7 @@ int SrsConfig::get_stream_caster_rtp_port_max(SrsConfDirective* conf) return ::atoi(conf->arg0().c_str()); } -int SrsConfig::get_stream_caster_gb28181_rtp_ide_timeout(SrsConfDirective* conf) +int SrsConfig::get_stream_caster_gb28181_rtp_idle_timeout(SrsConfDirective* conf) { static int DEFAULT = 30; @@ -4215,7 +4231,7 @@ int SrsConfig::get_stream_caster_gb28181_rtp_ide_timeout(SrsConfDirective* conf) return DEFAULT; } - conf = conf->get("rtp_ide_timeout"); + conf = conf->get("rtp_idle_timeout"); if (!conf || conf->arg0().empty()) { return DEFAULT; } @@ -4230,6 +4246,11 @@ int SrsConfig::get_stream_caster_gb28181_ack_timeout(SrsConfDirective* conf) if (!conf) { return DEFAULT; } + + conf = conf->get("sip"); + if (!conf) { + return DEFAULT; + } conf = conf->get("ack_timeout"); if (!conf || conf->arg0().empty()) { @@ -4246,6 +4267,11 @@ int SrsConfig::get_stream_caster_gb28181_keepalive_timeout(SrsConfDirective* con if (!conf) { return DEFAULT; } + + conf = conf->get("sip"); + if (!conf) { + return DEFAULT; + } conf = conf->get("keepalive_timeout"); if (!conf || conf->arg0().empty()) { @@ -4257,12 +4283,12 @@ int SrsConfig::get_stream_caster_gb28181_keepalive_timeout(SrsConfDirective* con string SrsConfig::get_stream_caster_gb28181_host(SrsConfDirective* conf) { - static string DEFAULT = "127.0.0.1"; + static string DEFAULT = ""; if (!conf) { return DEFAULT; } - + conf = conf->get("host"); if (!conf || conf->arg0().empty()) { return DEFAULT; @@ -4278,6 +4304,11 @@ string SrsConfig::get_stream_caster_gb28181_serial(SrsConfDirective* conf) if (!conf) { return DEFAULT; } + + conf = conf->get("sip"); + if (!conf) { + return DEFAULT; + } conf = conf->get("serial"); if (!conf || conf->arg0().empty()) { @@ -4294,6 +4325,11 @@ string SrsConfig::get_stream_caster_gb28181_realm(SrsConfDirective* conf) if (!conf) { return DEFAULT; } + + conf = conf->get("sip"); + if (!conf) { + return DEFAULT; + } conf = conf->get("realm"); if (!conf || conf->arg0().empty()) { @@ -4326,6 +4362,11 @@ bool SrsConfig::get_stream_caster_gb28181_print_sip_message(SrsConfDirective* co if (!conf) { return DEFAULT; } + + conf = conf->get("sip"); + if (!conf) { + return DEFAULT; + } conf = conf->get("print_sip_message"); if (!conf || conf->arg0().empty()) { @@ -4351,6 +4392,95 @@ bool SrsConfig::get_stream_caster_gb28181_wait_keyframe(SrsConfDirective* conf) return SRS_CONF_PERFER_FALSE(conf->arg0()); } +bool SrsConfig::get_stream_caster_gb28181_sip_enable(SrsConfDirective* conf) +{ + static bool DEFAULT = false; + + 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 = false; + + 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 = 0; + + 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()); + +} + + SrsConfDirective* SrsConfig::get_vhost(string vhost, bool try_default_vhost) { srs_assert(root); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index ffae3baff5..3e41e23df1 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -486,7 +486,7 @@ class SrsConfig // Get the max udp port for rtp of stream caster rtsp. virtual int get_stream_caster_rtp_port_max(SrsConfDirective* conf); - virtual int get_stream_caster_gb28181_rtp_ide_timeout(SrsConfDirective* conf); + virtual int get_stream_caster_gb28181_rtp_idle_timeout(SrsConfDirective* conf); virtual int get_stream_caster_gb28181_ack_timeout(SrsConfDirective* conf); virtual int get_stream_caster_gb28181_keepalive_timeout(SrsConfDirective* conf); virtual bool get_stream_caster_gb28181_audio_enable(SrsConfDirective* conf); @@ -495,6 +495,11 @@ class SrsConfig virtual std::string get_stream_caster_gb28181_realm(SrsConfDirective* conf); virtual bool get_stream_caster_gb28181_print_sip_message(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); + // vhost specified section public: diff --git a/trunk/src/app/srs_app_gb28181.cpp b/trunk/src/app/srs_app_gb28181.cpp index 46f7950ffc..39b1714bfc 100644 --- a/trunk/src/app/srs_app_gb28181.cpp +++ b/trunk/src/app/srs_app_gb28181.cpp @@ -32,6 +32,7 @@ using namespace std; #include +#include #include #include #include @@ -52,7 +53,7 @@ using namespace std; #include #include #include -#include + //#define W_PS_FILE @@ -94,170 +95,252 @@ srs_error_t SrsPsRtpPacket::decode(SrsBuffer* stream) // video codec. if (payload_type == 96) { - // ps stream atleast 4bytes content. - if (!stream->require(4)) { - return srs_error_new(ERROR_RTP_TYPE96_CORRUPT, "requires 4 only %d bytes", stream->left()); + // 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; } - -SrsPsRtpConn::SrsPsRtpConn(SrsGb28181Conn* conn, int p, std::string sid, bool b, bool k) +//SrsPsRtpListener +SrsPsRtpListener::SrsPsRtpListener(SrsGb28181Config* c, int p, std::string s) { - gb28181 = conn; + rtp_processor = new SrsGb28181PsRtpProcessor(c, s); _port = p; - session_id = sid; // TODO: support listen at <[ip:]port> listener = new SrsUdpListener(this, srs_any_address_for_listener(), p); - cache = new SrsPsRtpPacket(); - pprint = SrsPithyPrint::create_caster(); - pre_timestamp = -1; - - audio_enable = b; - first_keyframe_flag = false; - wait_first_keyframe = k; } -SrsPsRtpConn::~SrsPsRtpConn() +SrsPsRtpListener::~SrsPsRtpListener() { - ps_fw.close(); - video_fw.close(); - audio_fw.close(); - - dispose(); - srs_freep(listener); - srs_freep(cache); - srs_freep(pprint); + srs_freep(rtp_processor); } -int SrsPsRtpConn::port() +int SrsPsRtpListener::port() { return _port; } -srs_error_t SrsPsRtpConn::listen() +srs_error_t SrsPsRtpListener::listen() { return listener->listen(); } -void SrsPsRtpConn::dispose() -{ - map::iterator it; - for (it = cache_payload.begin(); it != cache_payload.end(); ++it) { - srs_freep(it->second); +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; +} - cache_payload.clear(); - return; +//SrsGb28181RtpMuxService +SrsGb28181RtpMuxService::SrsGb28181RtpMuxService(SrsConfDirective* c) +{ + config = new SrsGb28181Config(c); + rtp_processor = new SrsGb28181PsRtpProcessor(config,""); } -int64_t SrsPsRtpConn::parse_ps_timestamp(const uint8_t* p) +SrsGb28181RtpMuxService::~SrsGb28181RtpMuxService() { - unsigned long b; - //total 33 bits - unsigned long val, val2, val3; + srs_freep(config); + srs_freep(rtp_processor); +} - //1st byte, 5、6、7 bit - b = *p++; - val = (b & 0x0e); +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; +} - //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; +//SrsGb28181PsRtpProcessor +SrsGb28181PsRtpProcessor::SrsGb28181PsRtpProcessor(SrsGb28181Config* c, std::string id) +{ + config = c; + pprint = SrsPithyPrint::create_caster(); + channel_id = id; +} - //<32--val--30> <29----val2----15> <14----val3----0> - val = (val << 29) | (val2 << 15) | val3; - return val; +SrsGb28181PsRtpProcessor::~SrsGb28181PsRtpProcessor() +{ + dispose(); + srs_freep(pprint); } -srs_error_t SrsPsRtpConn::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) +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(); + + return; +} + +srs_error_t SrsGb28181PsRtpProcessor::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) { srs_error_t err = srs_success; bool completed = false; - int keyframe = 0; 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"); + } + + int peer_port = atoi(port_string); + if (true) { SrsBuffer stream(buf, nb_buf); - SrsPsRtpPacket pkt; if ((err = pkt.decode(&stream)) != srs_success) { - srs_trace("decode error"); - return srs_success; - //return srs_error_wrap(err, "decode"); + return srs_error_wrap(err, "ps rtp decode error"); } - if (pre_timestamp == -1) { - pre_timestamp = pkt.timestamp; - } + //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(); - //cache pkt payload by timestamp - if (cache_payload.find(pkt.timestamp) == cache_payload.end()) { - cache_payload[pkt.timestamp] = new SrsSimpleStream(); + 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(); } - - cache_payload[pkt.timestamp]->append(pkt.payload); - uint32_t cur_timestamp = pkt.timestamp; + //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 > pkt.sequence_number){ + // srs_info("gb28281: ps sequence_number out of order, ssrc=%#x, pre=%u, cur=%u, addr=%s,port=%s", + // pkt.ssrc, pre_sequence_number, pkt.sequence_number, address_string, port_string); + // //return err; + // } - - if (pkt.marker) { + //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){ - if (cache_payload.find(pre_timestamp) != cache_payload.end()) { + }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; - cur_timestamp = pre_timestamp; } } - pre_timestamp = pkt.timestamp; - if (pprint->can_print()) { srs_trace("<- " SRS_CONSTS_LOG_STREAM_CASTER " gb28181: client_id %s, ps rtp packet %dB, age=%d, vt=%d/%u, sts=%u/%u/%#x, paylod=%dB", - session_id.c_str(), nb_buf, pprint->age(), pkt.version, pkt.payload_type, pkt.sequence_number, pkt.timestamp, pkt.ssrc, + channel_id.c_str(), 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 - char *payload = cache_payload[cur_timestamp]->bytes(); - int payload_len = cache_payload[cur_timestamp]->length(); - on_ps_stream(payload, payload_len, cur_timestamp); - + //process completed frame data //clear processed one ps frame - map::iterator key = cache_payload.find(cur_timestamp); - if(key!=cache_payload.end()) + //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()) { - srs_freep(key->second); - cache_payload.erase(key); + 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(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_STREAM_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 conn to process, and then free + muxer->ps_packet_enqueue(key->second); + } + }else{ + //no connection process it, discarded + srs_freep(key->second); + } + cache_ps_rtp_packet.erase(pkt_key); } } - return err; } -bool SrsPsRtpConn::can_send_ps_av_packet(){ +//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; +} + +SrsPsStreamDemixer::~SrsPsStreamDemixer() +{ +} + +bool SrsPsStreamDemixer::can_send_ps_av_packet(){ if (!wait_first_keyframe) return true; @@ -267,11 +350,38 @@ bool SrsPsRtpConn::can_send_ps_av_packet(){ return false; } +int64_t SrsPsStreamDemixer::parse_ps_timestamp(const uint8_t* p) +{ + unsigned long b; + //total 33 bits + unsigned long val, val2, val3; -srs_error_t SrsPsRtpConn::on_ps_stream(char* ps_data, int ps_size, uint32_t timestamp) + //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; @@ -280,12 +390,11 @@ srs_error_t SrsPsRtpConn::on_ps_stream(char* ps_data, int ps_size, uint32_t time SrsSimpleStream audio_stream; uint64_t audio_pts = 0; uint64_t video_pts = 0; - int keyframe = 0; int pse_index = 0; #ifdef W_PS_FILE if (!ps_fw.is_open()) { - std::string filename = "test_ps_" + session_id + ".mpg"; + std::string filename = "test_ps_" + channel_id + ".mpg"; ps_fw.open(filename.c_str()); } ps_fw.write(ps_data, ps_size, NULL); @@ -345,19 +454,15 @@ srs_error_t SrsPsRtpConn::on_ps_stream(char* ps_data, int ps_size, uint32_t time && next_ps_pack[2] == (char)0x01 && next_ps_pack[3] == (char)0xE0) { - //pse - + //pse video stream SrsPsePacket* pse_pack = (SrsPsePacket*)next_ps_pack; unsigned char pts_dts_flags = (pse_pack->info[0] & 0xF0) >> 6; - int64_t pts = 0; + //in a frame of data, pts is obtained from the first PSE packet if (pse_index == 0 && pts_dts_flags > 0) { - pts = parse_ps_timestamp((unsigned char*)next_ps_pack + 9); - //srs_trace("vvvvvvvvvvvvvvvvvvvvvvv ts=%u pkt_ts=%u", pts, timestamp); + video_pts = parse_ps_timestamp((unsigned char*)next_ps_pack + 9); + srs_info("gb28181: ps stream video ts=%u pkt_ts=%u", pts, timestamp); } - - if (pse_index == 0) video_pts = pts; - pse_index +=1; int packlength = htons(pse_pack->length); @@ -370,7 +475,7 @@ srs_error_t SrsPsRtpConn::on_ps_stream(char* ps_data, int ps_size, uint32_t time #ifdef W_VIDEO_FILE if (!video_fw.is_open()) { - std::string filename = "test_video_" + session_id + ".h264"; + std::string filename = "test_video_" + channel_id + ".h264"; video_fw.open(filename.c_str()); } video_fw.write(next_ps_pack, payloadlen, NULL); @@ -379,9 +484,6 @@ srs_error_t SrsPsRtpConn::on_ps_stream(char* ps_data, int ps_size, uint32_t time next_ps_pack = next_ps_pack + payloadlen; complete_len = complete_len + payloadlen; incomplete_len = ps_size - complete_len; - - - //srs_trace("====================== V pts=%u", pts); } else if (next_ps_pack && next_ps_pack[0] == (char)0x00 @@ -413,8 +515,8 @@ srs_error_t SrsPsRtpConn::on_ps_stream(char* ps_data, int ps_size, uint32_t time 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_trace("aaaaaaaaaaaaaaaaaaaaaaaaaa ts=%u pkt_ts=%u", audio_pts, timestamp); - } + 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; @@ -424,7 +526,7 @@ srs_error_t SrsPsRtpConn::on_ps_stream(char* ps_data, int ps_size, uint32_t time #ifdef W_AUDIO_FILE if (!audio_fw.is_open()) { - std::string filename = "test_audio_" + session_id + ".aac"; + std::string filename = "test_audio_" + channel_id + ".aac"; audio_fw.open(filename.c_str()); } audio_fw.write(next_ps_pack, payload_len, NULL); @@ -434,63 +536,74 @@ srs_error_t SrsPsRtpConn::on_ps_stream(char* ps_data, int ps_size, uint32_t time complete_len = complete_len + (payload_len + 9 + pse_pack->stuffing_length); incomplete_len = ps_size - complete_len; - if (audio_enable && audio_stream.length() && can_send_ps_av_packet()) { - if ((err = gb28181->on_rtp_audio(&audio_stream, audio_pts)) != srs_success) { - srs_trace("process ps audio packet error %s", err); - //return srs_success; - //return srs_error_wrap(err, "process rtp packet"); + if (hander && audio_enable && audio_stream.length() && can_send_ps_av_packet()) { + if ((err = hander->on_rtp_audio(&audio_stream, audio_pts)) != srs_success) { + return srs_error_wrap(err, "process ps audio packet"); } } } else { srs_trace("gb28181: client_id %s, unkonw ps data %02x %02x %02x %02x\n", - session_id.c_str(), next_ps_pack[0], next_ps_pack[1], next_ps_pack[2], next_ps_pack[3]); - //srs_trace(" ps ps_size=%d complete=%d h264len=%d\n", ps_size, complete_len, *h264length); + channel_id.c_str(), next_ps_pack[0], next_ps_pack[1], next_ps_pack[2], next_ps_pack[3]); break; } } if (complete_len != ps_size){ srs_trace("gb28181: client_id %s decode ps packet error! ps_size=%d complete=%d \n", - session_id.c_str(), ps_size, complete_len); - }else if (video_stream.length() && can_send_ps_av_packet()) { - if ((err = gb28181->on_rtp_video(&video_stream, video_pts, keyframe)) != srs_success) { - srs_trace("process ps video packet error"); - //return srs_success; - return srs_error_wrap(err, "process ps video packet error"); + channel_id.c_str(), ps_size, complete_len); + }else if (hander && video_stream.length() && can_send_ps_av_packet()) { + if ((err = hander->on_rtp_video(&video_stream, video_pts)) != srs_success) { + return srs_error_wrap(err, "process ps video packet"); } } return err; } -SrsGb28281ClientInfo::SrsGb28281ClientInfo() + +//Gb28181 Config +SrsGb28181Config::SrsGb28181Config(SrsConfDirective* c) { - req = new SrsSipRequest(); + // TODO: FIXME: support reload. + host = _srs_config->get_stream_caster_gb28181_host(c); + output = _srs_config->get_stream_caster_output(c); + rtp_mux_port = _srs_config->get_stream_caster_listen(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); + + //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); + print_sip_message = _srs_config->get_stream_caster_gb28181_print_sip_message(c); + sip_invite_port_fixed = _srs_config->get_stream_caster_gb28181_sip_invite_port_fixed(c); } -SrsGb28281ClientInfo::~SrsGb28281ClientInfo() +SrsGb28181Config::~SrsGb28181Config() { - srs_freep(req); + } -SrsGb28181Conn::SrsGb28181Conn(SrsGb28181Caster* c, std::string id) +//SrsGb28181RtmpMuxer gb28181 rtmp muxer, process ps stream to rtmp +SrsGb28181RtmpMuxer::SrsGb28181RtmpMuxer(SrsGb28181Manger* c, std::string id, bool a, bool k) { - session_id = id; + channel_id = id; + gb28181_manger = c; + channel = new SrsGb28181StreamChannel(); - video_rtp = NULL; - audio_rtp = NULL; - - req = NULL; - caster = c; - info = new SrsGb28281ClientInfo; pprint = SrsPithyPrint::create_caster(); - - skt = new SrsStSocket(); - sip = new SrsSipStack(); - trd = new SrsSTCoroutine("gb28181conn", this); + trd = new SrsSTCoroutine("gb28181rtmpmuxer", this); sdk = NULL; vjitter = new SrsRtspJitter(); @@ -499,184 +612,197 @@ SrsGb28181Conn::SrsGb28181Conn(SrsGb28181Caster* c, std::string id) avc = new SrsRawH264Stream(); aac = new SrsRawAacStream(); + ps_demixer = new SrsPsStreamDemixer(this, id, a, k); + wait_ps_queue = srs_cond_new(); + h264_sps_changed = false; h264_pps_changed = false; h264_sps_pps_sent = false; - reg_expires = 3600; - register_time = 0; - alive_time = 0; - invite_time = 0; - register_status = Srs28181Unkonw; - alive_status = Srs28181Unkonw; - invite_status = Srs28181Unkonw; + stream_idle_timeout = -1; + recv_stream_time = 0; + + _rtmp_url = ""; } -SrsGb28181Conn::~SrsGb28181Conn() +SrsGb28181RtmpMuxer::~SrsGb28181RtmpMuxer() { close(); - - srs_freep(info); - - srs_freep(video_rtp); - srs_freep(audio_rtp); - + destroy(); + srs_cond_destroy(wait_ps_queue); + + srs_freep(channel); + srs_freep(ps_demixer); srs_freep(trd); - srs_freep(skt); - srs_freep(sip); - srs_freep(sdk); - srs_freep(req); - srs_freep(vjitter); srs_freep(ajitter); - srs_freep(pprint); } -srs_error_t SrsGb28181Conn::serve() +srs_error_t SrsGb28181RtmpMuxer::serve() { srs_error_t err = srs_success; if ((err = trd->start()) != srs_success) { - return srs_error_wrap(err, "gb28181 connection"); + return srs_error_wrap(err, "gb28181rtmpmuxer"); } return err; } -std::string SrsGb28181Conn::remote_ip() +std::string SrsGb28181RtmpMuxer::remote_ip() { return ""; } -void SrsGb28181Conn::set_request_info(SrsSipRequest *req) +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_rtp_peer_port(port); + } +} + +int SrsGb28181RtmpMuxer::channel_peer_port() +{ + return channel->get_rtp_peer_port(); +} + +std::string SrsGb28181RtmpMuxer::channel_peer_ip() { - srs_assert(req != NULL); - info->req->copy(req); + return channel->get_rtp_peer_ip(); } -std::string SrsGb28181Conn::get_session_id() +void SrsGb28181RtmpMuxer::set_rtmp_url(std::string url) +{ + _rtmp_url = url; +} +std::string SrsGb28181RtmpMuxer::rtmp_url() { - return session_id; + return _rtmp_url; } -srs_error_t SrsGb28181Conn::do_cycle() + +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::do_cycle() { srs_error_t err = srs_success; - - // consume all sip messages. + recv_stream_time = srs_get_system_time(); + + //consume ps stream, and check status while (true) { pprint->elapse(); if ((err = trd->pull()) != srs_success) { - return srs_error_wrap(err, "gb28181conn cycle"); + return srs_error_wrap(err, "gb28181 rtmp muxer cycle"); } - srs_utime_t now = srs_get_system_time(); - SrsGb28181Config config = caster->GetGb28181Config(); - - srs_utime_t reg_duration = 0; - srs_utime_t invite_duration = 0; - srs_utime_t alive_duration = 0; - srs_utime_t recv_rtp_duration = 0; - - if (register_status == Srs28181RegisterOk && register_time > 0) { - reg_duration = (now - register_time) / (1000*1000); - if (reg_duration > reg_expires) { - register_status = Srs28181Unkonw; - alive_status = Srs28181Unkonw; - invite_status = Srs28181Unkonw; - stop_rtp_listen(); + //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 (alive_status == Srs28181AliveOk && alive_time > 0){ - alive_duration = (now - alive_time) / (1000*1000); - if (alive_duration > config.sip_keepalive_timeout) { - srs_trace("gb28181: client id=%s alive timeout, remove conn", session_id.c_str()); - break; - } - } - - if (invite_status && invite_time > 0) { - invite_duration = (now - invite_time) / (1000*1000); - if (invite_status == Srs28181Trying && invite_duration > config.sip_ack_timeout) { - invite_status = Srs28181Unkonw; - stop_rtp_listen(); - } - recv_rtp_duration = (now - recv_rtp_time) / (1000*1000); - if (recv_rtp_duration > config.rtp_idle_timeout) { - invite_status = Srs28181Unkonw; - stop_rtp_listen(); - } + if (pprint->can_print()) { + srs_trace("gb28181: client id=%s, rtmp muxer is alive", channel_id.c_str()); + } + + srs_utime_t now = srs_get_system_time(); + srs_utime_t duration = (now - recv_stream_time) / (1000*1000); + + SrsGb28181Config config = gb28181_manger->get_gb28181_config(); + if (duration > config.rtp_idle_timeout){ + srs_trace("gb28181: client id=%s, stream idle timeout, stop!!!", channel_id.c_str()); + break; } - - if (pprint->can_print()) { - srs_trace("gb28181: client id=%s, druation reg=%u alive=%u invite=%u", - session_id.c_str(), reg_duration, alive_duration, invite_duration); - srs_trace("gb28181: client id=%s, status reg_status=%u alive_status=%u invite_status=%u", - session_id.c_str(), register_status, alive_status, invite_status); - } - - srs_usleep(1000 * 1000); + srs_cond_timedwait(wait_ps_queue, 5 * SRS_UTIME_MILLISECONDS); + //srs_usleep(1000 * 5); } return err; } -srs_error_t SrsGb28181Conn::start_rtp_listen(int port) -{ - srs_error_t err = srs_success; - - SrsPsRtpConn* rtp = NULL; - srs_freep(video_rtp); - SrsGb28181Config config = caster->GetGb28181Config(); - rtp = video_rtp = new SrsPsRtpConn(this, port, session_id, - config.audio_enable, config.wait_keyframe); - - if ((err = rtp->listen()) != srs_success) { - return srs_error_wrap(err, "rtp listen"); - } - srs_trace("gb28181conn: start rtp ps stream over server-port=%d", port); - return err; - -} - -srs_error_t SrsGb28181Conn::stop_rtp_listen() +void SrsGb28181RtmpMuxer::stop() { - srs_error_t err = srs_success; - - if (video_rtp) { - caster->free_port(video_rtp->port(), video_rtp->port() + 1); - srs_freep(video_rtp); - } - - if (audio_rtp) { - caster->free_port(audio_rtp->port(), audio_rtp->port() + 1); - srs_freep(audio_rtp); + if (trd){ + trd->interrupt(); } - //stop rtmp publish close(); - - return err; } +void SrsGb28181RtmpMuxer::ps_packet_enqueue(SrsPsRtpPacket *pkt) +{ + srs_assert(pkt); + + //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 SrsGb28181Conn::cycle() +srs_error_t SrsGb28181RtmpMuxer::cycle() { - // serve the sip client. + // serve the rtmp muxer. srs_error_t err = do_cycle(); - stop_rtp_listen(); + gb28181_manger->stop_rtp_listen(channel_id); - caster->remove(this); - srs_trace("gb28181conn: client id=%d conn is remove", session_id.c_str()); + 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."); @@ -688,27 +814,31 @@ srs_error_t SrsGb28181Conn::cycle() return err; } -srs_error_t SrsGb28181Conn::on_rtp_video(SrsSimpleStream *stream, int64_t fpts, int keyframe) +srs_error_t SrsGb28181RtmpMuxer::on_rtp_video(SrsSimpleStream *stream, int64_t fpts) { srs_error_t err = srs_success; // 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); + + recv_stream_time = srs_get_system_time(); - recv_rtp_time = srs_get_system_time(); - - //srs_trace("==========================================VVV pts=%u", dts); SrsBuffer *avs = new SrsBuffer(stream->bytes(), stream->length()); SrsAutoFree(SrsBuffer, avs); // send each frame. @@ -769,7 +899,6 @@ srs_error_t SrsGb28181Conn::on_rtp_video(SrsSimpleStream *stream, int64_t fpts, } // ibp frame. - // TODO: FIXME: we should group all frames to a rtmp/flv message from one ts message. 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"); @@ -779,29 +908,32 @@ srs_error_t SrsGb28181Conn::on_rtp_video(SrsSimpleStream *stream, int64_t fpts, return err; } -srs_error_t SrsGb28181Conn::on_rtp_audio(SrsSimpleStream* stream, int64_t fdts) +srs_error_t SrsGb28181RtmpMuxer::on_rtp_audio(SrsSimpleStream* stream, int64_t fdts) { srs_error_t err = srs_success; // 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"); } - // sip tbn is ts tbn. if ((err = ajitter->correct(fdts)) != srs_success) { return srs_error_wrap(err, "jitter"); } - recv_rtp_time = srs_get_system_time(); + recv_stream_time = srs_get_system_time(); - // ts tbn to flv tbn. uint32_t dts = (uint32_t)(fdts / 90); - // send each frame. - SrsBuffer *avs = new SrsBuffer(stream->bytes(), stream->length()); - SrsAutoFree(SrsBuffer, avs); - if (!avs->empty()) { + // send each frame. + SrsBuffer *avs = new SrsBuffer(stream->bytes(), stream->length()); + SrsAutoFree(SrsBuffer, avs); + if (!avs->empty()) { char* frame = NULL; int frame_size = 0; SrsRawAacStreamCodec codec; @@ -867,7 +999,7 @@ srs_error_t SrsGb28181Conn::on_rtp_audio(SrsSimpleStream* stream, int64_t fdts) return err; } -srs_error_t SrsGb28181Conn::write_h264_sps_pps(uint32_t dts, uint32_t pts) +srs_error_t SrsGb28181RtmpMuxer::write_h264_sps_pps(uint32_t dts, uint32_t pts) { srs_error_t err = srs_success; @@ -904,7 +1036,7 @@ srs_error_t SrsGb28181Conn::write_h264_sps_pps(uint32_t dts, uint32_t pts) return err; } -srs_error_t SrsGb28181Conn::write_h264_ipb_frame(char* frame, int frame_size, uint32_t dts, uint32_t pts) +srs_error_t SrsGb28181RtmpMuxer::write_h264_ipb_frame(char* frame, int frame_size, uint32_t dts, uint32_t pts) { srs_error_t err = srs_success; @@ -936,7 +1068,7 @@ srs_error_t SrsGb28181Conn::write_h264_ipb_frame(char* frame, int frame_size, ui return rtmp_write_packet(SrsFrameTypeVideo, timestamp, flv, nb_flv); } -srs_error_t SrsGb28181Conn::write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, uint32_t dts) +srs_error_t SrsGb28181RtmpMuxer::write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, uint32_t dts) { srs_error_t err = srs_success; @@ -949,7 +1081,7 @@ srs_error_t SrsGb28181Conn::write_audio_raw_frame(char* frame, int frame_size, S return rtmp_write_packet(SrsFrameTypeAudio, dts, data, size); } -srs_error_t SrsGb28181Conn::rtmp_write_packet(char type, uint32_t timestamp, char* data, int size) +srs_error_t SrsGb28181RtmpMuxer::rtmp_write_packet(char type, uint32_t timestamp, char* data, int size) { srs_error_t err = srs_success; @@ -973,7 +1105,7 @@ srs_error_t SrsGb28181Conn::rtmp_write_packet(char type, uint32_t timestamp, cha return err; } -srs_error_t SrsGb28181Conn::connect() +srs_error_t SrsGb28181RtmpMuxer::connect() { srs_error_t err = srs_success; @@ -983,19 +1115,8 @@ srs_error_t SrsGb28181Conn::connect() } // generate rtmp url to connect to. - std::string url; - if (true) { - std::string schema, host, vhost, app, param; - int port; - //srs_discovery_tc_url(rtmp_url, schema, host, vhost, app, rtsp_stream, port, param); - - // generate output by template. - std::string output = rtmp_url; - output = srs_string_replace(output, "[app]", "live"); - output = srs_string_replace(output, "[stream]", session_id); - output = srs_path_build_timestamp(output); - url = output; - } + std::string url = _rtmp_url; + // connect host. srs_utime_t cto = SRS_CONSTS_RTMP_TIMEOUT; srs_utime_t sto = SRS_CONSTS_RTMP_PULSE; @@ -1016,82 +1137,102 @@ srs_error_t SrsGb28181Conn::connect() return err; } -void SrsGb28181Conn::close() +void SrsGb28181RtmpMuxer::close() { srs_freep(sdk); } -SrsGb28181Config::SrsGb28181Config(SrsConfDirective* c) +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 = ""; +} + +SrsGb28181StreamChannel::~SrsGb28181StreamChannel() { - // TODO: FIXME: support reload. - output = _srs_config->get_stream_caster_output(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_ide_timeout(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); - listen_port = _srs_config->get_stream_caster_listen(c); - sip_host = _srs_config->get_stream_caster_gb28181_host(c); - sip_realm = _srs_config->get_stream_caster_gb28181_realm(c); - sip_serial = _srs_config->get_stream_caster_gb28181_serial(c); - audio_enable = _srs_config->get_stream_caster_gb28181_audio_enable(c); - print_sip_message = _srs_config->get_stream_caster_gb28181_print_sip_message(c); - wait_keyframe = _srs_config->get_stream_caster_gb28181_wait_keyframe(c); + } -SrsGb28181Config::~SrsGb28181Config() +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(); +} + +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("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())); } -//gb28181 caster -SrsGb28181Caster::SrsGb28181Caster(SrsConfDirective* c) + +//Global Singleton instance, init in SrsServer +SrsGb28181Manger* _srs_gb28181 = NULL; + +//SrsGb28181Manger +SrsGb28181Manger::SrsGb28181Manger(SrsConfDirective* c) { // TODO: FIXME: support reload. - //output = _srs_config->get_stream_caster_output(c); - //local_port_min = _srs_config->get_stream_caster_rtp_port_min(c); - //local_port_max = _srs_config->get_stream_caster_rtp_port_max(c); - sip = new SrsSipStack(); - manager = new SrsCoroutineManager(); config = new SrsGb28181Config(c); - lfd = NULL; + manager = new SrsCoroutineManager(); } -SrsGb28181Caster::~SrsGb28181Caster() +SrsGb28181Manger::~SrsGb28181Manger() { used_ports.clear(); srs_freep(manager); - srs_freep(sip); srs_freep(config); destroy(); } -srs_error_t SrsGb28181Caster::initialize() +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; } -void SrsGb28181Caster::set_stfd(srs_netfd_t fd) -{ - lfd = fd; -} - -SrsGb28181Config SrsGb28181Caster::GetGb28181Config() +SrsGb28181Config SrsGb28181Manger::get_gb28181_config() { return *config; } -srs_error_t SrsGb28181Caster::alloc_port(int* pport) +void SrsGb28181Manger::alloc_port(int* pport) { - srs_error_t err = srs_success; - // use a pair of port. for (int i = config->rtp_port_min; i < config->rtp_port_max - 1; i += 2) { if (!used_ports[i]) { @@ -1102,11 +1243,9 @@ srs_error_t SrsGb28181Caster::alloc_port(int* pport) } } srs_info("gb28181: alloc port=%d-%d", *pport, *pport + 1); - - return err; } -void SrsGb28181Caster::free_port(int lpmin, int lpmax) +void SrsGb28181Manger::free_port(int lpmin, int lpmax) { for (int i = lpmin; i < lpmax; i++) { used_ports[i] = false; @@ -1114,326 +1253,395 @@ void SrsGb28181Caster::free_port(int lpmin, int lpmax) srs_trace("gb28181: free rtp port=%d-%d", lpmin, lpmax); } -srs_error_t SrsGb28181Caster::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) +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) { - 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"); + srand(uint(time(0))); + // TODO: SSRC rules can be customized, + //uint8_t index = uint8_t(rand() % (0x0F - 0x01 + 1) + 0x01); + //uint32_t ssrc = 0x00FFFFF0 & (hash_code(id) << 4) | 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, SrsGb28181RtmpMuxer** gb28181) +{ + srs_error_t err = srs_success; + + SrsGb28181RtmpMuxer* muxer = NULL; + if ((muxer = fetch_rtmpmuxer(id)) != NULL) { + *gb28181 = muxer; + return err; } - std::string peer_ip = std::string(address_string); - int peer_port = atoi(port_string); - // append to buffer. - //buffer->append(buf, nb_buf); - srs_error_t err = on_udp_bytes(peer_ip, peer_port, buf, nb_buf, (sockaddr*)from, fromlen); - if (err != srs_success) { - return srs_error_wrap(err, "process udp"); + muxer = new SrsGb28181RtmpMuxer(this, id, config->audio_enable, config->wait_keyframe); + if ((err = muxer->serve()) != srs_success) { + return srs_error_wrap(err, "gb28281: rtmp muxer serve %s", id.c_str()); } + rtmpmuxers[id] = muxer; + *gb28181 = muxer; + return err; } -srs_error_t SrsGb28181Caster::on_udp_bytes(string peer_ip, int peer_port, - char* buf, int nb_buf, sockaddr* from, const int fromlen) +SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer(std::string id) { - srs_error_t err = srs_success; + SrsGb28181RtmpMuxer* muxer = NULL; - if (config->print_sip_message) - { - srs_trace("gb28181: request peer_ip=%s, peer_port=%d nbbuf=%d", peer_ip.c_str(), peer_port, nb_buf); - srs_trace("gb28181: request recv message=%s", buf); + if (rtmpmuxers.find(id) == rtmpmuxers.end()) { + return NULL; } - if (nb_buf < 10) { - return err; - } - - SrsSipRequest* req = NULL; - - if ((err = sip->parse_request(&req, buf, nb_buf)) != srs_success) { - return srs_error_wrap(err, "recv message"); - } + muxer = rtmpmuxers[id]; + return muxer; +} - if (config->print_sip_message) - { - 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()); - srs_trace("gb28281: request client id=%s", req->sip_auth_id.c_str()); +SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer_by_ssrc(uint32_t ssrc) +{ + SrsGb28181RtmpMuxer* muxer = NULL; + if (rtmpmuxers_ssrc.find(ssrc) == rtmpmuxers_ssrc.end()) { + return NULL; } - req->peer_ip = peer_ip; - req->peer_port = peer_port; - - SrsAutoFree(SrsSipRequest, req); - - if (req->is_register()) { - std::vector serial = srs_string_split(srs_string_replace(req->uri,"sip:", ""), "@"); - if (serial.at(0) != config->sip_serial){ - srs_trace("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 srs_success; - } + muxer = rtmpmuxers_ssrc[ssrc]; + return muxer; +} - srs_trace("gb28181: request peer_ip=%s, peer_port=%d", peer_ip.c_str(), peer_port, nb_buf); - srs_trace("gb28181: request %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()); - srs_trace("gb28281: request client id=%s", req->sip_auth_id.c_str()); +void SrsGb28181Manger::rtmpmuxer_map_by_ssrc(SrsGb28181RtmpMuxer*muxer, uint32_t ssrc) +{ + if (rtmpmuxers_ssrc.find(ssrc) == rtmpmuxers_ssrc.end()) { + rtmpmuxers_ssrc[ssrc] = muxer; + } +} - SrsGb28181Conn* conn = NULL; +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); + } +} - if ((err = fetch_or_create(req, &conn)) != srs_success) { - srs_trace("gb28181: conn create faild:%s", req->uri.c_str()); - return srs_error_wrap(err, "conn create faild");; - } - srs_assert(conn != NULL); - - // if (conn->register_status == Srs28181Unkonw) - // { - // }else{ - // srs_trace("gb28181: %s client is register", req->sip_auth_id.c_str()); - // } +void SrsGb28181Manger::destroy() +{ + //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 it2; + for (it2 = rtmpmuxers.begin(); it2 != rtmpmuxers.end(); ++it2) { + SrsGb28181RtmpMuxer* muxer = it2->second; + SrsGb28181StreamChannel sess = muxer->get_channel(); + rtmpmuxer_unmap_by_ssrc(sess.get_ssrc()); + manager->remove(muxer); + } + rtmpmuxers.clear(); +} - send_status(req, from, fromlen); - conn->register_status = Srs28181RegisterOk; - conn->register_time = srs_get_system_time(); - conn->reg_expires = req->expires; - +void SrsGb28181Manger::remove(SrsGb28181RtmpMuxer* muxer) +{ + std::string id = muxer->get_channel_id(); - }else if (req->is_message()) { - SrsGb28181Conn* conn = fetch(req); - if (!conn){ - srs_trace("gb28181: %s client not registered", req->sip_auth_id.c_str()); - return srs_success; - } - - if (conn->register_status == Srs28181Unkonw) { - send_bye(req, from, fromlen); - srs_trace("gb28181: %s client not registered", req->sip_auth_id.c_str()); - return srs_success; - } - - send_status(req, from, fromlen); - conn->alive_status = Srs28181AliveOk; - conn->alive_time = srs_get_system_time(); + 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); +} - if (conn->register_status == Srs28181RegisterOk && - conn->alive_status == Srs28181AliveOk && - conn->invite_status != Srs28181InviteOk) - { - int lpm = 0; - if (alloc_port(&lpm) != srs_success) { - return srs_error_wrap(err, "alloc port"); - } - if (lpm){ - send_invite(req, from, fromlen, lpm); - conn->rtmp_url = config->output; - conn->start_rtp_listen(lpm); - conn->invite_status == Srs28181Trying; - conn->invite_time = srs_get_system_time(); - } +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"); + } - } + map::iterator key = rtmpmuxers.find(id); + if (key == rtmpmuxers.end()){ + return srs_error_wrap(err, "start rtp listen port rtmp muxer is null"); + } - }else if (req->is_invite()) { - SrsGb28181Conn* conn = fetch(req); - - srs_trace("gb28181: request peer_ip=%s, peer_port=%d", peer_ip.c_str(), peer_port, nb_buf); - srs_trace("gb28181: request %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()); - srs_trace("gb28281: request client id=%s", req->sip_auth_id.c_str()); - - if (!conn){ - send_bye(req, from, fromlen); - srs_trace("gb28181: %s client not registered", req->sip_auth_id.c_str()); - return srs_success; + 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"); } - if (conn->register_status == Srs28181Unkonw || - conn->alive_status == Srs28181Unkonw) { - send_bye(req, from, fromlen); - srs_trace("gb28181: %s client not registered or not alive", req->sip_auth_id.c_str()); - return srs_success; - } - - if (req->cmdtype == SrsSipCmdRespone && req->status == "200") { - srs_trace("gb28181: INVITE response %s client status=%s", req->sip_auth_id.c_str(), req->status.c_str()); - send_ack(req, from, fromlen); - conn->invite_status = Srs28181InviteOk; - conn->invite_time = srs_get_system_time(); - } - }else if (req->is_bye()) { - srs_trace("gb28181: request peer_ip=%s, peer_port=%d", peer_ip.c_str(), peer_port, nb_buf); - srs_trace("gb28181: request %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()); - srs_trace("gb28281: request client id=%s", req->sip_auth_id.c_str()); - - SrsGb28181Conn* conn = fetch(req); - send_status(req, from, fromlen); - - if (!conn){ - srs_trace("gb28181: %s client not registered", req->sip_auth_id.c_str()); - return srs_success; - } - - conn->stop_rtp_listen(); - conn->invite_status = Srs28181Bye; - conn->invite_time = 0; - - }else{ - srs_trace("gb28181: ingor request method=%s", req->method.c_str()); + srs_trace("gb28181: start rtp ps stream over server-port=%d", port); } - + return err; } -srs_error_t SrsGb28181Caster::send_message(sockaddr* from, int fromlen, std::stringstream& ss) +void SrsGb28181Manger::stop_rtp_listen(std::string id) { srs_error_t err = srs_success; + + map::iterator it = rtmpmuxers.find(id); + if (it == rtmpmuxers.end()){ + return; + } - std::string str = ss.str(); - if (config->print_sip_message) - srs_trace("gb28181: send_message:%s", str.c_str()); - srs_assert(!str.empty()); + SrsGb28181RtmpMuxer* muxer = it->second; + SrsGb28181StreamChannel sess = muxer->get_channel(); - int ret = srs_sendto(lfd, (char*)str.c_str(), (int)str.length(), from, fromlen, SRS_UTIME_NO_TIMEOUT); - if (ret <= 0){ - return srs_error_wrap(err, "gb28181: send_message falid"); + int port = sess.get_rtp_port(); + if (port == config->rtp_mux_port) { + return; } - - return err; + + 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); } -srs_error_t SrsGb28181Caster::send_bye(SrsSipRequest *req, sockaddr *f, int l) +//api +uint32_t SrsGb28181Manger::create_stream_channel(SrsGb28181StreamChannel *channel) { - srs_error_t err = srs_success; - srs_assert(req); + srs_assert(channel); - std::stringstream ss; - - req->host = config->sip_host; - req->host_port = config->listen_port; - req->realm = config->sip_realm; - req->serial = config->sip_serial; + std::string id = channel->get_channel_id(); + SrsGb28181RtmpMuxer *muxer = NULL; - sip->req_bye(ss, req); - send_message(f, l, ss); + muxer = fetch_rtmpmuxer(id); + if (muxer){ + SrsGb28181StreamChannel s = muxer->get_channel(); + channel->copy(&s); + //return ERROR_GB28181_SESSION_IS_EXIST; + return ERROR_SUCCESS; + } - return err; + if (channel->get_stream().empty()){ + channel->set_stream("[stream]"); + } -} -srs_error_t SrsGb28181Caster::send_ack(SrsSipRequest *req, sockaddr *f, int l) -{ - srs_error_t err = srs_success; - srs_assert(req); + if (channel->get_app().empty()){ + channel->set_stream("[app]"); + } - std::stringstream ss; - - req->host = config->sip_host; - req->host_port = config->listen_port; - req->realm = config->sip_realm; - req->serial = config->sip_serial; + if (channel->get_port_mode().empty()){ + channel->set_port_mode(RTP_PORT_MODE_FIXED); + } + + //create on rtmp muxer, gb28281 stream to rtmp + srs_error_t err = srs_success; + if ((err = fetch_or_create_rtmpmuxer(id, &muxer)) != srs_success){ + srs_warn("gb28181: create rtmp muxer error, %s", srs_error_desc(err).c_str()); + srs_freep(err); + return ERROR_GB28281_CREATER_RTMPMUXER_FAILED; + } - sip->resp_ack(ss, req); - send_message(f, l, ss); + //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 == RTP_PORT_MODE_RANDOM){ + alloc_port(&rtp_port); + if (rtp_port <= 0){ + return ERROR_GB28181_RTP_PORT_FULL; + } + srs_error_t err = srs_success; + if ((err = start_ps_rtp_listen(id, rtp_port)) != srs_success){ + srs_warn("gb28181: start ps rtp listen error, %s", srs_error_desc(err).c_str()); + srs_freep(err); + free_port(rtp_port, rtp_port + 1); + return ERROR_GB28281_CREATER_RTMPMUXER_FAILED; + } + } + else if(port_mode == RTP_PORT_MODE_FIXED) { + rtp_port = config->rtp_mux_port; + } + else{ + return ERROR_GB28181_PORT_MODE_INVALID; + } - return err; -} + //Generate SSRC according to the hash code, + //of the string value of the id + uint32_t ssrc = generate_ssrc(id); + rtmpmuxer_map_by_ssrc(muxer, ssrc); -srs_error_t SrsGb28181Caster::send_invite(SrsSipRequest *req, sockaddr *f, int l, int port) -{ - srs_error_t err = srs_success; - srs_assert(req); + //Generate RTMP push stream address, + std::string app = channel->get_app(); + std::string stream = channel->get_stream(); + app = srs_string_replace(app, "[app]", "live"); + stream = srs_string_replace(stream, "[stream]", id); - std::stringstream ss; - - req->host = config->sip_host; - req->host_port = config->listen_port; - req->realm = config->sip_realm; - req->serial = config->sip_serial; + std::string url = "rtmp://" + config->output + "/" + app + "/" + stream; + int rtmp_port; + if (true) { + std::string schema, host, vhost, param, _app, _stream; + srs_discovery_tc_url(url, schema, host, vhost, _app, _stream, rtmp_port, param); + url = srs_generate_rtmp_url(host, rtmp_port, "", "", app, stream, ""); + std::stringstream ss; + ss << ssrc; + url = srs_string_replace(url, "[ssrc]", ss.str()); + url = srs_path_build_timestamp(url); + } + muxer->set_rtmp_url(url); + srs_trace("gb28181: create new stream channel id:%s rtmp url=%s", id.c_str(), muxer->rtmp_url().c_str()); - sip->req_invite(ss, req, port); - send_message(f, l, ss); + //generate the value returned to the api response + channel->set_app(app); + channel->set_stream(stream); + channel->set_rtp_port(rtp_port); + channel->set_rtmp_port(rtmp_port); + channel->set_ip(config->host); + channel->set_ssrc(ssrc); - return err; + muxer->copy_channel(channel); + return ERROR_SUCCESS; } -srs_error_t SrsGb28181Caster::send_status(SrsSipRequest *req, sockaddr *f, int l) +uint32_t SrsGb28181Manger::delete_stream_channel(std::string id) { - srs_error_t err = srs_success; - srs_assert(req); - - std::stringstream ss; - - req->host = config->sip_host; - req->host_port = config->listen_port; - req->realm = config->sip_realm; - req->serial = config->sip_serial; + //notify the device to stop streaming + //if an internal sip service controlled channel + notify_sip_bye(id); + + SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(id); + if (muxer){ + stop_rtp_listen(id); + muxer->stop(); + return ERROR_SUCCESS; + }else { + return ERROR_GB28181_SESSION_IS_NOTEXIST; + } +} - sip->resp_status(ss, req); - send_message(f, l, ss); - return err; +uint32_t SrsGb28181Manger::queue_stream_channel(std::string id, SrsJsonArray* arr) +{ + if (!id.empty()){ + SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(id); + if (!muxer){ + return ERROR_GB28181_SESSION_IS_NOTEXIST; + } + 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 ERROR_SUCCESS; } - -srs_error_t SrsGb28181Caster::fetch_or_create(SrsSipRequest* r, SrsGb28181Conn** gb28181) +uint32_t SrsGb28181Manger::notify_sip_invite(std::string id, std::string ip, int port, uint32_t ssrc) { - srs_error_t err = srs_success; + if (!sip_service){ + return ERROR_GB28181_SIP_NOT_RUN; + } + + //if RTMP Muxer does not exist, you need to create + SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(id); + + 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(id); + channel.set_app("live"); + channel.set_stream(id); + int code = create_stream_channel(&channel); + if (code != ERROR_SUCCESS){ + return code; + } - SrsGb28181Conn* conn = NULL; - if ((conn = fetch(r)) != NULL) { - *gb28181 = conn; - 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(); } - - string key = r->sip_auth_id; - conn = new SrsGb28181Conn(this, key); - conn->set_request_info(r); - if ((err = conn->serve()) != srs_success) { - return srs_error_wrap(err, "sipconn serve %s", key.c_str()); - } - clients[key] = conn; - *gb28181 = conn; - - return err; + + SrsSipRequest req; + req.sip_auth_id = id; + return sip_service->send_invite(&req, ip, port, ssrc); + } -SrsGb28181Conn* SrsGb28181Caster::fetch(const SrsSipRequest* r) +uint32_t SrsGb28181Manger::notify_sip_bye(std::string id) { - SrsGb28181Conn* conn = NULL; - - string key = r->sip_auth_id; - if (clients.find(key) == clients.end()) { - return NULL; + if (!sip_service){ + return ERROR_GB28181_SIP_NOT_RUN; } - - conn = clients[key]; - return conn; -} + SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(id); + if (muxer){ + muxer->rtmp_close(); + } + + SrsSipRequest req; + req.sip_auth_id = id; + return sip_service->send_bye(&req); +} -void SrsGb28181Caster::destroy() +uint32_t SrsGb28181Manger::notify_sip_raw_data(std::string id, std::string data) { - std::map::iterator it; - for (it = clients.begin(); it != clients.end(); ++it) { - SrsGb28181Conn* conn = it->second; - manager->remove(conn); + if (!sip_service){ + return ERROR_GB28181_SIP_NOT_RUN; } - clients.clear(); + + SrsSipRequest req; + req.sip_auth_id = id; + return sip_service->send_sip_raw_data(&req, data); + } -void SrsGb28181Caster::remove(SrsGb28181Conn* conn) +uint32_t SrsGb28181Manger::notify_sip_unregister(std::string id) { - std::string id = conn->get_session_id(); - map::iterator key = clients.find(id); - if (key != clients.end()) { - clients.erase(key); + if (!sip_service){ + return ERROR_GB28181_SIP_NOT_RUN; } - manager->remove(conn); + + delete_stream_channel(id); + sip_service->remove_session(id); + return ERROR_SUCCESS; } diff --git a/trunk/src/app/srs_app_gb28181.hpp b/trunk/src/app/srs_app_gb28181.hpp index 3d8bd13b0a..8eff26b327 100644 --- a/trunk/src/app/srs_app_gb28181.hpp +++ b/trunk/src/app/srs_app_gb28181.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -38,16 +39,14 @@ #include #include #include +#include +#include + +#define RTP_PORT_MODE_FIXED "fixed" +#define RTP_PORT_MODE_RANDOM "random" -class SrsStSocket; -class SrsRtpConn; -class SrsRtspConn; -class SrsRtspStack; -class SrsRtspCaster; class SrsConfDirective; class SrsRtpPacket; -class SrsRequest; -class SrsStSocket; class SrsRtmpClient; class SrsRawH264Stream; class SrsRawAacStream; @@ -58,74 +57,134 @@ class SrsSimpleStream; class SrsPithyPrint; class SrsSimpleRtmpClient; class SrsSipStack; -class SrsGb28181Caster; +class SrsGb28181Manger; class SrsRtspJitter; -class SrsRtspAudioCache; class SrsSipRequest; -class SrsGb28181Conn; -class SrsGb28281ClientInfo; - -/* gb28181 program stream struct define +class SrsGb28181RtmpMuxer; +class SrsGb28181Config; +class SrsGb28181PsRtpProcessor; +class SrsGb28181SipService; +class SrsGb28181StreamChannel; -*/ - -struct SrsPsPacketStartCode +//ps rtp header packet parse +class SrsPsRtpPacket: public SrsRtpPacket { - uint8_t start_code[3]; - uint8_t stream_id[1]; +public: + SrsPsRtpPacket(); + virtual ~SrsPsRtpPacket(); +public: + virtual srs_error_t decode(SrsBuffer* stream); }; -struct SrsPsPacketHeader +//randomly assigned ports receive gb28281 device streams +class SrsPsRtpListener: public ISrsUdpHandler { - SrsPsPacketStartCode start;// 4 - uint8_t info[9]; - uint8_t stuffing_length; +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); }; -struct SrsPsPacketBBHeader +//multiplexing service, single port receiving all gb28281 device streams +class SrsGb28181RtpMuxService : public ISrsUdpHandler { - SrsPsPacketStartCode start; - uint16_t length; -}; +private: + SrsGb28181Config *config; + SrsGb28181PsRtpProcessor *rtp_processor; +public: + SrsGb28181RtpMuxService(SrsConfDirective* c); + virtual ~SrsGb28181RtpMuxService(); -struct SrsPsePacket -{ - SrsPsPacketStartCode start; - uint16_t length; - uint8_t info[2]; - uint8_t stuffing_length; + // Interface ISrsUdpHandler +public: + virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); }; -struct SrsPsMapPacket + +//process gb28281 RTP package, generate a completed PS stream data, +//call the PS stream parser, parse the original video and audio +class SrsGb28181PsRtpProcessor: public ISrsUdpHandler { - SrsPsPacketStartCode start; - uint16_t length; +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(); +// Interface ISrsUdpHandler +public: + virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); }; - - -class SrsPsRtpPacket: public SrsRtpPacket +//ps stream processing parsing interface +class ISrsPsStreamHander { public: - SrsPsRtpPacket(); - virtual ~SrsPsRtpPacket(); + ISrsPsStreamHander(); + virtual ~ISrsPsStreamHander(); public: - virtual srs_error_t decode(SrsBuffer* stream); + 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)=0; }; -// A rtp connection which transport a stream. -class SrsPsRtpConn: public ISrsUdpHandler +//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 { -private: - SrsPithyPrint* pprint; - SrsUdpListener* listener; - SrsGb28181Conn* gb28181; - SrsPsRtpPacket* cache; - std::map cache_payload; - std::string session_id; - int _port; - uint32_t pre_timestamp; +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; @@ -133,117 +192,89 @@ class SrsPsRtpConn: public ISrsUdpHandler bool first_keyframe_flag; bool wait_first_keyframe; bool audio_enable; - -public: - SrsPsRtpConn(SrsGb28181Conn* r, int p, std::string sid, bool a, bool k); - virtual ~SrsPsRtpConn(); - -private: - int64_t parse_ps_timestamp(const uint8_t* p); + std::string channel_id; + ISrsPsStreamHander *hander; +public: + SrsPsStreamDemixer(ISrsPsStreamHander *h, std::string sid, bool a, bool k); + virtual ~SrsPsStreamDemixer(); private: bool can_send_ps_av_packet(); - void dispose(); -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); - virtual srs_error_t on_ps_stream(char* ps_data, int ps_size, uint32_t timestamp); -}; - -class SrsGb28281ClientInfo { -public: - SrsGb28281ClientInfo(); - virtual ~SrsGb28281ClientInfo(); - public: - sockaddr* sock_from; - int sock_fromlen; - srs_netfd_t stfd; - SrsSipRequest *req; + int64_t parse_ps_timestamp(const uint8_t* p); + virtual srs_error_t on_ps_stream(char* ps_data, int ps_size, uint32_t timestamp, uint32_t ssrc); }; -enum Srs28181CtrlStatusType{ - Srs28181Unkonw = 0, - Srs28181RegisterOk = 1, - Srs28181AliveOk = 2, - Srs28181InviteOk = 3, - Srs28181Trying = 4, - Srs28181Bye = 5, -}; -class SrsGb28181Conn : public ISrsCoroutineHandler, public ISrsConnection +//RTMP multiplexer, which processes the raw H264 / AAC, +//then publish it to RTMP server +class SrsGb28181RtmpMuxer : public ISrsCoroutineHandler, + public ISrsConnection, public ISrsPsStreamHander { private: - std::string output_template; SrsPithyPrint* pprint; -public: - Srs28181CtrlStatusType register_status; - Srs28181CtrlStatusType alive_status; - Srs28181CtrlStatusType invite_status; - srs_utime_t register_time; - srs_utime_t alive_time; - srs_utime_t invite_time; - srs_utime_t recv_rtp_time; - - std::string rtmp_url; - int reg_expires; - + SrsGb28181StreamChannel *channel; + int stream_idle_timeout; + srs_utime_t recv_stream_time; private: - std::string session_id; - // video stream. - int video_id; - std::string video_codec; - SrsPsRtpConn* video_rtp; - // audio stream. - int audio_id; - std::string audio_codec; + std::string channel_id; + std::string _rtmp_url; + std::string video_ssrc; + std::string audio_ssrc; int audio_sample_rate; int audio_channel; - SrsPsRtpConn* audio_rtp; -public: - SrsGb28281ClientInfo* info; -private: - SrsStSocket* skt; - SrsSipStack* sip; - SrsGb28181Caster* caster; + + SrsGb28181Manger* gb28181_manger; SrsCoroutine* trd; -private: - SrsSipRequest* req; + SrsPsStreamDemixer* ps_demixer; + srs_cond_t wait_ps_queue; + SrsSimpleRtmpClient* sdk; SrsRtspJitter* vjitter; SrsRtspJitter* ajitter; -private: + SrsRawH264Stream* avc; std::string h264_sps; std::string h264_pps; bool h264_sps_changed; bool h264_pps_changed; bool h264_sps_pps_sent; -private: + SrsRawAacStream* aac; std::string aac_specific_config; + +public: + std::queue ps_queue; + public: - SrsGb28181Conn(SrsGb28181Caster* c, std::string id); - virtual ~SrsGb28181Conn(); + SrsGb28181RtmpMuxer(SrsGb28181Manger* m, std::string id, bool a, bool k); + virtual ~SrsGb28181RtmpMuxer(); + public: virtual srs_error_t serve(); - virtual std::string remote_ip(); - virtual void set_request_info(SrsSipRequest *req); - virtual std::string get_session_id(); + virtual void stop(); + + 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(); + private: virtual srs_error_t do_cycle(); -// internal methods -public: - virtual srs_error_t start_rtp_listen(int port); - virtual srs_error_t stop_rtp_listen(); + virtual void destroy(); + // Interface ISrsOneCycleThreadHandler public: virtual srs_error_t cycle(); + virtual std::string remote_ip(); public: - virtual srs_error_t on_rtp_video(SrsSimpleStream* stream, int64_t dts, int keyframe); + virtual srs_error_t on_rtp_video(SrsSimpleStream* stream, int64_t dts); virtual srs_error_t on_rtp_audio(SrsSimpleStream* stream, int64_t dts); private: virtual srs_error_t write_h264_sps_pps(uint32_t dts, uint32_t pts); @@ -255,75 +286,152 @@ class SrsGb28181Conn : public ISrsCoroutineHandler, public ISrsConnection virtual srs_error_t connect(); // Close the connection to RTMP server. virtual void close(); +public: + virtual void rtmp_close(); }; +//system parameter configuration of gb28281 module, +//read file from configuration file to generate class SrsGb28181Config { public: - std::string sip_host; - std::string sip_port; - std::string sip_serial; - std::string sip_realm; - int sip_ack_timeout; - int sip_keepalive_timeout; + std::string host; int rtp_idle_timeout; bool audio_enable; + bool wait_keyframe; std::string output; int rtp_port_min; int rtp_port_max; - int listen_port; + int rtp_mux_port; + + //sip config + int sip_port; + std::string sip_serial; + std::string sip_realm; + bool sip_enable; + int sip_ack_timeout; + int sip_keepalive_timeout; bool print_sip_message; - bool wait_keyframe; + bool sip_auto_play; + bool sip_invite_port_fixed; + public: SrsGb28181Config(SrsConfDirective* c); virtual ~SrsGb28181Config(); }; -//gb28181 conn manager -class SrsGb28181Caster : public ISrsUdpHandler +class SrsGb28181StreamChannel +{ +private: + std::string channel_id; + std::string port_mode; + std::string app; + std::string stream; + + std::string ip; + int rtp_port; + int rtmp_port; + uint32_t ssrc; + + //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; } + + 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 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; - SrsSipStack *sip; - srs_netfd_t lfd; -private: - std::map clients; + std::map rtp_pool; + std::map rtmpmuxers_ssrc; + std::map rtmpmuxers; SrsCoroutineManager* manager; + SrsGb28181SipService* sip_service; + +public: + SrsGb28181Manger(SrsConfDirective* c); + virtual ~SrsGb28181Manger(); + +public: + srs_error_t fetch_or_create_rtmpmuxer(std::string id, SrsGb28181RtmpMuxer** gb28181); + SrsGb28181RtmpMuxer* fetch_rtmpmuxer(std::string id); + SrsGb28181RtmpMuxer* fetch_rtmpmuxer_by_ssrc(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; } + public: - SrsGb28181Caster(SrsConfDirective* c); - virtual ~SrsGb28181Caster(); + //stream channel api + uint32_t create_stream_channel(SrsGb28181StreamChannel *channel); + uint32_t delete_stream_channel(std::string id); + uint32_t queue_stream_channel(std::string id, SrsJsonArray* arr); + //sip api + uint32_t notify_sip_invite(std::string id, std::string ip, int port, uint32_t ssrc); + uint32_t notify_sip_bye(std::string id); + uint32_t notify_sip_raw_data(std::string id, std::string data); + uint32_t notify_sip_unregister(std::string id); private: - srs_error_t fetch_or_create(SrsSipRequest* r, SrsGb28181Conn** gb28181); - virtual SrsGb28181Conn* fetch(const SrsSipRequest* r); - virtual void destroy(); + void destroy(); + public: // Alloc a rtp port from local ports pool. // @param pport output the rtp port. - virtual srs_error_t alloc_port(int* pport); + void alloc_port(int* pport); // Free the alloced rtp port. - virtual void free_port(int lpmin, int lpmax); - virtual srs_error_t initialize(); + void free_port(int lpmin, int lpmax); + srs_error_t initialize(); - virtual void set_stfd(srs_netfd_t fd); - virtual SrsGb28181Config GetGb28181Config(); + SrsGb28181Config get_gb28181_config(); + srs_error_t start_ps_rtp_listen(std::string id, int port); + void stop_rtp_listen(std::string id); -// Interface ISrsUdpHandler -public: - virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); -private: - virtual srs_error_t on_udp_bytes(std::string host, int port, char* buf, int nb_buf, sockaddr* from, int fromlen); -// internal methods. public: - virtual srs_error_t send_message(sockaddr* f, int l, std::stringstream& ss); - virtual srs_error_t send_bye(SrsSipRequest *req, sockaddr *f, int l); - virtual srs_error_t send_ack(SrsSipRequest *req, sockaddr *f, int l); - virtual srs_error_t send_invite(SrsSipRequest *req, sockaddr *f, int l, int port); - virtual srs_error_t send_status(SrsSipRequest *req, sockaddr *f, int l); - virtual void remove(SrsGb28181Conn* conn); + void remove(SrsGb28181RtmpMuxer* conn); + }; #endif diff --git a/trunk/src/app/srs_app_gb28181_sip.cpp b/trunk/src/app/srs_app_gb28181_sip.cpp new file mode 100644 index 0000000000..64a8512b63 --- /dev/null +++ b/trunk/src/app/srs_app_gb28181_sip.cpp @@ -0,0 +1,471 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include + +using namespace std; + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +SrsGb28181SipSession::SrsGb28181SipSession(SrsGb28181SipService *c, SrsSipRequest* r) +{ + caster = c; + req = new SrsSipRequest(); + req->copy(r); + + _register_status = SrsGb28181SipSessionUnkonw; + _alive_status = SrsGb28181SipSessionUnkonw; + _invite_status = SrsGb28181SipSessionUnkonw; + _register_time = 0; + _alive_time = 0; + _invite_time = 0; + _recv_rtp_time = 0; + _reg_expires = 0; + + _peer_ip = ""; + _peer_port = 0; + + _from = NULL; + _fromlen = 0; +} + +SrsGb28181SipSession::~SrsGb28181SipSession() +{ + srs_freep(req); +} + +//gb28181 sip Service +SrsGb28181SipService::SrsGb28181SipService(SrsConfDirective* c) +{ + // TODO: FIXME: support reload. + config = new SrsGb28181Config(c); + sip = new SrsSipStack(); + + if (_srs_gb28181){ + _srs_gb28181->set_sip_service(this); + } +} + +SrsGb28181SipService::~SrsGb28181SipService() +{ + destroy(); + srs_freep(sip); + srs_freep(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"); + } + std::string peer_ip = std::string(address_string); + int peer_port = atoi(port_string); + + srs_error_t err = on_udp_sip(peer_ip, peer_port, buf, nb_buf, (sockaddr*)from, fromlen); + if (err != srs_success) { + return srs_error_wrap(err, "process udp"); + } + return err; +} + +srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port, + char* buf, int nb_buf, sockaddr* from, const int fromlen) +{ + srs_error_t err = srs_success; + + if (config->print_sip_message) + { + srs_trace("gb28181: request peer_ip=%s, peer_port=%d nbbuf=%d", peer_ip.c_str(), peer_port, nb_buf); + srs_trace("gb28181: request recv message=%s", buf); + } + + if (nb_buf < 10) { + return err; + } + + SrsSipRequest* req = NULL; + + if ((err = sip->parse_request(&req, buf, nb_buf)) != srs_success) { + return srs_error_wrap(err, "parse sip request"); + } + + if (config->print_sip_message) + { + 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()); + srs_trace("gb28281: request client id=%s", req->sip_auth_id.c_str()); + } + + 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.at(0) != config->sip_serial){ + srs_trace("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 peer_ip=%s, peer_port=%d", peer_ip.c_str(), peer_port, nb_buf); + srs_trace("gb28181: request %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()); + srs_trace("gb28281: request client id=%s", req->sip_auth_id.c_str()); + + SrsGb28181SipSession* sip_session = create_sip_session(req); + if (!sip_session) { + srs_trace("gb28181: create sip session faild:%s", req->uri.c_str()); + return err; + } + + 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(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->register_status() == SrsGb28181SipSessionUnkonw){ + srs_trace("gb28181: %s client not registered", req->sip_auth_id.c_str()); + return err; + } + + //reponse status + send_status(req, from, fromlen); + sip_session->set_register_status(SrsGb28181SipSessionRegisterOk); + sip_session->set_register_time(srs_get_system_time()); + sip_session->set_alive_status(SrsGb28181SipSessionAliveOk); + sip_session->set_alive_time(srs_get_system_time()); + sip_session->set_sockaddr(from); + sip_session->set_sockaddr_len(fromlen); + sip_session->set_peer_port(peer_port); + sip_session->set_peer_ip(peer_ip); + + //send invite, play client av + //start ps rtp listen, recv ps stream + if (config->sip_auto_play && sip_session->register_status() == SrsGb28181SipSessionRegisterOk && + sip_session->alive_status() == SrsGb28181SipSessionAliveOk && + sip_session->invite_status() == SrsGb28181SipSessionUnkonw) + { + //stop the possible stream and push a new stream + //send_bye(req, from, fromlen); + + SrsGb28181StreamChannel ch; + ch.set_channel_id(session_id); + ch.set_ip(config->host); + ch.set_stream(session_id); + ch.set_app("live"); + if (config->sip_invite_port_fixed){ + ch.set_port_mode(RTP_PORT_MODE_FIXED); + }else { + ch.set_port_mode(RTP_PORT_MODE_RANDOM); + } + + int code = _srs_gb28181->create_stream_channel(&ch); + if (code == ERROR_SUCCESS){ + code = send_invite(req, ch.get_ip(), + ch.get_rtp_port(), ch.get_ssrc()); + } + + if (code == ERROR_SUCCESS){ + sip_session->set_invite_status(SrsGb28181SipSessionTrying); + sip_session->set_invite_time(srs_get_system_time()); + } + + } + }else if (req->is_invite()) { + SrsGb28181SipSession* sip_session = fetch(session_id); + + srs_trace("gb28181: request peer_ip=%s, peer_port=%d", peer_ip.c_str(), peer_port, nb_buf); + srs_trace("gb28181: request %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()); + srs_trace("gb28281: request client id=%s", req->sip_auth_id.c_str()); + + if (!sip_session){ + send_bye(req); + srs_trace("gb28181: %s client not registered", req->sip_auth_id.c_str()); + return err; + } + + 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 && req->status == "200") { + srs_trace("gb28181: INVITE response %s client status=%s", req->sip_auth_id.c_str(), req->status.c_str()); + send_ack(req, from, fromlen); + sip_session->set_invite_status(SrsGb28181SipSessionInviteOk); + sip_session->set_invite_time(srs_get_system_time()); + //Record tag and branch, which are required by the 'bye' command, + sip_session->set_request(req); + }else{ + sip_session->set_invite_status(SrsGb28181SipSessionUnkonw); + sip_session->set_invite_time(0); + } + }else if (req->is_bye()) { + srs_trace("gb28181: request peer_ip=%s, peer_port=%d", peer_ip.c_str(), peer_port, nb_buf); + srs_trace("gb28181: request %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()); + srs_trace("gb28281: request client id=%s", req->sip_auth_id.c_str()); + + SrsGb28181SipSession* sip_session = fetch(session_id); + send_status(req, from, fromlen); + + if (!sip_session){ + srs_trace("gb28181: %s client not registered", req->sip_auth_id.c_str()); + return err; + } + + sip_session->set_invite_status(SrsGb28181SipSessionBye); + sip_session->set_invite_time(0); + + }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(); + if (config->print_sip_message) + srs_trace("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; + + sip->resp_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); +} + + +int SrsGb28181SipService::send_invite(SrsSipRequest *req, string ip, int port, uint32_t ssrc) +{ + srs_assert(req); + + SrsGb28181SipSession *sip_session = fetch(req->sip_auth_id); + + if (!sip_session){ + return ERROR_GB28181_SESSION_IS_NOTEXIST; + } + + //if you are inviting or succeed in invite, + //you cannot invite again. you need to 'bye' and try again + if (sip_session->invite_status() == SrsGb28181SipSessionTrying || + sip_session->invite_status() == SrsGb28181SipSessionInviteOk){ + return ERROR_GB28281_SIP_IS_INVITING; + } + + req->host = config->host; + req->host_port = config->sip_port; + req->realm = config->sip_realm; + req->serial = config->sip_serial; + + std::stringstream ss; + sip->req_invite(ss, req, ip, port, ssrc); + + if (send_message(sip_session->sockaddr_from(), sip_session->sockaddr_fromlen(), ss) <= 0) + { + return ERROR_GB28281_SIP_INVITE_FAILED; + } + + sip_session->set_invite_status(SrsGb28181SipSessionTrying); + + return ERROR_SUCCESS; + +} + +int SrsGb28181SipService::send_bye(SrsSipRequest *req) +{ + srs_assert(req); + + SrsGb28181SipSession *sip_session = fetch(req->sip_auth_id); + + if (!sip_session){ + return ERROR_GB28181_SESSION_IS_NOTEXIST; + } + + //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(&r); + + req->host = config->host; + req->host_port = config->sip_port; + req->realm = config->sip_realm; + req->serial = config->sip_serial; + + //get protocol stack + std::stringstream ss; + sip->req_bye(ss, req); + + if (send_message(sip_session->sockaddr_from(), sip_session->sockaddr_fromlen(), ss) <= 0) + { + return ERROR_GB28281_SIP_BYE_FAILED; + } + + return ERROR_SUCCESS; + + +} + + +int SrsGb28181SipService::send_sip_raw_data(SrsSipRequest *req, std::string data) +{ + srs_assert(req); + + SrsGb28181SipSession *sip_session = fetch(req->sip_auth_id); + + if (!sip_session){ + return ERROR_GB28181_SESSION_IS_NOTEXIST; + } + + std::stringstream ss; + ss << data; + + if (send_message(sip_session->sockaddr_from(), sip_session->sockaddr_fromlen(), ss) <= 0) + { + return ERROR_GB28281_SIP_BYE_FAILED; + } + + return ERROR_SUCCESS; +} + +SrsGb28181SipSession* SrsGb28181SipService::create_sip_session(SrsSipRequest *req) +{ + SrsGb28181SipSession *sess = NULL; + + std::map::iterator it = sessions.find(req->sip_auth_id); + if (it == sessions.end()){ + sess = new SrsGb28181SipSession(this, req); + }else{ + return it->second; + } + + sessions[req->sip_auth_id] = sess; + return sess; +} + +SrsGb28181SipSession* SrsGb28181SipService::fetch(std::string sid) +{ + std::map::iterator it = sessions.find(sid); + if (it == sessions.end()){ + return NULL; + }else{ + return it->second; + } +} + +void SrsGb28181SipService::remove_session(std::string sid) +{ + std::map::iterator it = sessions.find(sid); + if (it != sessions.end()){ + srs_freep(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); + } + sessions.clear(); +} + + diff --git a/trunk/src/app/srs_app_gb28181_sip.hpp b/trunk/src/app/srs_app_gb28181_sip.hpp new file mode 100644 index 0000000000..17e4313cbc --- /dev/null +++ b/trunk/src/app/srs_app_gb28181_sip.hpp @@ -0,0 +1,161 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_APP_GB28181_SIP_HPP +#define SRS_APP_GB28181_SIP_HPP + +#include + +#include +#include +#include + +#include +#include +#include + + +class SrsConfDirective; +class SrsSipRequest; +class SrsGb28181Config; +class SrsSipStack; +class SrsGb28181SipService; + +enum SrsGb28281SipSessionStatusType{ + SrsGb28181SipSessionUnkonw = 0, + SrsGb28181SipSessionRegisterOk = 1, + SrsGb28181SipSessionAliveOk = 2, + SrsGb28181SipSessionInviteOk = 3, + SrsGb28181SipSessionTrying = 4, + SrsGb28181SipSessionBye = 5, +}; + +class SrsGb28181SipSession +{ +private: + //SrsSipRequest *req; + SrsGb28181SipService *caster; + std::string session_id; +private: + SrsGb28281SipSessionStatusType _register_status; + SrsGb28281SipSessionStatusType _alive_status; + SrsGb28281SipSessionStatusType _invite_status; + srs_utime_t _register_time; + srs_utime_t _alive_time; + srs_utime_t _invite_time; + srs_utime_t _recv_rtp_time; + int _reg_expires; + + std::string _peer_ip; + int _peer_port; + + sockaddr *_from; + int _fromlen; + SrsSipRequest *req; + +public: + void set_register_status(SrsGb28281SipSessionStatusType s) { _register_status = s;} + void set_alive_status(SrsGb28281SipSessionStatusType s) { _alive_status = s;} + void set_invite_status(SrsGb28281SipSessionStatusType 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;} + 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);} + + SrsGb28281SipSessionStatusType register_status() { return _register_status;} + SrsGb28281SipSessionStatusType alive_status() { return _alive_status;} + SrsGb28281SipSessionStatusType 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;} + +public: + SrsGb28181SipSession(SrsGb28181SipService *c, SrsSipRequest* r); + virtual ~SrsGb28181SipSession(); + +}; + +class SrsGb28181SipService : public ISrsUdpHandler +{ +private: + SrsSipStack *sip; + SrsGb28181Config *config; + srs_netfd_t lfd; + + std::map sessions; +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, char* buf, int nb_buf, 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); + + int send_invite(SrsSipRequest *req, std::string ip, int port, uint32_t ssrc); + int send_bye(SrsSipRequest *req); + + // 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 + // + // + int send_sip_raw_data(SrsSipRequest *req, std::string data); + + SrsGb28181SipSession* create_sip_session(SrsSipRequest *req); + SrsGb28181SipSession* fetch(std::string id); + void remove_session(std::string id); +}; + +#endif + diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 5355068eb3..d2174d08bf 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1301,6 +1301,131 @@ srs_error_t SrsGoApiError::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage return srs_api_response_code(w, r, 100); } +SrsGoApiGb28181::SrsGoApiGb28181() +{ +} + +SrsGoApiGb28181::~SrsGoApiGb28181() +{ +} + +srs_error_t SrsGoApiGb28181::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) +{ + 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) { + if(action == "create_channel"){ + if (id.empty()){ + return srs_api_response_code(w, r, ERROR_GB28181_VALUE_EMPTY); + } + + SrsGb28181StreamChannel channel; + channel.set_channel_id(id); + channel.set_app(app); + channel.set_stream(stream); + channel.set_port_mode(port_mode); + + uint32_t code = _srs_gb28181->create_stream_channel(&channel); + if (code != ERROR_SUCCESS) { + return srs_api_response_code(w, r, code); + } + + 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"){ + if (id.empty()){ + return srs_api_response_code(w, r, ERROR_GB28181_VALUE_EMPTY); + } + + uint32_t code = _srs_gb28181->delete_stream_channel(id); + return srs_api_response_code(w, r, code); + } + else if(action == "query_channel") { + SrsJsonArray* arr = SrsJsonAny::array(); + data->set("channels", arr); + + uint32_t code = _srs_gb28181->queue_stream_channel(id, arr); + if (code != ERROR_SUCCESS) { + return srs_api_response_code(w, r, code); + } + + return srs_api_response(w, r, obj->dumps()); + } + else if(action == "sip_invite"){ + if (id.empty()){ + return srs_api_response_code(w, r, ERROR_GB28181_VALUE_EMPTY); + } + + 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)); + + + + int code = _srs_gb28181->notify_sip_invite(id, ip, _port, _ssrc); + return srs_api_response_code(w, r, code); + } + else if(action == "sip_bye"){ + if (id.empty()){ + return srs_api_response_code(w, r, ERROR_GB28181_VALUE_EMPTY); + } + + int code = _srs_gb28181->notify_sip_bye(id); + return srs_api_response_code(w, r, code); + } + else if(action == "sip_raw_data"){ + if (id.empty()){ + return srs_api_response_code(w, r, ERROR_GB28181_VALUE_EMPTY); + } + + std::string body; + r->body_read_all(body); + int code = _srs_gb28181->notify_sip_raw_data(id, body); + return srs_api_response_code(w, r, code); + } + else if(action == "sip_unregister"){ + if (id.empty()){ + return srs_api_response_code(w, r, ERROR_GB28181_VALUE_EMPTY); + } + + int code = _srs_gb28181->notify_sip_unregister(id); + return srs_api_response_code(w, r, code); + } + else + { + return srs_api_response_code(w, r, ERROR_GB28181_ACTION_INVALID); + } + + }else { + return srs_api_response_code(w, r, ERROR_GB28181_SERVER_NOT_RUN); + } +} + SrsHttpApi::SrsHttpApi(IConnectionManager* cm, srs_netfd_t fd, SrsHttpServeMux* m, string cip) : SrsConnection(cm, fd, cip) { diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 5957ff2f3f..7713d9816b 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -210,6 +210,16 @@ class SrsGoApiError : public ISrsHttpHandler virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); }; + +class SrsGoApiGb28181 : public ISrsHttpHandler +{ +public: + SrsGoApiGb28181(); + virtual ~SrsGoApiGb28181(); +public: + virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); +}; + class SrsHttpApi : virtual public SrsConnection, virtual public ISrsReloadHandler { private: diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 26106feaa9..b00f68237b 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -52,6 +52,7 @@ using namespace std; #include #include #include +#include // system interval in srs_utime_t, // all resolution times should be times togother, @@ -109,8 +110,10 @@ std::string srs_listener_type2string(SrsListenerType type) return "RTSP"; case SrsListenerFlv: return "HTTP-FLV"; - case SrsListenerGb28181: + case SrsListenerGb28181Sip: return "GB28181-SIP over UDP"; + case SrsListenerGb28181RtpMux: + return "GB28181-Stream over RTP"; default: return "UNKONWN"; } @@ -301,7 +304,9 @@ 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 == SrsListenerGb28181); + srs_assert(type == SrsListenerMpegTsOverUdp + || type == SrsListenerGb28181Sip + || type == SrsListenerGb28181RtpMux); ip = i; port = p; @@ -344,9 +349,13 @@ SrsGb28181Listener::SrsGb28181Listener(SrsServer* svr, SrsListenerType t, SrsCon { // the caller already ensure the type is ok, // we just assert here for unknown stream caster. - srs_assert(type == SrsListenerGb28181); - if (type == SrsListenerGb28181) { - caster = new SrsGb28181Caster(c); + srs_assert(type == SrsListenerGb28181Sip + ||type == SrsListenerGb28181RtpMux); + + if (type == SrsListenerGb28181Sip) { + caster = new SrsGb28181SipService(c); + }else if(type == SrsListenerGb28181RtpMux){ + caster = new SrsGb28181RtpMuxService(c); } } @@ -526,6 +535,9 @@ void SrsServer::destroy() srs_freep(signal_manager); srs_freep(conn_manager); + + //free global gb28281 manager + srs_freep(_srs_gb28181); } void SrsServer::dispose() @@ -771,6 +783,10 @@ 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 raw"); } + + if ((err = http_api_mux->handle("/api/v1/gb28181", new SrsGoApiGb28181())) != srs_success) { + return srs_error_wrap(err, "handle raw"); + } // test the request info. if ((err = http_api_mux->handle("/api/v1/tests/requests", new SrsGoApiRequests())) != srs_success) { @@ -1088,6 +1104,30 @@ srs_error_t SrsServer::listen_http_stream() return err; } +srs_error_t SrsServer::listen_gb28281_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; +} + srs_error_t SrsServer::listen_stream_caster() { srs_error_t err = srs_success; @@ -1113,19 +1153,33 @@ srs_error_t SrsServer::listen_stream_caster() } else if (srs_stream_caster_is_flv(caster)) { listener = new SrsHttpFlvListener(this, SrsListenerFlv, stream_caster); } else if (srs_stream_caster_is_gb28181(caster)) { - listener = new SrsGb28181Listener(this, SrsListenerGb28181, stream_caster); + //init global gb28281 manger + if (_srs_gb28181 == NULL){ + _srs_gb28181 = new SrsGb28181Manger(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_gb28281_sip(stream_caster)) != srs_success){ + return err; + } + } + + //gb28281 stream listener + listener = new SrsGb28181Listener(this, SrsListenerGb28181RtpMux, stream_caster); } else { return srs_error_new(ERROR_STREAM_CASTER_ENGINE, "invalid caster %s", caster.c_str()); } srs_assert(listener != NULL); listeners.push_back(listener); - int port = _srs_config->get_stream_caster_listen(stream_caster); if (port <= 0) { return srs_error_new(ERROR_STREAM_CASTER_PORT, "invalid port=%d", port); } - // TODO: support listen at <[ip:]port> if ((err = listener->listen(srs_any_address_for_listener(), port)) != srs_success) { return srs_error_wrap(err, "listen at %d", port); diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 46127b6c67..4a7fba9274 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -36,6 +36,8 @@ #include #include #include +#include +#include class SrsServer; class SrsConnection; @@ -52,6 +54,8 @@ class SrsTcpListener; class SrsAppCasterFlv; class SrsRtspCaster; class SrsCoroutineManager; +class SrsGb28181Caster; + // The listener type for server to identify the connection, // that is, use different type to process the connection. @@ -69,8 +73,10 @@ enum SrsListenerType SrsListenerRtsp = 4, // TCP stream, FLV stream over HTTP. SrsListenerFlv = 5, - // UDP stream, gb28181 stream - SrsListenerGb28181 = 6, + // UDP stream, gb28181 ps stream over rtp, + SrsListenerGb28181RtpMux = 6, + // UDP gb28181 sip server + SrsListenerGb28181Sip = 7, }; // A common tcp listener, for RTMP/HTTP server. @@ -158,7 +164,7 @@ class SrsUdpCasterListener : public SrsUdpStreamListener virtual ~SrsUdpCasterListener(); }; -// A UDP sip listener, for sip server. +// A UDP gb28181 listener, for sip and rtp stream mux server. class SrsGb28181Listener : public SrsUdpStreamListener { public: @@ -290,6 +296,7 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan virtual srs_error_t listen_http_api(); virtual srs_error_t listen_http_stream(); virtual srs_error_t listen_stream_caster(); + virtual srs_error_t listen_gb28281_sip(SrsConfDirective* c); // Close the listeners for specified type, // Remove the listen object from manager. virtual void close_listeners(SrsListenerType type); diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index f7375780a1..9180dfd540 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -322,6 +322,22 @@ #define ERROR_BASE64_DECODE 4039 #define ERROR_HTTP_STREAM_EOF 4040 +/////////////////////////////////////////////////////// +// 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_GB28281_SIP_INVITE_FAILED 6008 +#define ERROR_GB28281_SIP_BYE_FAILED 6009 +#define ERROR_GB28281_SIP_IS_INVITING 6010 +#define ERROR_GB28281_CREATER_RTMPMUXER_FAILED 6011 + /////////////////////////////////////////////////////// // HTTP API error. /////////////////////////////////////////////////////// diff --git a/trunk/src/protocol/srs_sip_stack.cpp b/trunk/src/protocol/srs_sip_stack.cpp index e3031fd207..1b5d498124 100644 --- a/trunk/src/protocol/srs_sip_stack.cpp +++ b/trunk/src/protocol/srs_sip_stack.cpp @@ -43,8 +43,6 @@ using namespace std; #include #include -#define SIP_MAX_HEADER_LEN 2049 - unsigned int srs_sip_random(int min,int max) { srand(int(time(0))); @@ -68,10 +66,34 @@ std::string srs_sip_get_form_to_uri(std::string msg) return msg; } - msg = msg.substr(0, pos2-1); + 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) { @@ -120,6 +142,8 @@ SrsSipRequest::SrsSipRequest() status = ""; expires = 3600; max_forwards = 70; + www_authenticate = ""; + authorization = ""; cmdtype = SrsSipCmdRequest; host = "127.0.0.1";; @@ -202,6 +226,8 @@ void SrsSipRequest::copy(SrsSipRequest* src) 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; @@ -215,10 +241,8 @@ void SrsSipRequest::copy(SrsSipRequest* src) sip_username = src->sip_username; peer_ip = src->peer_ip; peer_port = src->peer_port; - } - SrsSipStack::SrsSipStack() { buf = new SrsSimpleStream(); @@ -256,8 +280,8 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m body = header_body.at(1); } - //srs_trace("sip: header=%s\n", header.c_str()); - //srs_trace("sip: body=%s\n", body.c_str()); + 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(); @@ -274,7 +298,7 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m if (firstline == ""){ firstline = oneline; - //srs_trace("=== first line=%s", firstline.c_str()); + srs_info("sip: first line=%s", firstline.c_str()); }else{ size_t pos = oneline.find(":"); if (pos != string::npos){ @@ -322,6 +346,7 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m } } else if (!strcasecmp(phead, "via:")) { + std::vector vec_seq = srs_string_split(content, ";"); req->via = content; req->branch = srs_sip_get_param(content.c_str(), "branch"); } @@ -333,13 +358,19 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m } 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()); } } } - //srs_trace("====new line=%s", oneline.c_str()); } }else{ p++; @@ -370,24 +401,24 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m req->sip_username = req->sip_auth_id; - //srs_trace("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_trace("via=%s", req->via.c_str()); - // srs_trace("via_branch=%s", req->branch.c_str()); - //srs_trace("cseq=%d", req->seq); - // srs_trace("contact=%s", req->contact.c_str()); - //srs_trace("from=%s", req->from.c_str()); - //srs_trace("to=%s", req->to.c_str()); - //srs_trace("callid=%s", req->call_id.c_str()); - // srs_trace("status=%s", req->status.c_str()); - // srs_trace("from_tag=%s", req->from_tag.c_str()); - // srs_trace("to_tag=%s", req->to_tag.c_str()); - //srs_trace("sip_auth_id=%s", req->sip_auth_id.c_str()); + 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; } -srs_error_t SrsSipStack::resp_keepalive(std::stringstream& ss, SrsSipRequest *req){ +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 @@ -398,30 +429,43 @@ srs_error_t SrsSipStack::resp_keepalive(std::stringstream& ss, SrsSipRequest *re << "Max-Forwards: 70" << SRS_RTSP_CRLF << "User-Agent: "<< SRS_SIP_USER_AGENT << SRS_RTSP_CRLF << "Content-Length: 0" << SRS_RTSP_CRLFCRLF; - - return srs_success; -} - -srs_error_t SrsSipStack::resp_ack(std::stringstream& ss, SrsSipRequest *req){ - - ss << "ACK " << "sip:" << req->sip_auth_id << "@" << req->realm << " "<< SRS_SIP_VERSION << SRS_RTSP_CRLF - << "Via: " << SRS_SIP_VERSION << "/UDP " << req->host << ":" << req->host_port << ";branch=" << req->branch << SRS_RTSP_CRLF - << "From: serial << "@" << req->host + ":" << req->host_port << ">;tag=" << req->from_tag << SRS_RTSP_CRLF - << "To: sip_auth_id << "@" << req->realm << ">\r\n" - << "Call-ID: " << req->call_id << SRS_RTSP_CRLF - << "CSeq: " << req->seq << " " << req->method << SRS_RTSP_CRLF - << "Max-Forwards: 70" << SRS_RTSP_CRLF - << "User-Agent: "<< SRS_SIP_USER_AGENT << SRS_RTSP_CRLF - << "Content-Length: 0" << SRS_RTSP_CRLFCRLF; - - return srs_success; } -srs_error_t SrsSipStack::resp_status(stringstream& ss, SrsSipRequest *req) +void SrsSipStack::resp_status(stringstream& ss, SrsSipRequest *req) { - srs_error_t err = srs_success; - 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: " << req->via << SRS_RTSP_CRLF << "From: from << ">" << SRS_RTSP_CRLF @@ -430,8 +474,43 @@ srs_error_t SrsSipStack::resp_status(stringstream& ss, SrsSipRequest *req) << "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: " << req->via << SRS_RTSP_CRLF << "From: from << ">" << SRS_RTSP_CRLF @@ -442,61 +521,104 @@ srs_error_t SrsSipStack::resp_status(stringstream& ss, SrsSipRequest *req) << "Content-Length: 0" << SRS_RTSP_CRLFCRLF; } - return err; } -srs_error_t SrsSipStack::req_invite(stringstream& ss, SrsSipRequest *req, int port) +void SrsSipStack::req_invite(stringstream& ss, SrsSipRequest *req, string ip, int port, uint32_t ssrc) { - /* - INVITE sip:34020000001320000001@3402000000 SIP/2.0 - Via: SIP/2.0/UDP 192.168.1.22:15060;rport;branch=z9hG4bK369961166 - From: ;tag=536961166 - To: - Call-ID: 929961057 - CSeq: 3 INVITE - Content-Type: APPLICATION/SDP - Contact: - Max-Forwards: 70 - User-Agent: XXXXXXX XXXXXXX - Subject: 34020000001320000001:0200000001,34020000002020000001:0 - Content-Length: 247 + /* + //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=34020000002000000001 0 0 IN IP4 192.168.1.23 + o=34020000001320000003 0 0 IN IP4 39.100.155.146 s=Play - c=IN IP4 192.168.1.23 + c=IN IP4 39.100.155.146 t=0 0 - m=video 30000 RTP/AVP 96 97 98 99 + m=video 9000 RTP/AVP 96 a=recvonly a=rtpmap:96 PS/90000 - a=rtpmap:97 MPEG4/90000 - a=rtpmap:98 H264/90000 - a=rtpmap:99 H265/90000 - y=0200000001 + 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 */ - srs_error_t err = srs_success; - int ssrc = srs_sip_random(10000, 99999); std::stringstream sdp; sdp << "v=0" << SRS_RTSP_CRLF - << "o=" << req->sip_auth_id << " 0 0 IN IP4 " << req->host << SRS_RTSP_CRLF + << "o=" << req->sip_auth_id << " 0 0 IN IP4 " << ip << SRS_RTSP_CRLF << "s=Play" << SRS_RTSP_CRLF - << "c=IN IP4 " << req->host << SRS_RTSP_CRLF + << "c=IN IP4 " << ip << SRS_RTSP_CRLF << "t=0 0" << SRS_RTSP_CRLF - << "m=video " << port <<" RTP/AVP 96 97 98 99" << 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 - << "a=rtpmap:97 MPEG4/90000" << SRS_RTSP_CRLF - << "a=rtpmap:98 H264/90000" << SRS_RTSP_CRLF - << "a=rtpmap:99 H265/90000" << SRS_RTSP_CRLF - << "y=00181" << ssrc << 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; + int rand = srs_sip_random(1000, 9999); - std::stringstream from, to, uri; + std::stringstream from, to, uri, branch, from_tag; //"INVITE sip:34020000001320000001@3402000000 SIP/2.0\r\n uri << "sip:" << req->sip_auth_id << "@" << req->realm; //From: ;tag=500485%d\r\n @@ -507,9 +629,14 @@ srs_error_t SrsSipStack::req_invite(stringstream& ss, SrsSipRequest *req, int po req->to = to.str(); req->uri = uri.str(); + branch << "z9hG4bK3420" << rand; + from_tag << "51235" << rand; + req->branch = branch.str(); + req->from_tag = from_tag.str(); + ss << "INVITE " << req->uri << " " << SRS_SIP_VERSION << SRS_RTSP_CRLF - << "Via: " << SRS_SIP_VERSION << "/UDP "<< req->host << ":" << req->host_port << ";rport;branch=z9hG4bK3420" << rand << SRS_RTSP_CRLF - << "From: from << ">;tag=51235" << rand << SRS_RTSP_CRLF + << "Via: " << SRS_SIP_VERSION << "/UDP "<< req->host << ":" << req->host_port << ";rport;branch=" << req->branch << SRS_RTSP_CRLF + << "From: from << ">;tag=" << req->from_tag << SRS_RTSP_CRLF << "To: to << ">" << SRS_RTSP_CRLF << "Call-ID: 20000" << rand <to << ">" << SRS_RTSP_CRLF << "Max-Forwards: 70" << " \r\n" << "User-Agent: " << SRS_SIP_USER_AGENT <sip_auth_id << ":00181" << ssrc << "," << req->serial << ":0" << SRS_RTSP_CRLF + << "Subject: "<< req->sip_auth_id << ":" << ssrc << "," << req->serial << ":0" << SRS_RTSP_CRLF << "Content-Length: " << sdp.str().length() << SRS_RTSP_CRLFCRLF << sdp.str(); +} - return err; + +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: LiveGBS v200228 + 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: " << req->via << ";rport=" << req->peer_port << ";received=" << req->peer_ip << ";branch=" << req->branch << SRS_RTSP_CRLF + << "From: from << ">" << SRS_RTSP_CRLF + << "To: to << ">" << 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::resp_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->sip_auth_id << "@" << 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: serial << "@" << req->host + ":" << req->host_port << ">;tag=" << req->from_tag << SRS_RTSP_CRLF + << "To: sip_auth_id << "@" << req->realm << ">\r\n" + << "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; } -srs_error_t SrsSipStack::req_bye(std::stringstream& ss, SrsSipRequest *req) +void SrsSipStack::req_bye(std::stringstream& ss, SrsSipRequest *req) { - srs_error_t err = srs_success; + /* + //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->sip_auth_id << "@" << req->realm; - from << req->serial << "@" << req->host << ":" << req->host_port; - to << req->sip_auth_id << "@" << req->realm; + from << req->serial << "@" << req->realm; + to << req->sip_auth_id << "@" << req->realm; req->from = from.str(); req->to = to.str(); req->uri = uri.str(); - int rand = srs_sip_random(1000, 9999); + string to_tag, from_tag, branch; + + if (req->branch.empty()){ + branch = ""; + }else { + branch = ";branch=" + req->branch; + } + + if (req->from_tag.empty()){ + from_tag = ""; + }else { + from_tag = ";tag=" + req->from_tag; + } + + if (req->to_tag.empty()){ + to_tag = ""; + }else { + to_tag = ";tag=" + req->to_tag; + } + + int seq = srs_sip_random(22, 99); ss << "BYE " << req->uri << " "<< SRS_SIP_VERSION << SRS_RTSP_CRLF - << "Via: "<< SRS_SIP_VERSION << "/UDP "<< req->host << ":" << req->host_port << ";branch=z9hG4bK3420" << rand << SRS_RTSP_CRLF - << "From: from << ">;tag=51235" << rand << SRS_RTSP_CRLF - << "To: to << ">" << SRS_RTSP_CRLF - << "Call-ID: 20000" << rand << SRS_RTSP_CRLF - << "CSeq: 21 BYE" << SRS_RTSP_CRLF + << "Via: "<< SRS_SIP_VERSION << "/UDP "<< req->host << ":" << req->host_port << ";rport" << branch << SRS_RTSP_CRLF + << "From: from << ">" << from_tag << SRS_RTSP_CRLF + << "To: to << ">" << to_tag << SRS_RTSP_CRLF + << "Call-ID: " << req->call_id << SRS_RTSP_CRLF + << "CSeq: "<< 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; - return err; } - #endif diff --git a/trunk/src/protocol/srs_sip_stack.hpp b/trunk/src/protocol/srs_sip_stack.hpp index f4868a7244..26f7120817 100644 --- a/trunk/src/protocol/srs_sip_stack.hpp +++ b/trunk/src/protocol/srs_sip_stack.hpp @@ -83,6 +83,9 @@ class SrsSipRequest long expires; int max_forwards; + std::string www_authenticate; + std::string authorization; + public: std::string serial; std::string realm; @@ -128,12 +131,13 @@ class SrsSipStack virtual srs_error_t do_parse_request(SrsSipRequest* req, const char *recv_msg); public: - virtual srs_error_t resp_status(std::stringstream& ss, SrsSipRequest *req); - virtual srs_error_t resp_keepalive(std::stringstream& ss, SrsSipRequest *req); - virtual srs_error_t resp_ack(std::stringstream& ss, SrsSipRequest *req); + virtual void resp_status(std::stringstream& ss, SrsSipRequest *req); + virtual void resp_keepalive(std::stringstream& ss, SrsSipRequest *req); + virtual void resp_ack(std::stringstream& ss, SrsSipRequest *req); - virtual srs_error_t req_invite(std::stringstream& ss, SrsSipRequest *req, int port); - virtual srs_error_t req_bye(std::stringstream& ss, SrsSipRequest *req); + virtual void req_invite(std::stringstream& ss, SrsSipRequest *req, std::string ip, int port, uint32_t ssrc); + virtual void req_bye(std::stringstream& ss, SrsSipRequest *req); + virtual void req_401_unauthorized(std::stringstream& ss, SrsSipRequest *req); };