【owt】WebrtcNode,publish-SdpAnswer

erizo::WebRTCEvent

source/agent/webrtc/rtcConn/erizo/src/erizo/WebRtcConnection.h

/**
 * WebRTC Events
 */
enum WebRTCEvent {
  CONN_INITIAL = 101, CONN_STARTED = 102, CONN_GATHERED = 103, CONN_READY = 104, CONN_FINISHED = 105,
  CONN_CANDIDATE = 201, CONN_SDP = 202, CONN_SDP_PROCESSED = 203,
  CONN_FAILED = 500
};
WebRTC Events说明
CONN_INITIALWebrtcConnection对象创建后,需要外面手动调用init方法,该方法会回调notifyEvent,并传递事件为改枚举值,message和stream_id均为空值。
CONN_STARTED这个状态没有看到里面有明显调用的地方,有可能是保留的状态码
CONN_GATHEREDWebrtcConnection的createOffer或者第一次setRemoteSdp时启动自身ICE过程,ICE完成收集时,发送该通知。message为自己的sdp数据
CONN_READY当DTLS握手交互成功完成时,发送该通知
CONN_FINISHWebrtcConnection对象关闭,调用close时,发送该通知
CONN_CANDIDATE自身ICE获取到Candidate时,发送该通知。message为candidate信息
CONN_SDP-
CONN_SDP_PROCESSED处理remote sdp时,发送该通知。message为remote sdp
CONN_FAILEDICE失败,Dtls握手交互失败,均发送该通知。message为remote sdp

1. WrtcConnection.setupTransport——创建WrtcStream

const setupTransport = function (mid) {
    let rids = remoteSdp.rids(mid);
    const opSettings = operationMap.get(mid);
    const direction = (opSettings.sdpDirection === 'sendonly') ? 'in' : 'out';
    const simSsrcs = remoteSdp.getLegacySimulcast(mid);
    const trackSettings = remoteSdp.getMediaSettings(mid);
    const mediaType = remoteSdp.mediaType(mid);

    trackSettings.owner = owner;
    trackSettings.enableBWE = that.enableBWE;
    if (opSettings.finalFormat) {
      trackSettings[mediaType].format = opSettings.finalFormat;
      if (opSettings.finalFormat.codec === 'vp9' && simSsrcs) {
        // Legacy simulcast for VP9 SVC
        rids = null;
        trackSettings['video'].scalabilityMode = opSettings.scalabilityMode;
      }
    }

    if (rids) {
        ...
    } else {
        // 走这里的代码
      // No simulcast
      if (!trackMap.has(mid)) {
        // 1. Connection wrtc
        trackMap.set(mid, new WrtcStream(mid, wrtc, direction, trackSettings));
        // Set ssrc in local sdp for out direction
        // direct 是in
        if (direction === 'out') {
          ...
        }


          ///
        // 2. Connection wrtc
        // remoteSdp 是在processOffer 创建的对象,是客户端发送过来的
        wrtc.setRemoteSdp(remoteSdp.singleMediaSdp(mid).toString(), mid);
          ///


        // 3. Notify new track, 详细见小节 3.3, 3.4
        on_track({
          type: 'track-added',
          track: trackMap.get(mid),
          operationId: opSettings.operationId,
          mid: mid
        });
      } else {
        log.warn(`Conflict trackId ${mid} for ${wrtcId}`);
      }
    }

    return opSettings.operationId;
  };

2. Connection.setRemoteSdp

SdpInfo - singleMediaSdp,sdp :  v=0
o=- 9120114021792133801 2 IN IP4 127.0.0.1
s=-
t=0 0
a=msid-semantic: WMS MediaStream-40afcedd-368e-4d7b-98ea-902f224af377
a=group:BUNDLE 0
m=audio 9 UDP/TLS/RTP/SAVPF 111 110
c=IN IP4 0.0.0.0
a=rtpmap:111 opus/48000/2
a=rtpmap:110 telephone-event/48000
a=fmtp:111 minptime=10;useinbandfec=1
a=rtcp:9 IN IP4 0.0.0.0
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=setup:actpass
a=mid:0
a=msid:MediaStream-40afcedd-368e-4d7b-98ea-902f224af377 AudioTrack-412bcd09-1664-4066-8c37-17ccbfd19a0c
a=sendonly
a=ice-ufrag:3rxD
a=ice-pwd:IeUlIlJ+z4sZc3lxPsGEbRM2
a=fingerprint:sha-256 69:89:D4:18:D7:C2:31:AD:E4:9E:E4:80:35:1F:F7:A8:87:10:F7:F0:16:EB:8E:9C:57:2C:EA:45:5D:3D:1C:AE
a=ice-options:trickle
a=ssrc:802691093 cname:uEzfXLwBLsCq5krU
a=ssrc:802691093 msid:MediaStream-40afcedd-368e-4d7b-98ea-902f224af377 AudioTrack-412bcd09-1664-4066-8c37-17ccbfd19a0c
a=ssrc:802691093 mslabel:MediaStream-40afcedd-368e-4d7b-98ea-902f224af377
a=ssrc:802691093 label:AudioTrack-412bcd09-1664-4066-8c37-17ccbfd19a0c
a=rtcp-mux
// streamId = mid
setRemoteSdp(sdp, streamId) {
    // webRtcConnection wrtc
    this.wrtc.setRemoteSdp(sdp, streamId || this.id);
  }

2.1 NAN_METHOD(WebRtcConnection::setRemoteSdp)

NAN_METHOD(WebRtcConnection::setRemoteSdp) {
  WebRtcConnection* obj = Nan::ObjectWrap::Unwrap<WebRtcConnection>(info.Holder());
  std::shared_ptr<erizo::WebRtcConnection> me = obj->me;
  if (!me) {
    return;
  }

  std::string sdp = getString(info[0]);
  std::string stream_id = getString(info[1]);
  // erizo::WebRtcConnection me
  // sdp- remotesdp, single; stream_id- mid
  bool r = me->setRemoteSdp(sdp, stream_id);

  info.GetReturnValue().Set(Nan::New(r));
}

2.2 WebRtcConnection::setRemoteSdp

把remote sdp 保存到WebRtcConnection

source/agent/webrtc/rtcConn/erizo/src/erizo/WebRtcConnection.cpp

// streamId = mid
bool WebRtcConnection::setRemoteSdp(const std::string &sdp, std::string stream_id) {
  asyncTask([sdp, stream_id] (std::shared_ptr<WebRtcConnection> connection) {
    ELOG_DEBUG("%s message: setting remote SDP", connection->toLog());
    if (!connection->sending_) {
      return;
    }
    // remote_sdp_ 赋值
    connection->remote_sdp_->initWithSdp(sdp, "");
    // WebRtcConnection, 这里是异步调用
    connection->processRemoteSdp(stream_id);
  });
  return true;
}

2.3 erizo::WebRtcConnection::processRemoteSdp——创建了DTLSTranSport

source/agent/webrtc/rtcConn/erizo/src/erizo/WebRtcConnection.cpp

  1. 创建dtls transport,start
    注意:first_remote_sdp_processed_ 默认是false, 再收到一个track,比如mid=0,处理了sdp后,first_remote_sdp_processed_ = true;
    接着如果mid=1的track,在调用processRemoteSdp,那么就不会走创建dtls的流程,而是直接跳到第二步。

  2. remote sdp 设置给对应的MediaStream

