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_INITIAL | WebrtcConnection对象创建后,需要外面手动调用init方法,该方法会回调notifyEvent,并传递事件为改枚举值,message和stream_id均为空值。 | |
CONN_STARTED | 这个状态没有看到里面有明显调用的地方,有可能是保留的状态码 | |
CONN_GATHERED | WebrtcConnection的createOffer或者第一次setRemoteSdp时启动自身ICE过程,ICE完成收集时,发送该通知。message为自己的sdp数据 | |
CONN_READY | 当DTLS握手交互成功完成时,发送该通知 | |
CONN_FINISH | WebrtcConnection对象关闭,调用close时,发送该通知 | |
CONN_CANDIDATE | 自身ICE获取到Candidate时,发送该通知。message为candidate信息 | |
CONN_SDP | - | |
CONN_SDP_PROCESSED | 处理remote sdp时,发送该通知。message为remote sdp | |
CONN_FAILED | ICE失败,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
-
创建dtls transport,start
注意:first_remote_sdp_processed_ 默认是false, 再收到一个track,比如mid=0,处理了sdp后,first_remote_sdp_processed_ = true;
接着如果mid=1的track,在调用processRemoteSdp,那么就不会走创建dtls的流程,而是直接跳到第二步。 -
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