推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习

测试环境搭建

Clion运行srs

详情请参考我的另一篇文章Windows11+wsl+clion调试SRS
![image.png](https://img-blog.csdnimg.cn/img_convert/4af6e1c0a0394f50fb9ebb45f68a3fe1.png#clientId=u325e4c65-4edd-4&from=paste&height=1142&id=u000229b7&margin=[object Object]&name=image.png&originHeight=1142&originWidth=1908&originalType=binary&ratio=1&size=299871&status=done&style=none&taskId=u5e833296-b4c2-4b57-abe0-c3295f1b042&width=1908)

goland运行signaling

srs有自带一个webrtc的信令服务器使用go语言编写的,测试可以使用,如果实际生产环境不推荐使用。其源码位于srs/trunk/3rdparty/signaling。使用goland打开,然后找到main.go运行即可。
推荐将其输出目录更改到当前目录,方便更改前端代码
![image.png](https://img-blog.csdnimg.cn/img_convert/1f4a52422cc43e47e7a4ad53187c9abe.png#clientId=u325e4c65-4edd-4&from=paste&height=677&id=u8485e6d8&margin=[object Object]&name=image.png&originHeight=677&originWidth=1044&originalType=binary&ratio=1&size=60419&status=done&style=none&taskId=u539779be-a745-4041-9ebc-a61bee54716&width=1044)
运行后如图
![image.png](https://img-blog.csdnimg.cn/img_convert/b3abbd26c640774ee6a437e86cde9249.png#clientId=u325e4c65-4edd-4&from=paste&height=1196&id=u83caef91&margin=[object Object]&name=image.png&originHeight=1196&originWidth=1920&originalType=binary&ratio=1&size=317595&status=done&style=none&taskId=ud5b158f3-3814-4d09-a41e-78eb3688203&width=1920)

访问demo前端

信令有运行了一个web服务器,其端口为1989,所以我们直接访问1989即可,注意如果使用ip访问由于谷歌浏览器的限制必须要使用https,如果使用http我们需要将其加入到白名单中。

  1. 在浏览器中输入chrome://flags
  2. 找到**Insecure origins treated as secure**将白名单的url添加并设置为enabled

![image.png](https://img-blog.csdnimg.cn/img_convert/98523879595a3bd502f05a0e842ececa.png#clientId=u325e4c65-4edd-4&from=paste&height=518&id=u49775d81&margin=[object Object]&name=image.png&originHeight=518&originWidth=1502&originalType=binary&ratio=1&size=76804&status=done&style=none&taskId=u587163a2-1f6f-4eef-b022-48beeb0957e&width=1502)
然后访问localhost:1989ip:1989选择一对一通话进入,注意这里如果使用wsl的话需要将srs的ip设置成wsl的ip,然后点击开始通话就可以通话了。
![image.png](https://img-blog.csdnimg.cn/img_convert/31130fa85be1ace3229715cbe7457dd6.png#clientId=u325e4c65-4edd-4&from=paste&height=492&id=u4c07b779&margin=[object Object]&name=image.png&originHeight=492&originWidth=1302&originalType=binary&ratio=1&size=155948&status=done&style=none&taskId=u3f6e8263-8362-488a-9da4-c7f5cb880e1&width=1302)

WebRTC转rtmp

webrtc转rtmp主要是:

  • 编码转化,webrtc使用的音频编码是Opus,而rtmp使用的是aac则需要将opus转成aac
  • 协议转化,将RTP转RTMP封装

注:SRS目前在高码率转化下后RTMP会卡顿:https://github.com/ossrs/srs/issues/2677

WebRTC推流流程

在这里插入图片描述

开启http监听listen_api


srs_error_t SrsRtcServer::listen_api()
{
    srs_error_t err = srs_success;

    // TODO: FIXME: Fetch api from hybrid manager, not from SRS.
    SrsHttpServeMux* http_api_mux = _srs_hybrid->srs()->instance()->api_server();
	
    if ((err = http_api_mux->handle("/rtc/v1/play/", new SrsGoApiRtcPlay(this))) != srs_success) {
        return srs_error_wrap(err, "handle play");
    }

    if ((err = http_api_mux->handle("/rtc/v1/publish/", new SrsGoApiRtcPublish(this))) != srs_success) {
        return srs_error_wrap(err, "handle publish");
    }
		...

    return err;
}

src/app/srs_app_rtc_api.cpp大约331行SrsGoApiRtcPublish::do_serve_http:处理客户端请求的SDP,并创建RTC连接(SrsRtcConnection)

srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, SrsJsonObject* res)
{
    srs_error_t err = srs_success;

    ...
   	 // 解析SDP
    if ((err = ruc.remote_sdp_.parse(remote_sdp_str)) != srs_success) {
        return srs_error_wrap(err, "parse sdp failed: %s", remote_sdp_str.c_str());
    }

    if ((err = check_remote_sdp(ruc.remote_sdp_)) != srs_success) {
        return srs_error_wrap(err, "remote sdp check failed");
    }
	
    // 设置响应SDP
    SrsSdp local_sdp;

    // Config for SDP and session.
    local_sdp.session_config_.dtls_role = _srs_config->get_rtc_dtls_role(ruc.req_->vhost);
    local_sdp.session_config_.dtls_version = _srs_config->get_rtc_dtls_version(ruc.req_->vhost);

    // Whether enabled.
    bool server_enabled = _srs_config->get_rtc_server_enabled();
    bool rtc_enabled = _srs_config->get_rtc_enabled(ruc.req_->vhost);
    if (server_enabled && !rtc_enabled) {
        srs_warn("RTC disabled in vhost %s", ruc.req_->vhost.c_str());
    }
    if (!server_enabled || !rtc_enabled) {
        return srs_error_new(ERROR_RTC_DISABLED, "Disabled server=%d, rtc=%d, vhost=%s",
            server_enabled, rtc_enabled, ruc.req_->vhost.c_str());
    }

    // Whether RTC stream is active.
    bool is_rtc_stream_active = false;
    if (true) {
        SrsRtcSource* source = _srs_rtc_sources->fetch(ruc.req_);
        is_rtc_stream_active = (source && !source->can_publish());
    }

    // For RTMP to RTC, fail if disabled and RTMP is active, see https://github.com/ossrs/srs/issues/2728
    if (!is_rtc_stream_active && !_srs_config->get_rtc_from_rtmp(ruc.req_->vhost)) {
        SrsLiveSource* rtmp = _srs_sources->fetch(ruc.req_);
        if (rtmp && !rtmp->inactive()) {
            return srs_error_new(ERROR_RTC_DISABLED, "Disabled rtmp_to_rtc of %s, see #2728", ruc.req_->vhost.c_str());
        }
    }
	
    // 创建RTC会话
    SrsRtcConnection* session = NULL;
    if ((err = server_->create_session(&ruc, local_sdp, &session)) != srs_success) {
        return srs_error_wrap(err, "create session, dtls=%u, srtp=%u, eip=%s", ruc.dtls_, ruc.srtp_, eip.c_str());
    }

    ...

    return err;
}

src/app/srs_app_rtc.cpp大约53行SrsRtcServer::do_create_session

srs_error_t SrsRtcServer::do_create_session(SrsRtcUserConfig* ruc, SrsSdp& local_sdp, SrsRtcConnection* session)
{
    srs_error_t err = srs_success;

    SrsRequest* req = ruc->req_;

    // first add publisher/player for negotiate sdp media info
    if (ruc->publish_) {
        // 创建推流
        if ((err = session->add_publisher(ruc, local_sdp)) != srs_success) {
            return srs_error_wrap(err, "add publisher");
        }
    } else {
        if ((err = session->add_player(ruc, local_sdp)) != srs_success) {
            return srs_error_wrap(err, "add player");
        }
    }

    // All tracks default as inactive, so we must enable them.
    session->set_all_tracks_status(req->get_stream_url(), ruc->publish_, true);

    std::string local_pwd = srs_random_str(32);
    std::string local_ufrag = "";
    // TODO: FIXME: Rename for a better name, it's not an username.
    std::string username = "";
    while (true) {
        local_ufrag = srs_random_str(8);

        username = local_ufrag + ":" + ruc->remote_sdp_.get_ice_ufrag();
        if (!_srs_rtc_manager->find_by_name(username)) {
            break;
        }
    }

    local_sdp.set_ice_ufrag(local_ufrag);
    local_sdp.set_ice_pwd(local_pwd);
    local_sdp.set_fingerprint_algo("sha-256");
    local_sdp.set_fingerprint(_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
  1. 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
<unknown> 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
<unknown> 0x000055555613c0c0
<unknown> 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
  1. 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
<unknown> 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
<unknown> 0x000055555613c0c0
<unknown> 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;
}
  1. 音频转码 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
<unknown> 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
<unknown> 0x000055555613c0c0
<unknown> 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
  1. 音频包分发 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
<unknown> 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
<unknown> 0x000055555613c0c0
<unknown> 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)
{
    srs_error_t err = srs_success;

    // to common message.
    uint32_t ts = pkt->get_avsync_time();
    if (is_first_audio) {
        int header_len = 0;
        uint8_t* header = NULL;
        codec_->aac_codec_header(&header, &header_len);

        SrsCommonMessage out_rtmp;
        packet_aac(&out_rtmp, (char *)header, header_len, ts, is_first_audio);

        if ((err = source_->on_audio(&out_rtmp)) != srs_success) { //接收
            return srs_error_wrap(err, "source on audio");
        }

        is_first_audio = false;
    }

    std::vector<SrsAudioFrame *> out_pkts;
    SrsRtpRawPayload *payload = dynamic_cast<SrsRtpRawPayload *>(pkt->payload());

    SrsAudioFrame frame;
    frame.add_sample(payload->payload, payload->nn_payload);
    frame.dts = ts;
    frame.cts = 0;

    err = codec_->transcode(&frame, out_pkts); // 转码
    if (err != srs_success) {
        return err;
    }

    for (std::vector<SrsAudioFrame *>::iterator it = out_pkts.begin(); it != out_pkts.end(); ++it) {
        SrsCommonMessage out_rtmp;
        out_rtmp.header.timestamp = (*it)->dts;
        packet_aac(&out_rtmp, (*it)->samples[0].bytes, (*it)->samples[0].size, ts, is_first_audio);

        if ((err = source_->on_audio(&out_rtmp)) != srs_success) { //转码后的数据
            err = srs_error_wrap(err, "source on audio");
            break;
        }
    }
    codec_->free_frames(out_pkts);

    return err;
}
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