bool WebRtcConnection::processRemoteSdp(std::string stream_id) {
  ELOG_DEBUG("%s message: processing remote SDP", toLog());
  // update remote_sdp_'s ssrc map
  remote_sdp_->audio_ssrc_map = local_sdp_->audio_ssrc_map;
  remote_sdp_->video_ssrc_map = local_sdp_->video_ssrc_map;
  // 1. Update extensions
  local_sdp_->setOfferSdp(remote_sdp_);
  // 处理extension
  extension_processor_.setSdpInfo(local_sdp_);
  local_sdp_->updateSupportedExtensionMap(extension_processor_.getSupportedExtensionMap());

    // first_remote_sdp_processed_ 默认值是false
   // 注意:第一个mid =0 ,就是audio,processRemoteSdp ,
   // first_remote_sdp_processed_ = true;
   // 第二个mid =1 ,就是video, rocessRemoteSdp ,
   // 直接就return, 调用setRemoteSdpsToMediaStreams,不创建dtls
  if (first_remote_sdp_processed_) {
    setRemoteSdpsToMediaStreams(stream_id);
    return true;
  }

  // 音视频 是否公用一个peer connection, 这里是true
  bundle_ = remote_sdp_->isBundle;

  if (remote_sdp_->dtlsRole == ACTPASS) {
    local_sdp_->dtlsRole = ACTIVE;
  }

  audio_enabled_ = remote_sdp_->hasAudio;
  video_enabled_ = remote_sdp_->hasVideo;

  if (remote_sdp_->profile == SAVPF) {
    if (remote_sdp_->isFingerprint) {
      //  WebRtcConnection继承了TransportListener
      auto listener = std::dynamic_pointer_cast<TransportListener>(shared_from_this());
      // 走了这里的流程
      if (remote_sdp_->hasVideo || bundle_) {
        std::string username = remote_sdp_->getUsername(VIDEO_TYPE);
        std::string password = remote_sdp_->getPassword(VIDEO_TYPE);
        if (video_transport_.get() == nullptr) {
          // 走了这里流程,创建了DtlsTransport
          ELOG_DEBUG("%s message: Creating videoTransport, ufrag: %s, pass: %s",
                      toLog(), username.c_str(), password.c_str());
          video_transport_.reset(new DtlsTransport(VIDEO_TYPE, "video", connection_id_, bundle_, remote_sdp_->isRtcpMux,
                                                  listener, ice_config_ , username, password, false,
                                                  worker_, io_worker_));
          video_transport_->copyLogContextFrom(*this);
          video_transport_->start();
        } else {
          ELOG_DEBUG("%s message: Updating videoTransport, ufrag: %s, pass: %s",
                      toLog(), username.c_str(), password.c_str());
          video_transport_->getIceConnection()->setRemoteCredentials(username, password);
        }
      }
      if (!bundle_ && remote_sdp_->hasAudio) {
       ...
      }
    }
  }

  // CONN_GATHERED = 103
  if (this->getCurrentState() >= CONN_GATHERED) {
    if (!remote_sdp_->getCandidateInfos().empty()) {
      ELOG_DEBUG("%s message: Setting remote candidates after gathered", toLog());
      if (remote_sdp_->hasVideo) {
        video_transport_->setRemoteCandidates(remote_sdp_->getCandidateInfos(), bundle_);
      }
      if (!bundle_ && remote_sdp_->hasAudio) {
        audio_transport_->setRemoteCandidates(remote_sdp_->getCandidateInfos(), bundle_);
      }
    }
  }

  // 走了这里流程
  setRemoteSdpsToMediaStreams(stream_id);
  // 第一次处理sdp,防止重复创建transport
  first_remote_sdp_processed_ = true;
  return true;
}
2.3.1 DtlsTransport::DtlsTransport
  • 创建DtlsSocketContext, role是active-client

  • 创建LibNiceConnection

DtlsTransport::DtlsTransport(MediaType med, const std::string &transport_name, const std::string& connection_id,
                            bool bundle, bool rtcp_mux, std::weak_ptr<TransportListener> transport_listener,
                            const IceConfig& iceConfig, std::string username, std::string password,
                            bool isServer, std::shared_ptr<Worker> worker, std::shared_ptr<IOWorker> io_worker):
  Transport(med, transport_name, connection_id, bundle, rtcp_mux, transport_listener, iceConfig, worker, io_worker),
  readyRtp(false), readyRtcp(false), isServer_(isServer) {
    ELOG_DEBUG("%s message: constructor, transportName: %s, isBundle: %d", toLog(), transport_name.c_str(), bundle);
    dtlsRtp.reset(new DtlsSocketContext());

    int comps = 1;
    if (isServer_) {
     ...
    } else {
      ELOG_DEBUG("%s message: creating active-client", toLog());
      dtlsRtp->createClient();
      dtlsRtp->setDtlsReceiver(this);

      if (!rtcp_mux) {
        comps = 2;
        dtlsRtcp.reset(new DtlsSocketContext());
        dtlsRtcp->createClient();
        dtlsRtcp->setDtlsReceiver(this);
      }
    }
    iceConfig_.connection_id = connection_id_;
    iceConfig_.transport_name = transport_name;
    iceConfig_.media_type = med;
    iceConfig_.ice_components = comps;
    iceConfig_.username = username;
    iceConfig_.password = password;
    // We only use libnice connection
    ice_.reset(LibNiceConnection::create(iceConfig_, io_worker_));
    rtp_timeout_checker_.reset(new TimeoutChecker(this, dtlsRtp.get()));
    if (!rtcp_mux) {
      rtcp_timeout_checker_.reset(new TimeoutChecker(this, dtlsRtcp.get()));
    }
    ELOG_DEBUG("%s message: created", toLog());
  }
