local_sdp.set\_fingerprint\_algo("sha-256");
local_sdp.set\_fingerprint(_srs_rtc_dtls_certificate->get\_fingerprint());
// We allows to mock the eip of server.
if (true) {
int listen_port = _srs_config->get\_rtc\_server\_listen();
set<string> candidates = discover\_candidates(ruc);
for (set<string>::iterator it = candidates.begin(); it != candidates.end(); ++it) {
string hostname; int port = listen_port;
srs\_parse\_hostport(\*it, hostname,port);
local_sdp.add\_candidate(hostname, port, "host");
}
vector<string> v = vector<string>(candidates.begin(), candidates.end());
srs\_trace("RTC: Use candidates %s", srs\_join\_vector\_string(v, ", ").c\_str());
}
// Setup the negotiate DTLS by config.
local_sdp.session_negotiate_ = local_sdp.session_config_;
// Setup the negotiate DTLS role.
if (ruc->remote_sdp_.get\_dtls\_role() == "active") {
local_sdp.session_negotiate_.dtls_role = "passive";
} else if (ruc->remote_sdp_.get\_dtls\_role() == "passive") {
local_sdp.session_negotiate_.dtls_role = "active";
} else if (ruc->remote_sdp_.get\_dtls\_role() == "actpass") {
local_sdp.session_negotiate_.dtls_role = local_sdp.session_config_.dtls_role;
} else {
// @see: https://tools.ietf.org/html/rfc4145#section-4.1
// The default value of the setup attribute in an offer/answer exchange
// is 'active' in the offer and 'passive' in the answer.
local_sdp.session_negotiate_.dtls_role = "passive";
}
local_sdp.set\_dtls\_role(local_sdp.session_negotiate_.dtls_role);
session->set\_remote\_sdp(ruc->remote_sdp_);
// We must setup the local SDP, then initialize the session object.
session->set\_local\_sdp(local_sdp);
session->set\_state(WAITING_STUN);
// Before session initialize, we must setup the local SDP.
if ((err = session->initialize(req, ruc->dtls_, ruc->srtp_, username)) != srs_success) {
return srs\_error\_wrap(err, "init");
}
// We allows username is optional, but it never empty here.
_srs_rtc_manager->add\_with\_name(username, session);
return err;
}
src/app/srs\_app\_rtc\_conn.cpp大约1970行 SrsRtcConnection::add\_publisher 进行媒体协商,并创建SrsRtcSource对象和SrsRtcPublisherStream对象
srs_error_t SrsRtcConnection::add_publisher(SrsRtcUserConfig* ruc, SrsSdp& local_sdp) { srs_error_t err = srs_success;
SrsRequest\* req = ruc->req_;
SrsRtcSourceDescription\* stream_desc = new SrsRtcSourceDescription();
SrsAutoFree(SrsRtcSourceDescription, stream_desc);
// 媒体协商
// TODO: FIXME: Change to api of stream desc.
if ((err = negotiate\_publish\_capability(ruc, stream_desc)) != srs_success) {
return srs\_error\_wrap(err, "publish negotiate");
}
//生成响应SDP
if ((err = generate\_publish\_local\_sdp(req, local_sdp, stream_desc, ruc->remote_sdp_.is\_unified())) != srs_success) {
return srs\_error\_wrap(err, "generate local sdp");
}
SrsRtcSource\* source = NULL;
//创建SrsRtcSource对象
if ((err = _srs_rtc_sources->fetch\_or\_create(req, &source)) != srs_success) {
return srs\_error\_wrap(err, "create source");
}
// When SDP is done, we set the stream to create state, to prevent multiple publisher.
// @note Here, we check the stream again.
if (!source->can\_publish()) {
return srs\_error\_new(ERROR_RTC_SOURCE_BUSY, "stream %s busy", req->get\_stream\_url().c\_str());
}
source->set\_stream\_created();
// Apply the SDP to source.
source->set\_stream\_desc(stream_desc);
// 创建推流对象用于接收流
// TODO: FIXME: What happends when error?
if ((err = create\_publisher(req, stream_desc)) != srs_success) {
return srs\_error\_wrap(err, "create publish");
}
return err;
}
src/app/srs\_app\_rtc\_conn.cpp大约3569行 SrsRtcConnection::create\_publisher 创建推流对象,用于接收流
srs_error_t SrsRtcConnection::create_publisher(SrsRequest* req, SrsRtcSourceDescription* stream_desc) { srs_error_t err = srs_success;
srs\_assert(stream_desc);
// Ignore if exists.
if(publishers_.end() != publishers_.find(req->get\_stream\_url())) {
return err;
}
// 创建推流对象并初始化
SrsRtcPublishStream\* publisher = new SrsRtcPublishStream(this, _srs_context->get\_id());
if ((err = publisher->initialize(req, stream_desc)) != srs_success) {
srs\_freep(publisher);
return srs\_error\_wrap(err, "rtc publisher init");
}
publishers_[req->get\_stream\_url()] = publisher;
...
// If DTLS done, start the publisher. Because maybe create some publishers after DTLS done.
// For example, for single PC, we maybe start publisher when create it, because DTLS is done.
if(ESTABLISHED == state()) {
if(srs_success != (err = publisher->start())) { //启动流接收
return srs\_error\_wrap(err, "start publisher");
}
}
return err;
}
src/app/srs\_app\_rtc\_conn.cpp大约1217行 SrsRtcPublishStream::start
srs_error_t SrsRtcPublishStream::start() { srs_error_t err = srs_success;
if (is_started) {
return err;
}
if ((err = source->on\_publish()) != srs_success) {
return srs\_error\_wrap(err, "on publish");
}
if ((err = pli_worker_->start()) != srs_success) {
return srs\_error\_wrap(err, "start pli worker");
}
if (_srs_rtc_hijacker) {
if ((err = _srs_rtc_hijacker->on\_start\_publish(session_, this, req_)) != srs_success) {
return srs\_error\_wrap(err, "on start publish");
}
}
// update the statistic when client discoveried.
SrsStatistic\* stat = SrsStatistic::instance();
if ((err = stat->on\_client(cid_.c\_str(), req_, session_, SrsRtcConnPublish)) != srs_success) {
return srs\_error\_wrap(err, "rtc: stat client");
}
is_started = true;
return err;
}
src/app/srs\_app\_rtc\_source.cpp大约在518行SrsRtcSource::on\_publish
srs_error_t SrsRtcSource::on_publish() { srs_error_t err = srs_success;
// update the request object.
srs\_assert(req);
// For RTC, DTLS is done, and we are ready to deliver packets.
// @note For compatible with RTMP, we also set the is\_created\_, it MUST be created here.
is_created_ = true;
is_delivering_packets_ = true;
// Notify the consumers about stream change event.
if ((err = on\_source\_changed()) != srs_success) {
return srs\_error\_wrap(err, "source id change");
}
// If bridge to other source, handle event and start timer to request PLI.
if (bridger_) {
if ((err = bridger_->on\_publish()) != srs_success) {
return srs\_error\_wrap(err, "bridger on publish");
}
// The PLI interval for RTC2RTMP.
pli_for_rtmp_ = _srs_config->get\_rtc\_pli\_for\_rtmp(req->vhost);
// @see SrsRtcSource::on\_timer()
_srs_hybrid->timer100ms()->subscribe(this);
}
SrsStatistic\* stat = SrsStatistic::instance();
stat->on\_stream\_publish(req, _source_id.c\_str());
return err;
}
### WebRTC转RTMP
断点:
1. srs\_app\_source.cpp:1847 SrsLiveSource::SrsLiveSource()
SrsLiveSource::SrsLiveSource srs_app_source.cpp:1847 SrsLiveSourceManager::fetch_or_create srs_app_source.cpp:1734 SrsRtcPublishStream::initialize srs_app_rtc_conn.cpp:1196 SrsRtcConnection::create_publisher srs_app_rtc_conn.cpp:3582 SrsRtcConnection::add_publisher srs_app_rtc_conn.cpp:2008 SrsRtcServer::do_create_session srs_app_rtc_server.cpp:545 SrsRtcServer::create_session srs_app_rtc_server.cpp:526 SrsGoApiRtcPublish::do_serve_http srs_app_rtc_api.cpp:457 SrsGoApiRtcPublish::serve_http srs_app_rtc_api.cpp:323 SrsHttpServeMux::serve_http srs_http_stack.cpp:727 SrsHttpCorsMux::serve_http srs_http_stack.cpp:875 SrsHttpConn::process_request srs_app_http_conn.cpp:233 SrsHttpConn::process_requests srs_app_http_conn.cpp:206 SrsHttpConn::do_cycle srs_app_http_conn.cpp:160 SrsHttpConn::cycle srs_app_http_conn.cpp:105 SrsFastCoroutine::cycle srs_app_st.cpp:272 SrsFastCoroutine::pfn srs_app_st.cpp:287 _st_thread_main sched.c:363 st_thread_create sched.c:694
2. srs\_app\_souce.cpp:1273 SrsRtmpFromRtcBridger::SrsRtmpFromRtcBridger
SrsRtmpFromRtcBridger::SrsRtmpFromRtcBridger srs_app_rtc_source.cpp:1273 SrsRtcPublishStream::initialize srs_app_rtc_conn.cpp:1204 SrsRtcConnection::create_publisher srs_app_rtc_conn.cpp:3582 SrsRtcConnection::add_publisher srs_app_rtc_conn.cpp:2008 SrsRtcServer::do_create_session srs_app_rtc_server.cpp:545 SrsRtcServer::create_session srs_app_rtc_server.cpp:526 SrsGoApiRtcPublish::do_serve_http srs_app_rtc_api.cpp:457 SrsGoApiRtcPublish::serve_http srs_app_rtc_api.cpp:323 SrsHttpServeMux::serve_http srs_http_stack.cpp:727 SrsHttpCorsMux::serve_http srs_http_stack.cpp:875 SrsHttpConn::process_request srs_app_http_conn.cpp:233 SrsHttpConn::process_requests srs_app_http_conn.cpp:206 SrsHttpConn::do_cycle srs_app_http_conn.cpp:160 SrsHttpConn::cycle srs_app_http_conn.cpp:105 SrsFastCoroutine::cycle srs_app_st.cpp:272 SrsFastCoroutine::pfn srs_app_st.cpp:287 _st_thread_main sched.c:363 st_thread_create sched.c:694
fetch\_or\_create创建了rtmp对象,SrsRtmpFromRtcBridger将其从rtc转化成rtmp,其转化过程为
SrsRtcSource -> SrsRtmpFromRtcBridger -> SrsLiveSource
bool rtc_to_rtmp = _srs_config->get\_rtc\_to\_rtmp(req_->vhost);
if (rtc_to_rtmp) {
if ((err = _srs_sources->fetch\_or\_create(r, _srs_hybrid->srs()->instance(), &rtmp)) != srs_success) {
return srs\_error\_wrap(err, "create source");
}
// Disable GOP cache for RTC2RTMP bridger, to keep the streams in sync,
// especially for stream merging.
rtmp->set\_cache(false);
SrsRtmpFromRtcBridger \*bridger = new SrsRtmpFromRtcBridger(rtmp);
if ((err = bridger->initialize(r)) != srs_success) {
srs\_freep(bridger);
return srs\_error\_wrap(err, "create bridger");
}
//设置桥接器
source->set\_bridger(bridger);
}
然后我们再在下面打下断点
1. srs\_app\_rtc\_source.cpp大约1560 SrsRtmpFromRtcBridger::packet\_video\_rtmp
SrsRtmpFromRtcBridger::packet_video_rtmp srs_app_rtc_source.cpp:1561 SrsRtmpFromRtcBridger::packet_video srs_app_rtc_source.cpp:1451 SrsRtmpFromRtcBridger::on_rtp srs_app_rtc_source.cpp:1347 SrsRtcSource::on_rtp srs_app_rtc_source.cpp:632 SrsRtcVideoRecvTrack::on_rtp srs_app_rtc_source.cpp:2520 SrsRtcPublishStream::do_on_rtp_plaintext srs_app_rtc_conn.cpp:1451 SrsRtcPublishStream::on_rtp_plaintext srs_app_rtc_conn.cpp:1419 SrsRtcPublishStream::on_rtp srs_app_rtc_conn.cpp:1386 SrsRtcConnection::on_rtp srs_app_rtc_conn.cpp:2276 SrsRtcServer::on_udp_packet srs_app_rtc_server.cpp:462 SrsUdpMuxListener::cycle srs_app_listener.cpp:620 SrsFastCoroutine::cycle srs_app_st.cpp:272 SrsFastCoroutine::pfn srs_app_st.cpp:287 _st_thread_main sched.c:363 st_thread_create sched.c:694 SrsFileLog::info srs_app_log.cpp:118 0x00005555560ed6f0 __libc_calloc 0x00007ffff7af3d15 st_cond_new sync.c:157 st_thread_create sched.c:702 SrsFastCoroutine::start srs_app_st.cpp:180 SrsSTCoroutine::start srs_app_st.cpp:95 SrsResourceManager::start srs_app_conn.cpp:72 0x000055555613c0c0 0x00007fffffffe060 SrsWaitGroup::wait srs_app_st.cpp:328 SrsHybridServer::run srs_app_hybrid.cpp:281 run_hybrid_server srs_main_server.cpp:477 run_directly_or_daemon srs_main_server.cpp:407 do_main srs_main_server.cpp:198 main srs_main_server.cpp:207 __libc_start_main 0x00007ffff7a7c0b3 _start 0x0000555555809a1e
2. srs\_app\_rtc\_source.cpp大约1465 SrsRtmpFromRtcBridger::packet\_video\_key\_frame
SrsRtmpFromRtcBridger::packet_video_key_frame srs_app_rtc_source.cpp:1466 SrsRtmpFromRtcBridger::packet_video srs_app_rtc_source.cpp:1433 SrsRtmpFromRtcBridger::on_rtp srs_app_rtc_source.cpp:1347 SrsRtcSource::on_rtp srs_app_rtc_source.cpp:632 SrsRtcVideoRecvTrack::on_rtp srs_app_rtc_source.cpp:2520 SrsRtcPublishStream::do_on_rtp_plaintext srs_app_rtc_conn.cpp:1451 SrsRtcPublishStream::on_rtp_plaintext srs_app_rtc_conn.cpp:1419 SrsRtcPublishStream::on_rtp srs_app_rtc_conn.cpp:1386 SrsRtcConnection::on_rtp srs_app_rtc_conn.cpp:2276 SrsRtcServer::on_udp_packet srs_app_rtc_server.cpp:462 SrsUdpMuxListener::cycle srs_app_listener.cpp:620 SrsFastCoroutine::cycle srs_app_st.cpp:272 SrsFastCoroutine::pfn srs_app_st.cpp:287 _st_thread_main sched.c:363 st_thread_create sched.c:694 SrsFileLog::info srs_app_log.cpp:118 0x00005555560ed6f0 __libc_calloc 0x00007ffff7af3d15 st_cond_new sync.c:157 st_thread_create sched.c:702 SrsFastCoroutine::start srs_app_st.cpp:180 SrsSTCoroutine::start srs_app_st.cpp:95 SrsResourceManager::start srs_app_conn.cpp:72 0x000055555613c0c0 0x00007fffffffe060 SrsWaitGroup::wait srs_app_st.cpp:328 SrsHybridServer::run srs_app_hybrid.cpp:281 run_hybrid_server srs_main_server.cpp:477 run_directly_or_daemon srs_main_server.cpp:407 do_main srs_main_server.cpp:198 main srs_main_server.cpp:207 __libc_start_main 0x00007ffff7a7c0b3 _start 0x0000555555809a1e
srs_error_t SrsRtmpFromRtcBridger::packet_video_key_frame(SrsRtpPacket* pkt) { srs_error_t err = srs_success;
// TODO: handle sps and pps in 2 rtp packets
SrsRtpSTAPPayload\* stap_payload = dynamic\_cast<SrsRtpSTAPPayload\*>(pkt->payload());
if (stap_payload) {
SrsSample\* sps = stap_payload->get\_sps();
SrsSample\* pps = stap_payload->get\_pps();
if (NULL == sps || NULL == pps) {
return srs\_error\_new(ERROR_RTC_RTP_MUXER, "no sps or pps in stap-a rtp. sps: %p, pps:%p", sps, pps);
} else {
//type\_codec1 + avc\_type + composition time + fix header + count of sps + len of sps + sps + count of pps + len of pps + pps
int nb_payload = 1 + 1 + 3 + 5 + 1 + 2 + sps->size + 1 + 2 + pps->size;
SrsCommonMessage rtmp;
rtmp.header.initialize\_video(nb_payload, pkt->get\_avsync\_time(), 1);
rtmp.create\_payload(nb_payload);
rtmp.size = nb_payload;
SrsBuffer payload(rtmp.payload, rtmp.size);
//TODO: call api
payload.write\_1bytes(0x17);// type(4 bits): key frame; code(4bits): avc
payload.write\_1bytes(0x0); // avc\_type: sequence header
payload.write\_1bytes(0x0); // composition time
payload.write\_1bytes(0x0);
payload.write\_1bytes(0x0);
payload.write\_1bytes(0x01); // version
payload.write\_1bytes(sps->bytes[1]);
payload.write\_1bytes(sps->bytes[2]);
payload.write\_1bytes(sps->bytes[3]);
payload.write\_1bytes(0xff);
payload.write\_1bytes(0xe1);
payload.write\_2bytes(sps->size);
payload.write\_bytes(sps->bytes, sps->size);
payload.write\_1bytes(0x01);
payload.write\_2bytes(pps->size);
payload.write\_bytes(pps->bytes, pps->size);
if ((err = source_->on\_video(&rtmp)) != srs_success) {
return err;
}
}
}
if (-1 == rtp_key_frame_ts_) {
rtp_key_frame_ts_ = pkt->header.get\_timestamp();
header_sn_ = pkt->header.get\_sequence();
lost_sn_ = header_sn_ + 1;
// Received key frame and clean cache of old p frame pkts
clear\_cached\_video();
srs\_trace("set ts=%u, header=%hu, lost=%hu", (uint32\_t)rtp_key_frame_ts_, header_sn_, lost_sn_);
} else if (rtp_key_frame_ts_ != pkt->header.get\_timestamp()) {
//new key frame, clean cache
int64\_t old_ts = rtp_key_frame_ts_;
uint16\_t old_header_sn = header_sn_;
uint16\_t old_lost_sn = lost_sn_;
rtp_key_frame_ts_ = pkt->header.get\_timestamp();
header_sn_ = pkt->header.get\_sequence();
lost_sn_ = header_sn_ + 1;
clear\_cached\_video();
srs\_warn("drop old ts=%u, header=%hu, lost=%hu, set new ts=%u, header=%hu, lost=%hu",
(uint32\_t)old_ts, old_header_sn, old_lost_sn, (uint32\_t)rtp_key_frame_ts_, header_sn_, lost_sn_);
}
uint16\_t index = cache\_index(pkt->header.get\_sequence());
cache_video_pkts_[index].in_use = true;
srs\_freep(cache_video_pkts_[index].pkt);
cache_video_pkts_[index].pkt = pkt;
cache_video_pkts_[index].sn = pkt->header.get\_sequence();
cache_video_pkts_[index].ts = pkt->get\_avsync\_time();
cache_video_pkts_[index].rtp_ts = pkt->header.get\_timestamp();
int32\_t sn = lost_sn_;
uint16\_t tail_sn = 0;
if (srs\_rtp\_seq\_distance(header_sn_, pkt->header.get\_sequence()) < 0){
// When receive previous pkt in the same frame, update header sn;
header_sn_ = pkt->header.get\_sequence();
sn = find\_next\_lost\_sn(header_sn_, tail_sn);
} else if (lost_sn_ == pkt->header.get\_sequence()) {
sn = find\_next\_lost\_sn(lost_sn_, tail_sn);
}
if (-1 == sn) {
if (check\_frame\_complete(header_sn_, tail_sn)) {
if ((err = packet\_video\_rtmp(header_sn_, tail_sn)) != srs_success) {
err = srs\_error\_wrap(err, "fail to packet key frame");
}
}
} else if (-2 == sn) {
return srs\_error\_new(ERROR_RTC_RTP_MUXER, "video cache is overflow");
} else {
lost_sn_ = (uint16\_t)sn;
}
return err;
}
3. 音频转码 srs\_app\_rtc\_codec.cpp 大约156行 SrsAudioTranscoder::transcode
SrsAudioTranscoder::transcode srs_app_rtc_codec.cpp:157 SrsRtmpFromRtcBridger::transcode_audio srs_app_rtc_source.cpp:1388 SrsRtmpFromRtcBridger::on_rtp srs_app_rtc_source.cpp:1345 SrsRtcSource::on_rtp srs_app_rtc_source.cpp:632 SrsRtcAudioRecvTrack::on_rtp srs_app_rtc_source.cpp:2462 SrsRtcPublishStream::do_on_rtp_plaintext srs_app_rtc_conn.cpp:1446 SrsRtcPublishStream::on_rtp_plaintext srs_app_rtc_conn.cpp:1419 SrsRtcPublishStream::on_rtp srs_app_rtc_conn.cpp:1386 SrsRtcConnection::on_rtp srs_app_rtc_conn.cpp:2276 SrsRtcServer::on_udp_packet srs_app_rtc_server.cpp:462 SrsUdpMuxListener::cycle srs_app_listener.cpp:620 SrsFastCoroutine::cycle srs_app_st.cpp:272 SrsFastCoroutine::pfn srs_app_st.cpp:287 _st_thread_main sched.c:363 st_thread_create sched.c:694 SrsFileLog::info srs_app_log.cpp:118 0x00005555560ed6f0 __libc_calloc 0x00007ffff7af3d15 st_cond_new sync.c:157 st_thread_create sched.c:702 SrsFastCoroutine::start srs_app_st.cpp:180 SrsSTCoroutine::start srs_app_st.cpp:95 SrsResourceManager::start srs_app_conn.cpp:72 0x000055555613c0c0 0x00007fffffffe060 SrsWaitGroup::wait srs_app_st.cpp:328 SrsHybridServer::run srs_app_hybrid.cpp:281 run_hybrid_server srs_main_server.cpp:477 run_directly_or_daemon srs_main_server.cpp:407 do_main srs_main_server.cpp:198 main srs_main_server.cpp:207 __libc_start_main 0x00007ffff7a7c0b3 _start 0x0000555555809a1e
4. 音频包分发 srs\_app\_rtc\_source.cpp:1360 SrsRtmpFromRtcBridger::transcode\_audio
SrsRtmpFromRtcBridger::transcode_audio srs_app_rtc_source.cpp:1360 SrsRtmpFromRtcBridger::on_rtp srs_app_rtc_source.cpp:1345 SrsRtcSource::on_rtp srs_app_rtc_source.cpp:632 SrsRtcAudioRecvTrack::on_rtp srs_app_rtc_source.cpp:2462 SrsRtcPublishStream::do_on_rtp_plaintext srs_app_rtc_conn.cpp:1446 SrsRtcPublishStream::on_rtp_plaintext srs_app_rtc_conn.cpp:1419 SrsRtcPublishStream::on_rtp srs_app_rtc_conn.cpp:1386 SrsRtcConnection::on_rtp srs_app_rtc_conn.cpp:2276 SrsRtcServer::on_udp_packet srs_app_rtc_server.cpp:462 SrsUdpMuxListener::cycle srs_app_listener.cpp:620 SrsFastCoroutine::cycle srs_app_st.cpp:272 SrsFastCoroutine::pfn srs_app_st.cpp:287 _st_thread_main sched.c:363 st_thread_create sched.c:694 SrsFileLog::info srs_app_log.cpp:118 0x00005555560ed6f0 __libc_calloc 0x00007ffff7af3d15 st_cond_new sync.c:157 st_thread_create sched.c:702 SrsFastCoroutine::start srs_app_st.cpp:180 SrsSTCoroutine::start srs_app_st.cpp:95 SrsResourceManager::start srs_app_conn.cpp:72 0x000055555613c0c0 0x00007fffffffe060 SrsWaitGroup::wait srs_app_st.cpp:328 SrsHybridServer::run srs_app_hybrid.cpp:281 run_hybrid_server srs_main_server.cpp:477 run_directly_or_daemon srs_main_server.cpp:407 do_main srs_main_server.cpp:198 main srs_main_server.cpp:207 __libc_start_main 0x00007ffff7a7c0b3 _start 0x0000555555809a1e
srs_error_t SrsRtmpFromRtcBridger::transcode_audio(SrsRtpPacket *pkt) {
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!