iOS 集成WebRTC相关知识点总结

金歌  金牌会员 | 2022-6-21 10:08:54 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 811|帖子 811|积分 2433

前言

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

在使用WebRTC的库之前,需要对WebRTC进行初始化, 用到的代码如下:
  1. RTCInitializeSSL();
复制代码
转定义后可以看到方法的声明:
  1. /**
  2. * Initialize and clean up the SSL library. Failure is fatal. These call the
  3. * corresponding functions in webrtc/rtc_base/ssladapter.h.
  4. */
  5. RTC_EXTERN BOOL RTCInitializeSSL(void);
  6. RTC_EXTERN BOOL RTCCleanupSSL(void);
复制代码
Initialize and clean up the SSL library. Failure is fatal.  初始化SSL库,失败是致命的。
函数返回的是一个布尔类型, 表示初始化的结果。 如果失败,则不能继续使用其他特性。这是使用WebRTC的前提
PeerConnection工厂的创建

在 WebRTC Native 层,factory 可以说是 “万物的根源”,像 RTCVideoSource、RTCVideoTrack、RTCPeerConnection这些类型的对象,都需要通过 factory 来创建
  1. [RTCPeerConnectionFactory initialize];
  2.    
  3. //如果点对点工厂为空
  4. if (!factory)
  5. {
  6.     RTCDefaultVideoDecoderFactory* decoderFactory = [[RTCDefaultVideoDecoderFactory alloc] init];
  7.     RTCDefaultVideoEncoderFactory* encoderFactory = [[RTCDefaultVideoEncoderFactory alloc] init];
  8.     NSArray* codecs = [encoderFactory supportedCodecs];
  9.     [encoderFactory setPreferredCodec:codecs[2]];
  10.    
  11.     factory = [[RTCPeerConnectionFactory alloc] initWithEncoderFactory: encoderFactory
  12.                                                         decoderFactory: decoderFactory];
  13. }
复制代码


  • 首先要调用 RTCPeerConnectionFactory 类的 initialize 方法进行初始化;
  • 然后创建 factory 对象。需要注意的是,在创建 factory 对象时,传入了两个参数:一个是默认的编码器;一个是默认的解码器。我们可以通过修改这两个参数来达到使用不同编解码器的目的。
获取本地视频流

在获取视频之前,我们首先要选择使用哪个视频设备采集数据。在WebRTC中,我们可以通过RTCCameraVideoCapture类获取所有的视频设备。如下所示:
  1. NSArray<AVCaptureDevice*>* devices = [RTCCameraVideoCapture captureDevices];
  2. AVCaptureDevice* device = devices[0];
复制代码
通过上面两行代码,我们就拿到了视频设备中的第一个设备。当然,光有设备还不行。我们还要清楚从设备中采集的数据放到哪里了,这样我们才能将其展示出来。WebRTC 为我们提供了一个专门的类,即 RTCVideoSource , 它有两层含义:

  • 一是表明它是一个视频源。当我们要展示视频的时候,就从这里获取数据;
  • 另一方面,它也是一个终点。即,当我们从视频设备采集到视频数据时,要交给它暂存起来。
  1. RTCVideoSource* videoSource = [factory videoSource];
复制代码
除此之外,为了能更方便的控制视频设备,WebRTC 提供了一个专门用于操作设备的类,即 RTCCameraVideoCapture。通过它,我们就可以自如的控制视频设备了。
  1. RTCVideoSource* videoSource = [factory videoSource];
  2. capture = [[RTCCameraVideoCapturer alloc] initWithDelegate:videoSource];
  3. [capture startCaptureWithDevice:device
  4.                              format:format
  5.                                 fps:fps];
复制代码
现在已经可以通过RTCCameraVideoCapture类控制视频设备来采集视频了, 那如何获取采集的视频流呢 ? 上面的代码我们已经将视频采集到视频源RTCVideoSource了, 那RTCVideoSource就是我们的视频流吗 ?显然不是。  这里要提到的是WebRTC三大对象中的其中一个对象RTCMediaStream ,它才是我们说的视频流。那它和RTCVideoSource之间是什么关系呢,之间是如何建立关联的呢?
  1. //创建本地流
  2. _localStream = [_factory mediaStreamWithStreamId:@"ARDAMS"];
  3. //获取数据源
  4. _localVideoSource = [_factory videoSource];
  5.                
  6. //音频
  7. RTCAudioTrack * audioTrack = [_factory audioTrackWithTrackId:@"ARDAMSa0"];
  8. //视频
  9. RTCVideoTrack *videoTrack = [_factory videoTrackWithSource:_localVideoSource trackId:@"ARDAMSv0"];
  10. //将audioTrack、videoTrack添加到流
  11. [_localStream addAudioTrack:audioTrack];
  12. [_localStream addVideoTrack:videoTrack];
  13. //拿到capture对象
  14. RTCCameraVideoCapturer * capture = [[RTCCameraVideoCapturer alloc] initWithDelegate:_localVideoSource];
复制代码
原来是通过一个中间对象RTCVideoTrack 建立的关联。


  • RTCCameraVideoCapturer 将采集的视频数据交给RTCVideoSource
  • 通过RTCVideoSource创建  RTCVideoTrack
  • RTCMediaStream 添加视频轨 videoTrack。
获取本地流完整的代码如下:
  1. if (!_localStream) {
  2.         
  3.         NSArray<AVCaptureDevice *> *captureDevices = [RTCCameraVideoCapturer captureDevices];
  4.         AVCaptureDevice * device = captureDevices[0];
  5.         //检测摄像头权限
  6.         AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  7.         if(authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied)
  8.         {
  9.             NSLog(@"相机访问受限");
  10.             
  11.             //TODO:
  12.             if ([self.delegate respondsToSelector:@selector(webRTCClient:setLocalStream:)]) {
  13.                 [self.delegate webRTCClient:self setLocalStream:nil];
  14.             }
  15.         } else {
  16.             if (device) {
  17.                 //创建本地流
  18.                 _localStream = [_factory mediaStreamWithStreamId:@"ARDAMS"];
  19.                 //获取数据源
  20.                 _localVideoSource = [_factory videoSource];
  21.                
  22.                 //音频
  23.                 RTCAudioTrack * audioTrack = [_factory audioTrackWithTrackId:@"ARDAMSa0"];
  24.                 //视频
  25.                 RTCVideoTrack *videoTrack = [_factory videoTrackWithSource:_localVideoSource trackId:@"ARDAMSv0"];
  26.                
  27.                 //将audioTrack、videoTrack添加到流
  28.                 [_localStream addAudioTrack:audioTrack];
  29.                 [_localStream addVideoTrack:videoTrack];
  30.                
  31.                 //拿到capture对象
  32.                 RTCCameraVideoCapturer * capture = [[RTCCameraVideoCapturer alloc] initWithDelegate:_localVideoSource];
  33.                
  34.                 //format , fps
  35.                 AVCaptureDeviceFormat * format = [[RTCCameraVideoCapturer supportedFormatsForDevice:device] lastObject];
  36.                 CGFloat fps = [[format videoSupportedFrameRateRanges] firstObject].maxFrameRate;
  37.                
  38.                 //开始采集
  39.                 _videoCapture = capture;
  40.                 [capture startCaptureWithDevice:device format:format fps:fps completionHandler:^(NSError * error) {
  41.                     NSLog(@"startCaptureWithDevice---:%@",error);
  42.                     
  43.                     dispatch_async(dispatch_get_main_queue(), ^{
  44.                         //展示预览
  45.                         if ([self.delegate respondsToSelector:@selector(webRTCClient:setLocalStream:)]) {
  46.                             [self.delegate webRTCClient:self setLocalStream:self.localStream];
  47.                         }
  48.                     });
  49.                     
  50.                 }];
  51.             }
  52.             else
  53.             {
  54.                 NSLog(@"该设备不能打开摄像头");
  55.                 if ([self.delegate respondsToSelector:@selector(webRTCClient:setLocalStream:)]) {
  56.                     [self.delegate webRTCClient:self setLocalStream:nil];
  57.                 }
  58.                
  59.                
  60.             } //end device
  61.         }//end auth
  62.         
  63.     }
复制代码
PeerConnection对象的创建

RTCPeerConnection是WebRTC用于构建点对点之间稳定、高效的流传输的组件,是WebRTC三大核心组件之一。  使用它我们可以建立一条与远端通话的音视频数据传输通道。
上面提到了PeerConnection工厂 RTCPeerConnectionFactory,  RTCPeerConnection 的实例就是通过此工厂来创建.
  1. if (!ICEServers) {
  2.     ICEServers = [NSMutableArray array];
  3.     [ICEServers addObject:[self defaultSTUNServer]];
  4. }
  5. RTCConfiguration* configuration = [[RTCConfiguration alloc] init];
  6. [configuration setIceServers:ICEServers];
  7. RTCPeerConnection* conn = [factory
  8.                                  peerConnectionWithConfiguration:configuration
  9.                                                      constraints:[self defaultPeerConnContraints]
  10.                                                         delegate:self];
  11. - (RTCMediaConstraints *)defaultPeerConnContraints
  12. {
  13.     RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:@{kRTCMediaConstraintsOfferToReceiveAudio:kRTCMediaConstraintsValueTrue,kRTCMediaConstraintsOfferToReceiveVideo:kRTCMediaConstraintsValueTrue} optionalConstraints:nil];
  14.     return constraints;
  15. }
复制代码
对于 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

来源:https://www.cnblogs.com/reyzhang/p/16198230.html
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金歌

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表