2.3.2 DtlsTransport::start
void DtlsTransport::start() {
   // LibNiceConnection ice_
  ice_->setIceListener(shared_from_this());
  ice_->copyLogContextFrom(*this);
  ELOG_DEBUG("%s message: starting ice", toLog());
  ice_->start();
}
2.3.3 LibNiceConnection::start()
void LibNiceConnection::start() {
    boost::mutex::scoped_lock lock(close_mutex_);
    if (this->checkIceState() != INITIAL) {
      return;
    }
    ELOG_DEBUG("%s message: creating Nice Agent", toLog());
    nice_debug_enable(FALSE);
    // Create a nice agent
    agent_ = lib_nice_->NiceAgentNew(context_);
    GValue controllingMode = { 0 };
    g_value_init(&controllingMode, G_TYPE_BOOLEAN);
    g_value_set_boolean(&controllingMode, false);
    g_object_set_property(G_OBJECT(agent_), "controlling-mode", &controllingMode);

    GValue checks = { 0 };
    g_value_init(&checks, G_TYPE_UINT);
    g_value_set_uint(&checks, 100);
    g_object_set_property(G_OBJECT(agent_), "max-connectivity-checks", &checks);


    if (ice_config_.stun_server.compare("") != 0 && ice_config_.stun_port != 0) {
      GValue val = { 0 }, val2 = { 0 };
      g_value_init(&val, G_TYPE_STRING);
      g_value_set_string(&val, ice_config_.stun_server.c_str());
      g_object_set_property(G_OBJECT(agent_), "stun-server", &val);

      g_value_init(&val2, G_TYPE_UINT);
      g_value_set_uint(&val2, ice_config_.stun_port);
      g_object_set_property(G_OBJECT(agent_), "stun-server-port", &val2);

      ELOG_DEBUG("%s message: setting stun, stun_server: %s, stun_port: %d",
                 toLog(), ice_config_.stun_server.c_str(), ice_config_.stun_port);
    }

    // Connect the signals
    g_signal_connect(G_OBJECT(agent_), "candidate-gathering-done",
        G_CALLBACK(cb_candidate_gathering_done), this);
    g_signal_connect(G_OBJECT(agent_), "component-state-changed",
        G_CALLBACK(cb_component_state_changed), this);
    g_signal_connect(G_OBJECT(agent_), "new-selected-pair",
        G_CALLBACK(cb_new_selected_pair), this);
    g_signal_connect(G_OBJECT(agent_), "new-candidate",
        G_CALLBACK(cb_new_candidate), this);

    // Create a new stream and start gathering candidates
    ELOG_DEBUG("%s message: adding stream, iceComponents: %d", toLog(), ice_config_.ice_components);
    lib_nice_->NiceAgentAddStream(agent_, ice_config_.ice_components);
    gchar *ufrag = NULL, *upass = NULL;
    lib_nice_->NiceAgentGetLocalCredentials(agent_, 1, &ufrag, &upass);
    ufrag_ = std::string(ufrag); g_free(ufrag);
    upass_ = std::string(upass); g_free(upass);

    // Set our remote credentials.  This must be done *after* we add a stream.
    if (ice_config_.username.compare("") != 0 && ice_config_.password.compare("") != 0) {
      ELOG_DEBUG("%s message: setting remote credentials in constructor, ufrag:%s, pass:%s",
                 toLog(), ice_config_.username.c_str(), ice_config_.password.c_str());
      this->setRemoteCredentials(ice_config_.username, ice_config_.password);
    }
    // Set Port Range: If this doesn't work when linking the file libnice.sym has to be modified to include this call
    if (ice_config_.min_port != 0 && ice_config_.max_port != 0) {
      ELOG_DEBUG("%s message: setting port range, min_port: %d, max_port: %d",
                 toLog(), ice_config_.min_port, ice_config_.max_port);
      lib_nice_->NiceAgentSetPortRange(agent_, (guint)1, (guint)1, (guint)ice_config_.min_port,
          (guint)ice_config_.max_port);
    }

    if (!ice_config_.network_interface.empty()) {
      const char* public_ip = lib_nice_->NiceInterfacesGetIpForInterface(ice_config_.network_interface.c_str());
      if (public_ip) {
        lib_nice_->NiceAgentAddLocalAddress(agent_, public_ip);
      }
    }

    if (ice_config_.ip_addresses.size() > 0) {
      for (const auto& ipAddress : ice_config_.ip_addresses) {
        lib_nice_->NiceAgentAddLocalAddress(agent_, ipAddress.c_str());
      }
    }

    if (ice_config_.turn_server.compare("") != 0 && ice_config_.turn_port != 0) {
      ELOG_DEBUG("%s message: configuring TURN, turn_server: %s , turn_port: %d, turn_username: %s, turn_pass: %s",
                 toLog(), ice_config_.turn_server.c_str(),
          ice_config_.turn_port, ice_config_.turn_username.c_str(), ice_config_.turn_pass.c_str());

      for (unsigned int i = 1; i <= ice_config_.ice_components ; i++) {
        lib_nice_->NiceAgentSetRelayInfo(agent_,
            1,
            i,
            ice_config_.turn_server.c_str(),     // TURN Server IP
            ice_config_.turn_port,               // TURN Server PORT
            ice_config_.turn_username.c_str(),   // Username
            ice_config_.turn_pass.c_str());       // Pass
      }
    }

    if (agent_) {
      for (unsigned int i = 1; i <= ice_config_.ice_components; i++) {
        lib_nice_->NiceAgentAttachRecv(agent_, 1, i, context_, reinterpret_cast<void*>(cb_nice_recv), this);
      }
    }
    ELOG_DEBUG("%s message: gathering, this: %p", toLog(), this);
    lib_nice_->NiceAgentGatherCandidates(agent_, 1);
}
2.3.4 cb_new_candidat
void cb_new_candidate(NiceAgent *agent, guint stream_id, guint component_id, gchar *foundation,
    gpointer user_data) {
  LibNiceConnection *conn = reinterpret_cast<LibNiceConnection*>(user_data);
  std::string found(foundation);
  conn->getCandidate(stream_id, component_id, found);
}
2.3.4.1 LibNiceConnection::getCandidate
void LibNiceConnection::getCandidate(uint stream_id, uint component_id, const std::string &foundation) {
  GSList* lcands = lib_nice_->NiceAgentGetLocalCandidates(agent_, stream_id, component_id);
  // We only want to get the new candidates
  if (candsDelivered_ <= g_slist_length(lcands)) {
    lcands = g_slist_nth(lcands, (candsDelivered_));
  }
  for (GSList* iterator = lcands; iterator; iterator = iterator->next) {
    char address[NICE_ADDRESS_STRING_LEN], baseAddress[NICE_ADDRESS_STRING_LEN];
    NiceCandidate *cand = reinterpret_cast<NiceCandidate*>(iterator->data);
    nice_address_to_string(&cand->addr, address);
    nice_address_to_string(&cand->base_addr, baseAddress);
    candsDelivered_++;
    if (strstr(address, ":") != NULL) {  // We ignore IPv6 candidates at this point
      continue;
    }
    CandidateInfo cand_info;
    cand_info.componentId = cand->component_id;
    cand_info.foundation = cand->foundation;
    cand_info.priority = cand->priority;
    cand_info.hostAddress = std::string(address);
    cand_info.hostPort = nice_address_get_port(&cand->addr);
    if (cand_info.hostPort == 0) {
      continue;
    }
    cand_info.mediaType = ice_config_.media_type;

    /*
     *    NICE_CANDIDATE_TYPE_HOST,
     *    NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE,
     *    NICE_CANDIDATE_TYPE_PEER_REFLEXIVE,
     *    NICE_CANDIDATE_TYPE_RELAYED,
     */
    switch (cand->type) {
      case NICE_CANDIDATE_TYPE_HOST:
        cand_info.hostType = HOST;
        break;
      case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
        cand_info.hostType = SRFLX;
        cand_info.rAddress = std::string(baseAddress);
        cand_info.rPort = nice_address_get_port(&cand->base_addr);
        break;
      case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
        cand_info.hostType = PRFLX;
        break;
      case NICE_CANDIDATE_TYPE_RELAYED:
        char turnAddres[NICE_ADDRESS_STRING_LEN];
        nice_address_to_string(&cand->turn->server, turnAddres);
        cand_info.hostType = RELAY;
        cand_info.rAddress = std::string(baseAddress);
        cand_info.rPort = nice_address_get_port(&cand->base_addr);
        break;
      default:
        break;
    }
    cand_info.netProtocol = "udp";
    cand_info.transProtocol = ice_config_.transport_name;
    cand_info.username = ufrag_;
    cand_info.password = upass_;
///
    // localCandidates->push_back(cand_info);
    if (auto listener = this->getIceListener().lock()) {
      listener->onCandidate(cand_info, this);
    }
  }
  // for nice_agent_get_local_candidates, the caller owns the returned GSList as well as the candidates
  // contained within it.
  // let's free everything in the list, as well as the list.
  g_slist_free_full(lcands, (GDestroyNotify)&nice_candidate_free);
}
2.3.4.2 DtlsTransport:onCandidate
void DtlsTransport::onCandidate(const CandidateInfo &candidate, IceConnection *conn) {
  if (auto listener = getTransportListener().lock()) {
    listener->onCandidate(candidate, this);
  }
}
2.3.4.3 WebRtcConnection::onCandidate
2023-04-26 21:54:06,360  - DEBUG: WebRtcConnection - 
id: cb8fcfb93f174c24862feaa38915111a,  
message: Discovered New Candidate, 
candidate: a=candidate:1 1 udp 2013266431 192.168.221.62 41095 typ host
void WebRtcConnection::onCandidate(const CandidateInfo& cand, Transport *transport) {
  std::string sdp = local_sdp_->addCandidate(cand);
  ELOG_DEBUG("%s message: Discovered New Candidate, candidate: %s", toLog(), sdp.c_str());
  // 目前这里trickle_enabled_ = false, 所以2.3.4.5 不会往下走了 
  if (trickle_enabled_) {
    if (!bundle_) {
      std::string object = this->getJSONCandidate(transport->transport_name, sdp);
      maybeNotifyWebRtcConnectionEvent(CONN_CANDIDATE, object);
    } else {
      if (remote_sdp_->hasAudio) {
        std::string object = this->getJSONCandidate("audio", sdp);
        maybeNotifyWebRtcConnectionEvent(CONN_CANDIDATE, object);
      }
      if (remote_sdp_->hasVideo) {
        std::string object2 = this->getJSONCandidate("video", sdp);
        maybeNotifyWebRtcConnectionEvent(CONN_CANDIDATE, object2);
      }
    }
  }
}
2.3.4.4 CONN_CANDIDATE = 201——这里不会通知到js
2.3.4.5 maybeNotifyWebRtcConnectionEvent

参考2.7

