mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
gb28181模块可用性增强
主要改动, 1. 支持作为GB/T 28181上级平台 2. 新的目录接口sip_query_devicelist (/api/v1/gb28181?action=sip_query_devicelist) 3. 各种异常和问题修复 4. 其他一些小改动 以上改动基于feature/rtc分支,因为需要网页用WebRTC来拉GB28181的监控流,gb28181分支代码有点老了。 下面的序号n是指第n个差异块("@@ -"之间的内容)。 srs_gb28181.html 1. 原页面上多加了一个端口号 2-4. 给摄像头加上名称显示 5. 查询目录去掉chid 6. 删除通道参数分解为id和chid 7. API端口固定为1985 srs_app_gb28181.cpp 1-4. 四处因为错误而退出GB28181媒体处理循环,修改为不退出 5. payload为空异常 6. 修正判断startcode越界一个字符导致内存写越界的问题 ps流有可能末尾是全零填充,而且越界的那个字符正好是0x01,这样会多出一个nalu(末尾的三个0x00和一个越界的0x01),后面写video_data内存越界(if (first_pos != pre_pos){块,此处size - pre_pos - 4为-1,uint32_t naluLen得到的值为0,video_data[pre_pos+3] = p[0];写越界)破坏了其他数据,后续video_stream析构出错程序异常退出。 7. 此处srs后来已修复 8. 更新ssrc为被叫返回的值 原代码只支持标准中的《点播域内设备媒体流SSRC处理方式》(设备注册上来),不支持《点播外域设备媒体流SSRC处理方式》(即作为上级平台)。 这是因为如果srs作为上级平台,ssrc不是自己生成的,而是下级平台生成的。 9. 删除通道参数分解为id和chid 10. notify_sip_unregister后delete_stream_channel无效 11. notify_sip_query_catalog清空内存中的设备列表 12. 新函数query_device_list srs_app_gb28181.hpp 1. update_rtmpmuxer_to_newssrc_by_id声明 2. 新函数get_gb28181_config_ptr和函数delete_stream_channel声明修改 3. 新函数query_device_list srs_app_gb28181_sip.cpp 1-4. 在调试界面给摄像头加上名称显示;新函数clear_device_list和新函数dumpItemList 5-6. 两处因为错误而退出GB28181信令处理循环,修改为不退出 7. 设备注册上来,不检查服务器ID匹不匹配(支持作为上级平台) 8. 收到一个目录上报消息,更新内存中的数据 9. 更新ssrc为被叫返回的值 10. 新函数query_device_list srs_app_gb28181_sip.hpp 1. 在调试界面给摄像头加上名称显示 2. 每个设备加上item_list,用于存储目录;新函数clear_device_list和新函数dumpItemList 3. 新函数clear_device_list srs_app_http_api.cpp 1. 删除通道参数分解为id和chid 2. 新的接口sip_query_devicelist,用于查询所有设备的目录 srs_sip_stack.cpp 1. GB2312转UTF-8类 2. 被叫返回的ssrc初始化 3. parse_xml声明修改 4. 对XML内容进行字符集检测和转换 5-7. parse_xml定义修改 8. SIP BODY里面也有可能有\r\n 9-10. 防止恶意SIP消息 by vicious sip prober 11-12. 新的XML解析目录代码 13. 获取被叫返回的ssrc srs_sip_stack.hpp 1. 依赖vector 2. 每个设备加上item_list,用于存储目录 3. 被叫返回的ssrc 4. parse_xml声明修改
This commit is contained in:
parent
fe65c7bf84
commit
ffae1720ec
8 changed files with 370 additions and 53 deletions
|
@ -465,7 +465,12 @@
|
||||||
var url = null;
|
var url = null;
|
||||||
|
|
||||||
var query = parse_query_string();
|
var query = parse_query_string();
|
||||||
$("#txt_api_url").val("http://" + query.host + ":1985")
|
var query_host = query.host.split(':');
|
||||||
|
if (query_host && query_host.length == 2) {
|
||||||
|
$("#txt_api_url").val("http://" + query_host[0] + ":1985");
|
||||||
|
} else {
|
||||||
|
$("#txt_api_url").val("http://" + query.host + ":1985");
|
||||||
|
}
|
||||||
|
|
||||||
var __active_dar = null;
|
var __active_dar = null;
|
||||||
function select_dar(dar_id, num, den) {
|
function select_dar(dar_id, num, den) {
|
||||||
|
@ -588,7 +593,7 @@
|
||||||
for (idx2 in devices)
|
for (idx2 in devices)
|
||||||
{
|
{
|
||||||
//href="javascript:void(0)" onclick="fn(this)">
|
//href="javascript:void(0)" onclick="fn(this)">
|
||||||
var id = "-->" + devices[idx2].device_id + ":" + devices[idx2].device_status + ":" + devices[idx2].invite_status;
|
var id = "-->" + devices[idx2].device_name + ":" + devices[idx2].device_id + ":" + devices[idx2].device_status + ":" + devices[idx2].invite_status;
|
||||||
var li = "<li><a id='linkChannelId1' href='javascript:void(0)' onclick='sipSessionOnClick(this)' rel='"+ session.id + "'>" +id + "</a></li>";
|
var li = "<li><a id='linkChannelId1' href='javascript:void(0)' onclick='sipSessionOnClick(this)' rel='"+ session.id + "'>" +id + "</a></li>";
|
||||||
$("#sipSessionList").append(li);
|
$("#sipSessionList").append(li);
|
||||||
}
|
}
|
||||||
|
@ -1007,7 +1012,7 @@
|
||||||
var str = text.split("-->");
|
var str = text.split("-->");
|
||||||
id = str[0];
|
id = str[0];
|
||||||
var str2 = str[1].split(":")
|
var str2 = str[1].split(":")
|
||||||
chid = str2[0];
|
chid = str2[1];
|
||||||
|
|
||||||
url = $("#txt_api_url").val();
|
url = $("#txt_api_url").val();
|
||||||
var apiurl = url + "/api/v1/gb28181?action=sip_invite&id=" + id + "&chid="+chid;
|
var apiurl = url + "/api/v1/gb28181?action=sip_invite&id=" + id + "&chid="+chid;
|
||||||
|
@ -1026,7 +1031,7 @@
|
||||||
var str = text.split("-->");
|
var str = text.split("-->");
|
||||||
id = str[0];
|
id = str[0];
|
||||||
var str2 = str[1].split(":")
|
var str2 = str[1].split(":")
|
||||||
chid = str2[0];
|
chid = str2[1];
|
||||||
|
|
||||||
url = $("#txt_api_url").val();
|
url = $("#txt_api_url").val();
|
||||||
var apiurl = url + "/api/v1/gb28181?action=sip_bye&id=" + id + "&chid="+chid;
|
var apiurl = url + "/api/v1/gb28181?action=sip_bye&id=" + id + "&chid="+chid;
|
||||||
|
@ -1048,7 +1053,7 @@
|
||||||
chid = str2[0];
|
chid = str2[0];
|
||||||
|
|
||||||
url = $("#txt_api_url").val();
|
url = $("#txt_api_url").val();
|
||||||
var apiurl = url + "/api/v1/gb28181?action=sip_query_catalog&id=" + id + "&chid="+chid;
|
var apiurl = url + "/api/v1/gb28181?action=sip_query_catalog&id=" + id;
|
||||||
var ret = http_get(apiurl);
|
var ret = http_get(apiurl);
|
||||||
$('#sipSessionMessage').html(syntaxHighlight(ret));
|
$('#sipSessionMessage').html(syntaxHighlight(ret));
|
||||||
if (ret != undefined && ret.code == 0){
|
if (ret != undefined && ret.code == 0){
|
||||||
|
@ -1069,9 +1074,17 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_delete_channel").click(function(){
|
$("#btn_delete_channel").click(function(){
|
||||||
var id = $("#gb28181ChannelId").text();
|
var str = $("#gb28181ChannelId").text();
|
||||||
|
var str_array = str.split("@")
|
||||||
|
var chid = "";
|
||||||
|
var id = "";
|
||||||
|
if (str_array.length != 2){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
id = str_array[0];
|
||||||
|
chid = str_array[1];
|
||||||
url = $("#txt_api_url").val();
|
url = $("#txt_api_url").val();
|
||||||
var apiurl = url + "/api/v1/gb28181?action=delete_channel&id=" + id;
|
var apiurl = url + "/api/v1/gb28181?action=delete_channel&id=" + id + "&chid="+chid;
|
||||||
var ret = http_get(apiurl);
|
var ret = http_get(apiurl);
|
||||||
$('#gb28181ChannelMessage').html(syntaxHighlight(ret));
|
$('#gb28181ChannelMessage').html(syntaxHighlight(ret));
|
||||||
if (ret != undefined && ret.code == 0){
|
if (ret != undefined && ret.code == 0){
|
||||||
|
@ -1190,7 +1203,8 @@
|
||||||
return pc.setLocalDescription(offer).then(function(){ return offer; });
|
return pc.setLocalDescription(offer).then(function(){ return offer; });
|
||||||
}).then(function(offer) {
|
}).then(function(offer) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
var port = urlObject.port || 1985;
|
// var port = urlObject.port || 1985;
|
||||||
|
var port = 1985;
|
||||||
|
|
||||||
// @see https://github.com/rtcdn/rtcdn-draft
|
// @see https://github.com/rtcdn/rtcdn-draft
|
||||||
var api = urlObject.user_query.play || '/rtc/v1/play/';
|
var api = urlObject.user_query.play || '/rtc/v1/play/';
|
||||||
|
|
|
@ -215,7 +215,9 @@ srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet(const sockaddr* from, const
|
||||||
(char*)&address_string, sizeof(address_string),
|
(char*)&address_string, sizeof(address_string),
|
||||||
(char*)&port_string, sizeof(port_string),
|
(char*)&port_string, sizeof(port_string),
|
||||||
NI_NUMERICHOST|NI_NUMERICSERV)){
|
NI_NUMERICHOST|NI_NUMERICSERV)){
|
||||||
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
|
// return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
|
||||||
|
srs_warn("gb28181 ps rtp: bad address");
|
||||||
|
return srs_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
int peer_port = atoi(port_string);
|
int peer_port = atoi(port_string);
|
||||||
|
@ -225,7 +227,10 @@ srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet(const sockaddr* from, const
|
||||||
SrsPsRtpPacket pkt;
|
SrsPsRtpPacket pkt;
|
||||||
|
|
||||||
if ((err = pkt.decode(&stream)) != srs_success) {
|
if ((err = pkt.decode(&stream)) != srs_success) {
|
||||||
return srs_error_wrap(err, "ps rtp decode error");
|
// return srs_error_wrap(err, "ps rtp decode error");
|
||||||
|
srs_warn("gb28181 ps rtp: decode error");
|
||||||
|
srs_freep(err);
|
||||||
|
return srs_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: fixme: the same device uses the same SSRC to send with different local ports
|
//TODO: fixme: the same device uses the same SSRC to send with different local ports
|
||||||
|
@ -432,7 +437,9 @@ srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet_jitter(const sockaddr* from,
|
||||||
(char*)&address_string, sizeof(address_string),
|
(char*)&address_string, sizeof(address_string),
|
||||||
(char*)&port_string, sizeof(port_string),
|
(char*)&port_string, sizeof(port_string),
|
||||||
NI_NUMERICHOST|NI_NUMERICSERV)){
|
NI_NUMERICHOST|NI_NUMERICSERV)){
|
||||||
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
|
// return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
|
||||||
|
srs_warn("gb28181 ps rtp: bad address");
|
||||||
|
return srs_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
int peer_port = atoi(port_string);
|
int peer_port = atoi(port_string);
|
||||||
|
@ -443,7 +450,10 @@ srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet_jitter(const sockaddr* from,
|
||||||
|
|
||||||
if ((err = pkt->decode(&stream)) != srs_success) {
|
if ((err = pkt->decode(&stream)) != srs_success) {
|
||||||
srs_freep(pkt);
|
srs_freep(pkt);
|
||||||
return srs_error_wrap(err, "ps rtp decode error");
|
// return srs_error_wrap(err, "ps rtp decode error");
|
||||||
|
srs_warn("gb28181 ps rtp: decode error");
|
||||||
|
srs_freep(err);
|
||||||
|
return srs_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream ss3;
|
std::stringstream ss3;
|
||||||
|
@ -1588,6 +1598,9 @@ void SrsGb28181RtmpMuxer::insert_jitterbuffer(SrsPsRtpPacket *pkt)
|
||||||
recv_rtp_stream_time = srs_get_system_time();
|
recv_rtp_stream_time = srs_get_system_time();
|
||||||
|
|
||||||
char *payload = pkt->payload->bytes();
|
char *payload = pkt->payload->bytes();
|
||||||
|
if (!payload) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t p1 = (uint8_t)(payload[0]);
|
uint8_t p1 = (uint8_t)(payload[0]);
|
||||||
uint8_t p2 = (uint8_t)(payload[1]);
|
uint8_t p2 = (uint8_t)(payload[1]);
|
||||||
|
@ -1765,13 +1778,12 @@ srs_error_t SrsGb28181RtmpMuxer::write_h264_ipb_frame2(char *frame, int frame_si
|
||||||
std::list<int> list_index;
|
std::list<int> list_index;
|
||||||
|
|
||||||
for(; index < size; index++){
|
for(; index < size; index++){
|
||||||
|
if (index > (size-4))
|
||||||
|
break;
|
||||||
if (video_data[index] == 0x00 && video_data[index+1] == 0x00 &&
|
if (video_data[index] == 0x00 && video_data[index+1] == 0x00 &&
|
||||||
video_data[index+2] == 0x00 && video_data[index+3] == 0x01){
|
video_data[index+2] == 0x00 && video_data[index+3] == 0x01){
|
||||||
list_index.push_back(index);
|
list_index.push_back(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index > (size-4))
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list_index.size() == 1){
|
if (list_index.size() == 1){
|
||||||
|
@ -2153,6 +2165,8 @@ void SrsGb28181RtmpMuxer::close()
|
||||||
h264_pps = "";
|
h264_pps = "";
|
||||||
aac_specific_config = "";
|
aac_specific_config = "";
|
||||||
|
|
||||||
|
// BUGFIX: if don't unpublish, it will always be in the /api/v1/streams list
|
||||||
|
//if (source_publish && !source){
|
||||||
if (source_publish && source){
|
if (source_publish && source){
|
||||||
source->on_unpublish();
|
source->on_unpublish();
|
||||||
}
|
}
|
||||||
|
@ -2347,6 +2361,28 @@ SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer(std::string id)
|
||||||
return muxer;
|
return muxer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SrsGb28181Manger::update_rtmpmuxer_to_newssrc_by_id(std::string id, uint32_t ssrc)
|
||||||
|
{
|
||||||
|
SrsGb28181RtmpMuxer* muxer = NULL;
|
||||||
|
|
||||||
|
if (rtmpmuxers.find(id) == rtmpmuxers.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
muxer = rtmpmuxers[id];
|
||||||
|
SrsGb28181StreamChannel mc = muxer->get_channel();
|
||||||
|
uint32_t old_ssrc = mc.get_ssrc();
|
||||||
|
if (old_ssrc == ssrc) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
srs_trace("gb28181: update ssrc of muxer %s from %x to %x", id.c_str(), old_ssrc, ssrc);
|
||||||
|
}
|
||||||
|
rtmpmuxer_unmap_by_ssrc(old_ssrc);
|
||||||
|
mc.set_ssrc(ssrc);
|
||||||
|
muxer->copy_channel(&mc);
|
||||||
|
rtmpmuxer_map_by_ssrc(muxer, ssrc);
|
||||||
|
}
|
||||||
|
|
||||||
SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer_by_ssrc(uint32_t ssrc)
|
SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer_by_ssrc(uint32_t ssrc)
|
||||||
{
|
{
|
||||||
SrsGb28181RtmpMuxer* muxer = NULL;
|
SrsGb28181RtmpMuxer* muxer = NULL;
|
||||||
|
@ -2602,17 +2638,19 @@ srs_error_t SrsGb28181Manger::create_stream_channel(SrsGb28181StreamChannel *cha
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsGb28181Manger::delete_stream_channel(std::string id)
|
srs_error_t SrsGb28181Manger::delete_stream_channel(std::string id, std::string chid)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
//notify the device to stop streaming
|
//notify the device to stop streaming
|
||||||
//if an internal sip service controlled channel
|
//if an internal sip service controlled channel
|
||||||
notify_sip_bye(id, id);
|
notify_sip_bye(id, chid);
|
||||||
|
|
||||||
SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(id);
|
string channel_id = id + "@" + chid;
|
||||||
|
|
||||||
|
SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(channel_id);
|
||||||
if (muxer){
|
if (muxer){
|
||||||
stop_rtp_listen(id);
|
stop_rtp_listen(channel_id);
|
||||||
muxer->stop();
|
muxer->stop();
|
||||||
return err;
|
return err;
|
||||||
}else {
|
}else {
|
||||||
|
@ -2727,7 +2765,11 @@ srs_error_t SrsGb28181Manger::notify_sip_unregister(std::string id)
|
||||||
return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run");
|
return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run");
|
||||||
}
|
}
|
||||||
sip_service->remove_session(id);
|
sip_service->remove_session(id);
|
||||||
return delete_stream_channel(id);
|
return srs_success;
|
||||||
|
// useless, because
|
||||||
|
// sip session has been removed
|
||||||
|
// id is not channel id like id@chid
|
||||||
|
//return delete_stream_channel(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsGb28181Manger::notify_sip_query_catalog(std::string id)
|
srs_error_t SrsGb28181Manger::notify_sip_query_catalog(std::string id)
|
||||||
|
@ -2738,6 +2780,12 @@ srs_error_t SrsGb28181Manger::notify_sip_query_catalog(std::string id)
|
||||||
|
|
||||||
SrsSipRequest req;
|
SrsSipRequest req;
|
||||||
req.sip_auth_id = id;
|
req.sip_auth_id = id;
|
||||||
|
SrsGb28181SipSession *sip_session = sip_service->fetch(req.sip_auth_id);
|
||||||
|
if (sip_session) {
|
||||||
|
sip_session->item_list.clear();
|
||||||
|
sip_session->clear_device_list();
|
||||||
|
srs_trace("notify_sip_query_catalog, clear sip session item and device list");
|
||||||
|
}
|
||||||
return sip_service->send_query_catalog(&req);
|
return sip_service->send_query_catalog(&req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2750,8 +2798,14 @@ srs_error_t SrsGb28181Manger::query_sip_session(std::string id, SrsJsonArray* ar
|
||||||
return sip_service->query_sip_session(id, arr);
|
return sip_service->query_sip_session(id, arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsGb28181Manger::query_device_list(std::string id, SrsJsonArray* arr)
|
||||||
|
{
|
||||||
|
if (!sip_service){
|
||||||
|
return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run");
|
||||||
|
}
|
||||||
|
|
||||||
|
return sip_service->query_device_list(id, arr);
|
||||||
|
}
|
||||||
|
|
||||||
#define SRS_RTSP_BUFFER 262144
|
#define SRS_RTSP_BUFFER 262144
|
||||||
SrsGb28181Conn::SrsGb28181Conn(SrsGb28181Caster* c, srs_netfd_t fd, SrsGb28181TcpPsRtpProcessor *rtp_processor)
|
SrsGb28181Conn::SrsGb28181Conn(SrsGb28181Caster* c, srs_netfd_t fd, SrsGb28181TcpPsRtpProcessor *rtp_processor)
|
||||||
|
@ -2970,3 +3024,4 @@ void SrsGb28181Caster::remove(SrsGb28181Conn* conn)
|
||||||
|
|
||||||
manager->remove(conn);
|
manager->remove(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -518,6 +518,7 @@ public:
|
||||||
srs_error_t fetch_or_create_rtmpmuxer(std::string id, SrsRequest *req, SrsGb28181RtmpMuxer** gb28181);
|
srs_error_t fetch_or_create_rtmpmuxer(std::string id, SrsRequest *req, SrsGb28181RtmpMuxer** gb28181);
|
||||||
SrsGb28181RtmpMuxer* fetch_rtmpmuxer(std::string id);
|
SrsGb28181RtmpMuxer* fetch_rtmpmuxer(std::string id);
|
||||||
SrsGb28181RtmpMuxer* fetch_rtmpmuxer_by_ssrc(uint32_t ssrc);
|
SrsGb28181RtmpMuxer* fetch_rtmpmuxer_by_ssrc(uint32_t ssrc);
|
||||||
|
void update_rtmpmuxer_to_newssrc_by_id(std::string id, uint32_t ssrc);
|
||||||
void rtmpmuxer_map_by_ssrc(SrsGb28181RtmpMuxer*muxer, uint32_t ssrc);
|
void rtmpmuxer_map_by_ssrc(SrsGb28181RtmpMuxer*muxer, uint32_t ssrc);
|
||||||
void rtmpmuxer_unmap_by_ssrc(uint32_t ssrc);
|
void rtmpmuxer_unmap_by_ssrc(uint32_t ssrc);
|
||||||
uint32_t generate_ssrc(std::string id);
|
uint32_t generate_ssrc(std::string id);
|
||||||
|
@ -525,11 +526,12 @@ public:
|
||||||
|
|
||||||
void set_sip_service(SrsGb28181SipService *s) { sip_service = s; }
|
void set_sip_service(SrsGb28181SipService *s) { sip_service = s; }
|
||||||
SrsGb28181SipService* get_sip_service() { return sip_service; }
|
SrsGb28181SipService* get_sip_service() { return sip_service; }
|
||||||
|
SrsGb28181Config* get_gb28181_config_ptr() { return config;}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//stream channel api
|
//stream channel api
|
||||||
srs_error_t create_stream_channel(SrsGb28181StreamChannel *channel);
|
srs_error_t create_stream_channel(SrsGb28181StreamChannel *channel);
|
||||||
srs_error_t delete_stream_channel(std::string id);
|
srs_error_t delete_stream_channel(std::string id, std::string chid);
|
||||||
srs_error_t query_stream_channel(std::string id, SrsJsonArray* arr);
|
srs_error_t query_stream_channel(std::string id, SrsJsonArray* arr);
|
||||||
//sip api
|
//sip api
|
||||||
srs_error_t notify_sip_invite(std::string id, std::string ip, int port, uint32_t ssrc, std::string chid);
|
srs_error_t notify_sip_invite(std::string id, std::string ip, int port, uint32_t ssrc, std::string chid);
|
||||||
|
@ -539,6 +541,7 @@ public:
|
||||||
srs_error_t notify_sip_query_catalog(std::string id);
|
srs_error_t notify_sip_query_catalog(std::string id);
|
||||||
srs_error_t notify_sip_ptz(std::string id, std::string chid, std::string cmd, uint8_t speed, int priority);
|
srs_error_t notify_sip_ptz(std::string id, std::string chid, std::string cmd, uint8_t speed, int priority);
|
||||||
srs_error_t query_sip_session(std::string id, SrsJsonArray* arr);
|
srs_error_t query_sip_session(std::string id, SrsJsonArray* arr);
|
||||||
|
srs_error_t query_device_list(std::string id, SrsJsonArray* arr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
|
@ -68,6 +68,7 @@ std::string srs_get_sip_session_status_str(SrsGb28181SipSessionStatusType status
|
||||||
SrsGb28181Device::SrsGb28181Device()
|
SrsGb28181Device::SrsGb28181Device()
|
||||||
{
|
{
|
||||||
device_id = "";
|
device_id = "";
|
||||||
|
device_name = "";
|
||||||
invite_status = SrsGb28181SipSessionUnkonw;
|
invite_status = SrsGb28181SipSessionUnkonw;
|
||||||
invite_time = 0;
|
invite_time = 0;
|
||||||
device_status = "";
|
device_status = "";
|
||||||
|
@ -102,6 +103,8 @@ SrsGb28181SipSession::SrsGb28181SipSession(SrsGb28181SipService *c, SrsSipReques
|
||||||
_fromlen = 0;
|
_fromlen = 0;
|
||||||
_sip_cseq = 100;
|
_sip_cseq = 100;
|
||||||
|
|
||||||
|
item_list_sumnum = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsGb28181SipSession::~SrsGb28181SipSession()
|
SrsGb28181SipSession::~SrsGb28181SipSession()
|
||||||
|
@ -338,19 +341,42 @@ void SrsGb28181SipSession::update_device_list(std::map<std::string, std::string>
|
||||||
if (_device_list.find(id) == _device_list.end()){
|
if (_device_list.find(id) == _device_list.end()){
|
||||||
SrsGb28181Device *device = new SrsGb28181Device();
|
SrsGb28181Device *device = new SrsGb28181Device();
|
||||||
device->device_id = id;
|
device->device_id = id;
|
||||||
device->device_status = status;
|
if (status.find(",") != std::string::npos) {
|
||||||
|
device->device_status = status.substr(0,status.find(","));
|
||||||
|
device->device_name = status.substr(status.find(",")+1);
|
||||||
|
} else {
|
||||||
|
device->device_status = status;
|
||||||
|
device->device_name = "NONAME";
|
||||||
|
}
|
||||||
device->invite_status = SrsGb28181SipSessionUnkonw;
|
device->invite_status = SrsGb28181SipSessionUnkonw;
|
||||||
device->invite_time = 0;
|
device->invite_time = 0;
|
||||||
_device_list[id] = device;
|
_device_list[id] = device;
|
||||||
|
|
||||||
}else {
|
}else {
|
||||||
SrsGb28181Device *device = _device_list[id];
|
SrsGb28181Device *device = _device_list[id];
|
||||||
device->device_status = status;
|
if (status.find(",") != std::string::npos) {
|
||||||
|
device->device_status = status.substr(0,status.find(","));
|
||||||
|
device->device_name = status.substr(status.find(",")+1);
|
||||||
|
} else {
|
||||||
|
device->device_status = status;
|
||||||
|
device->device_name = "NONAME";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SrsGb28181SipSession::clear_device_list()
|
||||||
|
{
|
||||||
|
//destory all device
|
||||||
|
std::map<std::string, SrsGb28181Device*>::iterator it;
|
||||||
|
for (it = _device_list.begin(); it != _device_list.end(); ++it) {
|
||||||
|
srs_freep(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
_device_list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
SrsGb28181Device* SrsGb28181SipSession::get_device_info(std::string chid)
|
SrsGb28181Device* SrsGb28181SipSession::get_device_info(std::string chid)
|
||||||
{
|
{
|
||||||
if (_device_list.find(chid) != _device_list.end()){
|
if (_device_list.find(chid) != _device_list.end()){
|
||||||
|
@ -372,12 +398,33 @@ void SrsGb28181SipSession::dumps(SrsJsonObject* obj)
|
||||||
SrsJsonObject* obj = SrsJsonAny::object();
|
SrsJsonObject* obj = SrsJsonAny::object();
|
||||||
arr->append(obj);
|
arr->append(obj);
|
||||||
obj->set("device_id", SrsJsonAny::str(device->device_id.c_str()));
|
obj->set("device_id", SrsJsonAny::str(device->device_id.c_str()));
|
||||||
|
obj->set("device_name", SrsJsonAny::str(device->device_name.c_str()));
|
||||||
obj->set("device_status", SrsJsonAny::str(device->device_status.c_str()));
|
obj->set("device_status", SrsJsonAny::str(device->device_status.c_str()));
|
||||||
obj->set("invite_status", SrsJsonAny::str(srs_get_sip_session_status_str(device->invite_status).c_str()));
|
obj->set("invite_status", SrsJsonAny::str(srs_get_sip_session_status_str(device->invite_status).c_str()));
|
||||||
obj->set("invite_time", SrsJsonAny::integer(device->invite_time/SRS_UTIME_SECONDS));
|
obj->set("invite_time", SrsJsonAny::integer(device->invite_time/SRS_UTIME_SECONDS));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SrsGb28181SipSession::dumpItemList(SrsJsonObject* obj)
|
||||||
|
{
|
||||||
|
obj->set("TopDeviceID", SrsJsonAny::str(_session_id.c_str()));
|
||||||
|
obj->set("SumNum", SrsJsonAny::integer(item_list_sumnum));
|
||||||
|
obj->set("RealSumNum", SrsJsonAny::integer(item_list.size()));
|
||||||
|
|
||||||
|
SrsJsonArray* arr = SrsJsonAny::array();
|
||||||
|
obj->set("ItemList", arr);
|
||||||
|
std::map<std::string, std::map<std::string, std::string> >::iterator it;
|
||||||
|
for (it = item_list.begin(); it != item_list.end(); ++it) {
|
||||||
|
std::map<std::string, std::string> device = it->second;
|
||||||
|
SrsJsonObject* obj2 = SrsJsonAny::object();
|
||||||
|
arr->append(obj2);
|
||||||
|
std::map<std::string, std::string>::iterator it2;
|
||||||
|
for (it2 = device.begin(); it2 != device.end(); ++it2) {
|
||||||
|
obj2->set(it2->first, SrsJsonAny::str(it2->second.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//gb28181 sip Service
|
//gb28181 sip Service
|
||||||
SrsGb28181SipService::SrsGb28181SipService(SrsConfDirective* c)
|
SrsGb28181SipService::SrsGb28181SipService(SrsConfDirective* c)
|
||||||
{
|
{
|
||||||
|
@ -419,7 +466,9 @@ srs_error_t SrsGb28181SipService::on_udp_packet(const sockaddr* from, const int
|
||||||
(char*)&address_string, sizeof(address_string),
|
(char*)&address_string, sizeof(address_string),
|
||||||
(char*)&port_string, sizeof(port_string),
|
(char*)&port_string, sizeof(port_string),
|
||||||
NI_NUMERICHOST|NI_NUMERICSERV)) {
|
NI_NUMERICHOST|NI_NUMERICSERV)) {
|
||||||
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
|
// return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
|
||||||
|
srs_warn("gb28181: bad address");
|
||||||
|
return srs_success;
|
||||||
}
|
}
|
||||||
std::string peer_ip = std::string(address_string);
|
std::string peer_ip = std::string(address_string);
|
||||||
int peer_port = atoi(port_string);
|
int peer_port = atoi(port_string);
|
||||||
|
@ -427,7 +476,10 @@ srs_error_t SrsGb28181SipService::on_udp_packet(const sockaddr* from, const int
|
||||||
std::string recv_msg(buf, nb_buf);
|
std::string recv_msg(buf, nb_buf);
|
||||||
srs_error_t err = on_udp_sip(peer_ip, peer_port, recv_msg, (sockaddr*)from, fromlen);
|
srs_error_t err = on_udp_sip(peer_ip, peer_port, recv_msg, (sockaddr*)from, fromlen);
|
||||||
if (err != srs_success) {
|
if (err != srs_success) {
|
||||||
return srs_error_wrap(err, "process udp");
|
// return srs_error_wrap(err, "process udp");
|
||||||
|
srs_warn("gb28181: process udp");
|
||||||
|
srs_freep(err);
|
||||||
|
return srs_success;
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -465,11 +517,11 @@ srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port,
|
||||||
return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "register string split");
|
return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "register string split");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serial.at(0) != config->sip_serial){
|
//if (serial.at(0) != config->sip_serial){
|
||||||
srs_warn("gb28181: client:%s request serial and server serial inconformity(%s:%s)",
|
// srs_warn("gb28181: client:%s request serial and server serial inconformity(%s:%s)",
|
||||||
req->sip_auth_id.c_str(), serial.at(0).c_str(), config->sip_serial.c_str());
|
// req->sip_auth_id.c_str(), serial.at(0).c_str(), config->sip_serial.c_str());
|
||||||
return err;
|
// return err;
|
||||||
}
|
//}
|
||||||
|
|
||||||
srs_trace("gb28181: request client id=%s peer(%s, %d)", req->sip_auth_id.c_str(), peer_ip.c_str(), peer_port);
|
srs_trace("gb28181: request client id=%s peer(%s, %d)", req->sip_auth_id.c_str(), peer_ip.c_str(), peer_port);
|
||||||
srs_trace("gb28181: %s method=%s, uri=%s, version=%s expires=%d",
|
srs_trace("gb28181: %s method=%s, uri=%s, version=%s expires=%d",
|
||||||
|
@ -519,6 +571,24 @@ srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port,
|
||||||
if (req->device_list_map.size() > 0){
|
if (req->device_list_map.size() > 0){
|
||||||
sip_session->update_device_list(req->device_list_map);
|
sip_session->update_device_list(req->device_list_map);
|
||||||
}
|
}
|
||||||
|
if (!strcasecmp(req->content_type.c_str(),"application/manscdp+xml")
|
||||||
|
&& req->xml_body_map.find("Response@CmdType") != req->xml_body_map.end()
|
||||||
|
&& req->xml_body_map["Response@CmdType"] == "Catalog") {
|
||||||
|
if (req->xml_body_map.find("Response@SumNum") != req->xml_body_map.end()) {
|
||||||
|
sip_session->item_list_sumnum = atoi(req->xml_body_map["Response@SumNum"].c_str());
|
||||||
|
}
|
||||||
|
std::vector<std::map<std::string, std::string> >::iterator it;
|
||||||
|
for (it = req->item_list.begin(); it != req->item_list.end(); ++it) {
|
||||||
|
std::map<std::string, std::string> device = *it;
|
||||||
|
std::map<std::string, std::map<std::string, std::string> >::iterator it2 = sip_session->item_list.find(device["DeviceID"]);
|
||||||
|
if (it2 != sip_session->item_list.end()) {
|
||||||
|
sip_session->item_list.erase(it2);
|
||||||
|
sip_session->item_list[device["DeviceID"]] = device;
|
||||||
|
} else {
|
||||||
|
sip_session->item_list[device["DeviceID"]] = device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}else if (req->is_invite()) {
|
}else if (req->is_invite()) {
|
||||||
|
@ -547,6 +617,14 @@ srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port,
|
||||||
srs_trace("gb28181: INVITE response %s client status=%s", req->sip_auth_id.c_str(), req->status.c_str());
|
srs_trace("gb28181: INVITE response %s client status=%s", req->sip_auth_id.c_str(), req->status.c_str());
|
||||||
|
|
||||||
if (req->status == "200") {
|
if (req->status == "200") {
|
||||||
|
srs_trace("gb28181: device unique id is %s@%s", sip_session->session_id().c_str(), req->sip_auth_id.c_str());
|
||||||
|
// if srs is external realm, ssrc is generated by source realm rather than srs
|
||||||
|
// so update ssrc to the y line in source realm '200 OK' response
|
||||||
|
// actually, we should do this all the time
|
||||||
|
if (req->y_ssrc != 0) {
|
||||||
|
_srs_gb28181->update_rtmpmuxer_to_newssrc_by_id(sip_session->session_id()+"@"+req->sip_auth_id, req->y_ssrc);
|
||||||
|
req->y_ssrc = 0;
|
||||||
|
}
|
||||||
send_ack(req, from, fromlen);
|
send_ack(req, from, fromlen);
|
||||||
SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id);
|
SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id);
|
||||||
if (device){
|
if (device){
|
||||||
|
@ -919,6 +997,31 @@ srs_error_t SrsGb28181SipService::query_sip_session(std::string sid, SrsJsonArr
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsGb28181SipService::query_device_list(std::string sid, SrsJsonArray* arr)
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
if (!sid.empty()){
|
||||||
|
SrsGb28181SipSession* sess = fetch(sid);
|
||||||
|
if (!sess){
|
||||||
|
return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist");
|
||||||
|
}
|
||||||
|
SrsJsonObject* obj = SrsJsonAny::object();
|
||||||
|
arr->append(obj);
|
||||||
|
sess->dumpItemList(obj);
|
||||||
|
}else {
|
||||||
|
std::map<std::string, SrsGb28181SipSession*>::iterator it;
|
||||||
|
for (it = sessions.begin(); it != sessions.end(); ++it) {
|
||||||
|
SrsGb28181SipSession* sess = it->second;
|
||||||
|
SrsJsonObject* obj = SrsJsonAny::object();
|
||||||
|
arr->append(obj);
|
||||||
|
sess->dumpItemList(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
srs_error_t SrsGb28181SipService::fetch_or_create_sip_session(SrsSipRequest *req, SrsGb28181SipSession** sip_session)
|
srs_error_t SrsGb28181SipService::fetch_or_create_sip_session(SrsSipRequest *req, SrsGb28181SipSession** sip_session)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
|
@ -59,6 +59,7 @@ public:
|
||||||
virtual ~SrsGb28181Device();
|
virtual ~SrsGb28181Device();
|
||||||
public:
|
public:
|
||||||
std::string device_id;
|
std::string device_id;
|
||||||
|
std::string device_name;
|
||||||
std::string device_status;
|
std::string device_status;
|
||||||
SrsGb28181SipSessionStatusType invite_status;
|
SrsGb28181SipSessionStatusType invite_status;
|
||||||
srs_utime_t invite_time;
|
srs_utime_t invite_time;
|
||||||
|
@ -132,10 +133,14 @@ public:
|
||||||
int sip_cseq(){ return _sip_cseq++;}
|
int sip_cseq(){ return _sip_cseq++;}
|
||||||
|
|
||||||
std::string session_id() { return _session_id;}
|
std::string session_id() { return _session_id;}
|
||||||
|
std::map<std::string, std::map<std::string, std::string> > item_list;
|
||||||
|
int item_list_sumnum;
|
||||||
public:
|
public:
|
||||||
void update_device_list(std::map<std::string, std::string> devlist);
|
void update_device_list(std::map<std::string, std::string> devlist);
|
||||||
|
void clear_device_list();
|
||||||
SrsGb28181Device *get_device_info(std::string chid);
|
SrsGb28181Device *get_device_info(std::string chid);
|
||||||
void dumps(SrsJsonObject* obj);
|
void dumps(SrsJsonObject* obj);
|
||||||
|
void dumpItemList(SrsJsonObject* obj);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t serve();
|
virtual srs_error_t serve();
|
||||||
|
@ -201,6 +206,7 @@ public:
|
||||||
//
|
//
|
||||||
srs_error_t send_sip_raw_data(SrsSipRequest *req, std::string data);
|
srs_error_t send_sip_raw_data(SrsSipRequest *req, std::string data);
|
||||||
srs_error_t query_sip_session(std::string sid, SrsJsonArray* arr);
|
srs_error_t query_sip_session(std::string sid, SrsJsonArray* arr);
|
||||||
|
srs_error_t query_device_list(std::string sid, SrsJsonArray* arr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
srs_error_t fetch_or_create_sip_session(SrsSipRequest *req, SrsGb28181SipSession** sess);
|
srs_error_t fetch_or_create_sip_session(SrsSipRequest *req, SrsGb28181SipSession** sess);
|
||||||
|
|
|
@ -1476,11 +1476,12 @@ srs_error_t SrsGoApiGb28181::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
|
||||||
return srs_api_response(w, r, obj->dumps());
|
return srs_api_response(w, r, obj->dumps());
|
||||||
|
|
||||||
} else if(action == "delete_channel"){
|
} else if(action == "delete_channel"){
|
||||||
if (id.empty()){
|
string chid = r->query_get("chid");
|
||||||
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id");
|
if (id.empty() || chid.empty()){
|
||||||
|
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id or chid");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = _srs_gb28181->delete_stream_channel(id)) != srs_success) {
|
if ((err = _srs_gb28181->delete_stream_channel(id, chid)) != srs_success) {
|
||||||
return srs_error_wrap(err, "delete stream channel");
|
return srs_error_wrap(err, "delete stream channel");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1573,6 +1574,16 @@ srs_error_t SrsGoApiGb28181::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
|
||||||
}
|
}
|
||||||
|
|
||||||
return srs_api_response_code(w, r, 0);
|
return srs_api_response_code(w, r, 0);
|
||||||
|
} else if(action == "sip_query_devicelist"){
|
||||||
|
SrsJsonArray* arr = SrsJsonAny::array();
|
||||||
|
data->set("PlatformID", SrsJsonAny::str(_srs_gb28181->get_gb28181_config_ptr()->sip_serial.c_str()));
|
||||||
|
data->set("DeviceList", arr);
|
||||||
|
|
||||||
|
if ((err = _srs_gb28181->query_device_list("", arr)) != srs_success) {
|
||||||
|
return srs_error_wrap(err, "query device list");
|
||||||
|
}
|
||||||
|
|
||||||
|
return srs_api_response(w, r, obj->dumps());
|
||||||
} else if(action == "sip_query_session"){
|
} else if(action == "sip_query_session"){
|
||||||
SrsJsonArray* arr = SrsJsonAny::array();
|
SrsJsonArray* arr = SrsJsonAny::array();
|
||||||
data->set("sessions", arr);
|
data->set("sessions", arr);
|
||||||
|
|
|
@ -43,6 +43,66 @@ using namespace std;
|
||||||
#include <srs_kernel_codec.hpp>
|
#include <srs_kernel_codec.hpp>
|
||||||
#include <srs_rtsp_stack.hpp>
|
#include <srs_rtsp_stack.hpp>
|
||||||
|
|
||||||
|
#include <iconv.h>
|
||||||
|
|
||||||
|
/* Code (GB2312 <--> UTF-8) Convert Class */
|
||||||
|
class CodeConverter
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
iconv_t cd;
|
||||||
|
public:
|
||||||
|
CodeConverter(const char *pFromCharset, const char *pToCharset)
|
||||||
|
{
|
||||||
|
cd = iconv_open(pToCharset, pFromCharset);
|
||||||
|
if ((iconv_t)(-1) == cd)
|
||||||
|
srs_warn("CodeConverter: iconv_open failed <%s --> %s>", pFromCharset, pToCharset);
|
||||||
|
}
|
||||||
|
~CodeConverter()
|
||||||
|
{
|
||||||
|
if ((iconv_t)(-1) != cd)
|
||||||
|
iconv_close(cd);
|
||||||
|
}
|
||||||
|
int Convert(char *pInBuf, size_t InLen, char *pOutBuf, size_t OutLen)
|
||||||
|
{
|
||||||
|
return iconv(cd, &pInBuf, (size_t *)&InLen, &pOutBuf, (size_t *)&OutLen);
|
||||||
|
}
|
||||||
|
static bool IsUTF8(const char *pInBuf, int InLen)
|
||||||
|
{
|
||||||
|
if (InLen < 0)
|
||||||
|
return false;
|
||||||
|
int i = 0;
|
||||||
|
int nBytes = 0; //UTF8可用1-6个字节编码
|
||||||
|
unsigned char chr = 0;
|
||||||
|
|
||||||
|
while (i < InLen)
|
||||||
|
{
|
||||||
|
chr = *(pInBuf + i);
|
||||||
|
if (nBytes == 0) //计算字节数
|
||||||
|
{
|
||||||
|
if ((chr & 0x80) != 0)
|
||||||
|
{
|
||||||
|
while ((chr & 0x80) != 0)
|
||||||
|
{
|
||||||
|
chr <<= 1;
|
||||||
|
nBytes++;
|
||||||
|
}
|
||||||
|
if (nBytes < 2 || nBytes > 6)
|
||||||
|
return false; //第一个字节最少为110x xxxx
|
||||||
|
nBytes--; //减去自身占的一个字节
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //多字节除了第一个字节外剩下的字节
|
||||||
|
{
|
||||||
|
if ((chr & 0xc0) != 0x80)
|
||||||
|
return false; //剩下的字节都是10xx xxxx的形式
|
||||||
|
nBytes--;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return nBytes == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
unsigned int srs_sip_random(int min,int max)
|
unsigned int srs_sip_random(int min,int max)
|
||||||
{
|
{
|
||||||
//it is possible to duplicate data with time(0)
|
//it is possible to duplicate data with time(0)
|
||||||
|
@ -202,6 +262,7 @@ SrsSipRequest::SrsSipRequest()
|
||||||
|
|
||||||
from_realm = "";
|
from_realm = "";
|
||||||
to_realm = "";
|
to_realm = "";
|
||||||
|
y_ssrc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsSipRequest::~SrsSipRequest()
|
SrsSipRequest::~SrsSipRequest()
|
||||||
|
@ -321,7 +382,7 @@ srs_error_t SrsSipStack::parse_request(SrsSipRequest** preq, const char* recv_ms
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map<std::string, std::string> &json_map)
|
srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map<std::string, std::string> &json_map, std::vector<std::map<std::string, std::string> > &item_list)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
<?xml version="1.0" encoding="gb2312"?>
|
<?xml version="1.0" encoding="gb2312"?>
|
||||||
|
@ -341,6 +402,15 @@ srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map<std::string, st
|
||||||
</Notify>
|
</Notify>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (CodeConverter::IsUTF8(xml_msg.c_str(), xml_msg.size()) == false) {
|
||||||
|
char *outBuf = (char *)calloc(1, xml_msg.size() * 2);
|
||||||
|
CodeConverter cc("gb2312", "utf-8");
|
||||||
|
if (cc.Convert((char *)xml_msg.c_str(), xml_msg.size(), (char *)outBuf, xml_msg.size() * 2 - 1) != -1)
|
||||||
|
xml_msg = string(outBuf);
|
||||||
|
if (outBuf)
|
||||||
|
free(outBuf);
|
||||||
|
}
|
||||||
|
|
||||||
const char* start = xml_msg.c_str();
|
const char* start = xml_msg.c_str();
|
||||||
const char* end = start + xml_msg.size();
|
const char* end = start + xml_msg.size();
|
||||||
char* p = (char*)start;
|
char* p = (char*)start;
|
||||||
|
@ -349,9 +419,11 @@ srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map<std::string, st
|
||||||
|
|
||||||
std::string xml_header;
|
std::string xml_header;
|
||||||
int xml_layer = 0;
|
int xml_layer = 0;
|
||||||
|
int in_item_tag = 0;
|
||||||
|
|
||||||
//std::map<string, string> json_map;
|
//std::map<string, string> json_map;
|
||||||
std::map<int, string> json_key;
|
std::map<int, string> json_key;
|
||||||
|
std::map<std::string, std::string> one_item;
|
||||||
while (p < end) {
|
while (p < end) {
|
||||||
if (p[0] == '\n'){
|
if (p[0] == '\n'){
|
||||||
p +=1;
|
p +=1;
|
||||||
|
@ -410,9 +482,25 @@ srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map<std::string, st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in_item_tag && value != "" && (xml_layer - in_item_tag) == 2) {
|
||||||
|
// (xml_layer - in_item_tag) == 2, this condition filters all deeper tags under tag "Item"
|
||||||
|
one_item[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
value_start = NULL;
|
value_start = NULL;
|
||||||
xml_layer--;
|
xml_layer--;
|
||||||
|
|
||||||
|
if (json_key[xml_layer] == "Item") {
|
||||||
|
// std::map<string, string>::iterator it2;
|
||||||
|
// for (it2 = one_item.begin(); it2 != one_item.end(); ++it2) {
|
||||||
|
// srs_trace("========one_item========%s:%s", it2->first.c_str(), it2->second.c_str());
|
||||||
|
// }
|
||||||
|
// srs_trace("========one_item end========");
|
||||||
|
in_item_tag = 0;
|
||||||
|
// all items (DeviceList, Alarmstatus, RecordList) have "DeviceID"
|
||||||
|
if (one_item.find("DeviceID") != one_item.end())
|
||||||
|
item_list.push_back(one_item);
|
||||||
|
}
|
||||||
} else if (p[0] == '<') { //<Notify> xml item begin flag
|
} else if (p[0] == '<') { //<Notify> xml item begin flag
|
||||||
//skip <
|
//skip <
|
||||||
p +=1;
|
p +=1;
|
||||||
|
@ -443,6 +531,11 @@ srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map<std::string, st
|
||||||
//json_key[0] = "Notify"
|
//json_key[0] = "Notify"
|
||||||
//json_key[1] = "info"
|
//json_key[1] = "info"
|
||||||
json_key[xml_layer] = key;
|
json_key[xml_layer] = key;
|
||||||
|
if (json_key[xml_layer] == "Item") {
|
||||||
|
// "Item" won't be the first layer (xml_layer is 0)
|
||||||
|
in_item_tag = xml_layer;
|
||||||
|
one_item.clear();
|
||||||
|
}
|
||||||
xml_layer++;
|
xml_layer++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,7 +569,10 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
||||||
std::string body = "";
|
std::string body = "";
|
||||||
|
|
||||||
if (header_body.size() > 1){
|
if (header_body.size() > 1){
|
||||||
body = header_body.at(1);
|
// SRS_RTSP_CRLFCRLF may exist in content body (h3c)
|
||||||
|
string recv_str(recv_msg);
|
||||||
|
body = recv_str.substr(recv_str.find(SRS_RTSP_CRLFCRLF) + strlen(SRS_RTSP_CRLFCRLF));
|
||||||
|
//body = header_body.at(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_info("sip: header=%s\n", header.c_str());
|
srs_info("sip: header=%s\n", header.c_str());
|
||||||
|
@ -588,15 +684,15 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
||||||
|
|
||||||
std::vector<std::string> method_uri_ver = srs_string_split(firstline, " ");
|
std::vector<std::string> method_uri_ver = srs_string_split(firstline, " ");
|
||||||
|
|
||||||
if (method_uri_ver.empty()) {
|
if (method_uri_ver.empty() || method_uri_ver.size() < 3) {
|
||||||
return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "parse request firstline is empty");
|
return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "parse request firstline is empty or less than 3 fields");
|
||||||
}
|
}
|
||||||
|
|
||||||
//respone first line text:SIP/2.0 200 OK
|
//respone first line text:SIP/2.0 200 OK
|
||||||
if (!strcasecmp(method_uri_ver.at(0).c_str(), "sip/2.0")) {
|
if (!strcasecmp(method_uri_ver.at(0).c_str(), "sip/2.0")) {
|
||||||
req->cmdtype = SrsSipCmdRespone;
|
req->cmdtype = SrsSipCmdRespone;
|
||||||
//req->method= vec_seq.at(1);
|
//req->method= vec_seq.at(1);
|
||||||
req->status = method_uri_ver.size() > 0 ? method_uri_ver.at(1) : "";
|
req->status = method_uri_ver.size() > 1 ? method_uri_ver.at(1) : "";
|
||||||
req->version = method_uri_ver.at(0);
|
req->version = method_uri_ver.at(0);
|
||||||
req->uri = req->from;
|
req->uri = req->from;
|
||||||
|
|
||||||
|
@ -607,8 +703,8 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
||||||
}else {//request first line text :MESSAGE sip:34020000002000000001@3402000000 SIP/2.0
|
}else {//request first line text :MESSAGE sip:34020000002000000001@3402000000 SIP/2.0
|
||||||
req->cmdtype = SrsSipCmdRequest;
|
req->cmdtype = SrsSipCmdRequest;
|
||||||
req->method= method_uri_ver.at(0);
|
req->method= method_uri_ver.at(0);
|
||||||
req->uri = method_uri_ver.size() > 0 ? method_uri_ver.at(1) : "";
|
req->uri = method_uri_ver.size() > 1 ? method_uri_ver.at(1) : "";
|
||||||
req->version = method_uri_ver.size() > 1 ? method_uri_ver.at(2) : "";
|
req->version = method_uri_ver.size() > 2 ? method_uri_ver.at(2) : "";
|
||||||
|
|
||||||
vector<string> str = srs_string_split(req->from, "@");
|
vector<string> str = srs_string_split(req->from, "@");
|
||||||
std::string ss = str.empty() ? "" : str.at(0);
|
std::string ss = str.empty() ? "" : str.at(0);
|
||||||
|
@ -619,20 +715,20 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
||||||
|
|
||||||
//Content-Type: Application/MANSCDP+xml
|
//Content-Type: Application/MANSCDP+xml
|
||||||
if (!strcasecmp(req->content_type.c_str(),"application/manscdp+xml")){
|
if (!strcasecmp(req->content_type.c_str(),"application/manscdp+xml")){
|
||||||
std::map<std::string, std::string> body_map;
|
|
||||||
//xml to map
|
//xml to map
|
||||||
if ((err = parse_xml(body, body_map)) != srs_success) {
|
if ((err = parse_xml(body, req->xml_body_map, req->item_list)) != srs_success) {
|
||||||
return srs_error_wrap(err, "sip parse xml");
|
return srs_error_wrap(err, "sip parse xml");
|
||||||
};
|
};
|
||||||
|
|
||||||
//Response Cmd
|
//Response Cmd
|
||||||
if (body_map.find("Response") != body_map.end()){
|
if (req->xml_body_map.find("Response") != req->xml_body_map.end()){
|
||||||
std::string cmdtype = body_map["Response@CmdType"];
|
std::string cmdtype = req->xml_body_map["Response@CmdType"];
|
||||||
if (cmdtype == "Catalog"){
|
if (cmdtype == "Catalog"){
|
||||||
|
#if 0
|
||||||
//Response@DeviceList@Item@DeviceID:3000001,3000002
|
//Response@DeviceList@Item@DeviceID:3000001,3000002
|
||||||
std::vector<std::string> vec_device_id = srs_string_split(body_map["Response@DeviceList@Item@DeviceID"], ",");
|
std::vector<std::string> vec_device_id = srs_string_split(req->xml_body_map["Response@DeviceList@Item@DeviceID"], ",");
|
||||||
//Response@DeviceList@Item@Status:ON,OFF
|
//Response@DeviceList@Item@Status:ON,OFF
|
||||||
std::vector<std::string> vec_device_status = srs_string_split(body_map["Response@DeviceList@Item@Status"], ",");
|
std::vector<std::string> vec_device_status = srs_string_split(req->xml_body_map["Response@DeviceList@Item@Status"], ",");
|
||||||
|
|
||||||
//map key:devicd_id value:status
|
//map key:devicd_id value:status
|
||||||
for(int i=0 ; i< (int)vec_device_id.size(); i++){
|
for(int i=0 ; i< (int)vec_device_id.size(); i++){
|
||||||
|
@ -643,16 +739,28 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
||||||
|
|
||||||
req->device_list_map[vec_device_id.at(i)] = status;
|
req->device_list_map[vec_device_id.at(i)] = status;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
for(int i=0 ; i< (int)req->item_list.size(); i++){
|
||||||
|
std::map<std::string, std::string> one_item = req->item_list.at(i);
|
||||||
|
std::string status;
|
||||||
|
if (one_item.find("Status") != one_item.end() && one_item.find("Name") != one_item.end()) {
|
||||||
|
status = one_item["Status"] + "," + one_item["Name"];
|
||||||
|
} else {
|
||||||
|
// if no Status, it's not a camera but a group
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
req->device_list_map[one_item["DeviceID"]] = status;
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
//TODO: fixme
|
//TODO: fixme
|
||||||
srs_trace("sip: Response cmdtype=%s not processed", cmdtype.c_str());
|
srs_trace("sip: Response cmdtype=%s not processed", cmdtype.c_str());
|
||||||
}
|
}
|
||||||
} //Notify Cmd
|
} //Notify Cmd
|
||||||
else if (body_map.find("Notify") != body_map.end()){
|
else if (req->xml_body_map.find("Notify") != req->xml_body_map.end()){
|
||||||
std::string cmdtype = body_map["Notify@CmdType"];
|
std::string cmdtype = req->xml_body_map["Notify@CmdType"];
|
||||||
if (cmdtype == "Keepalive"){
|
if (cmdtype == "Keepalive"){
|
||||||
//TODO: ????
|
//TODO: ????
|
||||||
std::vector<std::string> vec_device_id = srs_string_split(body_map["Notify@Info@DeviceID"], ",");
|
std::vector<std::string> vec_device_id = srs_string_split(req->xml_body_map["Notify@Info@DeviceID"], ",");
|
||||||
for(int i=0; i< (int)vec_device_id.size(); i++){
|
for(int i=0; i< (int)vec_device_id.size(); i++){
|
||||||
//req->device_list_map[vec_device_id.at(i)] = "OFF";
|
//req->device_list_map[vec_device_id.at(i)] = "OFF";
|
||||||
}
|
}
|
||||||
|
@ -660,8 +768,20 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
||||||
//TODO: fixme
|
//TODO: fixme
|
||||||
srs_trace("sip: Notify cmdtype=%s not processed", cmdtype.c_str());
|
srs_trace("sip: Notify cmdtype=%s not processed", cmdtype.c_str());
|
||||||
}
|
}
|
||||||
}// end if(body_map)
|
}// end if(req->xml_body_map)
|
||||||
}//end if (!strcasecmp)
|
}//end if (!strcasecmp)
|
||||||
|
else if (!strcasecmp(req->content_type.c_str(),"application/sdp")) {
|
||||||
|
std::vector<std::string> sdp_lines = srs_string_split(body.c_str(), SRS_RTSP_CRLF);
|
||||||
|
for(int i=0 ; i< (int)sdp_lines.size(); i++){
|
||||||
|
if (!strncasecmp(sdp_lines.at(i).c_str(), "y=", 2)) {
|
||||||
|
string yline = sdp_lines.at(i);
|
||||||
|
string ssrc = yline.substr(2);
|
||||||
|
req->y_ssrc = strtoul(ssrc.c_str(), NULL, 10);
|
||||||
|
srs_trace("gb28181: ssrc in y line is %u:%x", req->y_ssrc, req->y_ssrc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
srs_info("sip: method=%s uri=%s version=%s cmdtype=%s",
|
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());
|
req->method.c_str(), req->uri.c_str(), req->version.c_str(), req->get_cmdtype_str().c_str());
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <srs_kernel_consts.hpp>
|
#include <srs_kernel_consts.hpp>
|
||||||
|
@ -105,6 +106,9 @@ public:
|
||||||
|
|
||||||
std::map<std::string, std::string> xml_body_map;
|
std::map<std::string, std::string> xml_body_map;
|
||||||
std::map<std::string, std::string> device_list_map;
|
std::map<std::string, std::string> device_list_map;
|
||||||
|
// add an item_list, you can do a lot of other things
|
||||||
|
// used by DeviceList, Alarmstatus, RecordList in "GB/T 28181—2016"
|
||||||
|
std::vector<std::map<std::string, std::string> > item_list;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::string serial;
|
std::string serial;
|
||||||
|
@ -120,6 +124,7 @@ public:
|
||||||
|
|
||||||
std::string from_realm;
|
std::string from_realm;
|
||||||
std::string to_realm;
|
std::string to_realm;
|
||||||
|
uint32_t y_ssrc;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsRtspSdp* sdp;
|
SrsRtspSdp* sdp;
|
||||||
|
@ -152,7 +157,7 @@ public:
|
||||||
virtual srs_error_t parse_request(SrsSipRequest** preq, const char *recv_msg, int nb_buf);
|
virtual srs_error_t parse_request(SrsSipRequest** preq, const char *recv_msg, int nb_buf);
|
||||||
protected:
|
protected:
|
||||||
virtual srs_error_t do_parse_request(SrsSipRequest* req, const char *recv_msg);
|
virtual srs_error_t do_parse_request(SrsSipRequest* req, const char *recv_msg);
|
||||||
virtual srs_error_t parse_xml(std::string xml_msg, std::map<std::string, std::string> &json_map);
|
virtual srs_error_t parse_xml(std::string xml_msg, std::map<std::string, std::string> &json_map, std::vector<std::map<std::string, std::string> > &item_list);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//response from
|
//response from
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue