Window环境 WebRTC demo 运行

背景

接上我的上一篇博客,在window环境,把webrtc的测试程序给运行起来,方便后面的代码分析

过程

bug修改

在实际测试中,发现运行程序时候,会遇到一些问题,这里有一些修改

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会流程失败

我猜测,这里涉及一个域名解析

    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(..) 不会被回调

    1. 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信息,然后关闭链接,这里不要被代码误导了

    1. 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);
}

我注释摄像头使用,使用模拟视频采集器的效果如下:

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

相关推荐
恋猫de小郭1 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅8 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅9 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅10 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊10 小时前
jwt介绍
前端