2.3.5 cb_candidate_gathering_done
void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer user_data) {
  LibNiceConnection *conn = reinterpret_cast<LibNiceConnection*>(user_data);
  conn->gatheringDone(stream_id);
}
2.3.5.1 LibNiceConnection::gatheringDone
void LibNiceConnection::gatheringDone(uint stream_id) {
  ELOG_DEBUG("%s message: gathering done, stream_id: %u", toLog(), stream_id);
  updateIceState(IceState::CANDIDATES_RECEIVED);
}
2.3.5.2 IceConnection::updateIceState
void IceConnection::updateIceState(IceState state) {
  if (state <= ice_state_) {
    if (state != IceState::READY)
      ELOG_WARN("%s message: unexpected ice state transition, iceState: %s,  newIceState: %s",
                 toLog(), iceStateToString(ice_state_).c_str(), iceStateToString(state).c_str());
    return;
  }

  ELOG_INFO("%s message: iceState transition, ice_config_.transport_name: %s, iceState: %s, newIceState: %s, this: %p",
             toLog(), ice_config_.transport_name.c_str(),
             iceStateToString(ice_state_).c_str(), iceStateToString(state).c_str(), this);
  this->ice_state_ = state;
  switch (ice_state_) {
    case IceState::FINISHED:
      return;
    case IceState::FAILED:
      ELOG_WARN("%s message: Ice Failed", toLog());
      break;

    case IceState::READY:
    case IceState::CANDIDATES_RECEIVED:
      break;
    default:
      break;
  }

  // Important: send this outside our state lock.  Otherwise, serious risk of deadlock.
  if (auto listener = this->listener_.lock()) {
    listener->updateIceState(state, this);
  }
}
2.3.5.3 DtlsTransport::updateIceState
void DtlsTransport::updateIceState(IceState state, IceConnection *conn) {
  std::weak_ptr<Transport> weak_transport = Transport::shared_from_this();
  worker_->task([weak_transport, state, conn, this]() {
    if (auto transport = weak_transport.lock()) {
      updateIceStateSync(state, conn);
    }
  });
}
2.3.5.4 DtlsTransport::updateIceStateSync
2023-04-26 21:54:06,360  - DEBUG: DtlsTransport - 
id: cb8fcfb93f174c24862feaa38915111a,  
message:IceState, transportName: video, state: 1, isBundle: 1
void DtlsTransport::updateIceStateSync(IceState state, IceConnection *conn) {
  if (!running_) {
    return;
  }
  ELOG_DEBUG("%s message:IceState, transportName: %s, state: %d, isBundle: %d",
             toLog(), transport_name.c_str(), state, bundle_);
  if (state == IceState::INITIAL && this->getTransportState() != TRANSPORT_STARTED) {
    updateTransportState(TRANSPORT_STARTED);
  } else if (state == IceState::CANDIDATES_RECEIVED && this->getTransportState() != TRANSPORT_GATHERED) {
    // 走这里的流程   
    updateTransportState(TRANSPORT_GATHERED);
  } else if (state == IceState::FAILED) {
    ELOG_DEBUG("%s message: Ice Failed", toLog());
    running_ = false;
    updateTransportState(TRANSPORT_FAILED);
  } else if (state == IceState::READY) {
    if (!isServer_ && dtlsRtp && !dtlsRtp->started) {
      ELOG_INFO("%s message: DTLSRTP Start, transportName: %s", toLog(), transport_name.c_str());
      dtlsRtp->start();
      rtp_timeout_checker_->scheduleCheck();
    }
    if (!isServer_ && dtlsRtcp != NULL && !dtlsRtcp->started) {
      ELOG_DEBUG("%s message: DTLSRTCP Start, transportName: %s", toLog(), transport_name.c_str());
      dtlsRtcp->start();
      rtcp_timeout_checker_->scheduleCheck();
    }
  }
}
2.3.5.6 Transport::updateTransportState
void updateTransportState(TransportState state) {
    if (state == state_) {
      return;
    }
    state_ = state;
    if (auto listener = getTransportListener().lock()) {
      listener->updateState(state, this);
    }
  }
2.3.5.7 WebRtcConnection::updateState
void WebRtcConnection::updateState(TransportState state, Transport * transport) {
  boost::mutex::scoped_lock lock(update_state_mutex_);
  WebRTCEvent temp = global_state_;
  std::string msg = "";
  ELOG_DEBUG("%s transportName: %s, new_state: %d", toLog(), transport->transport_name.c_str(), state);
  if (video_transport_.get() == nullptr && audio_transport_.get() == nullptr) {
    ELOG_ERROR("%s message: Updating NULL transport, state: %d", toLog(), state);
    return;
  }
  if (global_state_ == CONN_FAILED) {
    // if current state is failed -> noop
    return;
  }
  switch (state) {
    case TRANSPORT_STARTED:
      if (bundle_) {
        temp = CONN_STARTED;
      } else {
        if ((!remote_sdp_->hasAudio || (audio_transport_.get() != nullptr
                  && audio_transport_->getTransportState() == TRANSPORT_STARTED)) &&
            (!remote_sdp_->hasVideo || (video_transport_.get() != nullptr
                  && video_transport_->getTransportState() == TRANSPORT_STARTED))) {
            // WebRTCConnection will be ready only when all channels are ready.
            temp = CONN_STARTED;
          }
      }
      break;
    走这里代码
    case TRANSPORT_GATHERED:
      if (bundle_) {
        if (!remote_sdp_->getCandidateInfos().empty()) {
          // Passing now new candidates that could not be passed before
          if (remote_sdp_->hasVideo) {
            video_transport_->setRemoteCandidates(remote_sdp_->getCandidateInfos(), bundle_);
          }
          if (!bundle_ && remote_sdp_->hasAudio) {
            audio_transport_->setRemoteCandidates(remote_sdp_->getCandidateInfos(), bundle_);
          }
        }
        if (!trickle_enabled_) {
          temp = CONN_GATHERED;
          msg = this->getLocalSdp();
        }
      } else {
        if ((!local_sdp_->hasAudio || (audio_transport_.get() != nullptr
                  && audio_transport_->getTransportState() == TRANSPORT_GATHERED)) &&
            (!local_sdp_->hasVideo || (video_transport_.get() != nullptr
                  && video_transport_->getTransportState() == TRANSPORT_GATHERED))) {
            // WebRTCConnection will be ready only when all channels are ready.
            if (!trickle_enabled_) {
              temp = CONN_GATHERED;
              msg = this->getLocalSdp();
            }
          }
      }
      break;
    case TRANSPORT_READY:
      if (bundle_) {
        temp = CONN_READY;
        trackTransportInfo();
        forEachMediaStreamAsync([] (const std::shared_ptr<MediaStream> &media_stream) {
          media_stream->sendPLIToFeedback();
        });
      } else {
        if ((!remote_sdp_->hasAudio || (audio_transport_.get() != nullptr
                  && audio_transport_->getTransportState() == TRANSPORT_READY)) &&
            (!remote_sdp_->hasVideo || (video_transport_.get() != nullptr
                  && video_transport_->getTransportState() == TRANSPORT_READY))) {
            // WebRTCConnection will be ready only when all channels are ready.
            temp = CONN_READY;
            trackTransportInfo();
            forEachMediaStreamAsync([] (const std::shared_ptr<MediaStream> &media_stream) {
              media_stream->sendPLIToFeedback();
            });
          }
      }
      break;
    case TRANSPORT_FAILED:
      temp = CONN_FAILED;
      sending_ = false;
      msg = remote_sdp_->getSdp();
      ELOG_ERROR("%s message: Transport Failed, transportType: %s", toLog(), transport->transport_name.c_str() );
      cond_.notify_one();
      break;
    default:
      ELOG_DEBUG("%s message: Doing nothing on state, state %d", toLog(), state);
      break;
  }

  if (audio_transport_.get() != nullptr && video_transport_.get() != nullptr) {
    ELOG_DEBUG("%s message: %s, transportName: %s, videoTransportState: %d"
              ", audioTransportState: %d, calculatedState: %d, globalState: %d",
      toLog(),
      "Update Transport State",
      transport->transport_name.c_str(),
      static_cast<int>(audio_transport_->getTransportState()),
      static_cast<int>(video_transport_->getTransportState()),
      static_cast<int>(temp),
      static_cast<int>(global_state_));
  }

  if (global_state_ == temp) {
    return;
  }

  global_state_ = temp;

  ELOG_INFO("%s newGlobalState: %d", toLog(), global_state_);
  maybeNotifyWebRtcConnectionEvent(global_state_, msg);
}
2.3.5.8 CONN_GATHERED = 103——会通知js
2.3.5.9 maybeNotifyWebRtcConnectionEvent

参考2.7

log
2023-04-26 21:54:06,356  - DEBUG: MediaStreamWrapper - id: 0, message: Created

