背景
接上我的上一篇博客,在window环境,把webrtc的测试程序给运行起来,方便后面的代码分析
过程
bug修改
在实际测试中,发现运行程序时候,会遇到一些问题,这里有一些修改
-
- main.cc 的修改
ini
//const std::string server = absl::GetFlag(FLAGS_server);
const std::string server = "127.0.0.1";
这里修改后 peer_connectoin_client.cc 文件里面的如下代码块地方
c
class PeerConnectionClient
{
public:
void Connect(const std::string& server,
int port,
const std::string& client_name) {
...
if (server_address_.IsUnresolvedIP()) {
位置1
RTC_DCHECK_NE(state_, RESOLVING);
RTC_DCHECK(!resolver_);
state_ = RESOLVING;
resolver_ = std::make_unique<webrtc::AsyncDnsResolver>();
resolver_->Start(server_address_,
[this] { OnResolveResult(resolver_->result()); });
} else {
位置2
DoConnect();
}
....
}
}
就会走位置2
,走位置1会流程失败
我猜测,这里涉及一个域名解析
-
- peer_connection_client.cc 的修改
scss
void PeerConnectionClient::DoConnect() {
control_socket_.reset(CreateClientSocket(server_address_.ipaddr().family()));
hanging_get_.reset(CreateClientSocket(server_address_.ipaddr().family()));
InitSocketSignals();
char buffer[1024];
snprintf(buffer, sizeof(buffer), "GET /sign_in?%s HTTP/1.0\r\n\r\n",
client_name_.c_str());
onconnect_data_ = buffer;
bool ret = ConnectControlSocket();
if (ret)
state_ = SIGNING_IN;
if (!ret) {
callback_->OnServerConnectionFailure();
}
rtc::Thread::Current()->Start(); // 添加的代码
}
rtc::Thread::Current()->Start();
的作用是启动线程,否则 control_socket_ 的信号槽方法void PeerConnectionClient::OnConnect(..)
不会被回调
-
- peer_connection_client.cc 的修改
rust
bool PeerConnectionClient::SendToPeer(int peer_id, const std::string& message) {
if (state_ != CONNECTED)
return false;
RTC_DCHECK(is_connected());
RTC_DCHECK(control_socket_->GetState() == webrtc::Socket::CS_CLOSED);
if (!is_connected() || peer_id == -1)
return false;
char headers[1024];
snprintf(headers, sizeof(headers),
"POST /message?peer_id=%i&to=%i HTTP/1.0\r\n"
"Content-Length: %zu\r\n"
"Content-Type: text/plain\r\n"
"\r\n",
my_id_, peer_id, message.length());
onconnect_data_ = headers;
onconnect_data_ += message;
// 开始修改部分
ConnectControlSocket();
rtc::Thread::Current()->Quit();
rtc::Thread::Current()->Restart();
return true;
}
最后四行,就是修改的,它的作用和第二个修改类似,这里是先退出线程,然后重启线程。不这样修改的话,control_socket_ 的信号槽方法void PeerConnectionClient::OnConnect(..)
不会被回调。
其实,这里是一个http的短链接,他链接成功后,就会提交http信息,然后关闭链接,这里不要被代码误导了
-
- sink_filter_ds.cc 的修改
css
CaptureInputPin::Receive(IMediaSample* media_sample) {
//RTC_DCHECK_RUN_ON(&capture_checker_);
CaptureSinkFilter* const filter = static_cast<CaptureSinkFilter*>(Filter());
.....
就是注释掉 RTC_DCHECK_RUN_ON(&capture_checker_);
这里的功能是检查后面的调用后之前的调用是否同一个线程。这里是在视频通讯,采集的时候,会出问题。注释掉就好了。
以上的修改,主要是为了正常运行,后面还有一些修改,是为了模拟两个客户端程序。
一. 信令服务

peerconnection_server 是简易的信令服务器,负责两个终端之间的信息传递。
右键->生成 点击后,生成 peerconnection_server.exe
执行程序:

二. 终端程序

终端程序就是我们用于点对点呼叫的客户端程序,所以这里是需要两个客户端的,那么怎么办呢,我们这里可以先成一个客户端程序,然后把它的exe程序名称修改。然后再生成第二个客户端程序。
那么这里我们先修改一下代码,模拟一下 客户1
:
首先,把代码里面标识用户名的地方改一下,

这里的修改,就没有那么绝对,我是使用一个宏定义来控制是哪个用户,两个用户分别是"test1","test2"
然后 'peerconnection_client' 项目执行生成操作(右键->生成),然后把生成目录里面的"peerconnection_client.exe" 文件修改为 "peerconnection_client_test1.exe"。结果如下:

然后再把终端程序的 宏定义改回去

然后 'peerconnection_client' 项目执行生成操作(右键->生成)。 得到的 "peerconnection_client.exe" 程序,就是用户2的执行程序。

结果运行和展示
- 首先双击运行 peerconnection_server.exe 程序

- 运行用户(test1)程序 "peerconnection_client_test1.exe" 程序

- 点击 connect 按钮

- 运行用户(test2)程序 "peerconnection_client.exe" 程序,并且双击connect按钮

- 这个时候,就能看到对方了,然后点击 "test1" 用户

这个时候,就看到了最终效果,如果你有两个摄像头,那么就可以看到两个摄像头的互联了。
》这里有个重点,比较容易报错的地方,下面 "摄像头的使用" 章节会重点介绍这个内容。
摄像头的使用
摄像头的的核心代码如下:

它是在发其offer/answer的时候,创建peerconnection对象的时候,做这个操作的。这个伪代码逻辑如下:
csharp
class Conductor{
public:
void AddTracks()
{
.....
// 创建捕获轨道源
auto capturerSource = CreateCapturerTrackSource();
capturerSource->Create(); // 调用创建方法
...
}
}
class CapturerTrackSource
{
public:
...
void Create()
{
CreateCapturer();
}
....
}
这个过程,后面我会详细介绍。 我重点说明一下 std::unique_ptr<TestVideoCapturer> CreateCapturer
的含义,见我如下注释
rust
std::unique_ptr<TestVideoCapturer> CreateCapturer(
webrtc::TaskQueueFactory& task_queue_factory) {
// 指定目标的摄像头的分辨率和帧率
const size_t kWidth = 640;
const size_t kHeight = 480;
const size_t kFps = 30;
std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info(
webrtc::VideoCaptureFactory::CreateDeviceInfo());
if (!info) {
return nullptr;
}
// 这个方法会返回,摄像头的数量,然后遍历,去创建一个视频采集器,这里你可以自己控制这个索引
int num_devices = info->NumberOfDevices();
for (int i = 0; i < num_devices; ++i) {
std::unique_ptr<TestVideoCapturer> capturer =
webrtc::test::CreateVideoCapturer(kWidth, kHeight, kFps, i);
if (capturer) {
return capturer;
}
}
// 当摄像头视频采集器创建任然失败,或者没有摄像头的情况,下面就是创建一个模拟的视频采集器,可以用于测试
auto frame_generator = webrtc::test::CreateSquareFrameGenerator(
kWidth, kHeight, std::nullopt, std::nullopt);
return std::make_unique<webrtc::test::FrameGeneratorCapturer>(
webrtc::Clock::GetRealTimeClock(), std::move(frame_generator), kFps,
task_queue_factory);
}
我注释摄像头使用,使用模拟视频采集器的效果如下:

所以你不用担心没有摄像头的问题了