前言
webrtc越来越弱化流的概念,而是将轨交给用户。视频轨和音频轨。
实现
从下面的箭头位置打断点
先手动双击启动peerconnection_server.exe,peerconnection_client.exe,然后client单击连接信令服务器。此时再单击vs2019的调试器启动peerconnection_client并单击连接,此时该页面就会显示前面连接进来的client。双击该用户。
此时就会进来该断点处。
该部分代码逻辑
MainWnd::OnDefaultAction
else if (ui_ == LIST_PEERS) {
LRESULT sel = ::SendMessage(listbox_, LB_GETCURSEL, 0, 0);
if (sel != LB_ERR) {
LRESULT peer_id = ::SendMessage(listbox_, LB_GETITEMDATA, sel, 0);
if (peer_id != -1 && callback_) {
callback_->ConnectToPeer(peer_id);
}
}
先获取clientA的id,然后连接
Conductor::ConnectToPeer
void Conductor::ConnectToPeer(int peer_id) {
RTC_DCHECK(peer_id_ == -1);
RTC_DCHECK(peer_id != -1);
if (peer_connection_.get()) {
main_wnd_->MessageBox(
"Error", "We only support connecting to one peer at a time", true);
return;
}
// 初始化PeerConnection
if (InitializePeerConnection()) {
peer_id_ = peer_id;
peer_connection_->CreateOffer(
this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
} else {
main_wnd_->MessageBox("Error", "Failed to initialize PeerConnection", true);
}
}
Conductor::InitializePeerConnection
bool Conductor::InitializePeerConnection() {
RTC_DCHECK(!peer_connection_factory_);
RTC_DCHECK(!peer_connection_);
peer_connection_factory_ = webrtc::CreatePeerConnectionFactory(
nullptr /* network_thread */, nullptr /* worker_thread */,
nullptr /* signaling_thread */, nullptr /* default_adm */,
webrtc::CreateBuiltinAudioEncoderFactory(),
webrtc::CreateBuiltinAudioDecoderFactory(),
webrtc::CreateBuiltinVideoEncoderFactory(),
webrtc::CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
nullptr /* audio_processing */);
if (!peer_connection_factory_) {
main_wnd_->MessageBox("Error", "Failed to initialize PeerConnectionFactory",
true);
DeletePeerConnection();
return false;
}
if (!CreatePeerConnection(/*dtls=*/true)) {
main_wnd_->MessageBox("Error", "CreatePeerConnection failed", true);
DeletePeerConnection();
}
AddTracks();
return peer_connection_ != nullptr;
}
里面主要是 webrtc::CreatePeerConnectionFactory,和Conductor::CreatePeerConnection。
webrtc::CreatePeerConnectionFactory
Conductor::CreatePeerConnection
bool Conductor::CreatePeerConnection(bool dtls) {
RTC_DCHECK(peer_connection_factory_);
RTC_DCHECK(!peer_connection_);
// 先设定一些参数,包括sdp方式,使能dtls和添加iceserver信息
webrtc::PeerConnectionInterface::RTCConfiguration config;
//新版本是默认unifiedPlan,也可以选择PlanB
config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
config.enable_dtls_srtp = dtls;
// 设置ice server
webrtc::PeerConnectionInterface::IceServer server;
server.uri = GetPeerConnectionString();
config.servers.push_back(server);
// 调用PeerConnectionFactoryInterface::CreatePeerConnection
peer_connection_ = peer_connection_factory_->CreatePeerConnection(
config, nullptr, nullptr, this);
return peer_connection_ != nullptr;
}
PeerConnectionFactoryInterface::CreatePeerConnection
PROXYMETHOD4(rtc::scoped_refptr
CreatePeerConnection,
const PeerConnectionInterface::RTCConfiguration&,
std::unique_ptr
std::unique_ptr
PeerConnectionObserver*)
这里传入的参数 peer_connection
config, nullptr, nullptr, this);
最后的是this,则该类Conductor一定是继承了 webrtc::PeerConnectionObserver ,并实现它的一些方法。
当PeerConnection对象创建好后,还需要为其添加本地音视频轨,这是非常关键的一步。对于刚入门的读者来说,这一步是很容易被遗忘的。如果没有添加本地音视频轨,WebRTC内部就无法为其产生带有媒体信息的SDP,媒体协商时就会失败,双方也就无法进行通信了。所以Conductor::CreatePeerConnection调用完后,Conductor::InitializePeerConnection函数里面就会调用Conductor::AddTracks添加音视频轨。
Conductor::AddTracks
void Conductor::AddTracks() {
if (!peer_connection_->GetSenders().empty()) {
return; // Already added tracks.
}
// 创建音频轨,并添加到peerconnection
rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
peer_connection_factory_->CreateAudioTrack(
kAudioLabel, peer_connection_factory_->CreateAudioSource(
cricket::AudioOptions())));
auto result_or_error = peer_connection_->AddTrack(audio_track, {kStreamId});
if (!result_or_error.ok()) {
RTC_LOG(LS_ERROR) << "Failed to add audio track to PeerConnection: "
<< result_or_error.error().message();
}
// 创建视频设备
rtc::scoped_refptr<CapturerTrackSource> video_device =
CapturerTrackSource::Create();
if (video_device) {
// 创建视频轨
rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track_(
peer_connection_factory_->CreateVideoTrack(kVideoLabel, video_device));
// 显示本地视频
main_wnd_->StartLocalRenderer(video_track_);
// 添加视频轨
result_or_error = peer_connection_->AddTrack(video_track_, {kStreamId});
if (!result_or_error.ok()) {
RTC_LOG(LS_ERROR) << "Failed to add video track to PeerConnection: "
<< result_or_error.error().message();
}
} else {
RTC_LOG(LS_ERROR) << "OpenVideoCaptureDevice failed";
}
// 切换到显示视频渲染界面
main_wnd_->SwitchToStreamingUI();
}
视频源video_device是由自定义类CapturerTrackSource的静态方法Create()生成的。在Create()方法内部会遍历设备列表,从中找到第一个可用的设备,然后通过该设备采集视频
边看视频,边看电子书《WebRTC音视频实时互动技术:原理、实战与源码分析-李超编著》