2023-04-26 21:54:06,356  - DEBUG: WebRtcConnection - id: cb8fcfb93f174c24862feaa38915111a,  message: Adding mediaStream, id: 0
///getLocalSdpInfo, 是在wrtcConnection构造函数,
// setAudioSsrc的时候调用

2023-04-26 21:54:06,356  - DEBUG: WebRtcConnection - id: cb8fcfb93f174c24862feaa38915111a,  message: getting local SDPInfo
2023-04-26 21:54:06,356  - DEBUG: WebRtcConnection - id: cb8fcfb93f174c24862feaa38915111a,  message: getting local SDPInfo stream not running, stream_id: 0

//
// audio 部分
//

2.2 WebRtcConnection::setRemoteSdp
2023-04-26 21:54:06,357  - DEBUG: WebRtcConnection - id: cb8fcfb93f174c24862feaa38915111a,  message: setting remote SDP


2.3 erizo::WebRtcConnection::processRemoteSdp /
2023-04-26 21:54:06,357  - DEBUG: WebRtcConnection - 
id: cb8fcfb93f174c24862feaa38915111a,  
message: processing remote SDP


/
处理rtp extesion
/
2023-04-26 21:54:06,357  - DEBUG: rtp.RtpExtensionProcessor - Adding RTP Extension for Audio urn:ietf:params:rtp-hdrext:ssrc-audio-level, value 1
2023-04-26 21:54:06,357  - DEBUG: rtp.RtpExtensionProcessor - Adding RTP Extension for Audio http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, value 2
2023-04-26 21:54:06,357  - DEBUG: rtp.RtpExtensionProcessor - Adding RTP Extension for Audio http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01, value 3
2023-04-26 21:54:06,357  - DEBUG: rtp.RtpExtensionProcessor - Adding RTP Extension for Audio urn:ietf:params:rtp-hdrext:sdes:mid, value 4
2023-04-26 21:54:06,357  - DEBUG: rtp.RtpExtensionProcessor - Adding RTP Extension for Audio urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id, value 5
2023-04-26 21:54:06,357  - DEBUG: rtp.RtpExtensionProcessor - Adding RTP Extension for Audio urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id, value 6

/
创建dtls
/
2023-04-26 21:54:06,357  - DEBUG: WebRtcConnection - 
id: cb8fcfb93f174c24862feaa38915111a,  
message: Creating videoTransport, 
ufrag: on6P, 
pass: 2eQcZBbX6HECXpr9g2lilIMj
2023-04-26 21:54:06,357  - DEBUG: DtlsTransport - 
id: cb8fcfb93f174c24862feaa38915111a,  
message: constructor, 
transportName: video, 
isBundle: 1
2023-04-26 21:54:06,358  - DEBUG: dtls.DtlsSocketContext - 
Creating Dtls factory, Openssl v OpenSSL 1.1.1t  7 Feb 2023
/
/


=====================================================================================

processRemoteSdp video
2023-04-26 21:54:06,360  - DEBUG: WebRtcConnection - id: cb8fcfb93f174c24862feaa38915111a,  message: Adding mediaStream, id: 1


///getLocalSdpInfo, 是在wrtcConnection构造函数,
// setVideoSsrcList的时候调用

2023-04-26 21:54:06,360  - DEBUG: WebRtcConnection - id: cb8fcfb93f174c24862feaa38915111a,  message: Getting Local Sdp


2.2 WebRtcConnection::setRemoteSdp
2023-04-26 21:54:06,361  - DEBUG: WebRtcConnection - id: cb8fcfb93f174c24862feaa38915111a,  
message: setting remote SDP

2.3 erizo::WebRtcConnection::processRemoteSdp /
2023-04-26 21:54:06,361  - DEBUG: WebRtcConnection - id: cb8fcfb93f174c24862feaa38915111a,  
message: processing remote SDP


2023-04-26 21:54:06,361  - DEBUG: WebRtcConnection - 
id: cb8fcfb93f174c24862feaa38915111a,  
message: processing remote SDP
2023-04-26 21:54:06,361  - DEBUG: rtp.RtpExtensionProcessor - Adding RTP Extension for video urn:ietf:params:rtp-hdrext:toffset, value 14
2023-04-26 21:54:06,361  - DEBUG: rtp.RtpExtensionProcessor - Adding RTP Extension for video http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, value 2
2023-04-26 21:54:06,361  - DEBUG: owt.InternalServer - addSource cb8fcfb93f174c24862feaa38915111a-1, 0x5770918
2023-04-26 21:54:06,361  - WARN: rtp.RtpExtensionProcessor - Unsupported extension urn:3gpp:video-orientation
2023-04-26 21:54:06,361  - DEBUG: rtp.RtpExtensionProcessor - Adding RTP Extension for video http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01, value 3
2023-04-26 21:54:06,361  - WARN: rtp.RtpExtensionProcessor - Unsupported extension http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
2023-04-26 21:54:06,361  - WARN: rtp.RtpExtensionProcessor - Unsupported extension http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
2023-04-26 21:54:06,361  - WARN: rtp.RtpExtensionProcessor - Unsupported extension http://www.webrtc.org/experiments/rtp-hdrext/video-timing
2023-04-26 21:54:06,361  - WARN: rtp.RtpExtensionProcessor - Unsupported extension http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07
2023-04-26 21:54:06,361  - WARN: rtp.RtpExtensionProcessor - Unsupported extension http://www.webrtc.org/experiments/rtp-hdrext/color-space
2023-04-26 21:54:06,361  - DEBUG: rtp.RtpExtensionProcessor - Adding RTP Extension for video urn:ietf:params:rtp-hdrext:sdes:mid, value 4
2023-04-26 21:54:06,361  - DEBUG: rtp.RtpExtensionProcessor - Adding RTP Extension for video urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id, value 5
2023-04-26 21:54:06,361  - DEBUG: rtp.RtpExtensionProcessor - Adding RTP Extension for video urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id, value 6


setRemoteSdpsToMediaStreams
2023-04-26 21:54:06,361  - DEBUG: WebRtcConnection - 
id: cb8fcfb93f174c24862feaa38915111a,  
message: setting remote SDP, 
stream: 1
2023-04-26 21:54:06,361  - DEBUG: WebRtcConnection - 
id: cb8fcfb93f174c24862feaa38915111a,  
message: setting remote SDP, 
stream: 0, stream_id: 1
2023-04-26 21:54:06,361  - DEBUG: WebRtcConnection - 
id: cb8fcfb93f174c24862feaa38915111a,  
message: setting remote SDP, 
stream: 1, stream_id: 1
WebRtcConnection::getCurrentState

====2.4 WebRtcConnection::setRemoteSdpsToMediaStreams

remote sdp 设置给对应的MediaStream
同一个WebRtcConnection,如果有多个track,那么就会调用多少次。
所以CONN_SDP_PROCESSED = 203就会有多次。

third_party/licode/erizo/src/erizo/WebRtcConnection.cpp

2023-04-26 21:54:19,802  - DEBUG: WebRtcConnection - 
id: b149e44bb10d4e91bd162a8c6806ae7b,  
message: setting remote SDP, stream: 1

2023-04-26 21:54:19,802  - DEBUG: WebRtcConnection - 
id: b149e44bb10d4e91bd162a8c6806ae7b,  
message: setting remote SDP, stream: 0, stream_id: 1

2023-04-26 21:54:19,802  - DEBUG: WebRtcConnection - 
id: b149e44bb10d4e91bd162a8c6806ae7b,  
message: setting remote SDP, stream: 1, stream_id: 1


2023-04-26 21:54:19,802  - DEBUG: MediaStream - 
id: 1, role:subscriber,  message: setting remote SDP



2023-04-26 21:54:19,802  - DEBUG: WebRtcConnection - 
id: b149e44bb10d4e91bd162a8c6806ae7b,  
message: setting remote SDP to stream, stream: 1

