From 35ecf828f6256c481e9a0d174d08496a5eb8f6a0 Mon Sep 17 00:00:00 2001 From: Johnny Date: Wed, 21 Jul 2021 16:36:32 +0800 Subject: [PATCH 01/13] fix typo. --- trunk/src/app/srs_app_rtc_conn.cpp | 4 ++-- trunk/src/app/srs_app_server.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 3c1fb51da5..b133cdc13f 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -3107,7 +3107,7 @@ srs_error_t SrsRtcConnection::generate_publish_local_sdp(SrsRequest* req, SrsSdp local_media_desc.mid_ = audio_track->mid_; local_sdp.groups_.push_back(local_media_desc.mid_); - // anwer not need set stream_id and track_id; + // answer not need set stream_id and track_id; // local_media_desc.msid_ = stream_id; // local_media_desc.msid_tracker_ = audio_track->id_; local_media_desc.extmaps_ = audio_track->extmaps_; @@ -3140,7 +3140,7 @@ srs_error_t SrsRtcConnection::generate_publish_local_sdp(SrsRequest* req, SrsSdp local_media_desc.mid_ = video_track->mid_; local_sdp.groups_.push_back(local_media_desc.mid_); - // anwer not need set stream_id and track_id; + // answer not need set stream_id and track_id; //local_media_desc.msid_ = stream_id; //local_media_desc.msid_tracker_ = video_track->id_; local_media_desc.extmaps_ = video_track->extmaps_; diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 9ba3357ebc..232c86a9de 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -49,7 +49,7 @@ std::string srs_listener_type2string(SrsListenerType type) case SrsListenerHttpStream: return "HTTP-Server"; case SrsListenerHttpsStream: - return "HTTP-Server"; + return "HTTPS-Server"; case SrsListenerMpegTsOverUdp: return "MPEG-TS over UDP"; case SrsListenerFlv: From 1d5b242c4960c3d916839ef2fb306560f60be726 Mon Sep 17 00:00:00 2001 From: Johnny Date: Mon, 1 Mar 2021 19:39:44 +0800 Subject: [PATCH 02/13] refactor: update rtc conn. --- trunk/src/app/srs_app_rtc_conn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index b133cdc13f..57f54da359 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -2026,7 +2026,7 @@ srs_error_t SrsRtcConnection::add_player(SrsRtcUserConfig* ruc, SrsSdp& local_sd return srs_error_wrap(err, "play negotiate"); } - if (!play_sub_relations.size()) { + if (play_sub_relations.empty()) { return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no play relations"); } From 50dc1870af532bf7f962b9e0c2166c8aca4cfc4c Mon Sep 17 00:00:00 2001 From: Johnny Date: Thu, 24 Jun 2021 19:55:39 +0800 Subject: [PATCH 03/13] feat(simulcast): add rtc_publisher_simulcast page. --- trunk/research/players/rtc_player.html | 1 + trunk/research/players/rtc_publisher.html | 1 + .../players/rtc_publisher_simulcast.html | 139 ++++++++++++++++++ trunk/research/players/srs_bwt.html | 1 + trunk/research/players/srs_chat.html | 1 + trunk/research/players/srs_gb28181.html | 1 + trunk/research/players/srs_player.html | 1 + .../players/srs_player_deprecated.html | 1 + trunk/research/players/srs_publisher.html | 1 + trunk/research/players/vlc.html | 1 + 10 files changed, 148 insertions(+) create mode 100644 trunk/research/players/rtc_publisher_simulcast.html diff --git a/trunk/research/players/rtc_player.html b/trunk/research/players/rtc_player.html index ab0ad3ea4b..ea4c624ca8 100644 --- a/trunk/research/players/rtc_player.html +++ b/trunk/research/players/rtc_player.html @@ -26,6 +26,7 @@
  • SRS播放器
  • RTC播放器
  • RTC推流
  • +
  • Simulcast推流
  • iOS/Andriod
  • diff --git a/trunk/research/players/rtc_publisher.html b/trunk/research/players/rtc_publisher.html index a904c2f9e1..fd905a5e67 100644 --- a/trunk/research/players/rtc_publisher.html +++ b/trunk/research/players/rtc_publisher.html @@ -27,6 +27,7 @@
  • SRS播放器
  • RTC播放器
  • RTC推流
  • +
  • Simulcast推流
  • iOS/Andriod
  • diff --git a/trunk/research/players/rtc_publisher_simulcast.html b/trunk/research/players/rtc_publisher_simulcast.html new file mode 100644 index 0000000000..7048abe9c5 --- /dev/null +++ b/trunk/research/players/rtc_publisher_simulcast.html @@ -0,0 +1,139 @@ + + + + SRS + + + + + + + + + + + + + +
    +
    + URL: + + +
    + + + + + + SessionID: + + + Audio: +
    + Video: + + + + Simulator: Drop + + +
    + + + + + diff --git a/trunk/research/players/srs_bwt.html b/trunk/research/players/srs_bwt.html index a2858241b8..af1e8c2da0 100644 --- a/trunk/research/players/srs_bwt.html +++ b/trunk/research/players/srs_bwt.html @@ -25,6 +25,7 @@
  • SRS播放器
  • RTC播放器
  • RTC推流
  • +
  • Simulcast推流
  • SRS编码器
  • SRS会议
  • SRS测网速
  • diff --git a/trunk/research/players/srs_chat.html b/trunk/research/players/srs_chat.html index abed015fc2..577dec1039 100644 --- a/trunk/research/players/srs_chat.html +++ b/trunk/research/players/srs_chat.html @@ -24,6 +24,7 @@
  • SRS播放器
  • RTC播放器
  • RTC推流
  • +
  • Simulcast推流
  • SRS编码器
  • SRS会议
  • SRS测网速
  • diff --git a/trunk/research/players/srs_gb28181.html b/trunk/research/players/srs_gb28181.html index 2fd4a66e80..0580c51ee5 100644 --- a/trunk/research/players/srs_gb28181.html +++ b/trunk/research/players/srs_gb28181.html @@ -38,6 +38,7 @@
  • SRS播放器
  • RTC播放器
  • RTC推流
  • +
  • Simulcast推流
  • iOS/Andriod
  • diff --git a/trunk/research/players/srs_player.html b/trunk/research/players/srs_player.html index 62b89489c5..4009334517 100755 --- a/trunk/research/players/srs_player.html +++ b/trunk/research/players/srs_player.html @@ -21,6 +21,7 @@
  • SRS播放器
  • RTC播放器
  • RTC推流
  • +
  • Simulcast推流
  • iOS/Andriod
  • diff --git a/trunk/research/players/srs_player_deprecated.html b/trunk/research/players/srs_player_deprecated.html index 26f21fcfc3..563a30b14a 100755 --- a/trunk/research/players/srs_player_deprecated.html +++ b/trunk/research/players/srs_player_deprecated.html @@ -35,6 +35,7 @@
  • SRS播放器
  • RTC播放器
  • RTC推流
  • +
  • Simulcast推流
  • iOS/Andriod
  • diff --git a/trunk/research/players/srs_publisher.html b/trunk/research/players/srs_publisher.html index 1125c72a27..413f4e796e 100644 --- a/trunk/research/players/srs_publisher.html +++ b/trunk/research/players/srs_publisher.html @@ -24,6 +24,7 @@
  • SRS播放器
  • RTC播放器
  • RTC推流
  • +
  • Simulcast推流
  • diff --git a/trunk/research/players/vlc.html b/trunk/research/players/vlc.html index 4422301ef3..3f677bb8e7 100644 --- a/trunk/research/players/vlc.html +++ b/trunk/research/players/vlc.html @@ -21,6 +21,7 @@
  • SRS播放器
  • RTC播放器
  • RTC推流
  • +
  • Simulcast推流
  • SRS编码器
  • SRS会议
  • SRS测网速
  • From 8d746130d93918c1ae8ad92cf66447bfd273821a Mon Sep 17 00:00:00 2001 From: Johnny Date: Fri, 25 Jun 2021 14:24:56 +0800 Subject: [PATCH 04/13] feat(kSimulcastApiVersionSpecCompliant/js): update txt url in simulcast page. --- trunk/research/players/js/srs.page.js | 1 + trunk/research/players/js/srs.sdk.js | 25 ++++++++++++++++--- .../players/rtc_publisher_simulcast.html | 4 +++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/trunk/research/players/js/srs.page.js b/trunk/research/players/js/srs.page.js index 26b3971e1c..7e6d65773d 100755 --- a/trunk/research/players/js/srs.page.js +++ b/trunk/research/players/js/srs.page.js @@ -18,6 +18,7 @@ function update_nav() { $("#nav_rtc_player").attr("href", "rtc_player.html" + window.location.search); $("#nav_rtc_publisher").attr("href", "rtc_publisher.html" + window.location.search); $("#nav_srs_publisher").attr("href", "srs_publisher.html" + window.location.search); + $("#nav_srs_publisher_simulcast").attr("href", "srs_publisher_simulcast.html" + window.location.search); $("#nav_srs_chat").attr("href", "srs_chat.html" + window.location.search); $("#nav_srs_bwt").attr("href", "srs_bwt.html" + window.location.search); $("#nav_vlc").attr("href", "vlc.html" + window.location.search); diff --git a/trunk/research/players/js/srs.sdk.js b/trunk/research/players/js/srs.sdk.js index 86f87f8f68..eab996ae78 100644 --- a/trunk/research/players/js/srs.sdk.js +++ b/trunk/research/players/js/srs.sdk.js @@ -50,10 +50,14 @@ function SrsRtcPublisherAsync() { self.constraints.video = { wіdth: 1280, height: 720 } + UpdateNativeCreateOffer(numberOfSimulcastLayers); + console.log('kSimulcastApiVersionLegacy') + } else if (parameter === 'spec3') { + self.constraints.video = { + wіdth: 1280, height: 720 + } + console.log('kSimulcastApiVersionSpecCompliant') } - UpdateNativeCreateOffer(numberOfSimulcastLayers); - self.pc.addTransceiver("audio", {direction: "sendonly"}); - self.pc.addTransceiver("video", {direction: "sendonly"}); if (!navigator.mediaDevices && window.location.protocol === 'http:' && window.location.hostname !== 'localhost') { throw new Error(`Please use HTTPS or localhost to publish, read https://github.com/ossrs/srs/issues/2762#issuecomment-983147576`); @@ -62,7 +66,20 @@ function SrsRtcPublisherAsync() { // @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack stream.getTracks().forEach(function (track) { - self.pc.addTrack(track); + if (track.kind === 'video' && parameter === 'spec3') { + self.pc.addTransceiver(track, { + active: true, + direction: "sendonly", + sendEncodings: [ + // NOTE: modify from media/engine/simulcast.cc + {rid: "high", active: true, maxBitrate: 5000 * 1024}, + {rid: "mid", active: true, maxBitrate: 1500 * 1024, scaleResolutionDownBy: 2}, + {rid: "low", active: true, maxBitrate: 400 * 1024, scaleResolutionDownBy: 4}, + ] + }) + } else { + self.pc.addTrack(track, stream); + } // Notify about local track when stream is ok. self.ontrack && self.ontrack({track: track}); diff --git a/trunk/research/players/rtc_publisher_simulcast.html b/trunk/research/players/rtc_publisher_simulcast.html index 7048abe9c5..c41da0adcb 100644 --- a/trunk/research/players/rtc_publisher_simulcast.html +++ b/trunk/research/players/rtc_publisher_simulcast.html @@ -112,6 +112,10 @@ // For example: webrtc://r.ossrs.net/live/livestream var url = $("#txt_url").val(); + if (-1 === url.indexOf("?numberOfSimulcastLayers=spec3")) { + $("#txt_url").val(`${url}?numberOfSimulcastLayers=spec3`); + url = $("#txt_url").val(); + } sdk.publish(url).then(function(session){ $('#rtc_media_player').prop('srcObject', sdk.stream); $('#sessionid').html(session.sessionid); From d78fd5a26a071204ee8b5c64d6e9fe34e041e077 Mon Sep 17 00:00:00 2001 From: Johnny Date: Tue, 28 Sep 2021 15:22:03 +0800 Subject: [PATCH 05/13] feat(kSimulcastApiVersionSpecCompliant): support simulcast, use layer=N --- trunk/src/app/srs_app_rtc_conn.cpp | 153 +++++++++++++--- trunk/src/app/srs_app_rtc_conn.hpp | 6 + trunk/src/app/srs_app_rtc_sdp.cpp | 253 ++++++++++++++++++++++++++- trunk/src/app/srs_app_rtc_sdp.hpp | 76 +++++++- trunk/src/app/srs_app_rtc_source.cpp | 28 +++ trunk/src/app/srs_app_rtc_source.hpp | 4 + 6 files changed, 481 insertions(+), 39 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 57f54da359..3b26f02963 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1748,6 +1748,14 @@ void SrsRtcPublishStream::update_send_report_time(uint32_t ssrc, const SrsNtp& n } } +void SrsRtcPublishStream::bind_rid(const SrsRidInfo &rid_info) { + // todo: on ssrc check mid rid + auto video_track = get_video_track(0); + if (video_track) { + video_track->active_as(rid_info); + } +} + ISrsRtcConnectionHijacker::ISrsRtcConnectionHijacker() { } @@ -1985,6 +1993,16 @@ srs_error_t SrsRtcConnection::add_publisher(SrsRtcUserConfig* ruc, SrsSdp& local return srs_error_wrap(err, "generate local sdp"); } + // NOTE: Supplement Simulcast information in publish local sdp. + auto size = local_sdp.media_descs_.size(); + assert(size == ruc->remote_sdp_.media_descs_.size()); + for (size_t i = 0; i < size; ++i) { + auto& media_desc = ruc->remote_sdp_.media_descs_.at(i); + if (media_desc.is_video() && media_desc.simulcast_spec_version()) { + local_sdp.media_descs_.at(i).session_info_.simulcast_ = media_desc.session_info_.simulcast_; + } + } + SrsRtcSource* source = NULL; if ((err = _srs_rtc_sources->fetch_or_create(req, &source)) != srs_success) { return srs_error_wrap(err, "create source"); @@ -2287,7 +2305,11 @@ srs_error_t SrsRtcConnection::find_publisher(char* buf, int size, SrsRtcPublishS map::iterator it = publishers_ssrc_map_.find(ssrc); if(it == publishers_ssrc_map_.end()) { - return srs_error_new(ERROR_RTC_NO_PUBLISHER, "no publisher for ssrc:%u", ssrc); + if ((err = parse_rid(buf, size, ssrc)) != srs_success) { + return srs_error_wrap(err, "no publisher for ssrc:%u; parse_rid", ssrc); + } else { + return srs_error_new(ERROR_RTC_NO_PUBLISHER, "no publisher for ssrc:%u", ssrc); + } } *ppublisher = it->second; @@ -2295,6 +2317,55 @@ srs_error_t SrsRtcConnection::find_publisher(char* buf, int size, SrsRtcPublishS return err; } +srs_error_t SrsRtcConnection::parse_rid(char *buf, int size, uint32_t ssrc) { + srs_error_t err = srs_success; + if (publishers_ssrc_map_.empty()) { + return err; + } + + for (auto& media_desc: remote_sdp.media_descs_) { + if (!media_desc.simulcast_spec_version()) { + continue; + } + + auto &extmaps_ = media_desc.extmaps_; + auto &simulcast = media_desc.session_info_.simulcast_; + + // auto &publisher_ = publishers_ssrc_map_.begin()->second; + // publisher_->on_rtp(buf, size); + auto rid = extmaps_.parse_rid(buf, size, simulcast); + if (rid) { + assert(rid->ssrc == 0); + rid->ssrc = ssrc; + if ((err = bind_rid(*rid)) != srs_success) { + return srs_error_wrap(err, "bind rid"); + } + } + } + return err; +} + +srs_error_t SrsRtcConnection::bind_rid(const SrsRidInfo &rid_info) { + srs_error_t err = srs_success; + SrsRtcSource *source = NULL; + if ((err = _srs_rtc_sources->fetch_or_create(req_, &source)) != srs_success) { + return srs_error_wrap(err, "fetch_or_create source"); + } + auto track_descs = source->get_track_desc("video", "H264"); + for (auto &track_desc: track_descs) { + if (track_desc->ssrc_ == 0) { + track_desc->ssrc_ = rid_info.ssrc; + track_desc->rid_ = rid_info; + auto &publisher = publishers_ssrc_map_.begin()->second; + publisher->bind_rid(rid_info); + publishers_ssrc_map_[track_desc->ssrc_] = publisher; + srs_warn("find track_desc to (rid='%s', ssrc=%u)", rid_info.rid.c_str(), rid_info.ssrc); + return err; + } + } + return srs_error_new(ERROR_RTC_NO_TRACK, "no idle track_desc to (rid='%s', ssrc=%u)", rid_info.rid.c_str(), rid_info.ssrc); +} + srs_error_t SrsRtcConnection::on_connection_established() { srs_error_t err = srs_success; @@ -2832,7 +2903,12 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRtcUserConfig* ruc for(map::iterator it = extmaps.begin(); it != extmaps.end(); ++it) { if (it->second == kTWCCExt) { remote_twcc_id = it->first; - break; + // break; + } else if (remote_media_desc.simulcast_spec_version()) { + // note: add all ext map in simulcast_spec_version + if (it->second == kExtMapFieldArray[kSdesRtpStreamId] || it->second == kExtMapFieldArray[kSdesRepairedRtpStreamId]) { + track_desc->add_rtp_extension_desc(it->first, it->second); + } } } } @@ -3016,31 +3092,41 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRtcUserConfig* ruc ssrc_info.ssrc_, ssrc_info.msid_.c_str(), ssrc_info.msid_tracker_.c_str()); } } else if (remote_media_desc.is_video()) { - std::string track_id; - for (int j = 0; j < (int)remote_media_desc.ssrc_infos_.size(); ++j) { - const SrsSSRCInfo& ssrc_info = remote_media_desc.ssrc_infos_.at(j); - - // ssrc have same track id, will be description in the same track description. - if(track_id != ssrc_info.msid_tracker_) { - SrsRtcTrackDescription* track_desc_copy = track_desc->copy(); - track_desc_copy->ssrc_ = ssrc_info.ssrc_; - track_desc_copy->id_ = ssrc_info.msid_tracker_; - track_desc_copy->msid_ = ssrc_info.msid_; - if (remote_media_desc.is_original_ssrc(&ssrc_info)) { - // note: set ssrc related to single or simulcast(chrome munging style simulcast sdp) - // todo: support standard simulcast, like "a=simulcast:send a;b;c" - stream_desc->video_track_descs_.push_back(track_desc_copy); - srs_info("%d/%d#publish video track_id_=%s, ssrc_=%u, msid_=%s, msid_tracker_='%s'", j,(int)remote_media_desc.ssrc_infos_.size(), - track_id.c_str(), ssrc_info.ssrc_, ssrc_info.msid_.c_str(), ssrc_info.msid_tracker_.c_str()); + if (remote_media_desc.simulcast_spec_version()) { + // todo check simulcast kSimulcastApiVersionSpecCompliant + for (size_t i=0; ivideo_track_descs_.push_back(track_desc->copy()); + } + } else { + std::string track_id; + for (int j = 0; j < (int)remote_media_desc.ssrc_infos_.size(); ++j) { + const SrsSSRCInfo& ssrc_info = remote_media_desc.ssrc_infos_.at(j); + + // ssrc have same track id, will be description in the same track description. + if(track_id != ssrc_info.msid_tracker_) { + SrsRtcTrackDescription* track_desc_copy = track_desc->copy(); + track_desc_copy->ssrc_ = ssrc_info.ssrc_; + track_desc_copy->id_ = ssrc_info.msid_tracker_; + track_desc_copy->msid_ = ssrc_info.msid_; + if (remote_media_desc.is_original_ssrc(&ssrc_info)) { + // note: set ssrc related to single or simulcast(chrome munging style simulcast sdp) + // todo: support standard simulcast, like "a=simulcast:send a;b;c" + stream_desc->video_track_descs_.push_back(track_desc_copy); + srs_info("%d/%d#publish video track_id_=%s, ssrc_=%u, msid_=%s, msid_tracker_='%s'", j,(int)remote_media_desc.ssrc_infos_.size(), + track_id.c_str(), ssrc_info.ssrc_, ssrc_info.msid_.c_str(), ssrc_info.msid_tracker_.c_str()); + } else { + srs_info("%d/%d#ignore track_id_=%s, ssrc_=%u, msid_=%s, msid_tracker_='%s'", j, + (int) remote_media_desc.ssrc_infos_.size(), + track_id.c_str(), ssrc_info.ssrc_, ssrc_info.msid_.c_str(), + ssrc_info.msid_tracker_.c_str()); + } + track_id = ssrc_info.msid_tracker_; } else { - srs_info("%d/%d#ignore track_id_=%s, ssrc_=%u, msid_=%s, msid_tracker_='%s'", j, (int)remote_media_desc.ssrc_infos_.size(), - track_id.c_str(), ssrc_info.ssrc_, ssrc_info.msid_.c_str(), ssrc_info.msid_tracker_.c_str()); + srs_info("%d/%d#ignore track_id_/msid_tracker_=%s, ssrc_=%u, msid_=%s", j, + (int) remote_media_desc.ssrc_infos_.size(), + track_id.c_str(), ssrc_info.ssrc_, ssrc_info.msid_.c_str()); + track_id = ""; } - track_id = ssrc_info.msid_tracker_; - } else { - srs_info("%d/%d#ignore track_id_/msid_tracker_=%s, ssrc_=%u, msid_=%s", j, (int)remote_media_desc.ssrc_infos_.size(), - track_id.c_str(), ssrc_info.ssrc_, ssrc_info.msid_.c_str()); - track_id = ""; } } } else { @@ -3110,7 +3196,7 @@ srs_error_t SrsRtcConnection::generate_publish_local_sdp(SrsRequest* req, SrsSdp // answer not need set stream_id and track_id; // local_media_desc.msid_ = stream_id; // local_media_desc.msid_tracker_ = audio_track->id_; - local_media_desc.extmaps_ = audio_track->extmaps_; + local_media_desc.extmaps_.data = audio_track->extmaps_; if (audio_track->direction_ == "recvonly") { local_media_desc.recvonly_ = true; @@ -3143,7 +3229,7 @@ srs_error_t SrsRtcConnection::generate_publish_local_sdp(SrsRequest* req, SrsSdp // answer not need set stream_id and track_id; //local_media_desc.msid_ = stream_id; //local_media_desc.msid_tracker_ = video_track->id_; - local_media_desc.extmaps_ = video_track->extmaps_; + local_media_desc.extmaps_.data = video_track->extmaps_; if (video_track->direction_ == "recvonly") { local_media_desc.recvonly_ = true; @@ -3270,6 +3356,9 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRtcUserConfig* ruc, s track->mid_ = remote_media_desc.mid_; uint32_t publish_ssrc = track->ssrc_; + if (publish_ssrc == 0) { + continue; + } vector rtcp_fb; remote_payload.rtcp_fb_.swap(rtcp_fb); @@ -3300,6 +3389,9 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRtcUserConfig* ruc, s track->set_direction("sendonly"); sub_relations.insert(make_pair(publish_ssrc, track)); + if (track->rid_.ssrc > 0) { + srs_info("publish_ssrc=%u, play ssrc=%u, rid ssrc=%u, rid=%s", publish_ssrc, track->ssrc_, track->rid_.ssrc, track->rid_.rid.c_str()); + } } } @@ -3316,7 +3408,7 @@ void video_track_generate_play_offer(SrsRtcTrackDescription* track, string mid, local_media_desc.rtcp_mux_ = true; local_media_desc.rtcp_rsize_ = true; - local_media_desc.extmaps_ = track->extmaps_; + local_media_desc.extmaps_.data = track->extmaps_; // If mid not duplicated, use mid_ of track. Otherwise, use transformed mid. if (true) { @@ -3445,7 +3537,7 @@ srs_error_t SrsRtcConnection::generate_play_local_sdp(SrsRequest* req, SrsSdp& l local_media_desc.rtcp_mux_ = true; local_media_desc.rtcp_rsize_ = true; - local_media_desc.extmaps_ = audio_track->extmaps_; + local_media_desc.extmaps_.data = audio_track->extmaps_; local_media_desc.mid_ = audio_track->mid_; local_sdp.groups_.push_back(local_media_desc.mid_); @@ -3648,6 +3740,9 @@ srs_error_t SrsRtcConnection::create_publisher(SrsRequest* req, SrsRtcSourceDesc for(int i = 0; i < (int)stream_desc->video_track_descs_.size(); ++i) { SrsRtcTrackDescription* track_desc = stream_desc->video_track_descs_.at(i); if(publishers_ssrc_map_.end() != publishers_ssrc_map_.find(track_desc->ssrc_)) { + if (track_desc->ssrc_ == 0) { + continue; + } return srs_error_new(ERROR_RTC_DUPLICATED_SSRC, " duplicate ssrc %d, track id: %s", track_desc->ssrc_, track_desc->id_.c_str()); } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 17e5a7155c..61c5750cf8 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -404,6 +404,9 @@ class SrsRtcPublishStream : public ISrsRtspPacketDecodeHandler SrsRtcVideoRecvTrack* get_video_track(uint32_t ssrc); void update_rtt(uint32_t ssrc, int rtt); void update_send_report_time(uint32_t ssrc, const SrsNtp& ntp, uint32_t rtp_time); + +public: + void bind_rid(const SrsRidInfo& rid_info); }; // Callback for RTC connection. @@ -575,6 +578,9 @@ class SrsRtcConnection : public ISrsResource, public ISrsDisposingHandler, publi srs_error_t generate_play_local_sdp(SrsRequest* req, SrsSdp& local_sdp, SrsRtcSourceDescription* stream_desc, bool unified_plan); srs_error_t create_player(SrsRequest* request, std::map sub_relations); srs_error_t create_publisher(SrsRequest* request, SrsRtcSourceDescription* stream_desc); + + srs_error_t parse_rid(char *buf, int size, uint32_t ssrc); + srs_error_t bind_rid(const SrsRidInfo &rid_info); }; class ISrsRtcHijacker diff --git a/trunk/src/app/srs_app_rtc_sdp.cpp b/trunk/src/app/srs_app_rtc_sdp.cpp index 8bec5f2bd7..3e68895a47 100644 --- a/trunk/src/app/srs_app_rtc_sdp.cpp +++ b/trunk/src/app/srs_app_rtc_sdp.cpp @@ -7,6 +7,7 @@ #include #include +#include // for ntohs in linux #include #include @@ -110,8 +111,29 @@ srs_error_t SrsSessionInfo::parse_attribute(const std::string& attribute, const } else if (attribute == "setup") { // @see: https://tools.ietf.org/html/rfc4145#section-4 setup_ = value; + } else if (attribute == "simulcast") { + // kSimulcastApiVersionSpecCompliant + // todo + // a=simulcast:send 0;1;2 + // ignore attribute=simulcast, value=send 0;1;2 + // ignore attribute=rid, value=0 send + // ignore attribute=rid, value=1 send + // ignore attribute=rid, value=2 send + std::istringstream is(value); + FETCH(is, simulcast_.direction); + FETCH(is, simulcast_.line); + srs_warn("kSimulcastApiVersionSpecCompliant parse: %s %s", simulcast_.direction.c_str(), simulcast_.line.c_str()); + } else if (attribute == "rid") { + // a=rid:0 send + // a=rid:1 send + // a=rid:2 send + SrsRidInfo rid; + std::istringstream is(value); + FETCH(is, rid.rid); + FETCH(is, rid.direction); + simulcast_.rids.push_back(rid); } else { - srs_trace("ignore attribute=%s, value=%s", attribute.c_str(), value.c_str()); + srs_trace("ignore attribute='%s', value='%s'", attribute.c_str(), value.c_str()); } return err; @@ -390,7 +412,7 @@ srs_error_t SrsMediaDesc::encode(std::ostringstream& os) os << kCRLF; } - for(map::iterator it = extmaps_.begin(); it != extmaps_.end(); ++it) { + for(map::iterator it = extmaps_.data.begin(); it != extmaps_.data.end(); ++it) { os << "a=extmap:"<< it->first<< " "<< it->second<< kCRLF; } if (sendonly_) { @@ -420,11 +442,19 @@ srs_error_t SrsMediaDesc::encode(std::ostringstream& os) } } - for (std::vector::iterator iter = ssrc_infos_.begin(); iter != ssrc_infos_.end(); ++iter) { - SrsSSRCInfo& ssrc_info = *iter; + if (simulcast_spec_version()) { + srs_warn("kSimulcastApiVersionSpecCompliant %s %s", session_info_.simulcast_.direction.c_str(), session_info_.simulcast_.line.c_str()); + // todo check simulcast kSimulcastApiVersionSpecCompliant + if ((err = session_info_.simulcast_.encode(os)) != srs_success) { + return srs_error_wrap(err, "encode simulcast failed"); + } + } else { + for (std::vector::iterator iter = ssrc_infos_.begin(); iter != ssrc_infos_.end(); ++iter) { + SrsSSRCInfo &ssrc_info = *iter; - if ((err = ssrc_info.encode(os)) != srs_success) { - return srs_error_wrap(err, "encode ssrc failed"); + if ((err = ssrc_info.encode(os)) != srs_success) { + return srs_error_wrap(err, "encode ssrc failed"); + } } } @@ -503,12 +533,13 @@ srs_error_t SrsMediaDesc::parse_attr_extmap(const std::string& value) std::istringstream is(value); int id = 0; FETCH(is, id); - if(extmaps_.end() != extmaps_.find(id)) { + if(extmaps_.data.end() != extmaps_.data.find(id)) { return srs_error_new(ERROR_RTC_SDP_DECODE, "duplicate ext id: %d", id); } string ext; FETCH(is, ext); - extmaps_[id] = ext; + // note: check extmap get rid_ext_id, ridrtx_ext_id, mid_ext_id + extmaps_.parse_extmap(id, ext); return err; } @@ -1177,3 +1208,209 @@ srs_error_t SrsSdp::update_msid(string id) return err; } +srs_error_t SrsSimulcastInfo::encode(ostringstream &os) { + srs_error_t err = srs_success; + + // a=simulcast:send 0;1;2 + // a=rid:0 send + // a=rid:1 send + // a=rid:2 send + // check direction he rids rid.direction is send + for (auto& rid: rids) { + os << "a=rid:" << rid.rid << " recv" << kCRLF; + } + os << "a=simulcast:recv " << line << kCRLF; + + return err; +} + +void SrsExtMapInfo::parse_extmap(int id, std::string ext) { + data[id] = ext; + parse_ext_id(id, ext); +} + +void SrsExtMapInfo::parse_ext_id(int id, std::string ext) { + // a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level + // a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time + // a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 + // a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid + // a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id + // a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id + // + // a=extmap:14 urn:ietf:params:rtp-hdrext:toffset + // a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time + // a=extmap:13 urn:3gpp:video-orientation + // a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 + // a=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay + // a=extmap:11 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type + // a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing + // a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space + // a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid + // a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id + // a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id + + for (size_t i=0; iversion != 2) { + return -1; + } + int hlen = 12; + if(rtp->csrccount) /* Skip CSRC if needed */ + hlen += rtp->csrccount*4; + if(rtp->extension) { + janus_rtp_header_extension *ext = (janus_rtp_header_extension *)(buf+hlen); + int extlen = ntohs(ext->length)*4; + hlen += 4; + if(len > (hlen + extlen)) { + /* 1-Byte extension */ + if(ntohs(ext->type) == 0xBEDE) { + const uint8_t padding = 0x00, reserved = 0xF; + uint8_t extid = 0, idlen; + int i = 0; + while(i < extlen) { + extid = (uint8_t)buf[hlen+i] >> 4; + if(extid == reserved) { + break; + } else if(extid == padding) { + i++; + continue; + } + idlen = ((uint8_t)buf[hlen+i] & 0xF)+1; + if(extid == id) { + /* Found! */ + if(byte) + *byte = (uint8_t)buf[hlen+i+1]; + if(word && idlen >= 3 && (i+3) < extlen) { + memcpy(word, buf+hlen+i, sizeof(uint32_t)); + *word = ntohl(*word); + } + if(ref) + *ref = &buf[hlen+i]; + return 0; + } + i += 1 + idlen; + } + } + hlen += extlen; + } + } + return -1; +} + + +static int janus_rtp_header_extension_parse_rid(char *buf, int len, int id, + char *sdes_item, int sdes_len) { + char *ext = NULL; + if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext) < 0) + return -1; + /* a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id */ + /* a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id */ + if(ext == NULL) + return -2; + int val_len = (*ext & 0x0F) + 1; + if(val_len > (sdes_len-1)) { + // JANUS_LOG(LOG_WARN, "SDES buffer is too small (%d < %d), RTP stream ID will be cut\n", val_len, sdes_len); + val_len = sdes_len-1; + } + if (val_len > len-(ext-buf)-1 ) { + return -3; + } + memcpy(sdes_item, ext+1, val_len); + *(sdes_item+val_len) = '\0'; + return 0; + } + + +static int janus_rtp_header_extension_parse_mid(char *buf, int len, int id, + char *sdes_item, int sdes_len) { + char *ext = NULL; + if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext) < 0) + return -1; + /* a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid */ + if(ext == NULL) + return -2; + int val_len = (*ext & 0x0F) + 1; + if(val_len > (sdes_len-1)) { + // JANUS_LOG(LOG_WARN, "SDES buffer is too small (%d < %d), MID will be cut\n", val_len, sdes_len); + val_len = sdes_len-1; + } + if (val_len > len-(ext-buf)-1 ) { + return -3; + } + memcpy(sdes_item, ext+1, val_len); + *(sdes_item+val_len) = '\0'; + return 0; +} + +} + +SrsRidInfo* SrsExtMapInfo::parse_rid(char *buf, int len, SrsSimulcastInfo &simulcast) { + char sdes_item[16]; + int ret; + std::string rid, ridrtx; + std::string mid; + if((ret = janus_rtp_header_extension_parse_rid(buf, len, rid_ext_id(), sdes_item, sizeof(sdes_item))) == 0) { + rid = sdes_item; + } else { + return nullptr; + } + if((ret = janus_rtp_header_extension_parse_rid(buf, len, ridrtx_ext_id(), sdes_item, sizeof(sdes_item))) == 0) { + ridrtx = sdes_item; + srs_info("rid=%s, ridrtx_ext_id=%d, ridrtx=%s", rid.c_str(), ridrtx_ext_id(), ridrtx.c_str()); + } else { + srs_warn("bad=%d rid=%s, ridrtx_ext_id=%d", ret, rid.c_str(), ridrtx_ext_id()); + } + if((ret = janus_rtp_header_extension_parse_mid(buf, len, mid_ext_id(), sdes_item, sizeof(sdes_item))) == 0) { + mid = sdes_item; + srs_info("mid=%s", mid.c_str()); + } + for (size_t i=0; i rids; + + srs_error_t encode(std::ostringstream& os); +}; + class SrsSessionInfo { public: @@ -46,6 +63,8 @@ class SrsSessionInfo std::string fingerprint_algo_; std::string fingerprint_; std::string setup_; + + SrsSimulcastInfo simulcast_; }; class SrsSSRCInfo @@ -121,6 +140,55 @@ struct SrsCandidate std::string type_; }; + +#define DEFINDE_EXT_MAP_FIELD(EXT_MAP_FIELD) \ +EXT_MAP_FIELD(kSsrcAudioLevel, "urn:ietf:params:rtp-hdrext:ssrc-audio-level") \ +EXT_MAP_FIELD(kAbsSendTime, "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time") \ +EXT_MAP_FIELD(kTransportCC, "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01") \ +EXT_MAP_FIELD(kSdesMid, "urn:ietf:params:rtp-hdrext:sdes:mid") \ +EXT_MAP_FIELD(kSdesRtpStreamId, "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id") \ +EXT_MAP_FIELD(kSdesRepairedRtpStreamId, "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id") \ +EXT_MAP_FIELD(kVideoTiming, "http://www.webrtc.org/experiments/rtp-hdrext/video-timing") \ +EXT_MAP_FIELD(kColorSpace, "http://www.webrtc.org/experiments/rtp-hdrext/color-space") \ +EXT_MAP_FIELD(kCsrcAudioLevel, "urn:ietf:params:rtp-hdrext:csrc-audio-level") \ +EXT_MAP_FIELD(kFramemarking, "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07") \ +EXT_MAP_FIELD(kVideoContentType, "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type") \ +EXT_MAP_FIELD(kPlayoutDelay, "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay") \ +EXT_MAP_FIELD(kVideoOrientation, "urn:3gpp:video-orientation") \ +EXT_MAP_FIELD(kToffset, "urn:ietf:params:rtp-hdrext:toffset") \ +EXT_MAP_FIELD(kEncrypt, "urn:ietf:params:rtp-hdrext:encrypt") + +enum ExtMapFieldEnum { +#define DEFIDE_EXT_MAP_ENUM(a, b) a, + DEFINDE_EXT_MAP_FIELD(DEFIDE_EXT_MAP_ENUM) +#undef DEFIDE_EXT_MAP_ENUM + kExtMapFieldSize +}; + +static const char* const kExtMapFieldArray[] = { +#define DEFIDE_EXT_MAP_ARRAY(x, y) y, + DEFINDE_EXT_MAP_FIELD(DEFIDE_EXT_MAP_ARRAY) +#undef DEFIDE_EXT_MAP_ARRAY +}; + +class SrsExtMapInfo { + int ext_id_list_[kExtMapFieldSize] = {0}; + void parse_ext_id(int id, std::string ext); +public: + int mid_ext_id() const { return ext_id_list_[kSdesMid]; } + int rid_ext_id() const { return ext_id_list_[kSdesRtpStreamId]; } + int ridrtx_ext_id() const { return ext_id_list_[kSdesRepairedRtpStreamId]; } + int audiolevel_ext_id() const { return ext_id_list_[kSsrcAudioLevel]; } + int videoorientation_ext_id() const { return ext_id_list_[kVideoOrientation]; } + int transport_wide_cc_ext_id() const { return ext_id_list_[kTransportCC]; } + bool transport_wide_cc() const { return transport_wide_cc_ext_id() > 0; } + + std::map data; + void parse_extmap(int id, std::string ext); + + SrsRidInfo * parse_rid(char *buf, int len, SrsSimulcastInfo &simulcast); +}; + class SrsMediaDesc { public: @@ -131,7 +199,7 @@ class SrsMediaDesc srs_error_t encode(std::ostringstream& os); SrsMediaPayloadType* find_media_with_payload_type(int payload_type); std::vector find_media_with_encoding_name(const std::string& encoding_name) const; - const std::map& get_extmaps() const { return extmaps_; } + const std::map& get_extmaps() const { return extmaps_.data; } srs_error_t update_msid(std::string id); bool is_audio() const { return type_ == "audio"; } @@ -172,7 +240,11 @@ class SrsMediaDesc std::vector candidates_; std::vector ssrc_groups_; std::vector ssrc_infos_; - std::map extmaps_; + SrsExtMapInfo extmaps_; + + bool simulcast_spec_version() const { + return ssrc_infos_.empty() && !session_info_.simulcast_.line.empty(); + } public: // Whether SSRS is original stream. diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index e13ae93a16..f1c5df889a 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -2184,6 +2184,15 @@ int SrsRtcTrackDescription::get_rtp_extension_id(std::string uri) return 0; } +int SrsRtcTrackDescription::get_rtp_extension_id(ExtMapFieldEnum field) { + for (std::map::iterator it = extmaps_.begin(); it != extmaps_.end(); ++it) { + if(kExtMapFieldArray[field] == it->second) { + return it->first; + } + } + return 0; +} + SrsRtcTrackDescription* SrsRtcTrackDescription::copy() { SrsRtcTrackDescription* cp = new SrsRtcTrackDescription(); @@ -2202,6 +2211,7 @@ SrsRtcTrackDescription* SrsRtcTrackDescription::copy() cp->red_ = red_ ? red_->copy():NULL; cp->rtx_ = rtx_ ? rtx_->copy():NULL; cp->ulpfec_ = ulpfec_ ? ulpfec_->copy():NULL; + cp->rid_ = rid_; return cp; } @@ -2432,6 +2442,24 @@ srs_error_t SrsRtcRecvTrack::do_check_send_nacks(uint32_t& timeout_nacks) return err; } +bool SrsRtcRecvTrack::active_as(const SrsRidInfo &rid_info) { + if (track_desc_->ssrc_ > 0) { + return false; + } + track_desc_->ssrc_ = rid_info.ssrc; + track_desc_->rid_ = rid_info; + + // TODO: Improve the generation of FEC SSRC and RTX SSRC + track_desc_->set_fec_ssrc(rid_info.ssrc + 1); + track_desc_->set_rtx_ssrc(rid_info.ssrc + 2); + + // if (track_desc_->is_active_) { + // return false; + // } + // track_desc_->is_active_ = true; + return true; +} + SrsRtcAudioRecvTrack::SrsRtcAudioRecvTrack(SrsRtcConnection* session, SrsRtcTrackDescription* track_desc) : SrsRtcRecvTrack(session, track_desc, true) { diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp index 10e1d97c53..b29fad1688 100644 --- a/trunk/src/app/srs_app_rtc_source.hpp +++ b/trunk/src/app/srs_app_rtc_source.hpp @@ -445,6 +445,7 @@ class SrsRtcTrackDescription // ssrc is the primary ssrc for this track, // if sdp has ssrc-group, it is the first ssrc of the ssrc-group uint32_t ssrc_; + SrsRidInfo rid_; // rtx ssrc is the second ssrc of "FEC" src-group, // if no rtx ssrc, rtx_ssrc_ = 0. uint32_t fec_ssrc_; @@ -486,6 +487,7 @@ class SrsRtcTrackDescription void set_fec_ssrc(uint32_t ssrc); void set_mid(std::string mid); int get_rtp_extension_id(std::string uri); + int get_rtp_extension_id(ExtMapFieldEnum field); public: SrsRtcTrackDescription* copy(); }; @@ -533,6 +535,8 @@ class SrsRtcRecvTrack SrsRtcRecvTrack(SrsRtcConnection* session, SrsRtcTrackDescription* stream_descs, bool is_audio); virtual ~SrsRtcRecvTrack(); public: + bool active_as(const SrsRidInfo &rid_info); + // SrsRtcSendTrack::set_nack_no_copy void set_nack_no_copy(bool v) { nack_no_copy_ = v; } bool has_ssrc(uint32_t ssrc); From 2c7b9e2c6eda13f4bbf735f34a73f6df4e55c043 Mon Sep 17 00:00:00 2001 From: Johnny Date: Wed, 21 Jul 2021 17:08:32 +0800 Subject: [PATCH 06/13] Refine(rtc/negotiate_publish_capability): add set_audio_track_desc/set_video_track_descs. --- trunk/src/app/srs_app_rtc_conn.cpp | 54 +----------------------- trunk/src/app/srs_app_rtc_source.cpp | 62 ++++++++++++++++++++++++++++ trunk/src/app/srs_app_rtc_source.hpp | 2 + 3 files changed, 66 insertions(+), 52 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 3b26f02963..849d8b90ff 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -3076,59 +3076,9 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRtcUserConfig* ruc track_desc->create_auxiliary_payload(remote_media_desc.find_media_with_encoding_name("ulpfec")); if (remote_media_desc.is_audio()) { - for (int j = 0; j < (int)remote_media_desc.ssrc_infos_.size(); ++j) { - const SrsSSRCInfo& ssrc_info = remote_media_desc.ssrc_infos_.at(j); - - // ssrc have same track id, will be description in the same track description. - if (!stream_desc->audio_track_desc_) { - SrsRtcTrackDescription* track_desc_copy = track_desc->copy(); - track_desc_copy->ssrc_ = ssrc_info.ssrc_; - track_desc_copy->id_ = ssrc_info.msid_tracker_; - track_desc_copy->msid_ = ssrc_info.msid_; - stream_desc->audio_track_desc_ = track_desc_copy; - } - srs_info("%d/%d#publish audio ssrc_=%u, msid_=%s, msid_tracker_='%s'", j, - (int) remote_media_desc.ssrc_infos_.size(), - ssrc_info.ssrc_, ssrc_info.msid_.c_str(), ssrc_info.msid_tracker_.c_str()); - } + stream_desc->set_audio_track_desc(remote_media_desc, track_desc); } else if (remote_media_desc.is_video()) { - if (remote_media_desc.simulcast_spec_version()) { - // todo check simulcast kSimulcastApiVersionSpecCompliant - for (size_t i=0; ivideo_track_descs_.push_back(track_desc->copy()); - } - } else { - std::string track_id; - for (int j = 0; j < (int)remote_media_desc.ssrc_infos_.size(); ++j) { - const SrsSSRCInfo& ssrc_info = remote_media_desc.ssrc_infos_.at(j); - - // ssrc have same track id, will be description in the same track description. - if(track_id != ssrc_info.msid_tracker_) { - SrsRtcTrackDescription* track_desc_copy = track_desc->copy(); - track_desc_copy->ssrc_ = ssrc_info.ssrc_; - track_desc_copy->id_ = ssrc_info.msid_tracker_; - track_desc_copy->msid_ = ssrc_info.msid_; - if (remote_media_desc.is_original_ssrc(&ssrc_info)) { - // note: set ssrc related to single or simulcast(chrome munging style simulcast sdp) - // todo: support standard simulcast, like "a=simulcast:send a;b;c" - stream_desc->video_track_descs_.push_back(track_desc_copy); - srs_info("%d/%d#publish video track_id_=%s, ssrc_=%u, msid_=%s, msid_tracker_='%s'", j,(int)remote_media_desc.ssrc_infos_.size(), - track_id.c_str(), ssrc_info.ssrc_, ssrc_info.msid_.c_str(), ssrc_info.msid_tracker_.c_str()); - } else { - srs_info("%d/%d#ignore track_id_=%s, ssrc_=%u, msid_=%s, msid_tracker_='%s'", j, - (int) remote_media_desc.ssrc_infos_.size(), - track_id.c_str(), ssrc_info.ssrc_, ssrc_info.msid_.c_str(), - ssrc_info.msid_tracker_.c_str()); - } - track_id = ssrc_info.msid_tracker_; - } else { - srs_info("%d/%d#ignore track_id_/msid_tracker_=%s, ssrc_=%u, msid_=%s", j, - (int) remote_media_desc.ssrc_infos_.size(), - track_id.c_str(), ssrc_info.ssrc_, ssrc_info.msid_.c_str()); - track_id = ""; - } - } - } + stream_desc->set_video_track_descs(remote_media_desc, track_desc); } else { // TODO: FIXME: Handle for others. } diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index f1c5df889a..8500e55c1c 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -2261,6 +2261,68 @@ SrsRtcTrackDescription* SrsRtcSourceDescription::find_track_description_by_ssrc( return NULL; } +// NOTE: helper of SrsRtcConnection::negotiate_publish_capability +void SrsRtcSourceDescription::set_audio_track_desc(const SrsMediaDesc &remote_media_desc, + SrsRtcTrackDescription *track_desc) { + for (int j = 0; j < (int)remote_media_desc.ssrc_infos_.size(); ++j) { + const SrsSSRCInfo& ssrc_info = remote_media_desc.ssrc_infos_.at(j); + + // ssrc have same track id, will be description in the same track description. + if (!audio_track_desc_) { + SrsRtcTrackDescription* track_desc_copy = track_desc->copy(); + track_desc_copy->ssrc_ = ssrc_info.ssrc_; + track_desc_copy->id_ = ssrc_info.msid_tracker_; + track_desc_copy->msid_ = ssrc_info.msid_; + audio_track_desc_ = track_desc_copy; + } + srs_info("%d/%d#publish audio ssrc_=%u, msid_=%s, msid_tracker_='%s'", j, + (int) remote_media_desc.ssrc_infos_.size(), + ssrc_info.ssrc_, ssrc_info.msid_.c_str(), ssrc_info.msid_tracker_.c_str()); + } +} + +// NOTE: helper of SrsRtcConnection::negotiate_publish_capability +void SrsRtcSourceDescription::set_video_track_descs(const SrsMediaDesc &remote_media_desc, + SrsRtcTrackDescription *track_desc) { + if (remote_media_desc.simulcast_spec_version()) { + // todo check simulcast kSimulcastApiVersionSpecCompliant + for (size_t i=0; icopy()); + } + } else { + string track_id; + for (int j = 0; j < (int)remote_media_desc.ssrc_infos_.size(); ++j) { + const SrsSSRCInfo& ssrc_info = remote_media_desc.ssrc_infos_.at(j); + + // ssrc have same track id, will be description in the same track description. + if(track_id != ssrc_info.msid_tracker_) { + SrsRtcTrackDescription* track_desc_copy = track_desc->copy(); + track_desc_copy->ssrc_ = ssrc_info.ssrc_; + track_desc_copy->id_ = ssrc_info.msid_tracker_; + track_desc_copy->msid_ = ssrc_info.msid_; + if (remote_media_desc.is_original_ssrc(&ssrc_info)) { + // note: set ssrc related to single or simulcast(chrome munging style simulcast sdp) + // todo: support standard simulcast, like "a=simulcast:send a;b;c" + video_track_descs_.push_back(track_desc_copy); + srs_info("%d/%d#publish video track_id_=%s, ssrc_=%u, msid_=%s, msid_tracker_='%s'", j,(int)remote_media_desc.ssrc_infos_.size(), + track_id.c_str(), ssrc_info.ssrc_, ssrc_info.msid_.c_str(), ssrc_info.msid_tracker_.c_str()); + } else { + srs_info("%d/%d#ignore track_id_=%s, ssrc_=%u, msid_=%s, msid_tracker_='%s'", j, + (int) remote_media_desc.ssrc_infos_.size(), + track_id.c_str(), ssrc_info.ssrc_, ssrc_info.msid_.c_str(), + ssrc_info.msid_tracker_.c_str()); + } + track_id = ssrc_info.msid_tracker_; + } else { + srs_info("%d/%d#ignore track_id_/msid_tracker_=%s, ssrc_=%u, msid_=%s", j, + (int) remote_media_desc.ssrc_infos_.size(), + track_id.c_str(), ssrc_info.ssrc_, ssrc_info.msid_.c_str()); + track_id = ""; + } + } + } +} + SrsRtcRecvTrack::SrsRtcRecvTrack(SrsRtcConnection* session, SrsRtcTrackDescription* track_desc, bool is_audio) { session_ = session; diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp index b29fad1688..8e7e7cbe41 100644 --- a/trunk/src/app/srs_app_rtc_source.hpp +++ b/trunk/src/app/srs_app_rtc_source.hpp @@ -504,6 +504,8 @@ class SrsRtcSourceDescription SrsRtcSourceDescription(); virtual ~SrsRtcSourceDescription(); + void set_audio_track_desc(const SrsMediaDesc &remote_media_desc, SrsRtcTrackDescription *track_desc); + void set_video_track_descs(const SrsMediaDesc &remote_media_desc, SrsRtcTrackDescription *track_desc); public: SrsRtcSourceDescription* copy(); SrsRtcTrackDescription* find_track_description_by_ssrc(uint32_t ssrc); From 6f85a5f343a0b124dab79125f8e39383d46cd326 Mon Sep 17 00:00:00 2001 From: Johnny Date: Wed, 21 Jul 2021 17:50:45 +0800 Subject: [PATCH 07/13] fix: add msid and msid tracker. --- trunk/src/app/srs_app_rtc_source.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index 8500e55c1c..41bf76090a 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -2287,7 +2287,12 @@ void SrsRtcSourceDescription::set_video_track_descs(const SrsMediaDesc &remote_m if (remote_media_desc.simulcast_spec_version()) { // todo check simulcast kSimulcastApiVersionSpecCompliant for (size_t i=0; icopy()); + SrsRtcTrackDescription* track_desc_copy = track_desc->copy(); + // NOTE: here ssrc is 0 + // track_desc_copy->ssrc_ = 0; + track_desc_copy->id_ = remote_media_desc.msid_tracker_; + track_desc_copy->msid_ = remote_media_desc.msid_; + video_track_descs_.push_back(track_desc_copy); } } else { string track_id; From 0f403f0d19eb8543ed61ea0bb7e343d2989a8bdf Mon Sep 17 00:00:00 2001 From: Johnny Date: Mon, 27 Sep 2021 17:30:05 +0800 Subject: [PATCH 08/13] feat(kSimulcastApiVersionSpecCompliant): support layer=high,mid,low --- trunk/src/app/srs_app_rtc_conn.cpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 849d8b90ff..242d4170b2 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -3338,6 +3338,7 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRtcUserConfig* ruc, s } track->set_direction("sendonly"); + // fixme: order of track sub_relations.insert(make_pair(publish_ssrc, track)); if (track->rid_.ssrc > 0) { srs_info("publish_ssrc=%u, play ssrc=%u, rid ssrc=%u, rid=%s", publish_ssrc, track->ssrc_, track->rid_.ssrc, track->rid_.rid.c_str()); @@ -3399,7 +3400,7 @@ void video_track_generate_play_offer(SrsRtcTrackDescription* track, string mid, } // note: get [0,1,2] from "webrtc://127.0.0.1/live/livestream?layer=0,1,2&foo=bar" -bool parse_layers_in_url(std::vector& layers, std::string name) { +bool parse_layers_in_url(std::vector& layers, std::string name) { // livestream?layer=1 // livestream?layer=1,2,3 // livestream?layer=1,2,3&foo=bar @@ -3426,23 +3427,39 @@ bool parse_layers_in_url(std::vector& layers, std::string name) { istringstream f(layers_); string s; while (getline(f, s, ';')) { - layers.push_back(::atoi(s.c_str())); + layers.push_back(s); } return !layers.empty(); } +void add_desc_to_vector(std::vector& result, SrsRtcTrackDescription *desc) { + if (result.cend() == std::find(result.cbegin(), result.cend(), desc)) { + result.push_back(desc); + } +} + std::vector select_video_track_descs( std::vector video_track_descs, std::string url) { srs_trace("stream url: %s", url.c_str()); - std::vector layers; - if (!parse_layers_in_url(layers, url)) { + std::vector layers; + if (video_track_descs.empty() || !parse_layers_in_url(layers, url)) { return video_track_descs; } std::vector result; for (size_t i=0;i= 0 && layer < (int)video_track_descs.size(); + if (is_index) { + add_desc_to_vector(result, video_track_descs[layer]); + } else { + for (auto& desc: video_track_descs) { + assert(desc); + if (desc->rid_.rid == layers[i]) { + result.push_back(desc); + add_desc_to_vector(result, desc); + } + } } } return result.empty() ? video_track_descs : result; From 99c83c66eedd9a507ea602f513560c9e3eff8b5b Mon Sep 17 00:00:00 2001 From: Johnny Date: Wed, 21 Jul 2021 20:11:31 +0800 Subject: [PATCH 09/13] feat(simulcast): add x-google-min-bitrate=5000;x-google-max-bitrate=8000;x-google-start-bitrate=6000 --- trunk/src/app/srs_app_rtc_conn.cpp | 3 +++ trunk/src/app/srs_app_rtc_source.cpp | 3 +++ trunk/src/app/srs_app_rtc_source.hpp | 1 + 3 files changed, 7 insertions(+) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 242d4170b2..c1419a1677 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -3192,6 +3192,9 @@ srs_error_t SrsRtcConnection::generate_publish_local_sdp(SrsRequest* req, SrsSdp } SrsVideoPayload* payload = (SrsVideoPayload*)video_track->media_; + if (srs_string_contains(req->param,"?numberOfSimulcastLayers=spec3")) { + payload->h264_param_.x_google_bitrate = "x-google-min-bitrate=5000;x-google-max-bitrate=8000;x-google-start-bitrate=6000"; + } local_media_desc.payload_types_.push_back(payload->generate_media_payload_type()); if (video_track->red_) { diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index 41bf76090a..45af331fea 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -1865,6 +1865,9 @@ SrsMediaPayloadType SrsVideoPayload::generate_media_payload_type() if (!h264_param_.packetization_mode.empty()) { format_specific_param << ";packetization-mode=" << h264_param_.packetization_mode; } + if (!h264_param_.x_google_bitrate.empty()) { + format_specific_param << ";" << h264_param_.x_google_bitrate; + } if (!h264_param_.profile_level_id.empty()) { format_specific_param << ";profile-level-id=" << h264_param_.profile_level_id; } diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp index 8e7e7cbe41..29fb7abf08 100644 --- a/trunk/src/app/srs_app_rtc_source.hpp +++ b/trunk/src/app/srs_app_rtc_source.hpp @@ -363,6 +363,7 @@ class SrsVideoPayload : public SrsCodecPayload std::string profile_level_id; std::string packetization_mode; std::string level_asymmerty_allow; + std::string x_google_bitrate; }; H264SpecificParameter h264_param_; From 8533063ab694f6ac59d6ff62b9b4a2b9cdc9c6fa Mon Sep 17 00:00:00 2001 From: Johnny Date: Tue, 7 Dec 2021 14:05:41 +0800 Subject: [PATCH 10/13] add note about janus_rtp_header/janus_rtp_header_extension and helper functions. --- trunk/src/app/srs_app_rtc_sdp.cpp | 119 +++++++++++++++--------------- 1 file changed, 60 insertions(+), 59 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_sdp.cpp b/trunk/src/app/srs_app_rtc_sdp.cpp index 3e68895a47..01b22596ca 100644 --- a/trunk/src/app/srs_app_rtc_sdp.cpp +++ b/trunk/src/app/srs_app_rtc_sdp.cpp @@ -1255,42 +1255,44 @@ void SrsExtMapInfo::parse_ext_id(int id, std::string ext) { } } } -namespace { - typedef struct rtp_header - { + +// @see janus_rtp_header in https://github.com/meetecho/janus-gateway/blob/master/rtp.h +struct rtp_header +{ #ifdef ARCH_IS_BIG_ENDIAN - uint16_t version:2; - uint16_t padding:1; - uint16_t extension:1; - uint16_t csrccount:4; - uint16_t markerbit:1; - uint16_t type:7; + uint16_t version:2; + uint16_t padding:1; + uint16_t extension:1; + uint16_t csrccount:4; + uint16_t markerbit:1; + uint16_t type:7; #else - uint16_t csrccount:4; - uint16_t extension:1; - uint16_t padding:1; - uint16_t version:2; - uint16_t type:7; - uint16_t markerbit:1; + uint16_t csrccount:4; + uint16_t extension:1; + uint16_t padding:1; + uint16_t version:2; + uint16_t type:7; + uint16_t markerbit:1; #endif - uint16_t seq_number; - uint32_t timestamp; - uint32_t ssrc; - uint32_t csrc[16]; - } rtp_header; - typedef rtp_header janus_rtp_header; - - typedef struct janus_rtp_header_extension { - uint16_t type; - uint16_t length; - } janus_rtp_header_extension; + uint16_t seq_number; + uint32_t timestamp; + uint32_t ssrc; + uint32_t csrc[16]; +}; + +// @see janus_rtp_header_extension in https://github.com/meetecho/janus-gateway/blob/master/rtp.h +struct rtp_header_extension { + uint16_t type; + uint16_t length; +}; /* Static helper to quickly find the extension data */ -static int janus_rtp_header_extension_find(char *buf, int len, int id, - uint8_t *byte, uint32_t *word, char **ref) { +// @see janus_rtp_header_extension_find in https://github.com/meetecho/janus-gateway/blob/master/rtp.c +static int rtp_header_extension_find( + char *buf, int len, int id, uint8_t *byte, uint32_t *word, char **ref) { if(!buf || len < 12) return -1; - janus_rtp_header *rtp = (janus_rtp_header *)buf; + rtp_header *rtp = (rtp_header *)buf; if (rtp->version != 2) { return -1; } @@ -1298,7 +1300,7 @@ static int janus_rtp_header_extension_find(char *buf, int len, int id, if(rtp->csrccount) /* Skip CSRC if needed */ hlen += rtp->csrccount*4; if(rtp->extension) { - janus_rtp_header_extension *ext = (janus_rtp_header_extension *)(buf+hlen); + rtp_header_extension *ext = (rtp_header_extension *)(buf+hlen); int extlen = ntohs(ext->length)*4; hlen += 4; if(len > (hlen + extlen)) { @@ -1338,33 +1340,34 @@ static int janus_rtp_header_extension_find(char *buf, int len, int id, } -static int janus_rtp_header_extension_parse_rid(char *buf, int len, int id, - char *sdes_item, int sdes_len) { - char *ext = NULL; - if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext) < 0) - return -1; - /* a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id */ - /* a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id */ - if(ext == NULL) - return -2; - int val_len = (*ext & 0x0F) + 1; - if(val_len > (sdes_len-1)) { - // JANUS_LOG(LOG_WARN, "SDES buffer is too small (%d < %d), RTP stream ID will be cut\n", val_len, sdes_len); - val_len = sdes_len-1; - } - if (val_len > len-(ext-buf)-1 ) { - return -3; - } - memcpy(sdes_item, ext+1, val_len); - *(sdes_item+val_len) = '\0'; - return 0; +// @see janus_rtp_header_extension_parse_rid in https://github.com/meetecho/janus-gateway/blob/master/rtp.c +static int rtp_header_extension_parse_rid( + char *buf, int len, int id, char *sdes_item, int sdes_len) { + char *ext = NULL; + if(rtp_header_extension_find(buf, len, id, NULL, NULL, &ext) < 0) + return -1; + /* a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id */ + /* a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id */ + if(ext == NULL) + return -2; + int val_len = (*ext & 0x0F) + 1; + if(val_len > (sdes_len-1)) { + // JANUS_LOG(LOG_WARN, "SDES buffer is too small (%d < %d), RTP stream ID will be cut\n", val_len, sdes_len); + val_len = sdes_len-1; } + if (val_len > len-(ext-buf)-1 ) { + return -3; + } + memcpy(sdes_item, ext+1, val_len); + *(sdes_item+val_len) = '\0'; + return 0; +} - -static int janus_rtp_header_extension_parse_mid(char *buf, int len, int id, - char *sdes_item, int sdes_len) { +// @see janus_rtp_header_extension_parse_mid in https://github.com/meetecho/janus-gateway/blob/master/rtp.c +static int rtp_header_extension_parse_mid( + char *buf, int len, int id, char *sdes_item, int sdes_len) { char *ext = NULL; - if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext) < 0) + if(rtp_header_extension_find(buf, len, id, NULL, NULL, &ext) < 0) return -1; /* a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid */ if(ext == NULL) @@ -1382,25 +1385,23 @@ static int janus_rtp_header_extension_parse_mid(char *buf, int len, int id, return 0; } -} - SrsRidInfo* SrsExtMapInfo::parse_rid(char *buf, int len, SrsSimulcastInfo &simulcast) { char sdes_item[16]; int ret; std::string rid, ridrtx; std::string mid; - if((ret = janus_rtp_header_extension_parse_rid(buf, len, rid_ext_id(), sdes_item, sizeof(sdes_item))) == 0) { + if((ret = rtp_header_extension_parse_rid(buf, len, rid_ext_id(), sdes_item, sizeof(sdes_item))) == 0) { rid = sdes_item; } else { return nullptr; } - if((ret = janus_rtp_header_extension_parse_rid(buf, len, ridrtx_ext_id(), sdes_item, sizeof(sdes_item))) == 0) { + if((ret = rtp_header_extension_parse_rid(buf, len, ridrtx_ext_id(), sdes_item, sizeof(sdes_item))) == 0) { ridrtx = sdes_item; srs_info("rid=%s, ridrtx_ext_id=%d, ridrtx=%s", rid.c_str(), ridrtx_ext_id(), ridrtx.c_str()); } else { srs_warn("bad=%d rid=%s, ridrtx_ext_id=%d", ret, rid.c_str(), ridrtx_ext_id()); } - if((ret = janus_rtp_header_extension_parse_mid(buf, len, mid_ext_id(), sdes_item, sizeof(sdes_item))) == 0) { + if((ret = rtp_header_extension_parse_mid(buf, len, mid_ext_id(), sdes_item, sizeof(sdes_item))) == 0) { mid = sdes_item; srs_info("mid=%s", mid.c_str()); } From 2fc541c036fe37b4281f7ccc298ae286d1d295c4 Mon Sep 17 00:00:00 2001 From: Johnny Date: Fri, 8 Oct 2021 14:44:08 +0800 Subject: [PATCH 11/13] fix build in c++03. ./configure --cxx11=off --cxx14=off --ffmpeg-fit=off --- trunk/src/app/srs_app_rtc_conn.cpp | 33 +++++++++++++++++------------- trunk/src/app/srs_app_rtc_sdp.cpp | 12 ++++++++--- trunk/src/app/srs_app_rtc_sdp.hpp | 6 ++++-- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index c1419a1677..b877cabf75 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1749,8 +1749,8 @@ void SrsRtcPublishStream::update_send_report_time(uint32_t ssrc, const SrsNtp& n } void SrsRtcPublishStream::bind_rid(const SrsRidInfo &rid_info) { - // todo: on ssrc check mid rid - auto video_track = get_video_track(0); + // NOTE: get unused video_track, and active as rid info. + SrsRtcVideoRecvTrack* video_track = get_video_track(0); if (video_track) { video_track->active_as(rid_info); } @@ -1994,10 +1994,10 @@ srs_error_t SrsRtcConnection::add_publisher(SrsRtcUserConfig* ruc, SrsSdp& local } // NOTE: Supplement Simulcast information in publish local sdp. - auto size = local_sdp.media_descs_.size(); + size_t size = local_sdp.media_descs_.size(); assert(size == ruc->remote_sdp_.media_descs_.size()); for (size_t i = 0; i < size; ++i) { - auto& media_desc = ruc->remote_sdp_.media_descs_.at(i); + SrsMediaDesc& media_desc = ruc->remote_sdp_.media_descs_.at(i); if (media_desc.is_video() && media_desc.simulcast_spec_version()) { local_sdp.media_descs_.at(i).session_info_.simulcast_ = media_desc.session_info_.simulcast_; } @@ -2323,17 +2323,18 @@ srs_error_t SrsRtcConnection::parse_rid(char *buf, int size, uint32_t ssrc) { return err; } - for (auto& media_desc: remote_sdp.media_descs_) { + for (size_t i=0; isecond; // publisher_->on_rtp(buf, size); - auto rid = extmaps_.parse_rid(buf, size, simulcast); + SrsRidInfo* rid = extmaps_.parse_rid(buf, size, simulcast); if (rid) { assert(rid->ssrc == 0); rid->ssrc = ssrc; @@ -2351,12 +2352,13 @@ srs_error_t SrsRtcConnection::bind_rid(const SrsRidInfo &rid_info) { if ((err = _srs_rtc_sources->fetch_or_create(req_, &source)) != srs_success) { return srs_error_wrap(err, "fetch_or_create source"); } - auto track_descs = source->get_track_desc("video", "H264"); - for (auto &track_desc: track_descs) { + std::vector track_descs = source->get_track_desc("video", "H264"); + for (size_t i = 0; i < track_descs.size(); ++i) { + SrsRtcTrackDescription* track_desc = track_descs.at(i); if (track_desc->ssrc_ == 0) { track_desc->ssrc_ = rid_info.ssrc; track_desc->rid_ = rid_info; - auto &publisher = publishers_ssrc_map_.begin()->second; + SrsRtcPublishStream* publisher = publishers_ssrc_map_.begin()->second; publisher->bind_rid(rid_info); publishers_ssrc_map_[track_desc->ssrc_] = publisher; srs_warn("find track_desc to (rid='%s', ssrc=%u)", rid_info.rid.c_str(), rid_info.ssrc); @@ -3436,7 +3438,7 @@ bool parse_layers_in_url(std::vector& layers, std::string name) { } void add_desc_to_vector(std::vector& result, SrsRtcTrackDescription *desc) { - if (result.cend() == std::find(result.cbegin(), result.cend(), desc)) { + if (result.end() == std::find(result.begin(), result.end(), desc)) { result.push_back(desc); } } @@ -3452,11 +3454,14 @@ std::vector select_video_track_descs( std::vector result; for (size_t i=0;i= 0 && layer < (int)video_track_descs.size(); + char layer_text[32]; + sprintf(layer_text, "%d", layer); + bool is_index = layer_text == layers[i] && layer >= 0 && layer < (int)video_track_descs.size(); if (is_index) { add_desc_to_vector(result, video_track_descs[layer]); } else { - for (auto& desc: video_track_descs) { + for (size_t ii = 0; ii < video_track_descs.size(); ++ii) { + SrsRtcTrackDescription* desc = video_track_descs.at(ii); assert(desc); if (desc->rid_.rid == layers[i]) { result.push_back(desc); diff --git a/trunk/src/app/srs_app_rtc_sdp.cpp b/trunk/src/app/srs_app_rtc_sdp.cpp index 01b22596ca..acd69a5309 100644 --- a/trunk/src/app/srs_app_rtc_sdp.cpp +++ b/trunk/src/app/srs_app_rtc_sdp.cpp @@ -7,6 +7,7 @@ #include #include +#include // for memset #include // for ntohs in linux #include @@ -1216,7 +1217,8 @@ srs_error_t SrsSimulcastInfo::encode(ostringstream &os) { // a=rid:1 send // a=rid:2 send // check direction he rids rid.direction is send - for (auto& rid: rids) { + for (size_t i=0; i Date: Tue, 14 Dec 2021 13:53:29 +0800 Subject: [PATCH 12/13] Refactor rid base simulcast code --- trunk/src/app/srs_app_rtc_conn.cpp | 108 ++++++++----- trunk/src/app/srs_app_rtc_conn.hpp | 6 +- trunk/src/app/srs_app_rtc_sdp.cpp | 203 +----------------------- trunk/src/app/srs_app_rtc_sdp.hpp | 55 +------ trunk/src/app/srs_app_rtc_source.cpp | 9 -- trunk/src/app/srs_app_rtc_source.hpp | 1 - trunk/src/kernel/srs_kernel_rtc_rtp.cpp | 66 +++++++- trunk/src/kernel/srs_kernel_rtc_rtp.hpp | 40 ++++- 8 files changed, 174 insertions(+), 314 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index b877cabf75..c1613e8220 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1139,21 +1139,28 @@ srs_error_t SrsRtcPublishStream::initialize(SrsRequest* r, SrsRtcSourceDescripti } int twcc_id = -1; + int rid = -1; uint32_t media_ssrc = 0; // because audio_track_desc have not twcc id, for example, h5demo // fetch twcc_id from video track description, for (int i = 0; i < (int)stream_desc->video_track_descs_.size(); ++i) { SrsRtcTrackDescription* desc = stream_desc->video_track_descs_.at(i); - twcc_id = desc->get_rtp_extension_id(kTWCCExt); + twcc_id = desc->get_rtp_extension_id(kExtensions[kRtpExtTwcc].uri); + rid = desc->get_rtp_extension_id(kExtensions[kRtpExtSdesRtpStreamId].uri); media_ssrc = desc->ssrc_; break; } + if (twcc_id > 0) { twcc_id_ = twcc_id; - extension_types_.register_by_uri(twcc_id_, kTWCCExt); + extension_types_.register_by_uri(twcc_id_, kExtensions[kRtpExtTwcc].uri); rtcp_twcc_.set_media_ssrc(media_ssrc); } + if (rid > 0) { + extension_types_.register_by_uri(rid, kExtensions[kRtpExtSdesRtpStreamId].uri); + } + nack_enabled_ = _srs_config->get_rtc_nack_enabled(req_->vhost); nack_no_copy_ = _srs_config->get_rtc_nack_no_copy(req_->vhost); pt_to_drop_ = (uint16_t)_srs_config->get_rtc_drop_for_pt(req_->vhost); @@ -1823,7 +1830,6 @@ SrsRtcConnection::SrsRtcConnection(SrsRtcServer* s, const SrsContextId& cid) session_timeout = 0; disposing_ = false; - twcc_id_ = 0; nn_simulate_player_nack_drop = 0; pp_address_change = new SrsErrorPithyPrint(); pli_epp = new SrsErrorPithyPrint(); @@ -2304,67 +2310,91 @@ srs_error_t SrsRtcConnection::find_publisher(char* buf, int size, SrsRtcPublishS } map::iterator it = publishers_ssrc_map_.find(ssrc); - if(it == publishers_ssrc_map_.end()) { - if ((err = parse_rid(buf, size, ssrc)) != srs_success) { - return srs_error_wrap(err, "no publisher for ssrc:%u; parse_rid", ssrc); - } else { - return srs_error_new(ERROR_RTC_NO_PUBLISHER, "no publisher for ssrc:%u", ssrc); - } + // Found publisher, return directly. + if (it != publishers_ssrc_map_.end()) { + *ppublisher = it->second; + return err; } - *ppublisher = it->second; + // No found publisher, check if simulcast enabled. + if ((err = parse_rid(buf, size, ssrc, ppublisher)) != srs_success) { + return srs_error_wrap(err, "no simulcast publisher for ssrc:%u; parse_rid", ssrc); + } else { + return err; + } - return err; + return srs_error_new(ERROR_RTC_NO_PUBLISHER, "no publisher for ssrc:%u", ssrc); } -srs_error_t SrsRtcConnection::parse_rid(char *buf, int size, uint32_t ssrc) { +srs_error_t SrsRtcConnection::parse_rid(char *buf, int size, uint32_t ssrc, SrsRtcPublishStream** ppublisher) +{ srs_error_t err = srs_success; - if (publishers_ssrc_map_.empty()) { - return err; - } - for (size_t i=0; i::iterator it = media_desc.extmaps_.begin(); it != media_desc.extmaps_.end(); ++it) { + if (it->second == kExtensions[kRtpExtSdesRtpStreamId].uri) { + rid = it->first; + break; + } + } + + if (rid <= 0) { + continue; + } + SrsSimulcastInfo &simulcast = media_desc.session_info_.simulcast_; - // auto &publisher_ = publishers_ssrc_map_.begin()->second; - // publisher_->on_rtp(buf, size); - SrsRidInfo* rid = extmaps_.parse_rid(buf, size, simulcast); - if (rid) { - assert(rid->ssrc == 0); - rid->ssrc = ssrc; - if ((err = bind_rid(*rid)) != srs_success) { - return srs_error_wrap(err, "bind rid"); + std::string rtp_stream_id; + if ((err = srs_rtp_fast_parse_rid(buf, size, rid, rtp_stream_id)) != srs_success) { + return srs_error_wrap(err, "parse rid"); + } + + for (std::vector::iterator iter = simulcast.rids.begin(); iter != simulcast.rids.end(); ++iter) { + if (rtp_stream_id == iter->rid) { + srs_assert(iter->ssrc == 0); + iter->ssrc = ssrc; + if ((err = bind_rid(*iter, ppublisher)) != srs_success) { + return srs_error_wrap(err, "bind rid"); + } + + // Found publisher and bind success, return. + return err; } } } - return err; + + return srs_error_new(ERROR_RTC_NO_PUBLISHER, "no rid found in extmap", ssrc); } -srs_error_t SrsRtcConnection::bind_rid(const SrsRidInfo &rid_info) { +srs_error_t SrsRtcConnection::bind_rid(const SrsRidInfo &rid_info, SrsRtcPublishStream** ppublisher) { srs_error_t err = srs_success; SrsRtcSource *source = NULL; if ((err = _srs_rtc_sources->fetch_or_create(req_, &source)) != srs_success) { return srs_error_wrap(err, "fetch_or_create source"); } + std::vector track_descs = source->get_track_desc("video", "H264"); for (size_t i = 0; i < track_descs.size(); ++i) { SrsRtcTrackDescription* track_desc = track_descs.at(i); if (track_desc->ssrc_ == 0) { track_desc->ssrc_ = rid_info.ssrc; track_desc->rid_ = rid_info; + // TODO: maybe select wrong publisher? SrsRtcPublishStream* publisher = publishers_ssrc_map_.begin()->second; publisher->bind_rid(rid_info); publishers_ssrc_map_[track_desc->ssrc_] = publisher; + *ppublisher = publisher; srs_warn("find track_desc to (rid='%s', ssrc=%u)", rid_info.rid.c_str(), rid_info.ssrc); return err; } } + return srs_error_new(ERROR_RTC_NO_TRACK, "no idle track_desc to (rid='%s', ssrc=%u)", rid_info.rid.c_str(), rid_info.ssrc); } @@ -2901,14 +2931,14 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRtcUserConfig* ruc // Whether feature enabled in remote extmap. int remote_twcc_id = 0; if (true) { - map extmaps = remote_media_desc.get_extmaps(); + map extmaps = remote_media_desc.extmaps_; for(map::iterator it = extmaps.begin(); it != extmaps.end(); ++it) { - if (it->second == kTWCCExt) { + if (it->second == kExtensions[kRtpExtTwcc].uri) { remote_twcc_id = it->first; // break; } else if (remote_media_desc.simulcast_spec_version()) { // note: add all ext map in simulcast_spec_version - if (it->second == kExtMapFieldArray[kSdesRtpStreamId] || it->second == kExtMapFieldArray[kSdesRepairedRtpStreamId]) { + if (it->second == kExtensions[kRtpExtSdesRtpStreamId].uri || it->second == kExtensions[kRtpExtSdesRepairedRtpStreamId].uri) { track_desc->add_rtp_extension_desc(it->first, it->second); } } @@ -2916,7 +2946,7 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRtcUserConfig* ruc } if (twcc_enabled && remote_twcc_id) { - track_desc->add_rtp_extension_desc(remote_twcc_id, kTWCCExt); + track_desc->add_rtp_extension_desc(remote_twcc_id, kExtensions[kRtpExtTwcc].uri); } if (remote_media_desc.is_audio()) { @@ -3148,7 +3178,7 @@ srs_error_t SrsRtcConnection::generate_publish_local_sdp(SrsRequest* req, SrsSdp // answer not need set stream_id and track_id; // local_media_desc.msid_ = stream_id; // local_media_desc.msid_tracker_ = audio_track->id_; - local_media_desc.extmaps_.data = audio_track->extmaps_; + local_media_desc.extmaps_ = audio_track->extmaps_; if (audio_track->direction_ == "recvonly") { local_media_desc.recvonly_ = true; @@ -3181,7 +3211,7 @@ srs_error_t SrsRtcConnection::generate_publish_local_sdp(SrsRequest* req, SrsSdp // answer not need set stream_id and track_id; //local_media_desc.msid_ = stream_id; //local_media_desc.msid_tracker_ = video_track->id_; - local_media_desc.extmaps_.data = video_track->extmaps_; + local_media_desc.extmaps_ = video_track->extmaps_; if (video_track->direction_ == "recvonly") { local_media_desc.recvonly_ = true; @@ -3236,9 +3266,9 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRtcUserConfig* ruc, s // Whether feature enabled in remote extmap. int remote_twcc_id = 0; if (true) { - map extmaps = remote_media_desc.get_extmaps(); + map extmaps = remote_media_desc.extmaps_; for(map::iterator it = extmaps.begin(); it != extmaps.end(); ++it) { - if (it->second == kTWCCExt) { + if (it->second == kExtensions[kRtpExtTwcc].uri) { remote_twcc_id = it->first; break; } @@ -3327,7 +3357,7 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRtcUserConfig* ruc, s if (rtcp_fb.at(j) == "transport-cc") { track->media_->rtcp_fbs_.push_back(rtcp_fb.at(j)); } - track->add_rtp_extension_desc(remote_twcc_id, kTWCCExt); + track->add_rtp_extension_desc(remote_twcc_id, kExtensions[kRtpExtTwcc].uri); } } @@ -3364,7 +3394,7 @@ void video_track_generate_play_offer(SrsRtcTrackDescription* track, string mid, local_media_desc.rtcp_mux_ = true; local_media_desc.rtcp_rsize_ = true; - local_media_desc.extmaps_.data = track->extmaps_; + local_media_desc.extmaps_ = track->extmaps_; // If mid not duplicated, use mid_ of track. Otherwise, use transformed mid. if (true) { @@ -3512,7 +3542,7 @@ srs_error_t SrsRtcConnection::generate_play_local_sdp(SrsRequest* req, SrsSdp& l local_media_desc.rtcp_mux_ = true; local_media_desc.rtcp_rsize_ = true; - local_media_desc.extmaps_.data = audio_track->extmaps_; + local_media_desc.extmaps_ = audio_track->extmaps_; local_media_desc.mid_ = audio_track->mid_; local_sdp.groups_.push_back(local_media_desc.mid_); @@ -3650,7 +3680,7 @@ srs_error_t SrsRtcConnection::create_player(SrsRequest* req, std::mapsecond->type_ == "video") { SrsRtcTrackDescription* track = it->second; - twcc_id = track->get_rtp_extension_id(kTWCCExt); + twcc_id = track->get_rtp_extension_id(kExtensions[kRtpExtTwcc].uri); } ++it; } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 61c5750cf8..2c9a83575a 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -483,8 +483,6 @@ class SrsRtcConnection : public ISrsResource, public ISrsDisposingHandler, publi SrsSdp remote_sdp; SrsSdp local_sdp; private: - // twcc handler - int twcc_id_; // Simulators. int nn_simulate_player_nack_drop; // Pithy print for address change, use port as error code. @@ -579,8 +577,8 @@ class SrsRtcConnection : public ISrsResource, public ISrsDisposingHandler, publi srs_error_t create_player(SrsRequest* request, std::map sub_relations); srs_error_t create_publisher(SrsRequest* request, SrsRtcSourceDescription* stream_desc); - srs_error_t parse_rid(char *buf, int size, uint32_t ssrc); - srs_error_t bind_rid(const SrsRidInfo &rid_info); + srs_error_t parse_rid(char *buf, int size, uint32_t ssrc, SrsRtcPublishStream** ppublisher); + srs_error_t bind_rid(const SrsRidInfo &rid_info, SrsRtcPublishStream** ppublisher); }; class ISrsRtcHijacker diff --git a/trunk/src/app/srs_app_rtc_sdp.cpp b/trunk/src/app/srs_app_rtc_sdp.cpp index acd69a5309..fa026d51f3 100644 --- a/trunk/src/app/srs_app_rtc_sdp.cpp +++ b/trunk/src/app/srs_app_rtc_sdp.cpp @@ -413,7 +413,7 @@ srs_error_t SrsMediaDesc::encode(std::ostringstream& os) os << kCRLF; } - for(map::iterator it = extmaps_.data.begin(); it != extmaps_.data.end(); ++it) { + for(map::iterator it = extmaps_.begin(); it != extmaps_.end(); ++it) { os << "a=extmap:"<< it->first<< " "<< it->second<< kCRLF; } if (sendonly_) { @@ -534,13 +534,12 @@ srs_error_t SrsMediaDesc::parse_attr_extmap(const std::string& value) std::istringstream is(value); int id = 0; FETCH(is, id); - if(extmaps_.data.end() != extmaps_.data.find(id)) { + if(extmaps_.end() != extmaps_.find(id)) { return srs_error_new(ERROR_RTC_SDP_DECODE, "duplicate ext id: %d", id); } string ext; FETCH(is, ext); - // note: check extmap get rid_ext_id, ridrtx_ext_id, mid_ext_id - extmaps_.parse_extmap(id, ext); + extmaps_[id] = ext; return err; } @@ -1225,199 +1224,3 @@ srs_error_t SrsSimulcastInfo::encode(ostringstream &os) { return err; } - -void SrsExtMapInfo::parse_extmap(int id, std::string ext) { - data[id] = ext; - parse_ext_id(id, ext); -} - -void SrsExtMapInfo::parse_ext_id(int id, std::string ext) { - // a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level - // a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time - // a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 - // a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid - // a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id - // a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id - // - // a=extmap:14 urn:ietf:params:rtp-hdrext:toffset - // a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time - // a=extmap:13 urn:3gpp:video-orientation - // a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 - // a=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay - // a=extmap:11 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type - // a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing - // a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space - // a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid - // a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id - // a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id - - for (size_t i=0; iversion != 2) { - return -1; - } - int hlen = 12; - if(rtp->csrccount) /* Skip CSRC if needed */ - hlen += rtp->csrccount*4; - if(rtp->extension) { - rtp_header_extension *ext = (rtp_header_extension *)(buf+hlen); - int extlen = ntohs(ext->length)*4; - hlen += 4; - if(len > (hlen + extlen)) { - /* 1-Byte extension */ - if(ntohs(ext->type) == 0xBEDE) { - const uint8_t padding = 0x00, reserved = 0xF; - uint8_t extid = 0, idlen; - int i = 0; - while(i < extlen) { - extid = (uint8_t)buf[hlen+i] >> 4; - if(extid == reserved) { - break; - } else if(extid == padding) { - i++; - continue; - } - idlen = ((uint8_t)buf[hlen+i] & 0xF)+1; - if(extid == id) { - /* Found! */ - if(byte) - *byte = (uint8_t)buf[hlen+i+1]; - if(word && idlen >= 3 && (i+3) < extlen) { - memcpy(word, buf+hlen+i, sizeof(uint32_t)); - *word = ntohl(*word); - } - if(ref) - *ref = &buf[hlen+i]; - return 0; - } - i += 1 + idlen; - } - } - hlen += extlen; - } - } - return -1; -} - - -// @see janus_rtp_header_extension_parse_rid in https://github.com/meetecho/janus-gateway/blob/master/rtp.c -static int rtp_header_extension_parse_rid( - char *buf, int len, int id, char *sdes_item, int sdes_len) { - char *ext = NULL; - if(rtp_header_extension_find(buf, len, id, NULL, NULL, &ext) < 0) - return -1; - /* a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id */ - /* a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id */ - if(ext == NULL) - return -2; - int val_len = (*ext & 0x0F) + 1; - if(val_len > (sdes_len-1)) { - // JANUS_LOG(LOG_WARN, "SDES buffer is too small (%d < %d), RTP stream ID will be cut\n", val_len, sdes_len); - val_len = sdes_len-1; - } - if (val_len > len-(ext-buf)-1 ) { - return -3; - } - memcpy(sdes_item, ext+1, val_len); - *(sdes_item+val_len) = '\0'; - return 0; -} - -// @see janus_rtp_header_extension_parse_mid in https://github.com/meetecho/janus-gateway/blob/master/rtp.c -static int rtp_header_extension_parse_mid( - char *buf, int len, int id, char *sdes_item, int sdes_len) { - char *ext = NULL; - if(rtp_header_extension_find(buf, len, id, NULL, NULL, &ext) < 0) - return -1; - /* a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid */ - if(ext == NULL) - return -2; - int val_len = (*ext & 0x0F) + 1; - if(val_len > (sdes_len-1)) { - // JANUS_LOG(LOG_WARN, "SDES buffer is too small (%d < %d), MID will be cut\n", val_len, sdes_len); - val_len = sdes_len-1; - } - if (val_len > len-(ext-buf)-1 ) { - return -3; - } - memcpy(sdes_item, ext+1, val_len); - *(sdes_item+val_len) = '\0'; - return 0; -} - -SrsRidInfo* SrsExtMapInfo::parse_rid(char *buf, int len, SrsSimulcastInfo &simulcast) { - char sdes_item[16]; - int ret; - std::string rid, ridrtx; - std::string mid; - if((ret = rtp_header_extension_parse_rid(buf, len, rid_ext_id(), sdes_item, sizeof(sdes_item))) == 0) { - rid = sdes_item; - } else { - return NULL; - } - if((ret = rtp_header_extension_parse_rid(buf, len, ridrtx_ext_id(), sdes_item, sizeof(sdes_item))) == 0) { - ridrtx = sdes_item; - srs_info("rid=%s, ridrtx_ext_id=%d, ridrtx=%s", rid.c_str(), ridrtx_ext_id(), ridrtx.c_str()); - } else { - srs_warn("bad=%d rid=%s, ridrtx_ext_id=%d", ret, rid.c_str(), ridrtx_ext_id()); - } - if((ret = rtp_header_extension_parse_mid(buf, len, mid_ext_id(), sdes_item, sizeof(sdes_item))) == 0) { - mid = sdes_item; - srs_info("mid=%s", mid.c_str()); - } - for (size_t i=0; i #include +#include #include #include #include #include -const std::string kTWCCExt = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"; // TDOO: FIXME: Rename it, and add utest. extern std::vector split_str(const std::string& str, const std::string& delim); @@ -141,56 +141,6 @@ struct SrsCandidate std::string type_; }; - -#define DEFINDE_EXT_MAP_FIELD(EXT_MAP_FIELD) \ -EXT_MAP_FIELD(kSsrcAudioLevel, "urn:ietf:params:rtp-hdrext:ssrc-audio-level") \ -EXT_MAP_FIELD(kAbsSendTime, "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time") \ -EXT_MAP_FIELD(kTransportCC, "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01") \ -EXT_MAP_FIELD(kSdesMid, "urn:ietf:params:rtp-hdrext:sdes:mid") \ -EXT_MAP_FIELD(kSdesRtpStreamId, "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id") \ -EXT_MAP_FIELD(kSdesRepairedRtpStreamId, "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id") \ -EXT_MAP_FIELD(kVideoTiming, "http://www.webrtc.org/experiments/rtp-hdrext/video-timing") \ -EXT_MAP_FIELD(kColorSpace, "http://www.webrtc.org/experiments/rtp-hdrext/color-space") \ -EXT_MAP_FIELD(kCsrcAudioLevel, "urn:ietf:params:rtp-hdrext:csrc-audio-level") \ -EXT_MAP_FIELD(kFramemarking, "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07") \ -EXT_MAP_FIELD(kVideoContentType, "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type") \ -EXT_MAP_FIELD(kPlayoutDelay, "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay") \ -EXT_MAP_FIELD(kVideoOrientation, "urn:3gpp:video-orientation") \ -EXT_MAP_FIELD(kToffset, "urn:ietf:params:rtp-hdrext:toffset") \ -EXT_MAP_FIELD(kEncrypt, "urn:ietf:params:rtp-hdrext:encrypt") - -enum ExtMapFieldEnum { -#define DEFIDE_EXT_MAP_ENUM(a, b) a, - DEFINDE_EXT_MAP_FIELD(DEFIDE_EXT_MAP_ENUM) -#undef DEFIDE_EXT_MAP_ENUM - kExtMapFieldSize -}; - -static const char* const kExtMapFieldArray[] = { -#define DEFIDE_EXT_MAP_ARRAY(x, y) y, - DEFINDE_EXT_MAP_FIELD(DEFIDE_EXT_MAP_ARRAY) -#undef DEFIDE_EXT_MAP_ARRAY -}; - -class SrsExtMapInfo { - int ext_id_list_[kExtMapFieldSize]; - void parse_ext_id(int id, std::string ext); -public: - SrsExtMapInfo(); - int mid_ext_id() const { return ext_id_list_[kSdesMid]; } - int rid_ext_id() const { return ext_id_list_[kSdesRtpStreamId]; } - int ridrtx_ext_id() const { return ext_id_list_[kSdesRepairedRtpStreamId]; } - int audiolevel_ext_id() const { return ext_id_list_[kSsrcAudioLevel]; } - int videoorientation_ext_id() const { return ext_id_list_[kVideoOrientation]; } - int transport_wide_cc_ext_id() const { return ext_id_list_[kTransportCC]; } - bool transport_wide_cc() const { return transport_wide_cc_ext_id() > 0; } - - std::map data; - void parse_extmap(int id, std::string ext); - - SrsRidInfo * parse_rid(char *buf, int len, SrsSimulcastInfo &simulcast); -}; - class SrsMediaDesc { public: @@ -201,7 +151,6 @@ class SrsMediaDesc srs_error_t encode(std::ostringstream& os); SrsMediaPayloadType* find_media_with_payload_type(int payload_type); std::vector find_media_with_encoding_name(const std::string& encoding_name) const; - const std::map& get_extmaps() const { return extmaps_.data; } srs_error_t update_msid(std::string id); bool is_audio() const { return type_ == "audio"; } @@ -242,7 +191,7 @@ class SrsMediaDesc std::vector candidates_; std::vector ssrc_groups_; std::vector ssrc_infos_; - SrsExtMapInfo extmaps_; + std::map extmaps_; bool simulcast_spec_version() const { return ssrc_infos_.empty() && !session_info_.simulcast_.line.empty(); diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index 45af331fea..cb417cb24b 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -2187,15 +2187,6 @@ int SrsRtcTrackDescription::get_rtp_extension_id(std::string uri) return 0; } -int SrsRtcTrackDescription::get_rtp_extension_id(ExtMapFieldEnum field) { - for (std::map::iterator it = extmaps_.begin(); it != extmaps_.end(); ++it) { - if(kExtMapFieldArray[field] == it->second) { - return it->first; - } - } - return 0; -} - SrsRtcTrackDescription* SrsRtcTrackDescription::copy() { SrsRtcTrackDescription* cp = new SrsRtcTrackDescription(); diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp index 29fb7abf08..7d193e4df1 100644 --- a/trunk/src/app/srs_app_rtc_source.hpp +++ b/trunk/src/app/srs_app_rtc_source.hpp @@ -488,7 +488,6 @@ class SrsRtcTrackDescription void set_fec_ssrc(uint32_t ssrc); void set_mid(std::string mid); int get_rtp_extension_id(std::string uri); - int get_rtp_extension_id(ExtMapFieldEnum field); public: SrsRtcTrackDescription* copy(); }; diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp index f1173c3fb6..227a24548a 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp @@ -124,6 +124,68 @@ srs_error_t srs_rtp_fast_parse_twcc(char* buf, int size, uint8_t twcc_id, uint16 return err; } +srs_error_t srs_rtp_fast_parse_rid(char* buf, int size, uint8_t rid_id, std::string& rid) +{ + srs_error_t err = srs_success; + + int need_size = 12 /*rtp head fix len*/ + 4 /* extension header len*/ + 3 /* twcc extension len*/; + if(size < (need_size)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "required %d bytes, actual %d", need_size, size); + } + + uint8_t first = buf[0]; + bool extension = (first & 0x10); + uint8_t cc = (first & 0x0F); + + if(!extension) { + return srs_error_new(ERROR_RTC_RTP, "no extension in rtp"); + } + + need_size += cc * 4; // csrc size + if(size < (need_size)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "required %d bytes, actual %d", need_size, size); + } + buf += 12 + 4*cc; + + uint16_t value = *((uint16_t*)buf); + value = ntohs(value); + if(0xBEDE != value) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "no support this type(0x%02x) extension", value); + } + buf += 2; + + uint16_t extension_length = ntohs(*((uint16_t*)buf)); + buf += 2; + extension_length *= 4; + need_size += extension_length; // entension size + if(size < (need_size)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "required %d bytes, actual %d", need_size, size); + } + + while(extension_length > 0) { + uint8_t v = buf[0]; + buf++; + extension_length--; + if(0 == v) { + continue; + } + + uint8_t id = (v & 0xF0) >>4; + uint8_t len = (v & 0x0F) + 1; + + if(id == rid_id) { + rid.append(buf, len); + return err; + } else { + buf += len; + extension_length -= len; + } + } + + + return err; +} + // If value is newer than pre_value,return true; otherwise false bool srs_seq_is_newer(uint16_t value, uint16_t pre_value) { @@ -396,7 +458,7 @@ srs_error_t SrsRtpExtensions::decode_0xbede(SrsBuffer* buf) uint8_t len = (v & 0x0F) + 1; SrsRtpExtensionType xtype = types_? types_->get_type(id) : kRtpExtensionNone; - if (xtype == kRtpExtensionTransportSequenceNumber) { + if (xtype == kRtpExtTwcc) { if (decode_twcc_extension_) { if ((err = twcc_.decode(buf)) != srs_success) { return srs_error_wrap(err, "decode twcc extension"); @@ -408,7 +470,7 @@ srs_error_t SrsRtpExtensions::decode_0xbede(SrsBuffer* buf) } buf->skip(len + 1); } - } else if (xtype == kRtpExtensionAudioLevel) { + } else if (xtype == kRtpExtSsrcAudioLevel) { if((err = audio_level_.decode(buf)) != srs_success) { return srs_error_wrap(err, "decode audio level extension"); } diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp index 320d49534b..5f4c113a92 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp @@ -48,6 +48,7 @@ class SrsRtpExtensionTypes; uint32_t srs_rtp_fast_parse_ssrc(char* buf, int size); uint8_t srs_rtp_fast_parse_pt(char* buf, int size); srs_error_t srs_rtp_fast_parse_twcc(char* buf, int size, uint8_t twcc_id, uint16_t& twcc_sn); +srs_error_t srs_rtp_fast_parse_rid(char* buf, int size, uint8_t rid_id, std::string& rid); // The "distance" between two uint16 number, for example: // distance(prev_value=3, value=5) === (int16_t)(uint16_t)((uint16_t)3-(uint16_t)5) === -2 @@ -76,13 +77,26 @@ int32_t srs_seq_distance(uint16_t value, uint16_t pre_value); enum SrsRtpExtensionType { kRtpExtensionNone, - kRtpExtensionTransportSequenceNumber, - kRtpExtensionAudioLevel, + + kRtpExtTwcc, + kRtpExtSsrcAudioLevel, + kRtpExtSdesMid, + kRtpExtSdesRtpStreamId, + kRtpExtSdesRepairedRtpStreamId, + kRtpExtAbsSendTime, + kRtpExtVideoTiming, + kRtpExtColorSpace, + kRtpExtCsrcAudioLevel, + kRtpExtFramemarking, + kRtpExtVideoContentType, + kRtpExtPlayoutDelay, + kRtpExtVideoOrientation, + kRtpExtToffset, + kRtpExtEncrypt, + kRtpExtensionNumberOfExtensions // Must be the last entity in the enum. }; -const std::string kAudioLevelUri = "urn:ietf:params:rtp-hdrext:ssrc-audio-level"; - struct SrsExtensionInfo { SrsRtpExtensionType type; @@ -90,8 +104,22 @@ struct SrsExtensionInfo }; const SrsExtensionInfo kExtensions[] = { - {kRtpExtensionTransportSequenceNumber, std::string("http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01")}, - {kRtpExtensionAudioLevel, kAudioLevelUri}, + {kRtpExtensionNone, std::string("")}, + {kRtpExtTwcc, std::string("http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01")}, + {kRtpExtSsrcAudioLevel, std::string("urn:ietf:params:rtp-hdrext:ssrc-audio-level")}, + {kRtpExtSdesMid, std::string("urn:ietf:params:rtp-hdrext:sdes:mid")}, + {kRtpExtSdesRtpStreamId, std::string("urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id")}, + {kRtpExtSdesRepairedRtpStreamId, std::string("urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id")}, + {kRtpExtAbsSendTime, std::string("http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time")}, + {kRtpExtVideoTiming, std::string("http://www.webrtc.org/experiments/rtp-hdrext/video-timing")}, + {kRtpExtColorSpace, std::string("http://www.webrtc.org/experiments/rtp-hdrext/color-space")}, + {kRtpExtCsrcAudioLevel, std::string("urn:ietf:params:rtp-hdrext:csrc-audio-level")}, + {kRtpExtFramemarking, std::string("http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07")}, + {kRtpExtVideoContentType, std::string("http://www.webrtc.org/experiments/rtp-hdrext/video-content-type")}, + {kRtpExtPlayoutDelay, std::string("http://www.webrtc.org/experiments/rtp-hdrext/playout-delay")}, + {kRtpExtVideoOrientation, std::string("urn:3gpp:video-orientation")}, + {kRtpExtToffset, std::string("urn:ietf:params:rtp-hdrext:toffset")}, + {kRtpExtEncrypt, std::string("urn:ietf:params:rtp-hdrext:encrypt")} }; class SrsRtpExtensionTypes From ca7feaa528e97edd5fb04a7a08974a64397390b2 Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Wed, 15 Dec 2021 13:32:19 +0800 Subject: [PATCH 13/13] Mofidy x-google* from cpp code to html --- trunk/research/players/js/srs.sdk.js | 25 +++++++++++++++++++++---- trunk/src/app/srs_app_rtc_conn.cpp | 3 --- trunk/src/app/srs_app_rtc_source.cpp | 3 --- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/trunk/research/players/js/srs.sdk.js b/trunk/research/players/js/srs.sdk.js index eab996ae78..dcff97a5e0 100644 --- a/trunk/research/players/js/srs.sdk.js +++ b/trunk/research/players/js/srs.sdk.js @@ -46,6 +46,7 @@ function SrsRtcPublisherAsync() { var conf = self.__internal.prepareUrl(url); const parameter = QueryParameterByName('numberOfSimulcastLayers', conf.streamUrl); const numberOfSimulcastLayers = parseInt(parameter) + var forceSetBitrate = false if (numberOfSimulcastLayers > 1) { self.constraints.video = { wіdth: 1280, height: 720 @@ -56,6 +57,7 @@ function SrsRtcPublisherAsync() { self.constraints.video = { wіdth: 1280, height: 720 } + forceSetBitrate = true; console.log('kSimulcastApiVersionSpecCompliant') } @@ -110,9 +112,24 @@ function SrsRtcPublisherAsync() { reject(reason); }); }); - await self.pc.setRemoteDescription( - new RTCSessionDescription({type: 'answer', sdp: session.sdp}) - ); + + + if (forceSetBitrate) { + var arr = session.sdp.split('\r\n'); + arr.forEach((str, i) => { + // TODO: FIXME: adapter to different browers. + if (/^a=fmtp:\d*/.test(str)) { + arr[i] = str + ';x-google-min-bitrate=5000;x-google-max-bitrate=8000;x-google-start-bitrate=6000'; + } + }); + await self.pc.setRemoteDescription( + new RTCSessionDescription({type: 'answer', sdp: arr.join('\r\n')}) + ); + } else { + await self.pc.setRemoteDescription( + new RTCSessionDescription({type: 'answer', sdp: session.sdp}) + ); + } session.simulator = conf.schema + '//' + conf.urlObject.server + ':' + conf.port + '/rtc/v1/nack/'; return session; @@ -637,4 +654,4 @@ function QueryParameterByName(name, url) { if (!results) return null; if (!results[2]) return ''; return decodeURIComponent(results[2].replace(/\+/g, ' ')); -} \ No newline at end of file +} diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index c1613e8220..e255f65342 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -3224,9 +3224,6 @@ srs_error_t SrsRtcConnection::generate_publish_local_sdp(SrsRequest* req, SrsSdp } SrsVideoPayload* payload = (SrsVideoPayload*)video_track->media_; - if (srs_string_contains(req->param,"?numberOfSimulcastLayers=spec3")) { - payload->h264_param_.x_google_bitrate = "x-google-min-bitrate=5000;x-google-max-bitrate=8000;x-google-start-bitrate=6000"; - } local_media_desc.payload_types_.push_back(payload->generate_media_payload_type()); if (video_track->red_) { diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index cb417cb24b..d71cef1234 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -1865,9 +1865,6 @@ SrsMediaPayloadType SrsVideoPayload::generate_media_payload_type() if (!h264_param_.packetization_mode.empty()) { format_specific_param << ";packetization-mode=" << h264_param_.packetization_mode; } - if (!h264_param_.x_google_bitrate.empty()) { - format_specific_param << ";" << h264_param_.x_google_bitrate; - } if (!h264_param_.profile_level_id.empty()) { format_specific_param << ";profile-level-id=" << h264_param_.profile_level_id; }