From 7dd5db261ae007467b638a3b9e284d38dfee7e31 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 6 May 2020 07:37:00 +0800 Subject: [PATCH] Support server as offer --- trunk/src/app/srs_app_rtc_conn.cpp | 93 +++++++++++++++++++++++++----- trunk/src/app/srs_app_rtc_conn.hpp | 31 +++++++--- trunk/src/app/srs_app_sdp.cpp | 1 + 3 files changed, 103 insertions(+), 22 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index cc6e69298..f83e35fb5 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -63,6 +63,7 @@ using namespace std; #include #include #include +#include // The RTP payload max size, reserved some paddings for SRTP as such: // kRtpPacketSize = kRtpMaxPayloadSize + paddings @@ -90,7 +91,7 @@ static bool is_rtcp(const uint8_t* data, size_t len) return (len >= 12) && (data[0] & 0x80) && (data[1] >= 200 && data[1] <= 209); } -static string gen_random_str(int len) +string gen_random_str(int len) { static string random_table = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; @@ -2288,7 +2289,7 @@ SrsRtcSession::SrsRtcSession(SrsRtcServer* s) server_ = s; dtls_ = new SrsRtcDtls(this); - session_state = INIT; + state_ = INIT; last_stun_time = 0; sessionStunTimeout = 0; @@ -2328,14 +2329,14 @@ void SrsRtcSession::set_remote_sdp(const SrsSdp& sdp) remote_sdp = sdp; } -SrsRtcSessionStateType SrsRtcSession::get_session_state() +SrsRtcSessionStateType SrsRtcSession::state() { - return session_state; + return state_; } -void SrsRtcSession::set_session_state(SrsRtcSessionStateType state) +void SrsRtcSession::set_state(SrsRtcSessionStateType state) { - session_state = state; + state_ = state; } string SrsRtcSession::id() @@ -2714,13 +2715,13 @@ srs_error_t SrsRtcSession::on_binding_request(SrsStunPacket* r) return srs_error_wrap(err, "stun binding response send failed"); } - if (get_session_state() == WAITING_STUN) { - set_session_state(DOING_DTLS_HANDSHAKE); + if (state_ == WAITING_STUN) { + state_ = DOING_DTLS_HANDSHAKE; peer_id_ = sendonly_skt->peer_id(); server_->insert_into_id_sessions(peer_id_, this); - set_session_state(DOING_DTLS_HANDSHAKE); + state_ = DOING_DTLS_HANDSHAKE; srs_trace("rtc session=%s, STUN done, waitting DTLS handshake.", id().c_str()); } @@ -3242,10 +3243,12 @@ srs_error_t SrsUdpMuxSender::on_reload_rtc_server() SrsRtcServer::SrsRtcServer() { timer = new SrsHourGlass(this, 1 * SRS_UTIME_SECONDS); + janus = new SrsJanusServer(this); } SrsRtcServer::~SrsRtcServer() { + srs_freep(janus); srs_freep(timer); if (true) { @@ -3342,6 +3345,7 @@ srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* skt) srs_verbose("recv stun packet from %s, use-candidate=%d, ice-controlled=%d, ice-controlling=%d", skt->peer_id().c_str(), ping.get_use_candidate(), ping.get_ice_controlled(), ping.get_ice_controlling()); + // TODO: FIXME: For ICE trickle, we may get STUN packets before SDP answer, so maybe should response it. if (!session) { session = find_session_by_username(ping.get_username()); if (session) { @@ -3377,8 +3381,9 @@ srs_error_t SrsRtcServer::listen_api() { srs_error_t err = srs_success; - // TODO: FIXME: Fetch api from hybrid manager. + // TODO: FIXME: Fetch api from hybrid manager, not from SRS. SrsHttpServeMux* http_api_mux = _srs_hybrid->srs()->instance()->api_server(); + if ((err = http_api_mux->handle("/rtc/v1/play/", new SrsGoApiRtcPlay(this))) != srs_success) { return srs_error_wrap(err, "handle play"); } @@ -3386,11 +3391,15 @@ srs_error_t SrsRtcServer::listen_api() if ((err = http_api_mux->handle("/rtc/v1/publish/", new SrsGoApiRtcPublish(this))) != srs_success) { return srs_error_wrap(err, "handle publish"); } - if ((err = http_api_mux->handle("/rtc/v1/nack/", new SrsGoApiRtcNACK(this))) != srs_success) { return srs_error_wrap(err, "handle nack"); } + // For Janus style API. + if ((err = janus->listen_api()) != srs_success) { + return srs_error_wrap(err, "janus listen api"); + } + return err; } @@ -3451,11 +3460,69 @@ srs_error_t SrsRtcServer::create_session( } } - // TODO: FIXME: In answer, we should use the same SSRC as in offer. session->set_remote_sdp(remote_sdp); session->set_local_sdp(local_sdp); + session->set_state(WAITING_STUN); - session->set_session_state(WAITING_STUN); + return err; +} + +srs_error_t SrsRtcServer::create_session2(SrsSdp& local_sdp, SrsRtcSession** psession) +{ + srs_error_t err = srs_success; + + std::string local_pwd = gen_random_str(32); + // TODO: FIXME: Collision detect. + std::string local_ufrag = gen_random_str(8); + + SrsRtcSession* session = new SrsRtcSession(this); + *psession = session; + + local_sdp.set_ice_ufrag(local_ufrag); + local_sdp.set_ice_pwd(local_pwd); + local_sdp.set_fingerprint_algo("sha-256"); + local_sdp.set_fingerprint(SrsDtls::instance()->get_fingerprint()); + + // We allows to mock the eip of server. + std::vector candidate_ips = get_candidate_ips(); + for (int i = 0; i < (int)candidate_ips.size(); ++i) { + local_sdp.add_candidate(candidate_ips[i], _srs_config->get_rtc_server_listen(), "host"); + } + + session->set_local_sdp(local_sdp); + session->set_state(WAITING_ANSWER); + + return err; +} + +srs_error_t SrsRtcServer::setup_session2(SrsRtcSession* session, SrsRequest* req, const SrsSdp& remote_sdp) +{ + srs_error_t err = srs_success; + + if (session->state() != WAITING_ANSWER) { + return err; + } + + SrsSource* source = NULL; + + // TODO: FIXME: Should refactor it, directly use http server as handler. + ISrsSourceHandler* handler = _srs_hybrid->srs()->instance(); + if ((err = _srs_sources->fetch_or_create(req, handler, &source)) != srs_success) { + return srs_error_wrap(err, "create source"); + } + + // TODO: FIXME: Collision detect. + string username = session->get_local_sdp()->get_ice_ufrag() + ":" + remote_sdp.get_ice_ufrag(); + + int cid = _srs_context->get_id(); + if ((err = session->initialize(source, req, false, username, cid)) != srs_success) { + return srs_error_wrap(err, "init"); + } + + map_username_session.insert(make_pair(username, session)); + + session->set_remote_sdp(remote_sdp); + session->set_state(WAITING_STUN); return err; } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 2b09be28f..1af1c9a39 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -44,6 +44,9 @@ #include #include +// For Alibaba Tenfold. +class SrsJanusServer; + class SrsUdpMuxSocket; class SrsConsumer; class SrsStunPacket; @@ -78,6 +81,8 @@ const uint8_t kSLI = 2; const uint8_t kRPSI = 3; const uint8_t kAFB = 15; +extern std::string gen_random_str(int len); + class SrsNtp { public: @@ -99,10 +104,11 @@ enum SrsRtcSessionStateType { // TODO: FIXME: Should prefixed by enum name. INIT = -1, - WAITING_STUN = 1, - DOING_DTLS_HANDSHAKE = 2, - ESTABLISHED = 3, - CLOSED = 4, + WAITING_ANSWER = 1, + WAITING_STUN = 2, + DOING_DTLS_HANDSHAKE = 3, + ESTABLISHED = 4, + CLOSED = 5, }; class SrsRtcDtls @@ -327,7 +333,7 @@ class SrsRtcSession friend class SrsRtcPublisher; private: SrsRtcServer* server_; - SrsRtcSessionStateType session_state; + SrsRtcSessionStateType state_; SrsRtcDtls* dtls_; SrsRtcPlayer* player_; SrsRtcPublisher* publisher_; @@ -364,8 +370,8 @@ public: void set_local_sdp(const SrsSdp& sdp); SrsSdp* get_remote_sdp(); void set_remote_sdp(const SrsSdp& sdp); - SrsRtcSessionStateType get_session_state(); - void set_session_state(SrsRtcSessionStateType state); + SrsRtcSessionStateType state(); + void set_state(SrsRtcSessionStateType state); std::string id(); std::string peer_id(); void set_peer_id(std::string v); @@ -451,6 +457,8 @@ private: private: std::map map_username_session; // key: username(local_ufrag + ":" + remote_ufrag) std::map map_id_session; // key: peerip(ip + ":" + port) +private: + SrsJanusServer* janus; public: SrsRtcServer(); virtual ~SrsRtcServer(); @@ -459,14 +467,19 @@ public: public: // TODO: FIXME: Support gracefully quit. // TODO: FIXME: Support reload. - virtual srs_error_t listen_udp(); + srs_error_t listen_udp(); virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* skt); + srs_error_t listen_api(); public: - virtual srs_error_t listen_api(); + // Peer start offering, we answer it. srs_error_t create_session( SrsRequest* req, const SrsSdp& remote_sdp, SrsSdp& local_sdp, const std::string& mock_eip, bool publish, SrsRtcSession** psession ); + // We start offering, create_session2 to generate offer, setup_session2 to handle answer. + srs_error_t create_session2(SrsSdp& local_sdp, SrsRtcSession** psession); + srs_error_t setup_session2(SrsRtcSession* session, SrsRequest* req, const SrsSdp& remote_sdp); +public: bool insert_into_id_sessions(const std::string& peer_id, SrsRtcSession* session); void check_and_clean_timeout_session(); int nn_sessions(); diff --git a/trunk/src/app/srs_app_sdp.cpp b/trunk/src/app/srs_app_sdp.cpp index d2e4b3043..c744e229c 100644 --- a/trunk/src/app/srs_app_sdp.cpp +++ b/trunk/src/app/srs_app_sdp.cpp @@ -33,6 +33,7 @@ using namespace std; #include #include +// TODO: FIXME: Maybe we should use json.encode to escape it? const std::string kCRLF = "\\r\\n"; #define FETCH(is,word) \