///onRemoteSdpsSetToMediaStreams
2023-04-26 21:54:19,802  - DEBUG: WebRtcConnection - 
id: b149e44bb10d4e91bd162a8c6806ae7b,  
message: SDP processed
2023-04-26 21:54:19,802  - DEBUG: WebRtcConnection - 
id: b149e44bb10d4e91bd162a8c6806ae7b,  
message: Getting Local Sdp
// stream_id 就是 mid
void WebRtcConnection::setRemoteSdpsToMediaStreams(std::string stream_id) {
  ELOG_DEBUG("%s message: setting remote SDP, stream: %s", toLog(), stream_id);

   // 从media_streams_ 找到stream_id 对应的stream
  auto stream = std::find_if(media_streams_.begin(), media_streams_.end(),
    [stream_id, this](const std::shared_ptr<MediaStream> &media_stream) {
      ELOG_DEBUG("%s message: setting remote SDP, stream: %s, stream_id: %s",
        toLog(), media_stream->getId(), stream_id);
      return media_stream->getId() == stream_id;
    });

  if (stream != media_streams_.end()) {
    std::weak_ptr<WebRtcConnection> weak_this = shared_from_this();
    (*stream)->asyncTask([weak_this, stream_id] (const std::shared_ptr<MediaStream> &media_stream) {
      if (auto connection = weak_this.lock()) {
        // 设置remote sdp
        media_stream->setRemoteSdp(connection->remote_sdp_);
        // 走了这里的流程
        ELOG_DEBUG("%s message: setting remote SDP to stream, stream: %s", connection->toLog(), media_stream->getId());
        connection->onRemoteSdpsSetToMediaStreams(stream_id);
      }
    });
  } else {
    onRemoteSdpsSetToMediaStreams(stream_id);
  }
}
2.4.1 MediaStream::setRemoteSdp

source/agent/webrtc/rtcConn/erizo/src/erizo/MediaStream.cpp

bool MediaStream::setRemoteSdp(std::shared_ptr<SdpInfo> sdp) {
  ELOG_DEBUG("%s message: setting remote SDP", toLog());
  if (!sending_) {
    return true;
  }
  if (!sdp) {
    ELOG_WARN("%s message: setting remote SDP nullptr", toLog());
    return true;
  }
  remote_sdp_ =  std::make_shared<SdpInfo>(*sdp.get());
  if (remote_sdp_->videoBandwidth != 0) {
    ELOG_DEBUG("%s message: Setting remote BW, maxVideoBW: %u", toLog(), remote_sdp_->videoBandwidth);
    // this->rtcp_processor_->setMaxVideoBW(remote_sdp_->videoBandwidth*1000);
  }

  auto video_ssrc_list_it = remote_sdp_->video_ssrc_map.find(getLabel());
  if (video_ssrc_list_it != remote_sdp_->video_ssrc_map.end()) {
    setVideoSourceSSRCList(video_ssrc_list_it->second);
  }

  auto audio_ssrc_it = remote_sdp_->audio_ssrc_map.find(getLabel());
  if (audio_ssrc_it != remote_sdp_->audio_ssrc_map.end()) {
    setAudioSourceSSRC(audio_ssrc_it->second);
  }

  if (getVideoSourceSSRCList().empty() ||
      (getVideoSourceSSRCList().size() == 1 && getVideoSourceSSRCList()[0] == 0)) {
    std::vector<uint32_t> default_ssrc_list;
    default_ssrc_list.push_back(kDefaultVideoSinkSSRC);
    setVideoSourceSSRCList(default_ssrc_list);
  }

  if (getAudioSourceSSRC() == 0) {
    setAudioSourceSSRC(kDefaultAudioSinkSSRC);
  }

  if (pipeline_initialized_ && pipeline_) {
    pipeline_->notifyUpdate();
    return true;
  }

  bundle_ = remote_sdp_->isBundle;

  audio_enabled_ = remote_sdp_->hasAudio;
  video_enabled_ = remote_sdp_->hasVideo;

  /*
  rtcp_processor_->addSourceSsrc(getAudioSourceSSRC());
  std::for_each(video_source_ssrc_list_.begin(), video_source_ssrc_list_.end(), [this] (uint32_t new_ssrc){
      rtcp_processor_->addSourceSsrc(new_ssrc);
  });
  */

  if (remote_sdp_->rids().size() > 1) {
    simulcast_ = true;
  }

  initializePipeline();

  initializeStats();

  return true;
}
2.4.2 WebRtcConnection::onRemoteSdpsSetToMediaStreams

source/agent/webrtc/rtcConn/erizo/src/erizo/WebRtcConnection.cpp

void WebRtcConnection::onRemoteSdpsSetToMediaStreams(std::string stream_id) {
  asyncTask([stream_id] (std::shared_ptr<WebRtcConnection> connection) {
    ELOG_DEBUG("%s message: SDP processed", connection->toLog());
    // local sdp
    std::string sdp = connection->getLocalSdp();
    // 发送了CONN_SDP_PROCESSED 这个事件
    connection->maybeNotifyWebRtcConnectionEvent(CONN_SDP_PROCESSED, sdp, stream_id);
  });
}
2.4.3 CONN_SDP_PROCESSED = 203——通知js,但是js不做处理
2.4.4 WebRtcConnection::maybeNotifyWebRtcConnectionEvent

参考 3

3. WebRtcConnection::maybeNotifyWebRtcConnectionEvent

source/agent/webrtc/rtcConn/erizo/src/erizo/WebRtcConnection.cpp

void WebRtcConnection::maybeNotifyWebRtcConnectionEvent(const WebRTCEvent& event, const std::string& message,
    const std::string& stream_id) {
  boost::mutex::scoped_lock lock(event_listener_mutex_);
  if (!conn_event_listener_) {
      return;
  }
  conn_event_listener_->notifyEvent(event, message, stream_id);
}

处理remote sdp时,发送该通知。message为remote sdp

3.1 WebRtcConnection::setWebRtcConnectionEventListener

third_party/licode/erizo/src/erizo/WebRtcConnection.cpp

conn_event_listener_ 赋值,一个是setWebRtcConnectionEventListener,
还有一个是构造函数的时候;
实际上是在WebRtcConnection创建的时候赋值。

void WebRtcConnection::setWebRtcConnectionEventListener(WebRtcConnectionEventListener* listener) {
  boost::mutex::scoped_lock lock(event_listener_mutex_);
  this->conn_event_listener_ = listener;
}
WebRtcConnection::WebRtcConnection(std::shared_ptr<Worker> worker, std::shared_ptr<IOWorker> io_worker,
    const std::string& connection_id, const IceConfig& ice_config, const std::vector<RtpMap> rtp_mappings,
    const std::vector<erizo::ExtMap> ext_mappings, WebRtcConnectionEventListener* listener) :
    connection_id_{connection_id},
    audio_enabled_{false}, video_enabled_{false}, bundle_{false}, conn_event_listener_{listener},
...
NAN_METHOD(WebRtcConnection::New) {

  ...
    std::shared_ptr<erizo::Worker> worker = thread_pool->me->getLessUsedWorker();
    std::shared_ptr<erizo::IOWorker> io_worker = io_thread_pool->me->getLessUsedIOWorker();

    WebRtcConnection* obj = new WebRtcConnection();
      // obj 实现了 WebRtcConnectionEventListener
    obj->me = std::make_shared<erizo::WebRtcConnection>(worker, io_worker, wrtcId, iceConfig,
                                                        rtp_mappings, ext_mappings, obj);

    uv_async_init(uv_default_loop(), &obj->async_, &WebRtcConnection::eventsCallback);
    obj->Wrap(info.This());
    info.GetReturnValue().Set(info.This());
    obj->asyncResource_ = new Nan::AsyncResource("WebRtcConnectionCallback");
  } else {
    // TODO(pedro) Check what happens here
  }
}

3.2 WebRtcConnectionEventListener

class WebRtcConnectionEventListener {
 public:
    virtual ~WebRtcConnectionEventListener() {
    }
    virtual void notifyEvent(WebRTCEvent newEvent, 
    const std::string& message, 
    const std::string &stream_id = "") = 0;
};

3.3 addon.WebRtcConnection::notifyEvent

source/agent/webrtc/rtcConn/WebRtcConnection.cc

// Async methods
void WebRtcConnection::notifyEvent(erizo::WebRTCEvent event, const std::string& message, const std::string& stream_id) {
  boost::mutex::scoped_lock lock(mutex);
  this->eventSts.push(event);
  this->eventMsgs.emplace(message, stream_id);
  async_.data = this;
  uv_async_send(&async_);
}

