mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
RTC: Support multiple address for client. 4.0.36
This commit is contained in:
parent
7ec5ef8497
commit
21835c38b7
7 changed files with 91 additions and 64 deletions
|
@ -159,6 +159,7 @@ For previous versions, please read:
|
||||||
|
|
||||||
## V4 changes
|
## V4 changes
|
||||||
|
|
||||||
|
* v4.0, 2020-07-25, RTC: Support multiple address for client. 4.0.36
|
||||||
* v4.0, 2020-07-11, Refine log context with random string. 4.0.35
|
* v4.0, 2020-07-11, Refine log context with random string. 4.0.35
|
||||||
* v4.0, 2020-07-04, Fix some bugs for RTC. 4.0.34
|
* v4.0, 2020-07-04, Fix some bugs for RTC. 4.0.34
|
||||||
* v4.0, 2020-07-03, Merge [#1830][bug #1830] to fix bugs in GB28181. 4.0.33
|
* v4.0, 2020-07-03, Merge [#1830][bug #1830] to fix bugs in GB28181. 4.0.33
|
||||||
|
|
|
@ -808,8 +808,7 @@ srs_error_t SrsGoApiRtcNACK::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
|
||||||
|
|
||||||
session->simulate_nack_drop(drop);
|
session->simulate_nack_drop(drop);
|
||||||
|
|
||||||
srs_trace("RTC NACK session peer_id=%s, username=%s, drop=%s/%d", session->peer_id().c_str(),
|
srs_trace("RTC: NACK session username=%s, drop=%s/%d", username.c_str(), dropv.c_str(), drop);
|
||||||
username.c_str(), dropv.c_str(), drop);
|
|
||||||
|
|
||||||
return srs_success;
|
return srs_success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,8 @@ srs_error_t SrsSecurityTransport::on_dtls_handshake_done()
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_trace("RTC session=%s, DTLS handshake done.", session_->id().c_str());
|
// TODO: FIXME: Add cost for DTLS.
|
||||||
|
srs_trace("RTC: DTLS handshake done.");
|
||||||
|
|
||||||
handshake_done = true;
|
handshake_done = true;
|
||||||
if ((err = srtp_initialize()) != srs_success) {
|
if ((err = srtp_initialize()) != srs_success) {
|
||||||
|
@ -366,13 +367,13 @@ srs_error_t SrsRtcPlayStream::cycle()
|
||||||
realtime = _srs_config->get_realtime_enabled(req->vhost, true);
|
realtime = _srs_config->get_realtime_enabled(req->vhost, true);
|
||||||
mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime, true);
|
mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime, true);
|
||||||
|
|
||||||
srs_trace("RTC source url=%s, source_id=[%d][%s], encrypt=%d, realtime=%d, mw_msgs=%d", req->get_stream_url().c_str(),
|
// TODO: FIXME: Add cost in ms.
|
||||||
|
srs_trace("RTC: start play, url=%s, source_id=[%d][%s], encrypt=%d, realtime=%d, mw_msgs=%d", req->get_stream_url().c_str(),
|
||||||
::getpid(), source->source_id().c_str(), session_->encrypt, realtime, mw_msgs);
|
::getpid(), source->source_id().c_str(), session_->encrypt, realtime, mw_msgs);
|
||||||
|
|
||||||
SrsPithyPrint* pprint = SrsPithyPrint::create_rtc_play();
|
SrsPithyPrint* pprint = SrsPithyPrint::create_rtc_play();
|
||||||
SrsAutoFree(SrsPithyPrint, pprint);
|
SrsAutoFree(SrsPithyPrint, pprint);
|
||||||
|
|
||||||
srs_trace("RTC session=%s, start play", session_->id().c_str());
|
|
||||||
bool stat_enabled = _srs_config->get_rtc_server_perf_stat();
|
bool stat_enabled = _srs_config->get_rtc_server_perf_stat();
|
||||||
SrsStatistic* stat = SrsStatistic::instance();
|
SrsStatistic* stat = SrsStatistic::instance();
|
||||||
|
|
||||||
|
@ -1582,8 +1583,15 @@ SrsRtcConnection::~SrsRtcConnection()
|
||||||
srs_freep(publisher_);
|
srs_freep(publisher_);
|
||||||
srs_freep(transport_);
|
srs_freep(transport_);
|
||||||
srs_freep(req);
|
srs_freep(req);
|
||||||
srs_freep(sendonly_skt);
|
|
||||||
srs_freep(stat_);
|
srs_freep(stat_);
|
||||||
|
|
||||||
|
// Note that we should never delete the sendonly_skt,
|
||||||
|
// it's just point to the object in peer_addresses_.
|
||||||
|
map<string, SrsUdpMuxSocket*>::iterator it;
|
||||||
|
for (it = peer_addresses_.begin(); it != peer_addresses_.end(); ++it) {
|
||||||
|
SrsUdpMuxSocket* addr = it->second;
|
||||||
|
srs_freep(addr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsSdp* SrsRtcConnection::get_local_sdp()
|
SrsSdp* SrsRtcConnection::get_local_sdp()
|
||||||
|
@ -1616,22 +1624,24 @@ void SrsRtcConnection::set_state(SrsRtcConnectionStateType state)
|
||||||
state_ = state;
|
state_ = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
string SrsRtcConnection::id()
|
|
||||||
{
|
|
||||||
return peer_id_ + "/" + username_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
string SrsRtcConnection::peer_id()
|
|
||||||
{
|
|
||||||
return peer_id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
string SrsRtcConnection::username()
|
string SrsRtcConnection::username()
|
||||||
{
|
{
|
||||||
return username_;
|
return username_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<SrsUdpMuxSocket*> SrsRtcConnection::peer_addresses()
|
||||||
|
{
|
||||||
|
vector<SrsUdpMuxSocket*> addresses;
|
||||||
|
|
||||||
|
map<string, SrsUdpMuxSocket*>::iterator it;
|
||||||
|
for (it = peer_addresses_.begin(); it != peer_addresses_.end(); ++it) {
|
||||||
|
SrsUdpMuxSocket* addr = it->second;
|
||||||
|
addresses.push_back(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
void SrsRtcConnection::set_encrypt(bool v)
|
void SrsRtcConnection::set_encrypt(bool v)
|
||||||
{
|
{
|
||||||
encrypt = v;
|
encrypt = v;
|
||||||
|
@ -1774,8 +1784,8 @@ srs_error_t SrsRtcConnection::initialize(SrsRtcStream* source, SrsRequest* r, bo
|
||||||
session_timeout = _srs_config->get_rtc_stun_timeout(req->vhost);
|
session_timeout = _srs_config->get_rtc_stun_timeout(req->vhost);
|
||||||
last_stun_time = srs_get_system_time();
|
last_stun_time = srs_get_system_time();
|
||||||
|
|
||||||
srs_trace("RTC init session, DTLS(role=%s, version=%s), timeout=%dms",
|
srs_trace("RTC init session, user=%s, url=%s, DTLS(role=%s, version=%s), timeout=%dms", username.c_str(),
|
||||||
cfg->dtls_role.c_str(), cfg->dtls_version.c_str(), srsu2msi(session_timeout));
|
r->get_stream_url().c_str(), cfg->dtls_role.c_str(), cfg->dtls_version.c_str(), srsu2msi(session_timeout));
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -1792,9 +1802,7 @@ srs_error_t SrsRtcConnection::on_stun(SrsUdpMuxSocket* skt, SrsStunPacket* r)
|
||||||
|
|
||||||
// We are running in the ice-lite(server) mode. If client have multi network interface,
|
// 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.
|
// we only choose one candidate pair which is determined by client.
|
||||||
if (!sendonly_skt || sendonly_skt->peer_id() != skt->peer_id()) {
|
update_sendonly_socket(skt);
|
||||||
update_sendonly_socket(skt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write STUN messages to blackhole.
|
// Write STUN messages to blackhole.
|
||||||
if (_srs_blackhole->blackhole) {
|
if (_srs_blackhole->blackhole) {
|
||||||
|
@ -1865,8 +1873,8 @@ srs_error_t SrsRtcConnection::on_connection_established()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
srs_trace("RTC %s session=%s, to=%dms connection established", (is_publisher_? "Publisher":"Subscriber"),
|
srs_trace("RTC: session %s, to=%dms connection established", (is_publisher_? "Publisher":"Subscriber"),
|
||||||
id().c_str(), srsu2msi(session_timeout));
|
srsu2msi(session_timeout));
|
||||||
|
|
||||||
if (is_publisher_) {
|
if (is_publisher_) {
|
||||||
if ((err = start_publish()) != srs_success) {
|
if ((err = start_publish()) != srs_success) {
|
||||||
|
@ -1908,28 +1916,44 @@ bool SrsRtcConnection::is_stun_timeout()
|
||||||
return last_stun_time + session_timeout < srs_get_system_time();
|
return last_stun_time + session_timeout < srs_get_system_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: FIXME: We should support multiple addresses, because client may use more than one addresses.
|
|
||||||
void SrsRtcConnection::update_sendonly_socket(SrsUdpMuxSocket* skt)
|
void SrsRtcConnection::update_sendonly_socket(SrsUdpMuxSocket* skt)
|
||||||
{
|
{
|
||||||
std::string old_peer_id;
|
// TODO: FIXME: Refine performance.
|
||||||
|
string prev_peer_id, peer_id = skt->peer_id();
|
||||||
if (sendonly_skt) {
|
if (sendonly_skt) {
|
||||||
srs_trace("session %s address changed, update %s -> %s",
|
prev_peer_id = sendonly_skt->peer_id();
|
||||||
id().c_str(), sendonly_skt->peer_id().c_str(), skt->peer_id().c_str());
|
}
|
||||||
old_peer_id = sendonly_skt->peer_id();
|
|
||||||
|
// Ignore if same address.
|
||||||
|
if (prev_peer_id == peer_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect address change.
|
||||||
|
if (prev_peer_id.empty()) {
|
||||||
|
srs_trace("RTC: session address init %s", peer_id.c_str());
|
||||||
|
} else {
|
||||||
|
srs_trace("RTC: session address changed, update %s -> %s, total %u", prev_peer_id.c_str(),
|
||||||
|
peer_id.c_str(), peer_addresses_.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find object from cache.
|
||||||
|
SrsUdpMuxSocket* addr_cache = NULL;
|
||||||
|
if (true) {
|
||||||
|
map<string, SrsUdpMuxSocket*>::iterator it = peer_addresses_.find(peer_id);
|
||||||
|
if (it != peer_addresses_.end()) {
|
||||||
|
addr_cache = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no cache, build cache and setup the relations in connection.
|
||||||
|
if (!addr_cache) {
|
||||||
|
peer_addresses_[peer_id] = addr_cache = skt->copy_sendonly();
|
||||||
|
server_->insert_into_id_sessions(peer_id, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the transport.
|
// Update the transport.
|
||||||
srs_freep(sendonly_skt);
|
sendonly_skt = addr_cache;
|
||||||
sendonly_skt = skt->copy_sendonly();
|
|
||||||
|
|
||||||
// Update the sessions to handle packets from the new address.
|
|
||||||
peer_id_ = sendonly_skt->peer_id();
|
|
||||||
server_->insert_into_id_sessions(peer_id_, this);
|
|
||||||
|
|
||||||
// Remove the old address.
|
|
||||||
if (!old_peer_id.empty()) {
|
|
||||||
server_->remove_id_sessions(old_peer_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsRtcConnection::check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssrc)
|
void SrsRtcConnection::check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssrc)
|
||||||
|
@ -2248,7 +2272,8 @@ srs_error_t SrsRtcConnection::on_binding_request(SrsStunPacket* r)
|
||||||
|
|
||||||
if (state_ == WAITING_STUN) {
|
if (state_ == WAITING_STUN) {
|
||||||
state_ = DOING_DTLS_HANDSHAKE;
|
state_ = DOING_DTLS_HANDSHAKE;
|
||||||
srs_trace("RTC session=%s, STUN done, waiting DTLS handshake.", id().c_str());
|
// TODO: FIXME: Add cost.
|
||||||
|
srs_trace("RTC: session STUN done, waiting DTLS handshake.");
|
||||||
|
|
||||||
if((err = transport_->start_active_handshake()) != srs_success) {
|
if((err = transport_->start_active_handshake()) != srs_success) {
|
||||||
return srs_error_wrap(err, "fail to dtls handshake");
|
return srs_error_wrap(err, "fail to dtls handshake");
|
||||||
|
|
|
@ -323,9 +323,12 @@ private:
|
||||||
SrsRtcPublishStream* publisher_;
|
SrsRtcPublishStream* publisher_;
|
||||||
bool is_publisher_;
|
bool is_publisher_;
|
||||||
private:
|
private:
|
||||||
SrsUdpMuxSocket* sendonly_skt;
|
// The local:remote username, such as m5x0n128:jvOm where local name is m5x0n128.
|
||||||
std::string username_;
|
std::string username_;
|
||||||
std::string peer_id_;
|
// The peer address, client maybe use more than one address, it's the current selected one.
|
||||||
|
SrsUdpMuxSocket* sendonly_skt;
|
||||||
|
// The address list, client may use multiple addresses.
|
||||||
|
std::map<std::string, SrsUdpMuxSocket*> peer_addresses_;
|
||||||
private:
|
private:
|
||||||
// The timeout of session, keep alive by STUN ping pong.
|
// The timeout of session, keep alive by STUN ping pong.
|
||||||
srs_utime_t session_timeout;
|
srs_utime_t session_timeout;
|
||||||
|
@ -343,6 +346,7 @@ private:
|
||||||
SrsSdp remote_sdp;
|
SrsSdp remote_sdp;
|
||||||
SrsSdp local_sdp;
|
SrsSdp local_sdp;
|
||||||
public:
|
public:
|
||||||
|
// TODO: FIXME: Remove dead code.
|
||||||
// User debugging parameters, overwrite config.
|
// User debugging parameters, overwrite config.
|
||||||
std::string sequence_startup;
|
std::string sequence_startup;
|
||||||
std::string sequence_delta;
|
std::string sequence_delta;
|
||||||
|
@ -364,12 +368,10 @@ public:
|
||||||
// Connection level state machine, for ARQ of UDP packets.
|
// Connection level state machine, for ARQ of UDP packets.
|
||||||
SrsRtcConnectionStateType state();
|
SrsRtcConnectionStateType state();
|
||||||
void set_state(SrsRtcConnectionStateType state);
|
void set_state(SrsRtcConnectionStateType state);
|
||||||
// TODO: FIXME: Rename it.
|
// Get username pair for this connection, used as ID of session.
|
||||||
std::string id();
|
|
||||||
// TODO: FIXME: Rename it.
|
|
||||||
std::string peer_id();
|
|
||||||
// TODO: FIXME: Rename it.
|
|
||||||
std::string username();
|
std::string username();
|
||||||
|
// Get all addresses client used.
|
||||||
|
std::vector<SrsUdpMuxSocket*> peer_addresses();
|
||||||
public:
|
public:
|
||||||
void set_encrypt(bool v);
|
void set_encrypt(bool v);
|
||||||
void switch_to_context();
|
void switch_to_context();
|
||||||
|
|
|
@ -542,17 +542,20 @@ void SrsRtcServer::destroy(SrsRtcConnection* session)
|
||||||
|
|
||||||
std::map<std::string, SrsRtcConnection*>::iterator it;
|
std::map<std::string, SrsRtcConnection*>::iterator it;
|
||||||
|
|
||||||
if ((it = map_username_session.find(session->username())) != map_username_session.end()) {
|
string username = session->username();
|
||||||
|
if ((it = map_username_session.find(username)) != map_username_session.end()) {
|
||||||
map_username_session.erase(it);
|
map_username_session.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((it = map_id_session.find(session->peer_id())) != map_id_session.end()) {
|
vector<SrsUdpMuxSocket*> addresses = session->peer_addresses();
|
||||||
map_id_session.erase(it);
|
for (int i = 0; i < (int)addresses.size(); i++) {
|
||||||
|
SrsUdpMuxSocket* addr = addresses.at(i);
|
||||||
|
map_id_session.erase(addr->peer_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsContextRestore(_srs_context->get_id());
|
SrsContextRestore(_srs_context->get_id());
|
||||||
session->switch_to_context();
|
session->switch_to_context();
|
||||||
srs_trace("RTC session=%s, destroy, summary: %s", session->id().c_str(), session->stat_->summary().c_str());
|
srs_trace("RTC: session destroy, username=%s, summary: %s", username.c_str(), session->stat_->summary().c_str());
|
||||||
|
|
||||||
zombies_.push_back(session);
|
zombies_.push_back(session);
|
||||||
}
|
}
|
||||||
|
@ -562,14 +565,6 @@ bool SrsRtcServer::insert_into_id_sessions(const string& peer_id, SrsRtcConnecti
|
||||||
return map_id_session.insert(make_pair(peer_id, session)).second;
|
return map_id_session.insert(make_pair(peer_id, session)).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsRtcServer::remove_id_sessions(const string& peer_id)
|
|
||||||
{
|
|
||||||
std::map<std::string, SrsRtcConnection*>::iterator it;
|
|
||||||
if ((it = map_id_session.find(peer_id)) != map_id_session.end()) {
|
|
||||||
map_id_session.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SrsRtcServer::check_and_clean_timeout_session()
|
void SrsRtcServer::check_and_clean_timeout_session()
|
||||||
{
|
{
|
||||||
map<string, SrsRtcConnection*>::iterator iter = map_username_session.begin();
|
map<string, SrsRtcConnection*>::iterator iter = map_username_session.begin();
|
||||||
|
@ -585,14 +580,19 @@ void SrsRtcServer::check_and_clean_timeout_session()
|
||||||
// Now, we got the RTC session to cleanup, switch to its context
|
// Now, we got the RTC session to cleanup, switch to its context
|
||||||
// to make all logs write to the "correct" pid+cid.
|
// to make all logs write to the "correct" pid+cid.
|
||||||
session->switch_to_context();
|
session->switch_to_context();
|
||||||
srs_trace("RTC session=%s, STUN timeout, summary: %s", session->id().c_str(), session->stat_->summary().c_str());
|
srs_trace("RTC: session STUN timeout, summary: %s", session->stat_->summary().c_str());
|
||||||
|
|
||||||
session->disposing_ = true;
|
session->disposing_ = true;
|
||||||
zombies_.push_back(session);
|
zombies_.push_back(session);
|
||||||
|
|
||||||
// Use C++98 style: https://stackoverflow.com/a/4636230
|
// Use C++98 style: https://stackoverflow.com/a/4636230
|
||||||
map_username_session.erase(iter++);
|
map_username_session.erase(iter++);
|
||||||
map_id_session.erase(session->peer_id());
|
|
||||||
|
vector<SrsUdpMuxSocket*> addresses = session->peer_addresses();
|
||||||
|
for (int i = 0; i < (int)addresses.size(); i++) {
|
||||||
|
SrsUdpMuxSocket* addr = addresses.at(i);
|
||||||
|
map_id_session.erase(addr->peer_id());
|
||||||
|
}
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
handler->on_timeout(session);
|
handler->on_timeout(session);
|
||||||
|
|
|
@ -118,7 +118,7 @@ public:
|
||||||
void destroy(SrsRtcConnection* session);
|
void destroy(SrsRtcConnection* session);
|
||||||
public:
|
public:
|
||||||
bool insert_into_id_sessions(const std::string& peer_id, SrsRtcConnection* session);
|
bool insert_into_id_sessions(const std::string& peer_id, SrsRtcConnection* session);
|
||||||
void remove_id_sessions(const std::string& peer_id);
|
// TODO: FIXME: Change to private.
|
||||||
void check_and_clean_timeout_session();
|
void check_and_clean_timeout_session();
|
||||||
int nn_sessions();
|
int nn_sessions();
|
||||||
SrsRtcConnection* find_session_by_username(const std::string& ufrag);
|
SrsRtcConnection* find_session_by_username(const std::string& ufrag);
|
||||||
|
|
|
@ -24,6 +24,6 @@
|
||||||
#ifndef SRS_CORE_VERSION4_HPP
|
#ifndef SRS_CORE_VERSION4_HPP
|
||||||
#define SRS_CORE_VERSION4_HPP
|
#define SRS_CORE_VERSION4_HPP
|
||||||
|
|
||||||
#define SRS_VERSION4_REVISION 35
|
#define SRS_VERSION4_REVISION 36
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue