前言

本文主要是整理了使用WebRTC做音视频通讯时的各知识点及问题点。有理解不足和不到位的地方也欢迎指正。 对于你感兴趣的部分可以选择性观看。

WebRTC的初始化

在使用WebRTC的库之前,需要对WebRTC进行初始化, 用到的代码如下:

RTCInitializeSSL();

转定义后可以看到方法的声明:

/**
* Initialize and clean up the SSL library. Failure is fatal. These call the
* corresponding functions in webrtc/rtc_base/ssladapter.h.
*/
RTC_EXTERN BOOL RTCInitializeSSL(void);
RTC_EXTERN BOOL RTCCleanupSSL(void);

Initialize and clean up the SSL library. Failure is fatal. 初始化SSL库,失败是致命的。

函数返回的是一个布尔类型, 表示初始化的结果。 如果失败,则不能继续使用其他特性。这是使用WebRTC的前提

PeerConnection工厂的创建

在 WebRTC Native 层,factory 可以说是 “万物的根源”,像 RTCVideoSourceRTCVideoTrackRTCPeerConnection这些类型的对象,都需要通过 factory 来创建

[RTCPeerConnectionFactory initialize];

//如果点对点工厂为空
if (!factory)
{
RTCDefaultVideoDecoderFactory* decoderFactory = [[RTCDefaultVideoDecoderFactory alloc] init];
RTCDefaultVideoEncoderFactory* encoderFactory = [[RTCDefaultVideoEncoderFactory alloc] init];
NSArray* codecs = [encoderFactory supportedCodecs];
[encoderFactory setPreferredCodec:codecs[2]]; factory = [[RTCPeerConnectionFactory alloc] initWithEncoderFactory: encoderFactory
decoderFactory: decoderFactory]; }
  • 首先要调用 RTCPeerConnectionFactory 类的 initialize 方法进行初始化;
  • 然后创建 factory 对象。需要注意的是,在创建 factory 对象时,传入了两个参数:一个是默认的编码器;一个是默认的解码器。我们可以通过修改这两个参数来达到使用不同编解码器的目的。

获取本地视频流

在获取视频之前,我们首先要选择使用哪个视频设备采集数据。在WebRTC中,我们可以通过RTCCameraVideoCapture类获取所有的视频设备。如下所示:

NSArray<AVCaptureDevice*>* devices = [RTCCameraVideoCapture captureDevices];
AVCaptureDevice* device = devices[0];

通过上面两行代码,我们就拿到了视频设备中的第一个设备。当然,光有设备还不行。我们还要清楚从设备中采集的数据放到哪里了,这样我们才能将其展示出来。WebRTC 为我们提供了一个专门的类,即 RTCVideoSource , 它有两层含义:

  • 一是表明它是一个视频源。当我们要展示视频的时候,就从这里获取数据;
  • 另一方面,它也是一个终点。即,当我们从视频设备采集到视频数据时,要交给它暂存起来。
RTCVideoSource* videoSource = [factory videoSource];

除此之外,为了能更方便的控制视频设备,WebRTC 提供了一个专门用于操作设备的类,即 RTCCameraVideoCapture。通过它,我们就可以自如的控制视频设备了。

RTCVideoSource* videoSource = [factory videoSource];
capture = [[RTCCameraVideoCapturer alloc] initWithDelegate:videoSource]; [capture startCaptureWithDevice:device
format:format
fps:fps];

现在已经可以通过RTCCameraVideoCapture类控制视频设备来采集视频了, 那如何获取采集的视频流呢 ? 上面的代码我们已经将视频采集到视频源RTCVideoSource了, 那RTCVideoSource就是我们的视频流吗 ?显然不是。 这里要提到的是WebRTC三大对象中的其中一个对象RTCMediaStream ,它才是我们说的视频流。那它和RTCVideoSource之间是什么关系呢,之间是如何建立关联的呢?

//创建本地流
_localStream = [_factory mediaStreamWithStreamId:@"ARDAMS"];
//获取数据源
_localVideoSource = [_factory videoSource]; //音频
RTCAudioTrack * audioTrack = [_factory audioTrackWithTrackId:@"ARDAMSa0"];
//视频
RTCVideoTrack *videoTrack = [_factory videoTrackWithSource:_localVideoSource trackId:@"ARDAMSv0"]; //将audioTrack、videoTrack添加到流
[_localStream addAudioTrack:audioTrack];
[_localStream addVideoTrack:videoTrack]; //拿到capture对象
RTCCameraVideoCapturer * capture = [[RTCCameraVideoCapturer alloc] initWithDelegate:_localVideoSource];

原来是通过一个中间对象RTCVideoTrack 建立的关联。

  • RTCCameraVideoCapturer 将采集的视频数据交给RTCVideoSource
  • 通过RTCVideoSource创建 RTCVideoTrack
  • RTCMediaStream 添加视频轨 videoTrack。

获取本地流完整的代码如下:

if (!_localStream) {

        NSArray<AVCaptureDevice *> *captureDevices = [RTCCameraVideoCapturer captureDevices];
AVCaptureDevice * device = captureDevices[0]; //检测摄像头权限
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if(authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied)
{
NSLog(@"相机访问受限"); //TODO:
if ([self.delegate respondsToSelector:@selector(webRTCClient:setLocalStream:)]) {
[self.delegate webRTCClient:self setLocalStream:nil];
}
} else {
if (device) {
//创建本地流
_localStream = [_factory mediaStreamWithStreamId:@"ARDAMS"];
//获取数据源
_localVideoSource = [_factory videoSource]; //音频
RTCAudioTrack * audioTrack = [_factory audioTrackWithTrackId:@"ARDAMSa0"];
//视频
RTCVideoTrack *videoTrack = [_factory videoTrackWithSource:_localVideoSource trackId:@"ARDAMSv0"]; //将audioTrack、videoTrack添加到流
[_localStream addAudioTrack:audioTrack];
[_localStream addVideoTrack:videoTrack]; //拿到capture对象
RTCCameraVideoCapturer * capture = [[RTCCameraVideoCapturer alloc] initWithDelegate:_localVideoSource]; //format , fps
AVCaptureDeviceFormat * format = [[RTCCameraVideoCapturer supportedFormatsForDevice:device] lastObject];
CGFloat fps = [[format videoSupportedFrameRateRanges] firstObject].maxFrameRate; //开始采集
_videoCapture = capture;
[capture startCaptureWithDevice:device format:format fps:fps completionHandler:^(NSError * error) {
NSLog(@"startCaptureWithDevice---:%@",error); dispatch_async(dispatch_get_main_queue(), ^{
//展示预览
if ([self.delegate respondsToSelector:@selector(webRTCClient:setLocalStream:)]) {
[self.delegate webRTCClient:self setLocalStream:self.localStream];
}
}); }];
}
else
{
NSLog(@"该设备不能打开摄像头");
if ([self.delegate respondsToSelector:@selector(webRTCClient:setLocalStream:)]) {
[self.delegate webRTCClient:self setLocalStream:nil];
} } //end device
}//end auth }

PeerConnection对象的创建

RTCPeerConnection是WebRTC用于构建点对点之间稳定、高效的流传输的组件,是WebRTC三大核心组件之一。 使用它我们可以建立一条与远端通话的音视频数据传输通道

上面提到了PeerConnection工厂 RTCPeerConnectionFactoryRTCPeerConnection 的实例就是通过此工厂来创建.

if (!ICEServers) {
ICEServers = [NSMutableArray array];
[ICEServers addObject:[self defaultSTUNServer]];
} RTCConfiguration* configuration = [[RTCConfiguration alloc] init];
[configuration setIceServers:ICEServers];
RTCPeerConnection* conn = [factory
peerConnectionWithConfiguration:configuration
constraints:[self defaultPeerConnContraints]
delegate:self]; - (RTCMediaConstraints *)defaultPeerConnContraints
{
RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:@{kRTCMediaConstraintsOfferToReceiveAudio:kRTCMediaConstraintsValueTrue,kRTCMediaConstraintsOfferToReceiveVideo:kRTCMediaConstraintsValueTrue} optionalConstraints:nil];
return constraints;
}

对于 iOS 的 RTCPeerConnection 对象有三个参数:

  • 第一个,是 RTCConfiguration 类型的对象,该对象中最重要的一个字段是 iceservers。它里边存放了 stun/turn服务器地址。其主要作用是用于NAT穿越
  • 第二个参数,是 RTCMediaConstraints 类型对象,也就是对 RTCPeerConnection限制。如,是否接收视频数据?是否接收音频数据?如果要与浏览器互通还要开启 DtlsSrtpKeyAgreement 选项。
  • 第三个参数,是委托类型。相当于给 RTCPeerConnection 设置一个观察者。这样RTCPeerConnection 可以将一个状态/信息通过它通知给观察者。但它并不属于观察者模式,这一点大家一定要清楚。

更多内容

  • PeerConnection对象添加媒体流
  • PeerConnection对象的信令状态
  • PeerConnection对象获取sdp并设置
  • 获取Candidate并添加到PeerConnection对象
  • PeerConnection对象的几种状态
  • 多点连接建立的流程

详见: https://zhanglei.blog.csdn.net/article/details/122539459

iOS 集成WebRTC相关知识点总结的更多相关文章

  1. IOS开发涉及有点概念&相关知识点

    前言,IOS是基于UNIX的,用C/C+/OC直通系统底层,不想android有个jvm. 首先还是系统架构的分层架构 1.核心操作系统层 Core OS,就是内存管理.文件系统.电源管理等 2.核心 ...

  2. WebRTC相关的基础知识点

    这里主要用来记录自己整理的和webRTC相关的一些基本的知识点,后续整理的一些基础和零碎的知识点都会更新在这里.内容大部分来自于webRTC官网.w3c以及一些前辈们的博客中的文章和相关书籍等. 20 ...

  3. IOS之UI--小实例项目--添加商品和商品名(使用xib文件终结版) + xib相关知识点总结

    添加商品和商品名小项目(使用xib文件终结版) 小贴士:博文末尾有项目源码在百度云备份的下载链接. xib相关知识点总结 01-基本使用 一开始使用xib的时候,如果要使用自定义view的代码,就需要 ...

  4. Android开发涉及有点概念&相关知识点(待写)

    前言,承接之前的 IOS开发涉及有点概念&相关知识点,这次归纳的是Android开发相关,好废话不说了.. 先声明下,Android开发涉及概念比IOS杂很多,可能有很多都题不到的.. 首先由 ...

  5. iOS集成支付宝

    需要企业和支付宝签约这个是需要审核的[3天左右   以邮件形式告知你] 使用支付宝进行一个完整的支付功能,大致有以下步骤: 1>先与支付宝签约,获得商户ID(partner)和账号ID(sell ...

  6. iOS 集成Weex入门教程

    前言 自Weex发布伊始, 其口号 "Write Once, Run Everywhere"就吸引了大批前端与客户端程序猿纷纷入坑, 我也不能独善其中. 就我目前所学习Weex的经 ...

  7. iOS下WebRTC音视频通话(二)-局域网内音视频通话

    这里是iOS 下WebRTC音视频通话开发的第二篇,在这一篇会利用一个局域网内音视频通话的例子介绍WebRTC中常用的API. 如果你下载并编译完成之后,会看到一个iOS 版的WebRTC Demo. ...

  8. iOS下WebRTC音视频通话(一)

    在iOS下做IM功能时,难免都会涉及到音频通话和视频通话.QQ中的QQ电话和视频通话效果就非常好,但是如果你没有非常深厚的技术,也没有那么大的团队,很难做到QQ那么快速和稳定的通话效果. 但是利用We ...

  9. 李洪强iOS之集成极光推送三iOS集成指南

    李洪强iOS之集成极光推送三iOS集成指南 SDK说明 适用版本 本文匹配的 SDK版本:r2.1.5 以后.查看最近更新了解最新的SDK更新情况.使用Xcode 6及以上版本可以使用新版Push S ...

随机推荐

  1. 手把手教你实现一个Vue无限级联树形表格(增删改)

    前言平时我们可能在做项目时,会遇到一个业务逻辑.实现一个无限级联树形表格,什么叫做无限级联树形表格呢?就是下图所展示的内容,有一个祖元素,然后下面可能有很多子孙元素,你可以实现添加.编辑.删除这样几个 ...

  2. SAP IDOC

    物料主数据 供应商主数据 价格档案 采购订单 采购计划协议 srm发货单 物料凭证 发票校验 发票校验过账或删除信息返回 CALL FUNCTION 'BAPI_INCOMINGINVOICE_PAR ...

  3. RPA应用场景-自动轮询汇总报表

    场景概述 自动轮询汇总报表 所涉系统名称 券商披露网站 人工操作(时间/次) 36小时 所涉人工数量 1 操作频率 每月 场景流程 1.每月初机器人自动登录网站轮询36家券商披露的财务报告,并下载 2 ...

  4. c# 怎样能写个sql的解析器

    c# 怎样能写个sql的解析器 本示例主要是讲明sql解析的原理,真实的源代码下查看 sql解析器源代码 详细示例DEMO 请查看demo代码 前言 阅读本文需要有一定正则表达式基础 正则表达式基础教 ...

  5. 通过input的name属性取值

    HTML中 Script中 根据选中的值,res也就拿到相应的值.

  6. 不是吧?30秒 就能学会一个python小技巧?!

    大家好鸭!我是小熊猫 很多学习Python的朋友在项目实战中会遇到不少功能实现上的问题,有些问题并不是很难的问题,或者已经有了很好的方法来解决.当然,孰能生巧,当我们代码熟练了,自然就能总结一些好用的 ...

  7. Day04 HTML标记

    路径 ./ 同级目录 ./ 进入该目录名下 ../ 上一级目录 HTML标记 图片 <!-- 图片标记 src 图片的路径 width 设置图片宽度 height 设置图片高度 title 鼠标 ...

  8. 以脚本形式运行python库

    技术背景 当我们尝试运行python的帮助文档时,会看到如下这样的一个说明: $ python3 -h usage: python3 [option] ... [-c cmd | -m mod | f ...

  9. Jenkins安装推荐插件前,更换插件源

    网上找了很多都解决不了问题,直到看到jenkins-update-center,还有一个问题,就是尽量在实体机上装,感觉docker坑太多.... 安装jenkins,以Debian系为例 安装包在这 ...

  10. Java多线程交替打印

    1. synchronized实现双线程交替打印 class Print implements Runnable{ static int i=0; static final int n=100; @O ...