3.4 NAUV_WORK_CB(WebRtcConnection::eventsCallback)

NAUV_WORK_CB(WebRtcConnection::eventsCallback) {
  Nan::HandleScope scope;
  WebRtcConnection* obj = reinterpret_cast<WebRtcConnection*>(async->data);
  if (!obj || obj->me == NULL)
    return;
  boost::mutex::scoped_lock lock(obj->mutex);
  while (!obj->eventSts.empty()) {
    Local<Value> args[] = {
      Nan::New(obj->eventSts.front()),
      Nan::New(obj->eventMsgs.front().first.c_str()).ToLocalChecked(),
      Nan::New(obj->eventMsgs.front().second.c_str()).ToLocalChecked()
    };
    // eventCallback_ 就是 js 丢下的回调函数
    // Connection.init 调用 addon.WebRtcConnection.init的时候注册的回调函数
    obj->asyncResource_->runInAsyncScope(Nan::GetCurrentContext()->Global(), obj->eventCallback_->GetFunction(), 3, args);
    obj->eventMsgs.pop();
    obj->eventSts.pop();
  }
}

3. Connection.init

dist-debug/webrtc_agent/webrtc/connection.js

  init(streamId) {
   ...
        //  addon.WebRtcConnection
     // mess 就是sdp
    this.wrtc.init((newStatus, mess, streamId) => {
      log.debug('message: WebRtcConnection status update, ' +
               'id: ' + this.id + ', status: ' + newStatus +
                ', ' + logger.objectToLog(this.metadata) + mess);
      switch(newStatus) {
        case CONN_INITIAL:
          this.emit('status_event', {type: 'started'}, newStatus);
          break;

        // 走了这里的流程, 什么没做, CONN_SDP_PROCESSED = 203
        case CONN_SDP_PROCESSED:
          // 这个变量没用
          this.isProcessingRemoteSdp = false;
          // this.latestSdp = mess;
          // this._maybeSendAnswer(newStatus, streamId);
          break;

        case CONN_SDP:
          this.latestSdp = mess;
          this._maybeSendAnswer(newStatus, streamId);
          break;

        case CONN_GATHERED:
          this.alreadyGathered = true;
          this.latestSdp = mess;
          this._maybeSendAnswer(newStatus, firstStreamId);
          break;

        case CONN_CANDIDATE:
          mess = mess.replace(this.options.privateRegexp, this.options.publicIP);
          this.emit('status_event', {type: 'candidate', candidate: mess}, newStatus);
          break;

        case CONN_FAILED:
          log.warn('message: failed the ICE process, ' + 'code: ' + WARN_BAD_CONNECTION +
                   ', id: ' + this.id);
          this.emit('status_event', {type: 'failed', sdp: mess}, newStatus);
          break;

        case CONN_READY:
          log.debug('message: connection ready, ' + 'id: ' + this.id +
                    ', ' + 'status: ' + newStatus + ' ' + mess + ',' + streamId);
          if (!this.ready) {
            this.ready = true;
            this.emit('status_event', {type: 'ready'}, newStatus);
          }
          break;
      }
    });
  
    // this.options.createOffer 应该是一直是false,所以这里代码不会进入
    if (this.options.createOffer) {
      log.debug('message: create offer requested, id:', this.id);
      const audioEnabled = this.options.createOffer.audio;
      const videoEnabled = this.options.createOffer.video;
      const bundle = this.options.createOffer.bundle;
      this.wrtc.createOffer(videoEnabled, audioEnabled, bundle);
    }
    this.emit('status_event', {type: 'initializing'});
    return true;
  }
CONN_GATHERED = 103
2023-04-26T21:54:06.362  - DEBUG: Connection - message: WebRtcConnection status update,
id: cb8fcfb93f174c24862feaa38915111a, 
status: 103, {}v=0
o=- 0 0 IN IP4 127.0.0.1
s=IntelWebRTCMCU
t=0 0
a=group:BUNDLE 0
a=msid-semantic: WMS IWXvVgkKkO
m=audio 1 UDP/TLS/RTP/SAVPF 111
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=candidate:1 1 udp 2013266431 192.168.221.62 41095 typ host
a=ice-ufrag:xiRT
a=ice-pwd:dVh81XL4ksAgr7IziV4iMT
a=fingerprint:sha-256 9F:A1:E4:34:8E:B1:3B:0D:4B:98:BC:D5:8B:CA:60:2F:9B:C4:32:16:A1:B3:62:3C:90:56:B8:C9:B3:03:D8:E8
a=setup:active
a=sendrecv
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=mid:0
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10;useinbandfec=1
CONN_SDP_PROCESSED = 203
2023-04-26T21:54:06.365  - DEBUG: Connection - message: WebRtcConnection status update, id: cb8fcfb93f174c24862feaa38915111a, status: 203, {}v=0
o=- 0 0 IN IP4 127.0.0.1
s=IntelWebRTCMCU
t=0 0
a=group:BUNDLE 0
a=msid-semantic: WMS ef6WZSl7A5
m=audio 1 UDP/TLS/RTP/SAVPF 111
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=candidate:1 1 udp 2013266431 192.168.221.62 41095 typ host
a=ice-ufrag:xiRT
a=ice-pwd:dVh81XL4ksAgr7IziV4iMT
a=fingerprint:sha-256 9F:A1:E4:34:8E:B1:3B:0D:4B:98:BC:D5:8B:CA:60:2F:9B:C4:32:16:A1:B3:62:3C:90:56:B8:C9:B3:03:D8:E8
a=setup:active
a=sendrecv
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=mid:0
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10;useinbandfec=1
2023-04-26T21:54:06.365  - DEBUG: Connection - message: WebRtcConnection status update, id: cb8fcfb93f174c24862feaa38915111a, status: 203, {}v=0
o=- 0 0 IN IP4 127.0.0.1
s=IntelWebRTCMCU
t=0 0
a=group:BUNDLE 1
a=msid-semantic: WMS jY2yf5QwkH
m=audio 1 UDP/TLS/RTP/SAVPF 
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=candidate:1 1 udp 2013266431 192.168.221.62 41095 typ host
a=ice-ufrag:xiRT
a=ice-pwd:dVh81XL4ksAgr7IziV4iMT
a=fingerprint:sha-256 9F:A1:E4:34:8E:B1:3B:0D:4B:98:BC:D5:8B:CA:60:2F:9B:C4:32:16:A1:B3:62:3C:90:56:B8:C9:B3:03:D8:E8
a=setup:active
a=recvonly
a=rtcp-mux
m=video 1 UDP/TLS/RTP/SAVPF 123 114 116
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=candidate:1 1 udp 2013266431 192.168.221.62 41095 typ host
a=ice-ufrag:xiRT
a=ice-pwd:dVh81XL4ksAgr7IziV4iMT
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
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=fingerprint:sha-256 9F:A1:E4:34:8E:B1:3B:0D:4B:98:BC:D5:8B:CA:60:2F:9B:C4:32:16:A1:B3:62:3C:90:56:B8:C9:B3:03:D8:E8
a=setup:active
a=recvonly
a=mid:1
a=rtcp-mux
a=rtpmap:123 AV1/90000
a=rtcp-fb:123 nack
a=rtcp-fb:123 transport-cc
a=rtcp-fb:123 goog-remb
a=rtpmap:114 red/90000
a=rtpmap:116 ulpfec/90000

4. Connnection._maybeSendAnswer

这里只有CONN_GATHERED = 103 才会走这里

dist-debug/webrtc_agent/webrtc/connection.js

_maybeSendAnswer(evt, streamId, forceOffer = false) {
  if (this.isProcessingRemoteSdp) {
    return;
  }
  if (!this.alreadyGathered && !this.trickleIce) {
    return;
  }
  if (!this.latestSdp) {
    return;
  }
   // this.options.createOffer 一直是false,
  const info = {type: this.options.createOffer || forceOffer ? 'offer' : 'answer', sdp: this.latestSdp};
  log.debug(`message: _maybeSendAnswer sending event, type: ${info.type}, streamId: ${streamId}`);
  this.emit('status_event', info, evt, streamId);
}

