继续对licode中的WebRtcConnection源码进行分析:
// 设置远端sdp信息
boost::future<void> WebRtcConnection::setRemoteSdpInfo(
std::shared_ptr<SdpInfo> sdp) {
std::weak_ptr<WebRtcConnection> weak_this = shared_from_this();
auto task_promise = std::make_shared<boost::promise<void>>();
worker_->task([weak_this, sdp, task_promise] {
if (auto connection = weak_this.lock()) {
ELOG_DEBUG("%s message: setting remote SDPInfo", connection->toLog());
if (!connection->sending_) {
task_promise->set_value();
return;
}
connection->remote_sdp_ = sdp;
boost::future<void> future = connection->processRemoteSdp().then(
[task_promise] (boost::future<void>) {
task_promise->set_value();
});
return;
}
task_promise->set_value();
});
return task_promise->get_future();
}
// 拷贝sdp info到local_sdp_中
void WebRtcConnection::copyDataToLocalSdpIndo(std::shared_ptr<SdpInfo> sdp_info) {
asyncTask([sdp_info] (std::shared_ptr<WebRtcConnection> connection) {
if (connection->sending_) {
connection->local_sdp_->copyInfoFromSdp(sdp_info);
connection->local_sdp_->updateSupportedExtensionMap(connection->extension_processor_.getSupportedExtensionMap());
}
});
}
// 获取local_sdp_的内容
std::shared_ptr<SdpInfo> WebRtcConnection::getLocalSdpInfo() {
boost::mutex::scoped_lock lock(update_state_mutex_);
ELOG_DEBUG("%s message: getting local SDPInfo", toLog());
forEachMediaStream([this] (const std::shared_ptr<MediaStream> &media_stream) {
if (!media_stream->isReady() || media_stream->isPublisher()) {
ELOG_DEBUG("%s message: getting local SDPInfo stream not running, stream_id: %s", toLog(), media_stream->getId());
return;
}
std::vector<uint32_t> video_ssrc_list = std::vector<uint32_t>();
if (media_stream->getVideoSinkSSRC() != kDefaultVideoSinkSSRC && media_stream->getVideoSinkSSRC() != 0) {
video_ssrc_list.push_back(media_stream->getVideoSinkSSRC());
}
ELOG_DEBUG("%s message: getting local SDPInfo, stream_id: %s, audio_ssrc: %u",
toLog(), media_stream->getId(), media_stream->getAudioSinkSSRC());
if (!video_ssrc_list.empty()) {
local_sdp_->video_ssrc_map[media_stream->getLabel()] = video_ssrc_list;
}
if (media_stream->getAudioSinkSSRC() != kDefaultAudioSinkSSRC && media_stream->getAudioSinkSSRC() != 0) {
local_sdp_->audio_ssrc_map[media_stream->getLabel()] = media_stream->getAudioSinkSSRC();
}
});
bool sending_audio = local_sdp_->audio_ssrc_map.size() > 0;
bool sending_video = local_sdp_->video_ssrc_map.size() > 0;
bool receiving_audio = remote_sdp_->audio_ssrc_map.size() > 0;
bool receiving_video = remote_sdp_->video_ssrc_map.size() > 0;
audio_enabled_ = sending_audio || receiving_audio;
video_enabled_ = sending_video || receiving_video;
if (!sending_audio && receiving_audio) {
local_sdp_->audioDirection = erizo::RECVONLY;
} else if (sending_audio && !receiving_audio) {
local_sdp_->audioDirection = erizo::SENDONLY;
} else {
local_sdp_->audioDirection = erizo::SENDRECV;
}
if (!sending_video && receiving_video) {
local_sdp_->videoDirection = erizo::RECVONLY;
} else if (sending_video && !receiving_video) {
local_sdp_->videoDirection = erizo::SENDONLY;
} else {
local_sdp_->videoDirection = erizo::SENDRECV;
}
return local_sdp_;
}
// 设置远端sdp,remote_sdp_,较上面的setRemoteSdpInfo多了一步操作:processRemoteSdp
boost::future<void> WebRtcConnection::setRemoteSdp(const std::string &sdp) {
std::shared_ptr<boost::promise<void>> p = std::make_shared<boost::promise<void>>();
boost::future<void> f = p->get_future();
asyncTask([sdp, p] (std::shared_ptr<WebRtcConnection> connection) {
ELOG_DEBUG("%s message: setting remote SDP", connection->toLog());
if (!connection->sending_) {
p->set_value();
return;
}
connection->remote_sdp_->initWithSdp(sdp, "");
boost::future<void> f = connection->processRemoteSdp();
f.then([p](boost::future<void> future) {
p->set_value();
});
});
return f;
}
// 将远端sdp内容设置到media_streams_中
boost::future<void> WebRtcConnection::setRemoteSdpsToMediaStreams() {
ELOG_DEBUG("%s message: setting remote SDP, streams: %d", toLog(), media_streams_.size());
std::weak_ptr<WebRtcConnection> weak_this = shared_from_this();
std::shared_ptr<SdpInfo> remote_sdp = std::make_shared<SdpInfo>(*remote_sdp_.get());
return forEachMediaStreamAsync([weak_this, remote_sdp](std::shared_ptr<MediaStream> media_stream) {
if (auto connection = weak_this.lock()) {
media_stream->setRemoteSdp(remote_sdp);
ELOG_DEBUG("%s message: setting remote SDP to stream, stream: %s",
connection->toLog(), media_stream->getId());
}
});
}
// 将remote_sdp_相关内容设置到audio_transport_和video_transport_中
boost::future<void> WebRtcConnection::processRemoteSdp() {
ELOG_DEBUG("%s message: processing remote SDP", toLog());
if (!first_remote_sdp_processed_ && local_sdp_->internal_dtls_role == ACTPASS) {
local_sdp_->internal_dtls_role = ACTIVE;
}
local_sdp_->dtlsRole = local_sdp_->internal_dtls_role;
ELOG_DEBUG("%s message: process remote sdp, setup: %d", toLog(), local_sdp_->internal_dtls_role);
if (first_remote_sdp_processed_) {
return setRemoteSdpsToMediaStreams();
}
bundle_ = remote_sdp_->isBundle;
local_sdp_->setOfferSdp(remote_sdp_);
extension_processor_.setSdpInfo(local_sdp_);
local_sdp_->updateSupportedExtensionMap(extension_processor_.getSupportedExtensionMap());
audio_enabled_ = remote_sdp_->hasAudio;
video_enabled_ = remote_sdp_->hasVideo;
if (remote_sdp_->profile == SAVPF) {
if (remote_sdp_->isFingerprint) {
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) {
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) {
std::string username = remote_sdp_->getUsername(AUDIO_TYPE);
std::string password = remote_sdp_->getPassword(AUDIO_TYPE);
if (audio_transport_.get() == nullptr) {
ELOG_DEBUG("%s message: Creating audioTransport, ufrag: %s, pass: %s",
toLog(), username.c_str(), password.c_str());
audio_transport_.reset(new DtlsTransport(AUDIO_TYPE, "audio", connection_id_, bundle_, remote_sdp_->isRtcpMux,
listener, ice_config_, username, password, false,
worker_, io_worker_));
audio_transport_->copyLogContextFrom(*this);
audio_transport_->start();
} else {
ELOG_DEBUG("%s message: Update audioTransport, ufrag: %s, pass: %s",
toLog(), username.c_str(), password.c_str());
audio_transport_->getIceConnection()->setRemoteCredentials(username, password);
}
}
}
}
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_);
}
}
}
first_remote_sdp_processed_ = true;
return setRemoteSdpsToMediaStreams();
}
// 异步将远端candidate加入remote_sdp_中
boost::future<void> WebRtcConnection::addRemoteCandidate(std::string mid, int mLineIndex, std::string sdp) {
return asyncTask([mid, mLineIndex, sdp] (std::shared_ptr<WebRtcConnection> connection) {
connection->addRemoteCandidateSync(mid, mLineIndex, sdp);
});
}
// 将远端candidate加入remote_sdp_中
bool WebRtcConnection::addRemoteCandidateSync(std::string mid, int mLineIndex, std::string sdp) {
// TODO(pedro) Check type of transport.
ELOG_DEBUG("%s message: Adding remote Candidate, candidate: %s, mid: %s, sdpMLine: %d",
toLog(), sdp.c_str(), mid.c_str(), mLineIndex);
if (video_transport_ == nullptr && audio_transport_ == nullptr) {
ELOG_WARN("%s message: addRemoteCandidate on NULL transport", toLog());
return false;
}
MediaType theType;
std::string theMid;
// TODO(pedro) check if this works with video+audio and no bundle
if (mLineIndex == -1) {
ELOG_DEBUG("%s message: All candidates received", toLog());
if (video_transport_) {
video_transport_->getIceConnection()->setReceivedLastCandidate(true);
} else if (audio_transport_) {
audio_transport_->getIceConnection()->setReceivedLastCandidate(true);
}
return true;
}
if ((!mid.compare("video")) || (mLineIndex == remote_sdp_->videoSdpMLine)) {
theType = VIDEO_TYPE;
theMid = "video";
} else {
theType = AUDIO_TYPE;
theMid = "audio";
}
SdpInfo tempSdp(rtp_mappings_);
std::string username = remote_sdp_->getUsername(theType);
std::string password = remote_sdp_->getPassword(theType);
tempSdp.setCredentials(username, password, OTHER);
bool res = false;
if (tempSdp.initWithSdp(sdp, theMid)) {
if (theType == VIDEO_TYPE || bundle_) {
res = video_transport_->setRemoteCandidates(tempSdp.getCandidateInfos(), bundle_);
} else if (theType == AUDIO_TYPE) {
res = audio_transport_->setRemoteCandidates(tempSdp.getCandidateInfos(), bundle_);
} else {
ELOG_ERROR("%s message: add remote candidate with no Media (video or audio), candidate: %s",
toLog(), sdp.c_str() );
}
}
for (uint8_t it = 0; it < tempSdp.getCandidateInfos().size(); it++) {
remote_sdp_->addCandidate(tempSdp.getCandidateInfos()[it]);
}
return res;
}