diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index ee4a562ed..691b42799 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -242,16 +242,18 @@ srs_error_t SrsRtcPlayStream::initialize(SrsRequest* req, std::map::iterator it = sub_relations.begin(); - while (it != sub_relations.end()) { - if (it->second->type_ == "audio") { - audio_tracks_.insert(make_pair(it->first, new SrsRtcAudioSendTrack(session_, it->second))); - } + if (true) { + std::map::iterator it = sub_relations.begin(); + while (it != sub_relations.end()) { + if (it->second->type_ == "audio") { + audio_tracks_.insert(make_pair(it->first, new SrsRtcAudioSendTrack(session_, it->second))); + } - if (it->second->type_ == "video") { - video_tracks_.insert(make_pair(it->first, new SrsRtcVideoSendTrack(session_, it->second))); + if (it->second->type_ == "video") { + video_tracks_.insert(make_pair(it->first, new SrsRtcVideoSendTrack(session_, it->second))); + } + ++it; } - ++it; } // TODO: FIXME: Support reload. @@ -500,6 +502,14 @@ srs_error_t SrsRtcPlayStream::do_send_packets(const std::vector& // Marshal packet to bytes in iovec. if (true) { +#ifdef SRS_CXX14 + // should set twcc sn before packet encode. + if(twcc_id_) { + twcc_sn = twcc_controller.allocate_twcc_sn(); + pkt->header.set_twcc_sequence_number(twcc_id_, twcc_sn); + } +#endif + SrsBuffer stream((char*)iov->iov_base, iov->iov_len); if ((err = pkt->encode(&stream)) != srs_success) { return srs_error_wrap(err, "encode packet"); @@ -546,7 +556,9 @@ void SrsRtcPlayStream::nack_fetch(vector& pkts, uint32_t ssrc, u for (it = audio_tracks_.begin(); it != audio_tracks_.end(); ++it) { if (it->second->has_ssrc(ssrc)) { SrsRtpPacket2* pkt = it->second->fetch_rtp_packet(seq); - pkts.push_back(pkt); + if (pkt != NULL) { + pkts.push_back(pkt); + } return; } } @@ -557,7 +569,9 @@ void SrsRtcPlayStream::nack_fetch(vector& pkts, uint32_t ssrc, u for (it = video_tracks_.begin(); it != video_tracks_.end(); ++it) { if (it->second->has_ssrc(ssrc)) { SrsRtpPacket2* pkt = it->second->fetch_rtp_packet(seq); - pkts.push_back(pkt); + if (pkt != NULL) { + pkts.push_back(pkt); + } return; } } @@ -854,12 +868,16 @@ srs_error_t SrsRtcPublishStream::initialize(SrsRequest* r, SrsRtcStreamDescripti int twcc_id = -1; uint32_t media_ssrc = 0; - if (stream_desc->audio_track_desc_) { - SrsRtcTrackDescription* desc = stream_desc->audio_track_desc_; + // because audio_track_desc have not twcc id, for example, h5demo + // fetch twcc_id from video track description, + for (int i = 0; i < stream_desc->video_track_descs_.size(); ++i) { + SrsRtcTrackDescription* desc = stream_desc->video_track_descs_.at(i); twcc_id = desc->get_rtp_extension_id(kTWCCExt); media_ssrc = desc->ssrc_; + break; } if (twcc_id != -1) { + twcc_id_ = twcc_id; extension_types_.register_by_uri(twcc_id_, kTWCCExt); rtcp_twcc_.set_media_ssrc(media_ssrc); } @@ -1703,6 +1721,45 @@ srs_error_t SrsRtcConnection::add_player(SrsRequest* req, const SrsSdp& remote_s return err; } +srs_error_t SrsRtcConnection::add_player2(SrsRequest* req, SrsSdp& local_sdp) +{ + srs_error_t err = srs_success; + + std::map play_sub_relations; + if ((err = fetch_source_capability(req, play_sub_relations)) != srs_success) { + return srs_error_wrap(err, "remote sdp have error or unsupport attributes"); + } + + if (!play_sub_relations.size()) { + return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "cannot negotiate sub relations"); + } + + SrsRtcStreamDescription* stream_desc = new SrsRtcStreamDescription(); + SrsAutoFree(SrsRtcStreamDescription, stream_desc); + + std::map::iterator it = play_sub_relations.begin(); + while (it != play_sub_relations.end()) { + if (it->second->type_ == "audio" || !stream_desc->audio_track_desc_) { + stream_desc->audio_track_desc_ = it->second->copy(); + } + + if (it->second->type_ == "video") { + stream_desc->video_track_descs_.push_back(it->second->copy()); + } + ++it; + } + + if ((err = generate_play_local_sdp(req, local_sdp, stream_desc)) != srs_success) { + return srs_error_wrap(err, "generate local sdp"); + } + + if ((err = create_player(req, play_sub_relations)) != srs_success) { + return srs_error_wrap(err, "create player"); + } + + return err; +} + srs_error_t SrsRtcConnection::initialize(SrsRtcStream* source, SrsRequest* r, bool is_publisher, string username, SrsContextId context_id) { srs_error_t err = srs_success; @@ -2517,25 +2574,19 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRequest* req, const S // TODO: FIXME: if we support downlink RTX, MUST assign rtx_ssrc_, rtx_pt, rtx_apt // not support rtx if (true) { - if (track->rtx_) { - srs_freep(track->rtx_); - } + srs_freep(track->rtx_); track->rtx_ssrc_ = 0; } // TODO: FIXME: if we support downlink ulpfec, MUST assign ulpfec params // set_ulpfec_config; if (true) { - if (track->ulpfec_) { - srs_freep(track->ulpfec_); - } + srs_freep(track->ulpfec_); track->fec_ssrc_ = 0; } // TODO: FIXME: if we support downlink , MUST assign fec_ssrc_ // set_rsfec_config; if (true) { - if (track->rsfec_) { - srs_freep(track->rsfec_); - } + srs_freep(track->rsfec_); track->fec_ssrc_ = 0; } @@ -2547,6 +2598,69 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRequest* req, const S return err; } +srs_error_t SrsRtcConnection::fetch_source_capability(SrsRequest* req, std::map& sub_relations) +{ + srs_error_t err = srs_success; + + bool nack_enabled = _srs_config->get_rtc_nack_enabled(req->vhost); + bool twcc_enabled = _srs_config->get_rtc_twcc_enabled(req->vhost); + + SrsRtcStream* source = NULL; + if ((err = _srs_rtc_sources->fetch_or_create(req, &source)) != srs_success) { + return srs_error_wrap(err, "fetch rtc source"); + } + + // TODO: FIXME: Avoid SSRC collision. + if (!ssrc_num) { + ssrc_num = ::getpid() * 10000 + ::getpid() * 100 + ::getpid(); + } + + std::vector track_descs = source->get_track_desc("audio", "opus"); + std::vector video_track_desc = source->get_track_desc("video", "H264"); + + track_descs.insert(track_descs.end(), video_track_desc.begin(), video_track_desc.end()); + for (int i = 0; i < track_descs.size(); ++i) { + SrsRtcTrackDescription* track = track_descs[i]->copy(); + uint32_t publish_ssrc = track->ssrc_; + + track->media_->rtcp_fbs_.clear(); + if (nack_enabled) { + track->media_->rtcp_fbs_.push_back("nack"); + track->media_->rtcp_fbs_.push_back("nack pli"); + } + + int local_twcc_id = track->get_rtp_extension_id(kTWCCExt); + track->extmaps_.clear(); + if (twcc_enabled && local_twcc_id) { + track->media_->rtcp_fbs_.push_back("transport-cc"); + track->add_rtp_extension_desc(local_twcc_id, kTWCCExt); + } + + track->ssrc_ = ++ssrc_num; + // TODO: FIXME: set audio_payload rtcp_fbs_, + // according by whether downlink is support transport algorithms. + // TODO: FIXME: if we support downlink RTX, MUST assign rtx_ssrc_, rtx_pt, rtx_apt + // not support rtx + srs_freep(track->rtx_); + track->rtx_ssrc_ = 0; + + // TODO: FIXME: if we support downlink ulpfec, MUST assign ulpfec params + // set_ulpfec_config; + srs_freep(track->ulpfec_); + track->fec_ssrc_ = 0; + + // TODO: FIXME: if we support downlink , MUST assign fec_ssrc_ + // set_rsfec_config; + srs_freep(track->rsfec_); + track->fec_ssrc_ = 0; + + track->set_direction("sendonly"); + sub_relations.insert(make_pair(publish_ssrc, track)); + } + + return err; +} + srs_error_t SrsRtcConnection::generate_play_local_sdp(SrsRequest* req, SrsSdp& local_sdp, SrsRtcStreamDescription* stream_desc) { srs_error_t err = srs_success; @@ -2586,9 +2700,6 @@ 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.mid_ = audio_track->mid_; - local_media_desc.msid_ = stream_id; - local_media_desc.msid_tracker_ = audio_track->id_; local_media_desc.extmaps_ = audio_track->extmaps_; local_media_desc.mid_ = audio_track->mid_; @@ -2610,7 +2721,6 @@ srs_error_t SrsRtcConnection::generate_play_local_sdp(SrsRequest* req, SrsSdp& l //TODO: FIXME: add red, rtx, ulpfec, rsfec..., payload_types_. //local_media_desc.payload_types_.push_back(payload->generate_media_payload_type()); - local_media_desc.ssrc_infos_.push_back(SrsSSRCInfo(audio_track->ssrc_, cname, stream_id, audio_track->id_)); if (audio_track->rtx_) { @@ -2645,9 +2755,6 @@ 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.mid_ = track->mid_; - local_media_desc.msid_ = stream_id; - local_media_desc.msid_tracker_ = track->id_; local_media_desc.extmaps_ = track->extmaps_; local_media_desc.mid_ = track->mid_; @@ -2688,8 +2795,6 @@ srs_error_t SrsRtcConnection::generate_play_local_sdp(SrsRequest* req, SrsSdp& l local_media_desc.ssrc_infos_.push_back(SrsSSRCInfo(track->fec_ssrc_, cname, stream_id, track->id_)); } - // only need media desc info, not ssrc info; - break; } return err; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 0e47c1707..b11a205e9 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -358,6 +358,8 @@ public: SrsContextId context_id(); srs_error_t add_publisher(SrsRequest* request, const SrsSdp& remote_sdp, SrsSdp& local_sdp); srs_error_t add_player(SrsRequest* request, const SrsSdp& remote_sdp, SrsSdp& local_sdp); + // server send offer sdp to client, local sdp derivate from source stream desc. + srs_error_t add_player2(SrsRequest* request, SrsSdp& local_sdp); public: // Before initialize, user must set the local SDP, which is used to inititlize DTLS. srs_error_t initialize(SrsRtcStream* source, SrsRequest* r, bool is_publisher, std::string username, SrsContextId context_id); @@ -388,6 +390,7 @@ private: srs_error_t generate_publish_local_sdp(SrsRequest* req, SrsSdp& local_sdp, SrsRtcStreamDescription* stream_desc); // play media capabilitiy negotiate srs_error_t negotiate_play_capability(SrsRequest* req, const SrsSdp& remote_sdp, std::map& sub_relations); + srs_error_t fetch_source_capability(SrsRequest* req, std::map& sub_relations); srs_error_t generate_play_local_sdp(SrsRequest* req, SrsSdp& local_sdp, SrsRtcStreamDescription* stream_desc); srs_error_t create_player(SrsRequest* request, std::map sub_relations); srs_error_t create_publisher(SrsRequest* request, SrsRtcStreamDescription* stream_desc); diff --git a/trunk/src/app/srs_app_rtc_server.cpp b/trunk/src/app/srs_app_rtc_server.cpp index a3a073eb1..27d8867ce 100644 --- a/trunk/src/app/srs_app_rtc_server.cpp +++ b/trunk/src/app/srs_app_rtc_server.cpp @@ -337,7 +337,7 @@ srs_error_t SrsRtcServer::do_create_session( } } else { if ((err = session->add_player(req, remote_sdp, local_sdp)) != srs_success) { - return srs_error_wrap(err, "add publisher"); + return srs_error_wrap(err, "add player"); } } @@ -397,7 +397,7 @@ srs_error_t SrsRtcServer::do_create_session( return err; } -srs_error_t SrsRtcServer::create_session2(SrsSdp& local_sdp, SrsRtcConnection** psession) +srs_error_t SrsRtcServer::create_session2(SrsRequest* req, SrsSdp& local_sdp, SrsRtcConnection** psession) { srs_error_t err = srs_success; @@ -406,8 +406,14 @@ srs_error_t SrsRtcServer::create_session2(SrsSdp& local_sdp, SrsRtcConnection** std::string local_ufrag = srs_random_str(8); SrsRtcConnection* session = new SrsRtcConnection(this); + // first add player for negotiate local sdp media info + if ((err = session->add_player2(req, local_sdp)) != srs_success) { + srs_freep(session); + return srs_error_wrap(err, "add player2"); + } *psession = session; + local_sdp.set_dtls_role("actpass"); local_sdp.set_ice_ufrag(local_ufrag); local_sdp.set_ice_pwd(local_pwd); local_sdp.set_fingerprint_algo("sha-256"); diff --git a/trunk/src/app/srs_app_rtc_server.hpp b/trunk/src/app/srs_app_rtc_server.hpp index 8ea233a24..1da9b831c 100644 --- a/trunk/src/app/srs_app_rtc_server.hpp +++ b/trunk/src/app/srs_app_rtc_server.hpp @@ -88,7 +88,7 @@ private: ); public: // We start offering, create_session2 to generate offer, setup_session2 to handle answer. - srs_error_t create_session2(SrsSdp& local_sdp, SrsRtcConnection** psession); + srs_error_t create_session2(SrsRequest* req, SrsSdp& local_sdp, SrsRtcConnection** psession); srs_error_t setup_session2(SrsRtcConnection* session, SrsRequest* req, const SrsSdp& remote_sdp); // Destroy the session from server. void destroy(SrsRtcConnection* session); diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index 5d98bc961..169ee1024 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -1207,7 +1207,9 @@ SrsMediaPayloadType SrsAudioPayload::generate_media_payload_type() media_payload_type.encoding_name_ = name_; media_payload_type.clock_rate_ = sample_; - media_payload_type.encoding_param_ = srs_int2str(channel_); + if (channel_ != 0) { + media_payload_type.encoding_param_ = srs_int2str(channel_); + } media_payload_type.rtcp_fb_ = rtcp_fbs_; std::ostringstream format_specific_param; @@ -1220,7 +1222,6 @@ SrsMediaPayloadType SrsAudioPayload::generate_media_payload_type() if (opus_param_.usedtx) { format_specific_param << ";usedtx=1"; } - media_payload_type.format_specific_param_ = format_specific_param.str(); return media_payload_type; @@ -1339,7 +1340,7 @@ int SrsRtcTrackDescription::get_rtp_extension_id(std::string uri) } } - return -1; + return 0; } SrsRtcTrackDescription* SrsRtcTrackDescription::copy()