5. WrtcConnection.initWebRtcConnection

dist/webrtc_agent/webrtc/wrtcConnection.js

var initWebRtcConnection = function (wrtc) {
    wrtc.on('status_event', (evt, status) => {
      if (evt.type === 'answer') {
        processAnswer(evt.sdp);

        const message = localSdp.toString();
        log.debug('Answer SDP', message);
        on_status({type: 'answer', sdp: message});

      } else if (evt.type === 'candidate') {
        let message = evt.candidate;
        networkInterfaces.forEach((i) => {
          if (i.ip_address && i.replaced_ip_address) {
            message = message.replace(new RegExp(i.ip_address, 'g'), i.replaced_ip_address);
          }
        });
        on_status({type: 'candidate', candidate: message});

      } else if (evt.type === 'failed') {
        log.warn('ICE failed, ', status, wrtc.id);
        on_status({type: 'failed', reason: 'Ice procedure failed.'});

      } else if (evt.type === 'ready') {
        log.debug('Connection ready, ', wrtc.wrtcId);
        on_status({
          type: 'ready'
        });
      }
    });
    wrtc.init(wrtcId);
  };

5.1WrtcConnection.processAnswer

dist-debug/webrtc_agent/webrtc/wrtcConnection.js

const processAnswer = function (sdpMsg) {
    if (sdpMsg) {
      // First answer from native
      networkInterfaces.forEach((i) => {
        if (i.ip_address && i.replaced_ip_address) {
          sdpMsg = sdpMsg.replace(new RegExp(i.ip_address, 'g'), i.replaced_ip_address);
        }
      });

      const tempSdp = new SdpInfo(sdpMsg);
      if (tempSdp.mids().length > 0) {
        const tempMid = tempSdp.mids()[0];
        localSdp.setMsidSemantic(tempSdp.getMsidSemantic());
        localSdp.setCredentials(tempSdp.getCredentials(tempMid));
        localSdp.setCandidates(tempSdp.getCandidates(tempMid));
      } else {
        log.warn('No mid in answer', wrtcId);
      }

    }
  };

6.Node.createWebRTCConnection

var createWebRTCConnection = function (transportId, controller, owner) {
        if (peerConnections.has(transportId)) {
            log.debug('PeerConnection already created:', transportId);
            return peerConnections.get(transportId);
        }
        var connection = new WrtcConnection({
            connectionId: transportId,
            threadPool: threadPool,
            ioThreadPool: ioThreadPool,
            network_interfaces: global.config.webrtc.network_interfaces,
            owner,
        }, function onTransportStatus(status) {
            notifyTransportStatus(controller, transportId, status);
        }, function onTrack(trackInfo) {
            handleTrackInfo(transportId, trackInfo, controller);
        });

        peerConnections.set(transportId, connection);
        mappingPublicId.set(transportId, new Map());
        connection.controller = controller;
        return connection;
    };

6.1 Node.notifyTransportStatus

    var notifyTransportStatus = function (controller, transportId, status) {
        rpcClient.remoteCast(controller, 'onTransportProgress', [transportId, status]);
        // Emit GRPC notifications
        const notification = {
            name: 'onTransportProgress',
            data: {transportId, status},
        };
        streamingEmitter.emit('notification', notification);
    };

WebRtcConnection::syncClose()——CONN_FINISHED

void WebRtcConnection::syncClose() {
  ELOG_DEBUG("%s message: Close called", toLog());
  if (!sending_) {
    return;
  }
  sending_ = false;
  media_streams_.clear();
  if (video_transport_.get()) {
    video_transport_->close();
  }
  if (audio_transport_.get()) {
    audio_transport_->close();
  }
  global_state_ = CONN_FINISHED;
  if (conn_event_listener_ != nullptr) {
    conn_event_listener_ = nullptr;
  }

  ELOG_DEBUG("%s message: Close ended", toLog());
}

log

publish cb8fcfb93f174c24862feaa38915111a
2023-04-26T21:54:05.938  - DEBUG: Connection - message: WebRtcConnection status update, id: cb8fcfb93f174c24862feaa38915111a, status: 101, {} 初始化
2023-04-26T21:54:06.362  - DEBUG: Connection - message: WebRtcConnection status update, id: cb8fcfb93f174c24862feaa38915111a, status: 103, {}v=0 收集
2023-04-26T21:54:06.365  - DEBUG: Connection - message: WebRtcConnection status update, id: cb8fcfb93f174c24862feaa38915111a, status: 203, {}v=0 sdp 处理
2023-04-26T21:54:06.365  - DEBUG: Connection - message: WebRtcConnection status update, id: cb8fcfb93f174c24862feaa38915111a, status: 203, {}v=0 sdp 处理
2023-04-26T21:54:06.718  - DEBUG: Connection - message: WebRtcConnection status update, id: cb8fcfb93f174c24862feaa38915111a, status: 104, {} 连接ready
publish 7c497d10719d48d192fc355cd8a9d38a
2023-04-26T21:54:18.371  - DEBUG: Connection - message: WebRtcConnection status update, id: 7c497d10719d48d192fc355cd8a9d38a, status: 101, {} 初始化
2023-04-26T21:54:18.992  - DEBUG: Connection - message: WebRtcConnection status update, id: 7c497d10719d48d192fc355cd8a9d38a, status: 103, {}v=0 收集
2023-04-26T21:54:18.993  - DEBUG: Connection - message: WebRtcConnection status update, id: 7c497d10719d48d192fc355cd8a9d38a, status: 203, {}v=0 sdp 处理
2023-04-26T21:54:18.993  - DEBUG: Connection - message: WebRtcConnection status update, id: 7c497d10719d48d192fc355cd8a9d38a, status: 203, {}v=0 sdp 处理
2023-04-26T21:54:20.108  - DEBUG: Connection - message: WebRtcConnection status update, id: 7c497d10719d48d192fc355cd8a9d38a, status: 104, {} 连接ready
2023-04-26T21:54:53.797  - DEBUG: Connection - message: WebRtcConnection status update, id: 7c497d10719d48d192fc355cd8a9d38a, status: 500, {}v=0 连接fail
2023-04-26T21:54:53.813  - INFO: Connection - message: WebRtcConnection status update, id: 7c497d10719d48d192fc355cd8a9d38a, status: 105, {} 连接 finish????
subscribe b149e44bb10d4e91bd162a8c6806ae7b
2023-04-26T21:54:18.419  - DEBUG: Connection - message: WebRtcConnection status update, id: b149e44bb10d4e91bd162a8c6806ae7b, status: 101, {} 初始化
2023-04-26T21:54:19.804  - DEBUG: Connection - message: WebRtcConnection status update, id: b149e44bb10d4e91bd162a8c6806ae7b, status: 103, {}v=0 收集
2023-04-26T21:54:19.806  - DEBUG: Connection - message: WebRtcConnection status update, id: b149e44bb10d4e91bd162a8c6806ae7b, status: 203, {}v=0 sdp 处理
2023-04-26T21:54:19.806  - DEBUG: Connection - message: WebRtcConnection status update, id: b149e44bb10d4e91bd162a8c6806ae7b, status: 203, {}v=0 sdp 处理
subscribe b801af2aac214c09ae0100bdc52b2f0f
2023-04-26T21:54:20.346  - DEBUG: Connection - message: WebRtcConnection status update, id: b801af2aac214c09ae0100bdc52b2f0f, status: 101, {} 初始化
2023-04-26T21:54:21.430  - DEBUG: Connection - message: WebRtcConnection status update, id: b801af2aac214c09ae0100bdc52b2f0f, status: 103, {}v=0 收集
2023-04-26T21:54:21.436  - DEBUG: Connection - message: WebRtcConnection status update, id: b801af2aac214c09ae0100bdc52b2f0f, status: 203, {}v=0 sdp 处理
2023-04-26T21:54:21.437  - DEBUG: Connection - message: WebRtcConnection status update, id: b801af2aac214c09ae0100bdc52b2f0f, status: 203, {}v=0 sdp 处理
2023-04-26T21:54:22.128  - DEBUG: Connection - message: WebRtcConnection status update, id: b801af2aac214c09ae0100bdc52b2f0f, status: 104, {} 连接ready
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值