diff --git a/trunk/research/players/srs_gb28181.html b/trunk/research/players/srs_gb28181.html index b5ff6b837..b32acf276 100644 --- a/trunk/research/players/srs_gb28181.html +++ b/trunk/research/players/srs_gb28181.html @@ -465,7 +465,12 @@ var url = null; 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; function select_dar(dar_id, num, den) { @@ -588,7 +593,7 @@ for (idx2 in devices) { //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 = "
  • " +id + "
  • "; $("#sipSessionList").append(li); } @@ -1007,7 +1012,7 @@ var str = text.split("-->"); id = str[0]; var str2 = str[1].split(":") - chid = str2[0]; + chid = str2[1]; url = $("#txt_api_url").val(); var apiurl = url + "/api/v1/gb28181?action=sip_invite&id=" + id + "&chid="+chid; @@ -1026,7 +1031,7 @@ var str = text.split("-->"); id = str[0]; var str2 = str[1].split(":") - chid = str2[0]; + chid = str2[1]; url = $("#txt_api_url").val(); var apiurl = url + "/api/v1/gb28181?action=sip_bye&id=" + id + "&chid="+chid; @@ -1048,7 +1053,7 @@ chid = str2[0]; 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); $('#sipSessionMessage').html(syntaxHighlight(ret)); if (ret != undefined && ret.code == 0){ @@ -1069,9 +1074,17 @@ }); $("#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(); - 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); $('#gb28181ChannelMessage').html(syntaxHighlight(ret)); if (ret != undefined && ret.code == 0){ @@ -1190,7 +1203,8 @@ return pc.setLocalDescription(offer).then(function(){ return offer; }); }).then(function(offer) { 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 var api = urlObject.user_query.play || '/rtc/v1/play/'; diff --git a/trunk/src/app/srs_app_gb28181.cpp b/trunk/src/app/srs_app_gb28181.cpp index 1c4f4bc70..541365e3e 100644 --- a/trunk/src/app/srs_app_gb28181.cpp +++ b/trunk/src/app/srs_app_gb28181.cpp @@ -215,7 +215,9 @@ srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet(const sockaddr* from, const (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"); + // 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); @@ -225,7 +227,10 @@ srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet(const sockaddr* from, const SrsPsRtpPacket pkt; 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 @@ -432,7 +437,9 @@ srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet_jitter(const sockaddr* from, (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"); + // 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); @@ -443,7 +450,10 @@ srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet_jitter(const sockaddr* from, if ((err = pkt->decode(&stream)) != srs_success) { 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; @@ -1588,6 +1598,9 @@ void SrsGb28181RtmpMuxer::insert_jitterbuffer(SrsPsRtpPacket *pkt) recv_rtp_stream_time = srs_get_system_time(); char *payload = pkt->payload->bytes(); + if (!payload) { + return; + } uint8_t p1 = (uint8_t)(payload[0]); uint8_t p2 = (uint8_t)(payload[1]); @@ -1765,13 +1778,12 @@ srs_error_t SrsGb28181RtmpMuxer::write_h264_ipb_frame2(char *frame, int frame_si std::list list_index; for(; index < size; index++){ + if (index > (size-4)) + break; if (video_data[index] == 0x00 && video_data[index+1] == 0x00 && video_data[index+2] == 0x00 && video_data[index+3] == 0x01){ list_index.push_back(index); } - - if (index > (size-4)) - break; } if (list_index.size() == 1){ @@ -2153,6 +2165,8 @@ void SrsGb28181RtmpMuxer::close() h264_pps = ""; aac_specific_config = ""; + // BUGFIX: if don't unpublish, it will always be in the /api/v1/streams list + //if (source_publish && !source){ if (source_publish && source){ source->on_unpublish(); } @@ -2347,6 +2361,28 @@ SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer(std::string id) return muxer; } +void SrsGb28181Manger::update_rtmpmuxer_to_newssrc_by_id(std::string id, uint32_t ssrc) +{ + SrsGb28181RtmpMuxer* muxer = NULL; + + if (rtmpmuxers.find(id) == rtmpmuxers.end()) { + return; + } + + muxer = rtmpmuxers[id]; + SrsGb28181StreamChannel mc = muxer->get_channel(); + uint32_t old_ssrc = mc.get_ssrc(); + if (old_ssrc == ssrc) { + return; + } else { + srs_trace("gb28181: update ssrc of muxer %s from %x to %x", id.c_str(), old_ssrc, ssrc); + } + rtmpmuxer_unmap_by_ssrc(old_ssrc); + mc.set_ssrc(ssrc); + muxer->copy_channel(&mc); + rtmpmuxer_map_by_ssrc(muxer, ssrc); +} + SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer_by_ssrc(uint32_t ssrc) { SrsGb28181RtmpMuxer* muxer = NULL; @@ -2602,17 +2638,19 @@ srs_error_t SrsGb28181Manger::create_stream_channel(SrsGb28181StreamChannel *cha 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; //notify the device to stop streaming //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){ - stop_rtp_listen(id); + stop_rtp_listen(channel_id); muxer->stop(); return err; }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"); } 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) @@ -2738,6 +2780,12 @@ srs_error_t SrsGb28181Manger::notify_sip_query_catalog(std::string id) SrsSipRequest req; req.sip_auth_id = id; + SrsGb28181SipSession *sip_session = sip_service->fetch(req.sip_auth_id); + if (sip_session) { + sip_session->item_list.clear(); + sip_session->clear_device_list(); + srs_trace("notify_sip_query_catalog, clear sip session item and device list"); + } return sip_service->send_query_catalog(&req); } @@ -2750,8 +2798,14 @@ srs_error_t SrsGb28181Manger::query_sip_session(std::string id, SrsJsonArray* ar 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 SrsGb28181Conn::SrsGb28181Conn(SrsGb28181Caster* c, srs_netfd_t fd, SrsGb28181TcpPsRtpProcessor *rtp_processor) @@ -2970,3 +3024,4 @@ void SrsGb28181Caster::remove(SrsGb28181Conn* conn) manager->remove(conn); } + diff --git a/trunk/src/app/srs_app_gb28181.hpp b/trunk/src/app/srs_app_gb28181.hpp index cc9e1c304..80a87a0f1 100644 --- a/trunk/src/app/srs_app_gb28181.hpp +++ b/trunk/src/app/srs_app_gb28181.hpp @@ -518,6 +518,7 @@ public: srs_error_t fetch_or_create_rtmpmuxer(std::string id, SrsRequest *req, SrsGb28181RtmpMuxer** gb28181); SrsGb28181RtmpMuxer* fetch_rtmpmuxer(std::string id); SrsGb28181RtmpMuxer* fetch_rtmpmuxer_by_ssrc(uint32_t ssrc); + void update_rtmpmuxer_to_newssrc_by_id(std::string id, uint32_t ssrc); void rtmpmuxer_map_by_ssrc(SrsGb28181RtmpMuxer*muxer, uint32_t ssrc); void rtmpmuxer_unmap_by_ssrc(uint32_t ssrc); uint32_t generate_ssrc(std::string id); @@ -525,11 +526,12 @@ public: void set_sip_service(SrsGb28181SipService *s) { sip_service = s; } SrsGb28181SipService* get_sip_service() { return sip_service; } + SrsGb28181Config* get_gb28181_config_ptr() { return config;} public: //stream channel api srs_error_t create_stream_channel(SrsGb28181StreamChannel *channel); - srs_error_t delete_stream_channel(std::string id); + srs_error_t delete_stream_channel(std::string id, std::string chid); srs_error_t query_stream_channel(std::string id, SrsJsonArray* arr); //sip api srs_error_t notify_sip_invite(std::string id, std::string ip, int port, uint32_t ssrc, std::string chid); @@ -539,6 +541,7 @@ public: srs_error_t notify_sip_query_catalog(std::string id); srs_error_t notify_sip_ptz(std::string id, std::string chid, std::string cmd, uint8_t speed, int priority); srs_error_t query_sip_session(std::string id, SrsJsonArray* arr); + srs_error_t query_device_list(std::string id, SrsJsonArray* arr); private: void destroy(); diff --git a/trunk/src/app/srs_app_gb28181_sip.cpp b/trunk/src/app/srs_app_gb28181_sip.cpp index b4bf2a3be..6342cfd77 100644 --- a/trunk/src/app/srs_app_gb28181_sip.cpp +++ b/trunk/src/app/srs_app_gb28181_sip.cpp @@ -68,6 +68,7 @@ std::string srs_get_sip_session_status_str(SrsGb28181SipSessionStatusType status SrsGb28181Device::SrsGb28181Device() { device_id = ""; + device_name = ""; invite_status = SrsGb28181SipSessionUnkonw; invite_time = 0; device_status = ""; @@ -102,6 +103,8 @@ SrsGb28181SipSession::SrsGb28181SipSession(SrsGb28181SipService *c, SrsSipReques _fromlen = 0; _sip_cseq = 100; + item_list_sumnum = 0; + } SrsGb28181SipSession::~SrsGb28181SipSession() @@ -338,19 +341,42 @@ void SrsGb28181SipSession::update_device_list(std::map if (_device_list.find(id) == _device_list.end()){ SrsGb28181Device *device = new SrsGb28181Device(); 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_time = 0; _device_list[id] = device; }else { 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::iterator it; + for (it = _device_list.begin(); it != _device_list.end(); ++it) { + srs_freep(it->second); + } + + _device_list.clear(); +} + SrsGb28181Device* SrsGb28181SipSession::get_device_info(std::string chid) { if (_device_list.find(chid) != _device_list.end()){ @@ -372,12 +398,33 @@ void SrsGb28181SipSession::dumps(SrsJsonObject* obj) SrsJsonObject* obj = SrsJsonAny::object(); arr->append(obj); obj->set("device_id", SrsJsonAny::str(device->device_id.c_str())); + obj->set("device_name", SrsJsonAny::str(device->device_name.c_str())); obj->set("device_status", SrsJsonAny::str(device->device_status.c_str())); obj->set("invite_status", SrsJsonAny::str(srs_get_sip_session_status_str(device->invite_status).c_str())); obj->set("invite_time", SrsJsonAny::integer(device->invite_time/SRS_UTIME_SECONDS)); } } +void SrsGb28181SipSession::dumpItemList(SrsJsonObject* obj) +{ + obj->set("TopDeviceID", SrsJsonAny::str(_session_id.c_str())); + obj->set("SumNum", SrsJsonAny::integer(item_list_sumnum)); + obj->set("RealSumNum", SrsJsonAny::integer(item_list.size())); + + SrsJsonArray* arr = SrsJsonAny::array(); + obj->set("ItemList", arr); + std::map >::iterator it; + for (it = item_list.begin(); it != item_list.end(); ++it) { + std::map device = it->second; + SrsJsonObject* obj2 = SrsJsonAny::object(); + arr->append(obj2); + std::map::iterator it2; + for (it2 = device.begin(); it2 != device.end(); ++it2) { + obj2->set(it2->first, SrsJsonAny::str(it2->second.c_str())); + } + } +} + //gb28181 sip Service SrsGb28181SipService::SrsGb28181SipService(SrsConfDirective* c) { @@ -419,7 +466,9 @@ srs_error_t SrsGb28181SipService::on_udp_packet(const sockaddr* from, const int (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"); + // return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address"); + srs_warn("gb28181: bad address"); + return srs_success; } std::string peer_ip = std::string(address_string); int peer_port = atoi(port_string); @@ -427,7 +476,10 @@ srs_error_t SrsGb28181SipService::on_udp_packet(const sockaddr* from, const int std::string recv_msg(buf, nb_buf); srs_error_t err = on_udp_sip(peer_ip, peer_port, recv_msg, (sockaddr*)from, fromlen); if (err != srs_success) { - return srs_error_wrap(err, "process udp"); + // return srs_error_wrap(err, "process udp"); + srs_warn("gb28181: process udp"); + srs_freep(err); + return srs_success; } 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"); } - if (serial.at(0) != config->sip_serial){ - srs_warn("gb28181: client:%s request serial and server serial inconformity(%s:%s)", - req->sip_auth_id.c_str(), serial.at(0).c_str(), config->sip_serial.c_str()); - return err; - } + //if (serial.at(0) != config->sip_serial){ + // srs_warn("gb28181: client:%s request serial and server serial inconformity(%s:%s)", + // req->sip_auth_id.c_str(), serial.at(0).c_str(), config->sip_serial.c_str()); + // return err; + //} srs_trace("gb28181: request client id=%s peer(%s, %d)", req->sip_auth_id.c_str(), peer_ip.c_str(), peer_port); srs_trace("gb28181: %s method=%s, uri=%s, version=%s expires=%d", @@ -519,6 +571,24 @@ srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port, if (req->device_list_map.size() > 0){ sip_session->update_device_list(req->device_list_map); } + if (!strcasecmp(req->content_type.c_str(),"application/manscdp+xml") + && req->xml_body_map.find("Response@CmdType") != req->xml_body_map.end() + && req->xml_body_map["Response@CmdType"] == "Catalog") { + if (req->xml_body_map.find("Response@SumNum") != req->xml_body_map.end()) { + sip_session->item_list_sumnum = atoi(req->xml_body_map["Response@SumNum"].c_str()); + } + std::vector >::iterator it; + for (it = req->item_list.begin(); it != req->item_list.end(); ++it) { + std::map device = *it; + std::map >::iterator it2 = sip_session->item_list.find(device["DeviceID"]); + if (it2 != sip_session->item_list.end()) { + sip_session->item_list.erase(it2); + sip_session->item_list[device["DeviceID"]] = device; + } else { + sip_session->item_list[device["DeviceID"]] = device; + } + } + } } }else if (req->is_invite()) { @@ -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()); if (req->status == "200") { + srs_trace("gb28181: device unique id is %s@%s", sip_session->session_id().c_str(), req->sip_auth_id.c_str()); + // if srs is external realm, ssrc is generated by source realm rather than srs + // so update ssrc to the y line in source realm '200 OK' response + // actually, we should do this all the time + if (req->y_ssrc != 0) { + _srs_gb28181->update_rtmpmuxer_to_newssrc_by_id(sip_session->session_id()+"@"+req->sip_auth_id, req->y_ssrc); + req->y_ssrc = 0; + } send_ack(req, from, fromlen); SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id); if (device){ @@ -919,6 +997,31 @@ srs_error_t SrsGb28181SipService::query_sip_session(std::string sid, SrsJsonArr return err; } +srs_error_t SrsGb28181SipService::query_device_list(std::string sid, SrsJsonArray* arr) +{ + srs_error_t err = srs_success; + + if (!sid.empty()){ + SrsGb28181SipSession* sess = fetch(sid); + if (!sess){ + return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist"); + } + SrsJsonObject* obj = SrsJsonAny::object(); + arr->append(obj); + sess->dumpItemList(obj); + }else { + std::map::iterator it; + for (it = sessions.begin(); it != sessions.end(); ++it) { + SrsGb28181SipSession* sess = it->second; + SrsJsonObject* obj = SrsJsonAny::object(); + arr->append(obj); + sess->dumpItemList(obj); + } + } + + return err; +} + srs_error_t SrsGb28181SipService::fetch_or_create_sip_session(SrsSipRequest *req, SrsGb28181SipSession** sip_session) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_gb28181_sip.hpp b/trunk/src/app/srs_app_gb28181_sip.hpp index 434a522f3..6c47dd2ee 100644 --- a/trunk/src/app/srs_app_gb28181_sip.hpp +++ b/trunk/src/app/srs_app_gb28181_sip.hpp @@ -59,6 +59,7 @@ public: virtual ~SrsGb28181Device(); public: std::string device_id; + std::string device_name; std::string device_status; SrsGb28181SipSessionStatusType invite_status; srs_utime_t invite_time; @@ -132,10 +133,14 @@ public: int sip_cseq(){ return _sip_cseq++;} std::string session_id() { return _session_id;} + std::map > item_list; + int item_list_sumnum; public: void update_device_list(std::map devlist); + void clear_device_list(); SrsGb28181Device *get_device_info(std::string chid); void dumps(SrsJsonObject* obj); + void dumpItemList(SrsJsonObject* obj); public: virtual srs_error_t serve(); @@ -201,6 +206,7 @@ public: // srs_error_t send_sip_raw_data(SrsSipRequest *req, std::string data); srs_error_t query_sip_session(std::string sid, SrsJsonArray* arr); + srs_error_t query_device_list(std::string sid, SrsJsonArray* arr); public: srs_error_t fetch_or_create_sip_session(SrsSipRequest *req, SrsGb28181SipSession** sess); diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index c73b692e4..b9f5b73a6 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1476,11 +1476,12 @@ srs_error_t SrsGoApiGb28181::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe return srs_api_response(w, r, obj->dumps()); } else if(action == "delete_channel"){ - if (id.empty()){ - return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id"); + string chid = r->query_get("chid"); + if (id.empty() || chid.empty()){ + return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id or chid"); } - if ((err = _srs_gb28181->delete_stream_channel(id)) != srs_success) { + if ((err = _srs_gb28181->delete_stream_channel(id, chid)) != srs_success) { 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); + } else if(action == "sip_query_devicelist"){ + SrsJsonArray* arr = SrsJsonAny::array(); + data->set("PlatformID", SrsJsonAny::str(_srs_gb28181->get_gb28181_config_ptr()->sip_serial.c_str())); + data->set("DeviceList", arr); + + if ((err = _srs_gb28181->query_device_list("", arr)) != srs_success) { + return srs_error_wrap(err, "query device list"); + } + + return srs_api_response(w, r, obj->dumps()); } else if(action == "sip_query_session"){ SrsJsonArray* arr = SrsJsonAny::array(); data->set("sessions", arr); diff --git a/trunk/src/protocol/srs_sip_stack.cpp b/trunk/src/protocol/srs_sip_stack.cpp index 97004d226..022dd3903 100644 --- a/trunk/src/protocol/srs_sip_stack.cpp +++ b/trunk/src/protocol/srs_sip_stack.cpp @@ -43,6 +43,66 @@ using namespace std; #include #include +#include + +/* Code (GB2312 <--> UTF-8) Convert Class */ +class CodeConverter +{ +private: + iconv_t cd; +public: + CodeConverter(const char *pFromCharset, const char *pToCharset) + { + cd = iconv_open(pToCharset, pFromCharset); + if ((iconv_t)(-1) == cd) + srs_warn("CodeConverter: iconv_open failed <%s --> %s>", pFromCharset, pToCharset); + } + ~CodeConverter() + { + if ((iconv_t)(-1) != cd) + iconv_close(cd); + } + int Convert(char *pInBuf, size_t InLen, char *pOutBuf, size_t OutLen) + { + return iconv(cd, &pInBuf, (size_t *)&InLen, &pOutBuf, (size_t *)&OutLen); + } + static bool IsUTF8(const char *pInBuf, int InLen) + { + if (InLen < 0) + return false; + int i = 0; + int nBytes = 0; //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) { //it is possible to duplicate data with time(0) @@ -202,6 +262,7 @@ SrsSipRequest::SrsSipRequest() from_realm = ""; to_realm = ""; + y_ssrc = 0; } SrsSipRequest::~SrsSipRequest() @@ -321,7 +382,7 @@ srs_error_t SrsSipStack::parse_request(SrsSipRequest** preq, const char* recv_ms return err; } -srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map &json_map) +srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map &json_map, std::vector > &item_list) { /* @@ -340,7 +401,16 @@ srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map */ - + + if (CodeConverter::IsUTF8(xml_msg.c_str(), xml_msg.size()) == false) { + char *outBuf = (char *)calloc(1, xml_msg.size() * 2); + CodeConverter cc("gb2312", "utf-8"); + if (cc.Convert((char *)xml_msg.c_str(), xml_msg.size(), (char *)outBuf, xml_msg.size() * 2 - 1) != -1) + xml_msg = string(outBuf); + if (outBuf) + free(outBuf); + } + const char* start = xml_msg.c_str(); const char* end = start + xml_msg.size(); char* p = (char*)start; @@ -349,9 +419,11 @@ srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map json_map; std::map json_key; + std::map one_item; while (p < end) { if (p[0] == '\n'){ p +=1; @@ -409,10 +481,26 @@ srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map::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] == '<') { // xml item begin flag //skip < p +=1; @@ -443,6 +531,11 @@ srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map 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()); @@ -588,15 +684,15 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m std::vector method_uri_ver = srs_string_split(firstline, " "); - if (method_uri_ver.empty()) { - return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "parse request firstline is 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 or less than 3 fields"); } //respone first line text:SIP/2.0 200 OK if (!strcasecmp(method_uri_ver.at(0).c_str(), "sip/2.0")) { req->cmdtype = SrsSipCmdRespone; //req->method= vec_seq.at(1); - req->status = method_uri_ver.size() > 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->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 req->cmdtype = SrsSipCmdRequest; req->method= method_uri_ver.at(0); - req->uri = method_uri_ver.size() > 0 ? method_uri_ver.at(1) : ""; - req->version = method_uri_ver.size() > 1 ? method_uri_ver.at(2) : ""; + req->uri = method_uri_ver.size() > 1 ? method_uri_ver.at(1) : ""; + req->version = method_uri_ver.size() > 2 ? method_uri_ver.at(2) : ""; vector str = srs_string_split(req->from, "@"); std::string ss = str.empty() ? "" : str.at(0); @@ -619,20 +715,20 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m //Content-Type: Application/MANSCDP+xml if (!strcasecmp(req->content_type.c_str(),"application/manscdp+xml")){ - std::map body_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"); }; //Response Cmd - if (body_map.find("Response") != body_map.end()){ - std::string cmdtype = body_map["Response@CmdType"]; + if (req->xml_body_map.find("Response") != req->xml_body_map.end()){ + std::string cmdtype = req->xml_body_map["Response@CmdType"]; if (cmdtype == "Catalog"){ + #if 0 //Response@DeviceList@Item@DeviceID:3000001,3000002 - std::vector vec_device_id = srs_string_split(body_map["Response@DeviceList@Item@DeviceID"], ","); + std::vector vec_device_id = srs_string_split(req->xml_body_map["Response@DeviceList@Item@DeviceID"], ","); //Response@DeviceList@Item@Status:ON,OFF - std::vector vec_device_status = srs_string_split(body_map["Response@DeviceList@Item@Status"], ","); + std::vector vec_device_status = srs_string_split(req->xml_body_map["Response@DeviceList@Item@Status"], ","); //map key:devicd_id value:status for(int i=0 ; i< (int)vec_device_id.size(); i++){ @@ -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; } + #endif + for(int i=0 ; i< (int)req->item_list.size(); i++){ + std::map one_item = req->item_list.at(i); + std::string status; + if (one_item.find("Status") != one_item.end() && one_item.find("Name") != one_item.end()) { + status = one_item["Status"] + "," + one_item["Name"]; + } else { + // if no Status, it's not a camera but a group + continue; + } + req->device_list_map[one_item["DeviceID"]] = status; + } }else{ //TODO: fixme srs_trace("sip: Response cmdtype=%s not processed", cmdtype.c_str()); } } //Notify Cmd - else if (body_map.find("Notify") != body_map.end()){ - std::string cmdtype = body_map["Notify@CmdType"]; + else if (req->xml_body_map.find("Notify") != req->xml_body_map.end()){ + std::string cmdtype = req->xml_body_map["Notify@CmdType"]; if (cmdtype == "Keepalive"){ //TODO: ???? - std::vector vec_device_id = srs_string_split(body_map["Notify@Info@DeviceID"], ","); + std::vector vec_device_id = srs_string_split(req->xml_body_map["Notify@Info@DeviceID"], ","); for(int i=0; i< (int)vec_device_id.size(); i++){ //req->device_list_map[vec_device_id.at(i)] = "OFF"; } @@ -660,8 +768,20 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m //TODO: fixme srs_trace("sip: Notify cmdtype=%s not processed", cmdtype.c_str()); } - }// end if(body_map) + }// end if(req->xml_body_map) }//end if (!strcasecmp) + else if (!strcasecmp(req->content_type.c_str(),"application/sdp")) { + std::vector sdp_lines = srs_string_split(body.c_str(), SRS_RTSP_CRLF); + for(int i=0 ; i< (int)sdp_lines.size(); i++){ + if (!strncasecmp(sdp_lines.at(i).c_str(), "y=", 2)) { + string yline = sdp_lines.at(i); + string ssrc = yline.substr(2); + req->y_ssrc = strtoul(ssrc.c_str(), NULL, 10); + srs_trace("gb28181: ssrc in y line is %u:%x", req->y_ssrc, req->y_ssrc); + break; + } + } + } srs_info("sip: method=%s uri=%s version=%s cmdtype=%s", req->method.c_str(), req->uri.c_str(), req->version.c_str(), req->get_cmdtype_str().c_str()); diff --git a/trunk/src/protocol/srs_sip_stack.hpp b/trunk/src/protocol/srs_sip_stack.hpp index 18b726436..c6d4e1131 100644 --- a/trunk/src/protocol/srs_sip_stack.hpp +++ b/trunk/src/protocol/srs_sip_stack.hpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -105,6 +106,9 @@ public: std::map xml_body_map; std::map device_list_map; + // add an item_list, you can do a lot of other things + // used by DeviceList, Alarmstatus, RecordList in "GB/T 28181—2016" + std::vector > item_list; public: std::string serial; @@ -120,6 +124,7 @@ public: std::string from_realm; std::string to_realm; + uint32_t y_ssrc; public: SrsRtspSdp* sdp; @@ -152,7 +157,7 @@ public: virtual srs_error_t parse_request(SrsSipRequest** preq, const char *recv_msg, int nb_buf); protected: virtual srs_error_t do_parse_request(SrsSipRequest* req, const char *recv_msg); - virtual srs_error_t parse_xml(std::string xml_msg, std::map &json_map); + virtual srs_error_t parse_xml(std::string xml_msg, std::map &json_map, std::vector > &item_list); private: //response from