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

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

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

相关推荐
胡八一1 分钟前
使用qianjkun uniapp 主应用 集成 vue微应用
前端·vue.js·uni-app
是罐装可乐23 分钟前
前端架构知识体系:css架构模式和代码规范
前端·css·代码规范·tailwind·bem·css原子化
闲不住的李先森26 分钟前
AI 基础调用实现:从原理到代码实现
前端·llm·全栈
轻语呢喃26 分钟前
async/await:从语法糖到并发优化的异步编程
前端·面试
南雨北斗28 分钟前
Vue 3 中computed的优势
前端
202630 分钟前
15.1 JSON schema- 创建基础样例
前端·javascript
ze_juejin31 分钟前
Linux查看日志常用命令总结
前端
奔赴_向往31 分钟前
Vue 中的 inheritAttrs 属性:深入理解与实战应用
前端
blueblood34 分钟前
在 Ant Design Vue 2 中隐藏 a-modal 右下角自带的确定按钮
前端·vue.js
zayyo1 小时前
深入理解 JavaScript 中的 new:工作原理、边界与最佳实践
前端