diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 748aab636..b213093a0 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -639,13 +639,15 @@ srs_error_t SrsRtcSession::on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* if ((err = on_binding_request(udp_mux_skt, stun_req)) != srs_success) { return srs_error_wrap(err, "stun binding request failed"); } - } - last_stun_time = srs_get_system_time(); + last_stun_time = srs_get_system_time(); - if (strd && strd->sendonly_ukt) { - if (strd->sendonly_ukt->get_peer_id() != udp_mux_skt->get_peer_id()) { - strd->update_sendonly_socket(udp_mux_skt); + if (strd && strd->sendonly_ukt) { + // We are running in the ice-lite(server) mode. If client have multi network interface, + // we only choose one candidate pair which is determined by client. + if (stun_req->get_use_candidate() && strd->sendonly_ukt->get_peer_id() != udp_mux_skt->get_peer_id()) { + strd->update_sendonly_socket(udp_mux_skt); + } } } @@ -678,6 +680,10 @@ srs_error_t SrsRtcSession::on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsS { srs_error_t err = srs_success; + if (stun_req->get_ice_controlled()) { + return srs_error_new(ERROR_RTC_STUN, "Peer must not in ice-controlled role in ice-lite mode."); + } + SrsStunPacket stun_binding_response; char buf[1460]; SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); @@ -1159,13 +1165,14 @@ srs_error_t SrsRtcServer::on_stun(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; - srs_verbose("recv stun packet from %s", udp_mux_skt->get_peer_id().c_str()); - SrsStunPacket stun_req; if ((err = stun_req.decode(udp_mux_skt->data(), udp_mux_skt->size())) != srs_success) { return srs_error_wrap(err, "decode stun packet failed"); } + srs_verbose("recv stun packet from %s, use-candidate=%d, ice-controlled=%d, ice-controlling=%d", + udp_mux_skt->get_peer_id().c_str(), stun_req.get_use_candidate(), stun_req.get_ice_controlled(), stun_req.get_ice_controlling()); + std::string username = stun_req.get_username(); SrsRtcSession* rtc_session = find_rtc_session_by_username(username); if (rtc_session == NULL) { diff --git a/trunk/src/app/srs_app_sdp.cpp b/trunk/src/app/srs_app_sdp.cpp index 49323aee9..f9ec31b13 100644 --- a/trunk/src/app/srs_app_sdp.cpp +++ b/trunk/src/app/srs_app_sdp.cpp @@ -349,9 +349,18 @@ srs_error_t SrsMediaDesc::encode(std::ostringstream& os) } } - // TODO: Candidate priority + int foundation = 0; + int component_id = 1; /* RTP */ for (std::vector::iterator iter = candidates_.begin(); iter != candidates_.end(); ++iter) { - os << "a=candidate:10 1 udp 2115783679 " << iter->ip_ << " " << iter->port_ <<" typ " << iter->type_ << " generation 0" << kCRLF; + // @see: https://tools.ietf.org/html/draft-ietf-ice-rfc5245bis-00#section-4.2 + uint32_t priority = (1<<24)*(126) + (1<<8)*(65535) + (1)*(256 - component_id); + + // @see: https://tools.ietf.org/id/draft-ietf-mmusic-ice-sip-sdp-14.html#rfc.section.5.1 + os << "a=candidate:" << foundation++ << " " + << component_id << " udp " << priority << " " + << iter->ip_ << " " << iter->port_ + << " typ " << iter->type_ + << " generation 0" << kCRLF; } return err; @@ -656,7 +665,7 @@ srs_error_t SrsSdp::encode(std::ostringstream& os) os << "o=" << username_ << " " << session_id_ << " " << session_version_ << " " << nettype_ << " " << addrtype_ << " " << unicast_address_ << kCRLF; os << "s=" << session_name_ << kCRLF; os << "t=" << start_time_ << " " << end_time_ << kCRLF; - // @see: ice-lite is a minimal version of the ICE specification, intended for servers running on a public IP address. + // ice-lite is a minimal version of the ICE specification, intended for servers running on a public IP address. os << "a=ice-lite" << kCRLF; if (! groups_.empty()) { diff --git a/trunk/src/protocol/srs_stun_stack.cpp b/trunk/src/protocol/srs_stun_stack.cpp index e32ce6ad1..ed3377762 100644 --- a/trunk/src/protocol/srs_stun_stack.cpp +++ b/trunk/src/protocol/srs_stun_stack.cpp @@ -89,6 +89,9 @@ SrsStunPacket::SrsStunPacket() message_type = 0; local_ufrag = ""; remote_ufrag = ""; + use_candidate = false; + ice_controlled = false; + ice_controlling = false; } SrsStunPacket::~SrsStunPacket() @@ -140,8 +143,32 @@ srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) } break; } + + case UseCandidate: { + use_candidate = true; + srs_verbose("stun use-candidate"); + break; + } + + // @see: https://tools.ietf.org/html/draft-ietf-ice-rfc5245bis-00#section-5.1.2 + // One agent full, one lite: The full agent MUST take the controlling + // role, and the lite agent MUST take the controlled role. The full + // agent will form check lists, run the ICE state machines, and + // generate connectivity checks. + case IceControlled: { + ice_controlled = true; + srs_verbose("stun ice-controlled"); + break; + } + + case IceControlling: { + ice_controlling = true; + srs_verbose("stun ice-controlling"); + break; + } default: { + srs_verbose("stun type=%u, no process", type); break; } } diff --git a/trunk/src/protocol/srs_stun_stack.hpp b/trunk/src/protocol/srs_stun_stack.hpp index dda33c194..92242018d 100644 --- a/trunk/src/protocol/srs_stun_stack.hpp +++ b/trunk/src/protocol/srs_stun_stack.hpp @@ -69,6 +69,11 @@ enum SrsStunMessageAttribute Software = 0x8022, AlternateServer = 0x8023, Fingerprint = 0x8028, + + Priority = 0x0024, + UseCandidate = 0x0025, + IceControlled = 0x8029, + IceControlling = 0x802A, }; class SrsStunPacket @@ -81,6 +86,9 @@ private: std::string transcation_id; uint32_t mapped_address; uint16_t mapped_port; + bool use_candidate; + bool ice_controlled; + bool ice_controlling; public: SrsStunPacket(); virtual ~SrsStunPacket(); @@ -95,6 +103,9 @@ public: std::string get_transcation_id() const { return transcation_id; } uint32_t get_mapped_address() const { return mapped_address; } uint16_t get_mapped_port() const { return mapped_port; } + bool get_ice_controlled() const { return ice_controlled; } + bool get_ice_controlling() const { return ice_controlling; } + bool get_use_candidate() const { return use_candidate; } void set_message_type(const uint16_t& m) { message_type = m; } void set_local_ufrag(const std::string& u) { local_ufrag = u; }