美文网首页
WebRTC -ios

WebRTC -ios

作者: 稀释1 | 来源:发表于2020-09-11 11:41 被阅读0次

    1.podfile 文件

    source 'https://github.com/CocoaPods/Specs.git'
     platform :ios, '9.0'
    
    target 'iosWebRTCDemo' do
      # Comment the next line if you don't want to use dynamic frameworks
      use_frameworks!
    pod 'GoogleWebRTC','1.1.24595'
    
    pod 'ReactiveObjC'
    pod 'SocketRocket','0.5.1'
    pod 'HGAlertViewController', '~> 1.0.1'
    
      target 'iosWebRTCDemoTests' do
        inherit! :search_paths
        # Pods for testing
      end
    
      target 'iosWebRTCDemoUITests' do
        # Pods for testing
      end
    
    end
    
     [[WebRTCHelper shareInstance] connectServer:@"172.27.104.54" port:@"9090/SocketServer"];
    
    1. WebRTCHelper.h
    //
    //  WebRTCHelper.h
    //  WebRTC_new
    //
    //  Created by
    //  Copyright © 2020年
    //
    
    #import <Foundation/Foundation.h>
    #import <WebRTC/WebRTC.h>
    #import <SocketRocket/SocketRocket.h>
    #import <WebRTC/RTCMacros.h>
    #import <WebRTC/RTCVideoCodec.h>
    
    //@import SocketIO;
    
    typedef enum : NSUInteger {
        WebSocketConnectSuccess = 0,
        WebSocketConnectField,
        WebSocketConnectClosed,
    } WebSocketConnectState;
    
    @protocol WebRTCHelperDelegate;
    @protocol WebRTCHelperFrindDelegate;
    
    @interface WebRTCHelper : NSObject
    
    /**
     * 单例
     */
    +(instancetype)shareInstance;
    
    /*注释*/
    @property (nonatomic,weak) id<WebRTCHelperDelegate> delegate;
    /*注释*/
    @property (nonatomic,weak) id<WebRTCHelperFrindDelegate> friendDelegate;
    
    /**
     * 与服务器建立连接
     * @param server 服务器地址
     * @param port 端口号
     */
    -(void)connectServer:(NSString *)server port:(NSString *)port;
    /**
     * 切换摄像头
     */
    - (void)swichCamera:(BOOL)_usingFrontCamera;
    /**
     * 是否显示本地视频
     */
    - (void)showLocaolCamera:(BOOL)_usingCamera;
    /**
     * 退出房间
     */
    -(void)exitRoom;
    
    @end
    
    @protocol WebRTCHelperDelegate <NSObject>
    @optional
    /**
     * 获取到发送信令消息
     * @param webRTCHelper 本类
     * @param message 消息内容
     */
    -(void)webRTCHelper:(WebRTCHelper *)webRTCHelper receiveMessage:(NSString *)message;
    /**
     * 获取本地的localVideoStream数据
     * @param webRTCHelper 本类
     * @param steam 视频流
     * @param userId 用户标识
     */
    -(void)webRTCHelper:(WebRTCHelper *)webRTCHelper setLocalStream:(RTCMediaStream *)steam userId:(NSString *)userId;
    /**
     * 获取远程的remoteVideoStream数据
     * @param webRTCHelper 本类
     * @param stream 视频流
     * @param userId 用户标识
     */
    -(void)webRTCHelper:(WebRTCHelper *)webRTCHelper addRemoteStream:(RTCMediaStream *)stream userId:(NSString *)userId;
    /**
     * 某个用户退出后,关闭用户的连接
     * @param webRTCHelper 本类
     * @param userId 用户标识
     */
    - (void)webRTCHelper:(WebRTCHelper *)webRTCHelper closeWithUserId:(NSString *)userId;
    
    /**
     * 获取socket连接状态
     * @param webRTCHelper 本类
     * @param connectState 连接状态,分为
     WebSocketConnectSuccess 成功,
     WebSocketConnectField, 失败
     WebSocketConnectClosed 关闭
     */
    -(void)webRTCHelper:(WebRTCHelper *)webRTCHelper socketConnectState:(WebSocketConnectState)connectState;
    -(void)webRTCHelper:(WebRTCHelper *)webRTCHelper capturerSession:(AVCaptureSession *)captureSession;
    @end
    
    @protocol WebRTCHelperFrindDelegate <NSObject>
    @optional
    /**
     * 获取房间内所有的用户(除了自己)
     * @param friendList 用户列表
     */
    -(void)webRTCHelper:(WebRTCHelper *)webRTCHelper gotFriendList:(NSArray *)friendList;
    /**
     * 获取新加入的用户信息
     * @param friendId 新用户的id
     */
    -(void)webRTCHelper:(WebRTCHelper *)webRTCHelper gotNewFriend:(NSString *)friendId;
    /**
     * 获取离开房间用户的信息
     * @param friendId 离开用户的ID
     */
    -(void)webRTCHelper:(WebRTCHelper *)webRTCHelper removeFriend:(NSString *)friendId;
    @end
    
    
    
    
    

    3 .WebRTCHelper.m

    //
    //  WebRTCHelper.m
    //  WebRTC_new
    //
    //  Created by
    //  Copyright © 2020年
    //
    
    #import "WebRTCHelper.h"
    
    #define kAPPID  @"1234567890abcdefg"
    #define kDeviceUUID [[[UIDevice currentDevice] identifierForVendor] UUIDString]
    
    //google提供的
    static NSString *const RTCSTUNServerURL = @"stun:stun.l.google.com:19302";
    //static NSString *const RTCSTUNServerURL2 = @"stun:23.21.150.121";
    static NSString *const RTCSTUNServerURL2 =@"stun:global.stun.twilio.com:3478?transport=udp";
    
    
    @interface WebRTCHelper()<RTCPeerConnectionDelegate,RTCVideoCapturerDelegate,SRWebSocketDelegate>
    {
        SRWebSocket *_socket;
        NSString *_server;
        
        RTCPeerConnectionFactory *_factory;
        RTCMediaStream *_localStream;
        
        NSString *_myId;
        NSMutableDictionary *_connectionDic; // 存放 所有用户 对应的链接集合
        NSMutableArray *_connectionIdArray; // 存放 房间人数的 id
        
        NSMutableArray *ICEServers;
      
        //是否显示我的视频流(默认为yes,显示;no为不显示)
        BOOL _usingCamera;
        
        RTCCameraVideoCapturer * _capture;
    }
    
    @end
    
    @implementation WebRTCHelper
    
    static WebRTCHelper * instance = nil;
    
    +(instancetype)shareInstance{
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instance = [[[self class] alloc] init];
            [instance initData];
        });
        return instance;
    }
    
    -(void)initData{
        _connectionDic = [NSMutableDictionary dictionary];
        _connectionIdArray = [NSMutableArray array];
        _usingCamera = YES;
    }
    
    
    #pragma mark -提供给外部的方法
    
    /**
     * 与服务器进行连接
     */
    - (void)connectServer:(NSString *)server port:(NSString *)port{
        _server = server;
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"ws://%@:%@",server,port]] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20];
    
        _socket = [[SRWebSocket alloc] initWithURLRequest:request];
        _socket.delegate = self;
        [_socket open];
    
        
    }
    
    
    /**
     *  退出房间
     */
    - (void)exitRoom
    {
        _localStream = nil;
        [_capture stopCapture];
        _capture = nil;
        NSArray *arr =_connectionIdArray.copy;
        [arr enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL * _Nonnull stop) {
          [self closePeerConnection:obj];
    
        }];
        [_socket close];
    }
    
    /**
     * 切换摄像头
     */
    - (void)swichCamera:(BOOL)_usingFrontCamera{
    
        [self switchFrontBackCamera:_usingFrontCamera];
    }
    
    /**
     * 是否显示本地摄像头
     */
    - (void)showLocaolCamera:(BOOL)_usingCamera{
        _usingCamera = _usingCamera;
        //如果为空,则创建点对点工厂
        if (!_factory)
        {
            //设置SSL传输
            [RTCPeerConnectionFactory initialize];
            [self create_factory];
        }
        //如果本地视频流为空
        if (!_localStream)
        {
            //创建本地流
            [self createLocalStream];
        }
    //    [_capture stopCapture];
        //创建连接
        [self createPeerConnections];
        
        //添加
        [self addStreams];
        [self createOffers];
    }
    
    #pragma mark -内部方法
    /**
     *  关闭peerConnection
     *
     *  @param connectionId <#connectionId description#>
     */
    - (void)closePeerConnection:(NSString *)connectionId
    {
        RTCPeerConnection *peerConnection = [_connectionDic objectForKey:connectionId];
        if (peerConnection)
        {
            [peerConnection close];
        }
        [_connectionIdArray removeObject:connectionId];
        [_connectionDic removeObjectForKey:connectionId];
        dispatch_async(dispatch_get_main_queue(), ^{
            if ([self->_delegate respondsToSelector:@selector(webRTCHelper:closeWithUserId:)])
            {
                [self->_delegate webRTCHelper:self closeWithUserId:connectionId];
            }
        });
    }
    
    
    /**
     *  创建点对点连接
     *
     *  @param connectionId connectionId description
     *
     *  @return <#return value description#>
     */
    - (RTCPeerConnection *)createPeerConnection:(NSString *)connectionId
    {
        //如果点对点工厂为空
        if (!_factory)
        {
            [self create_factory];
        }
        
        //得到ICEServer
        if (!ICEServers) {
            ICEServers = [NSMutableArray array];
            [ICEServers addObject:[self defaultSTUNServer]];
        }
        
        //用工厂来创建连接
        RTCConfiguration *configuration = [[RTCConfiguration alloc] init];
        configuration.iceServers = ICEServers;
        RTCPeerConnection *connection = [_factory peerConnectionWithConfiguration:configuration constraints:[self creatPeerConnectionConstraint] delegate:self];
        return connection;
    }
    
    - (RTCMediaConstraints *)creatPeerConnectionConstraint
    {
        RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:@{kRTCMediaConstraintsOfferToReceiveAudio:kRTCMediaConstraintsValueTrue,kRTCMediaConstraintsOfferToReceiveVideo:kRTCMediaConstraintsValueTrue} optionalConstraints:@{@"DtlsSrtpKeyAgreement":@"true"}];
        
        return constraints;
    }
    
    //初始化STUN Server (ICE Server)
    - (RTCIceServer *)defaultSTUNServer{
        return [[RTCIceServer alloc] initWithURLStrings:@[RTCSTUNServerURL,RTCSTUNServerURL2]];
    }
    
    
    /**
     *  为所有连接添加流
     */
    - (void)addStreams
    {
        //给每一个点对点连接,都加上本地流
        NSDictionary *dic = [_connectionDic copy];
        [dic enumerateKeysAndObjectsUsingBlock:^(NSString *key, RTCPeerConnection *obj, BOOL * _Nonnull stop) {
            if (!self->_localStream)
            {
                [self createLocalStream];
            }
            [obj addStream:self->_localStream];
        }];
    }
    /**
     *  创建所有连接
     */
    - (void)createPeerConnections
    {
        //从我们的连接数组里快速遍历
        NSArray *arr = _connectionIdArray.copy;
        [arr enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL * _Nonnull stop) {
            
            //根据连接ID去初始化 RTCPeerConnection 连接对象
            RTCPeerConnection *connection = [self createPeerConnection:obj];
            
            //设置这个ID对应的 RTCPeerConnection对象
            [self->_connectionDic setObject:connection forKey:obj];
           
        }];
    }
    
    
    /**
     * 创建本地视频流
     */
    -(void)createLocalStream{
        _localStream = [_factory mediaStreamWithStreamId:@"ARDAMS"];
        //音频
        RTCAudioTrack * audioTrack = [_factory audioTrackWithTrackId:@"ARDAMSa0"];
        [_localStream addAudioTrack:audioTrack];
        NSArray<AVCaptureDevice *> *captureDevices = [RTCCameraVideoCapturer captureDevices];
        AVCaptureDevicePosition position =  AVCaptureDevicePositionFront;
        AVCaptureDevice * device = captureDevices[0];
        for (AVCaptureDevice *obj in captureDevices) {
            if (obj.position == position) {
                device = obj;
                break;
            }
        }
        
        //检测摄像头权限
        AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
        if(authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied)
        {
            NSLog(@"相机访问受限");
            if ([_delegate respondsToSelector:@selector(webRTCHelper:setLocalStream:userId:)])
            {
                
                [_delegate webRTCHelper:self setLocalStream:nil userId:_myId];
            }
        }
        else
        {
            if (device)
            {
                
                RTCVideoSource *videoSource = [_factory videoSource];
                  [videoSource adaptOutputFormatToWidth:640 height:480 fps:20];
             _capture = [[RTCCameraVideoCapturer alloc] initWithDelegate:videoSource];
    //            AVCaptureDeviceFormat * format = [[RTCCameraVideoCapturer supportedFormatsForDevice:device] lastObject];
                 AVCaptureDeviceFormat* format = device.activeFormat;
    
                RTCVideoTrack *videoTrack = [_factory videoTrackWithSource:videoSource trackId:@"ARDAMSv0"];
                __weak RTCCameraVideoCapturer *weakCapture = _capture;
                [_localStream addVideoTrack:videoTrack];
                if ([self->_delegate respondsToSelector:@selector(webRTCHelper:capturerSession:)])
                {
                    [self->_delegate webRTCHelper:self capturerSession:weakCapture.captureSession];
                }
          
                  [weakCapture stopCapture];
                [weakCapture startCaptureWithDevice:device format:format fps:20 completionHandler:^(NSError * error) {
                    NSLog(@"11111111");
                }];
            }
            else
            {
                NSLog(@"该设备不能打开摄像头");
                if ([_delegate respondsToSelector:@selector(webRTCHelper:setLocalStream:userId:)])
                {
                    [_delegate webRTCHelper:self setLocalStream:nil userId:_myId];
                }
            }
        }
    }
    // 切换摄像头
    -(void)switchFrontBackCamera:(BOOL)usingFrontCamera
    {
        if (_localStream == nil)
            return;
        
        NSArray<AVCaptureDevice *> *captureDevices = [RTCCameraVideoCapturer captureDevices];
        AVCaptureDevicePosition position = usingFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
        AVCaptureDevice * device = nil;
        for (AVCaptureDevice *obj in captureDevices) {
            if (obj.position == position) {
                device = obj;
                break;
            }
        }
        
    //    AVCaptureDeviceFormat * format = [[RTCCameraVideoCapturer supportedFormatsForDevice:device] lastObject];
         AVCaptureDeviceFormat* format = device.activeFormat;
        [_capture stopCapture];
        [_capture startCaptureWithDevice:device format:format fps:15 completionHandler:^(NSError * _Nonnull error)
         {
             
         }];
    }
    /**
     *  视频的相关约束
     */
    - (RTCMediaConstraints *)localVideoConstraints
    {
        NSDictionary *mandatory = @{kRTCMediaConstraintsMaxWidth:@640,kRTCMediaConstraintsMinWidth:@640,kRTCMediaConstraintsMaxHeight:@480,kRTCMediaConstraintsMinHeight:@480,kRTCMediaConstraintsMinFrameRate:@15};
        
        RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatory optionalConstraints:@{@"DtlsSrtpKeyAgreement":@"true"}];
        return constraints;
    }
    
    /**
     * 创建offer
     */
    -(void)createOffer:(RTCPeerConnection *)peerConnection{
        if (peerConnection == nil) {
            peerConnection = [self createPeerConnection:nil];
        }
        
        [peerConnection offerForConstraints:[self offerOranswerConstraint] completionHandler:^(RTCSessionDescription * _Nullable sdp, NSError * _Nullable error) {
            if (error == nil) {
    //             RTCSessionDescription *newSdp = [self descriptionForDescription:sdp preferredVideoCodec:@"H264"];
                __weak RTCPeerConnection * weakPeerConnction = peerConnection;
                [peerConnection setLocalDescription:sdp completionHandler:^(NSError * _Nullable error) {
                    if (error == nil) {
                        [self setSessionDescriptionWithPeerConnection:weakPeerConnction];
                    }
                }];
            }
        }];
    
    }
    /**
     *  为所有连接创建offer
     */
    - (void)createOffers
    {
        //给每一个点对点连接,都去创建offer
        NSDictionary *dic = [_connectionDic copy];
        [dic enumerateKeysAndObjectsUsingBlock:^(NSString *key, RTCPeerConnection *obj, BOOL * _Nonnull stop) {
            [self createOffer:obj];
        }];
    }
    
    /**
     *  设置offer/answer的约束d
     */
    - (RTCMediaConstraints *)offerOranswerConstraint
    {
        NSMutableDictionary * dic = [@{kRTCMediaConstraintsOfferToReceiveAudio:kRTCMediaConstraintsValueTrue,kRTCMediaConstraintsOfferToReceiveVideo:kRTCMediaConstraintsValueTrue} mutableCopy];
        [dic setObject:(_usingCamera ? kRTCMediaConstraintsValueTrue : kRTCMediaConstraintsValueFalse) forKey:kRTCMediaConstraintsOfferToReceiveVideo];
        RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:dic optionalConstraints:@{@"DtlsSrtpKeyAgreement":@"true"}];
        return constraints;
    }
    
    // Called when setting a local or remote description.
    //当一个远程或者本地的SDP被设置就会调用
    - (void)setSessionDescriptionWithPeerConnection:(RTCPeerConnection *)peerConnection
    {
        NSLog(@"%s",__func__);
        NSString *currentId = [self getKeyFromConnectionDic:peerConnection];
       
        if (currentId == nil)
        {
            NSLog(@"找不到用户");
            return;
        }
        
        
        //判断,当前连接状态为,收到了远程点发来的offer,这个是进入房间的时候,尚且没人,来人就调到这里
        if (peerConnection.signalingState == RTCSignalingStateHaveRemoteOffer)
        {
            //创建一个answer,会把自己的SDP信息返回出去
            [peerConnection answerForConstraints:[self offerOranswerConstraint] completionHandler:^(RTCSessionDescription * _Nullable sdp, NSError * _Nullable error) {
                __weak RTCPeerConnection *obj = peerConnection;
                [peerConnection setLocalDescription:sdp completionHandler:^(NSError * _Nullable error) {
                    [self setSessionDescriptionWithPeerConnection:obj];
                }];
            }];
        }
        //判断连接状态为本地发送offer
        else if (peerConnection.signalingState == RTCSignalingStateHaveLocalOffer)
        {
            if (peerConnection.localDescription.type == RTCSdpTypeAnswer)
            {
                NSDictionary *dic = @{@"event": @"answer", @"data": @{@"sdp": peerConnection.localDescription.sdp}, @"sender": _myId, @"receiver":currentId};
                NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
                NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                [_socket send:jsonString];
                
            }
            //发送者,发送自己的offer
            else if(peerConnection.localDescription.type == RTCSdpTypeOffer)
            {
                NSDictionary *dic = @{@"event": @"offer", @"data": @{@"sdp": peerConnection.localDescription.sdp}, @"sender": _myId, @"receiver":currentId};
                NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
                 NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                [_socket send:jsonString];
            }
        }
        else if (peerConnection.signalingState == RTCSignalingStateStable)
        {
            if (peerConnection.localDescription.type == RTCSdpTypeAnswer)
            {
                NSDictionary *dic = @{@"event": @"answer", @"data": @{@"sdp": peerConnection.localDescription.sdp}, @"sender": _myId, @"receiver":currentId};
                NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
                 NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                [_socket send:jsonString];
            }
        }
        
    }
    
    
    #pragma mark RTCPeerConnectionDelegate
    /**获取远程视频流*/
    - (void)peerConnection:( RTCPeerConnection *)peerConnection didAddStream:( RTCMediaStream *)stream {
        NSString * userId = [self getKeyFromConnectionDic:peerConnection];
        dispatch_async(dispatch_get_main_queue(), ^{
            if ([self->_delegate respondsToSelector:@selector(webRTCHelper:addRemoteStream:userId:)]) {
                [self->_delegate webRTCHelper:self addRemoteStream:stream userId:userId];
            }
        });
    }
    
    /**RTCIceConnectionState 状态变化*/
    - (void)peerConnection:(nonnull RTCPeerConnection *)peerConnection didChangeIceConnectionState:(RTCIceConnectionState)newState {
        NSLog(@"%s",__func__);
        NSLog(@"newState=====%ld",(long)newState);
        NSString * connectId = [self getKeyFromConnectionDic:peerConnection];
       
        if (newState == RTCIceConnectionStateDisconnected) {
    //         [self createOffer:peerConnection];
            //断开connection的连接
    //        dispatch_async(dispatch_get_main_queue(), ^{
    //            if ([self->_delegate respondsToSelector:@selector(webRTCHelper:closeWithUserId:)]) {
    //                [self->_delegate webRTCHelper:self closeWithUserId:connectId];
    //            }
    //            [self closePeerConnection:connectId];
    //        });
        }
    }
    //[candidate.sdpMid isEqualToString:@"audio"]?@"audio":@"video"
    /**获取到新的candidate*/
    - (void)peerConnection:(RTCPeerConnection *)peerConnection didGenerateIceCandidate:(RTCIceCandidate *)candidate{
        NSLog(@"+++%s",__func__);
        
        NSString *currentId = [self getKeyFromConnectionDic: peerConnection];
        
        NSDictionary *dic = @{
                              @"event": @"_ice_candidate",
                              @"data":@{
                                      @"candidate":@{
                                              @"sdpMid":candidate.sdpMid ,
                                              @"sdpMLineIndex":[NSNumber numberWithInteger:candidate.sdpMLineIndex],
                                              @"candidate": candidate.sdp
                                              }
                                      
                                      } ,
                              @"sender":_myId ,
                              @"receiver":currentId
                              };
         NSLog(@"%d-------%@",candidate.sdpMLineIndex,candidate.sdpMid);
        NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
          NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        [_socket send:jsonString];
    }
    
    /**删除某个视频流*/
    - (void)peerConnection:(nonnull RTCPeerConnection *)peerConnection didRemoveStream:(nonnull RTCMediaStream *)stream {
        NSLog(@"%s",__func__);
    }
    
    - (void)peerConnectionShouldNegotiate:(RTCPeerConnection *)peerConnection{
        NSLog(@"%s,line = %d object = %@",__FUNCTION__,__LINE__,peerConnection);
    }
    
    - (void)peerConnection:(nonnull RTCPeerConnection *)peerConnection didRemoveIceCandidates:(nonnull NSArray<RTCIceCandidate *> *)candidates {
        NSLog(@"%s,line = %d object = %@",__FUNCTION__,__LINE__,candidates);
    }
    
    - (void)peerConnection:(RTCPeerConnection *)peerConnection didChangeSignalingState:(RTCSignalingState)stateChanged{
         NSString *currentId = [self getKeyFromConnectionDic: peerConnection];
        
        NSLog(@"stateChanged = %ld=======currentId=====%@",(long)stateChanged,currentId);
    }
    - (void)peerConnection:(RTCPeerConnection *)peerConnection didChangeIceGatheringState:(RTCIceGatheringState)newState{
        NSLog(@"newState = %ld",newState);
    }
    
    
    #pragma mark -消息相关
    -(void)peerConnection:(RTCPeerConnection *)peerConnection didOpenDataChannel:(RTCDataChannel *)dataChannel{
        
    }
    
    #pragma mark -视频分辨率代理
    - (void)capturer:(nonnull RTCVideoCapturer *)capturer didCaptureVideoFrame:(nonnull RTCVideoFrame *)frame {
        
    }
    -(void)create_factory
    {
        if(!_factory)
        {
            RTCInitializeSSL();
            RTCDefaultVideoEncoderFactory *encodeFac = [[RTCDefaultVideoEncoderFactory alloc]init];
            RTCDefaultVideoDecoderFactory *decodeFac = [[RTCDefaultVideoDecoderFactory  alloc]init];
            NSArray *arrCodecs  = [encodeFac supportedCodecs];
    //        RTCVideoCodecInfo *info = arrCodecs[2];
    //         RTCVideoCodecInfo *info1 = arrCodecs[2];
    //        [encodeFac setPreferredCodec :info];
        
            _factory = [[RTCPeerConnectionFactory alloc]initWithEncoderFactory:encodeFac decoderFactory:decodeFac];
    //        _factory = [[RTCPeerConnectionFactory alloc] init];
            }
       
    }
    #pragma mark --open
    -(void)openWith:(NSDictionary*)dic{
        //得到data
        //得到所有的连接
        NSArray *connections = dic[@"remoteIds"];
        //加到连接数组中去
        [_connectionIdArray addObjectsFromArray:connections];
        
        //拿到给自己分配的ID
        _myId = dic[@"sender"];
        
        //如果为空,则创建点对点工厂
        if (!_factory)
        {
            //设置SSL传输
            [RTCPeerConnectionFactory initialize];
            [self create_factory];
            
        }
      
        //如果本地视频流为空
        if (!_localStream)
        {
            //创建本地流
            [self createLocalStream];
        }
        //创建连接
        [self createPeerConnections];
        
        //添加
        [self addStreams];
    //    [self createOffers];
        
        //获取房间内所有用户的代理回调
        dispatch_async(dispatch_get_main_queue(), ^{
          
            if ([self->_friendDelegate respondsToSelector:@selector(webRTCHelper:gotFriendList:)]) {
                [self->_friendDelegate webRTCHelper:self gotFriendList:connections];
            }
        });
    }
    
    #pragma mark --_ice_candidate
    -(void)_ice_candidateWith:(NSDictionary *)dic{
        NSDictionary *dataDic = dic[@"data"];
        NSString *socketId = dic[@"sender"];
        NSDictionary *candidateDic =dataDic[@"candidate"];
        NSString *sdpMid = candidateDic[@"sdpMid"];
        
        int sdpMLineIndex = [candidateDic[@"sdpMLineIndex"] intValue];
        NSString *sdp = candidateDic[@"candidate"];
        //生成远端网络地址对象
        RTCIceCandidate *candidate = [[RTCIceCandidate alloc] initWithSdp:sdp sdpMLineIndex:sdpMLineIndex sdpMid:sdpMid];
        //拿到当前对应的点对点连接
        RTCPeerConnection *peerConnection = [_connectionDic objectForKey:socketId];
        //添加到点对点连接中
        [peerConnection addIceCandidate:candidate];
    }
    #pragma mark ------join
    -(void)joinWith:(NSDictionary *)dic{
        //拿到新人的ID
        NSString *socketId = dic[@"sender"];
        
        //再去创建一个连接
        RTCPeerConnection *peerConnection = [self createPeerConnection:socketId];
        if (!_localStream)
        {
            [self createLocalStream];
        }
        //把本地流加到连接中去
        [peerConnection addStream:_localStream];
        //连接ID新加一个
        [_connectionIdArray addObject:socketId];
        //并且设置到Dic中去
        [_connectionDic setObject:peerConnection forKey:socketId];
    
       [self createOffer:peerConnection];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            //设置新加入用户代理
            if ([self->_friendDelegate respondsToSelector:@selector(webRTCHelper:gotNewFriend:)]) {
                [self->_friendDelegate webRTCHelper:self gotNewFriend:socketId];
            }
        });
    }
    
    #pragma mark --remove
    -(void)removeWith:(NSDictionary *)dic{
        //得到socketId,关闭这个peerConnection
        NSString *socketId = dic[@"sender"];
        [self closePeerConnection:socketId];
        
        //设置关闭某个用户聊天代理回调
        dispatch_async(dispatch_get_main_queue(), ^{
    //        if ([self->_delegate respondsToSelector:@selector(webRTCHelper:closeWithUserId:)])
    //        {
    //            [self->_delegate webRTCHelper:self closeWithUserId:socketId];
    //        }
            //设置退出房间用户代理回调
            if ([self->_friendDelegate respondsToSelector:@selector(webRTCHelper:removeFriend:)]) {
                [self->_friendDelegate webRTCHelper:self removeFriend:socketId];
            }
        });
    }
    
    #pragma mark --offer
    -(void)offerWith:(NSDictionary *)dic{
        NSDictionary *dataDic = dic[@"data"];
        //拿到SDP
        NSString *sdp = dataDic[@"sdp"];
        NSString *socketId =  dic[@"sender"];
        
        //拿到这个点对点的连接
        RTCPeerConnection *peerConnection = [_connectionDic objectForKey:socketId];
        //根据类型和SDP 生成SDP描述对象
        RTCSessionDescription *remoteSdp = [[RTCSessionDescription alloc] initWithType:RTCSdpTypeOffer sdp:sdp];
    //    RTCSessionDescription *newSdp = [self descriptionForDescription:remoteSdp preferredVideoCodec:@"H264"];
        //设置给这个点对点连接
        __weak RTCPeerConnection *weakPeerConnection = peerConnection;
        [peerConnection setRemoteDescription:remoteSdp completionHandler:^(NSError * _Nullable error) {
            [self setSessionDescriptionWithPeerConnection:weakPeerConnection];
        }];
        
        //设置当前角色状态为被呼叫,(被发offer)
        //        _role = RoleCallee;
    }
    #pragma mark --answer
    -(void)answerWith:(NSDictionary *)dic{
        NSDictionary *dataDic = dic[@"data"];
        if([dataDic count]==0){
            return;
        }
        NSString *sdp = dataDic[@"sdp"];
        
        NSString *socketId = dic[@"sender"];
        RTCPeerConnection *peerConnection = [_connectionDic objectForKey:socketId];
        RTCSessionDescription *remoteSdp = [[RTCSessionDescription alloc] initWithType:RTCSdpTypeAnswer sdp:sdp];
    //    RTCSessionDescription *newSdp = [self descriptionForDescription:remoteSdp preferredVideoCodec:@"H264"];
        __weak RTCPeerConnection * weakPeerConnection = peerConnection;
        [peerConnection setRemoteDescription:remoteSdp completionHandler:^(NSError * _Nullable error) {
    //                    [self setSessionDescriptionWithPeerConnection:weakPeerConnection];
        }];
    }
    #pragma mark WebSocketDelegate
    - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message{
        NSLog(@"收到服务器消息:%@",message);
        NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:[message dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil];
        NSString *eventName = dic[@"event"];
        NSLog(@"====================eventName===============%@",eventName);
        
        //1.发送加入房间后的反馈
        if ([eventName isEqualToString:@"open"])
        {
            [self openWith:dic];
            
        }
        //4.接收到新加入的人发了ICE候选,(即经过ICEServer而获取到的地址)
        else if ([eventName isEqualToString:@"_ice_candidate"])
        {
            [self _ice_candidateWith:dic];
        }
        //2.其他新人加入房间的信息
        else if ([eventName isEqualToString:@"join"])
        {
            [self joinWith:dic];
            
        }
        //有人离开房间的事件
        else if ([eventName isEqualToString:@"remove"])
        {
            [self removeWith:dic];
            
        }
        //这个新加入的人发了个offer
        else if ([eventName isEqualToString:@"offer"])
        {
            [self offerWith:dic];
        }
        //回应offer
        else if ([eventName isEqualToString:@"answer"])
        {
            [self answerWith:dic];
        }
    }
    
    - (void)webSocketDidOpen:(SRWebSocket *)webSocket{
        NSLog(@"socket连接成功");
     
        dispatch_async(dispatch_get_main_queue(), ^{
            if ([self->_delegate respondsToSelector:@selector(webRTCHelper:socketConnectState:)]) {
                [self->_delegate webRTCHelper:self socketConnectState:WebSocketConnectSuccess];
            }
        });
    }
    
    - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error{
        NSLog(@"socket连接失败");
        dispatch_async(dispatch_get_main_queue(), ^{
            if ([self->_delegate respondsToSelector:@selector(webRTCHelper:socketConnectState:)]) {
                [self->_delegate webRTCHelper:self socketConnectState:WebSocketConnectSuccess];
            }
        });
    }
    
    - (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean{
        NSLog(@"socket关闭。code = %ld,reason = %@",code,reason);
        
    }
    
    - (NSString *)getKeyFromConnectionDic:(RTCPeerConnection *)peerConnection
    {
        //find socketid by pc
        static NSString *socketId;
        [_connectionDic enumerateKeysAndObjectsUsingBlock:^(NSString *key, RTCPeerConnection *obj, BOOL * _Nonnull stop) {
            if ([obj isEqual:peerConnection])
            {
                NSLog(@"%@",key);
                socketId = key;
            }
        }];
        return socketId;
    }
    
    - (RTCSessionDescription *)descriptionForDescription:(RTCSessionDescription *)description preferredVideoCodec:(NSString *)codec
    {
        NSString *sdpString = description.sdp;
        NSString *lineSeparator = @"\n";
        NSString *mLineSeparator = @" ";
        // Copied from PeerConnectionClient.java.
        // TODO(tkchin): Move this to a shared C++ file.
        NSMutableArray *lines =
        [NSMutableArray arrayWithArray:
         [sdpString componentsSeparatedByString:lineSeparator]];
        NSInteger mLineIndex = -1;
        NSString *codecRtpMap = nil;
        // a=rtpmap:<payload type> <encoding name>/<clock rate>
        // [/<encoding parameters>]
        NSString *pattern =
        [NSString stringWithFormat:@"^a=rtpmap:(\\d+) %@(/\\d+)+[\r]?$", codec];
        NSRegularExpression *regex =
        [NSRegularExpression regularExpressionWithPattern:pattern
                                                  options:0
                                                    error:nil];
        for (NSInteger i = 0; (i < lines.count) && (mLineIndex == -1 || !codecRtpMap);
             ++i) {
            NSString *line = lines[i];
            if ([line hasPrefix:@"m=video"]) {
                mLineIndex = i;
                continue;
            }
            NSTextCheckingResult *codecMatches =
            [regex firstMatchInString:line
                              options:0
                                range:NSMakeRange(0, line.length)];
            if (codecMatches) {
                codecRtpMap =
                [line substringWithRange:[codecMatches rangeAtIndex:1]];
                continue;
            }
        }
        if (mLineIndex == -1) {
            RTCLog(@"No m=video line, so can't prefer %@", codec);
            return description;
        }
        if (!codecRtpMap) {
            RTCLog(@"No rtpmap for %@", codec);
            return description;
        }
        NSArray *origMLineParts =
        [lines[mLineIndex] componentsSeparatedByString:mLineSeparator];
        if (origMLineParts.count > 3) {
            NSMutableArray *newMLineParts =
            [NSMutableArray arrayWithCapacity:origMLineParts.count];
            NSInteger origPartIndex = 0;
            // Format is: m=<media> <port> <proto> <fmt> ...
            [newMLineParts addObject:origMLineParts[origPartIndex++]];
            [newMLineParts addObject:origMLineParts[origPartIndex++]];
            [newMLineParts addObject:origMLineParts[origPartIndex++]];
            [newMLineParts addObject:codecRtpMap];
            for (; origPartIndex < origMLineParts.count; ++origPartIndex) {
                if (![codecRtpMap isEqualToString:origMLineParts[origPartIndex]]) {
                    [newMLineParts addObject:origMLineParts[origPartIndex]];
                }
            }
            NSString *newMLine =
            [newMLineParts componentsJoinedByString:mLineSeparator];
            [lines replaceObjectAtIndex:mLineIndex
                             withObject:newMLine];
        } else {
            RTCLogWarning(@"Wrong SDP media description format: %@", lines[mLineIndex]);
        }
        NSString *mangledSdpString = [lines componentsJoinedByString:lineSeparator];
        return [[RTCSessionDescription alloc] initWithType:description.type
                                                       sdp:mangledSdpString];
    }
    
    @end
    
    1. ChatViewController.h
    #import <UIKit/UIKit.h>
    
    @interface ChatViewController : UIViewController
    
    @end
    
    
    1. ChatViewController.m
    //
    //  ChatViewController.m
    //  WebRTC_new
    //
    //  Created by
    //  Copyright © 2020年
    //
    
    #import "ChatViewController.h"
    #import <WebRTC/WebRTC.h>
    #import "WebRTCHelper.h"
    #import <HGAlertViewController/HGAlertViewController.h>
    
    #define kWidth [UIScreen mainScreen].bounds.size.width
    #define kHeight [UIScreen mainScreen].bounds.size.height
    
    @interface ChatCell:UICollectionViewCell
    /*注释*/
    @property (nonatomic,strong)  RTCEAGLVideoView *videoView;
    /*注释*/
    @property (nonatomic,strong) RTCVideoTrack *track;
    /*注释*/
    @property (nonatomic,strong) CALayer *baseLayer;
    @end
    
    @implementation ChatCell
    
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            self.videoView = [[RTCEAGLVideoView alloc] initWithFrame:CGRectMake(0, 0, (kWidth-40)/3, (kWidth-40)/3 + 50)];
            [self.contentView addSubview:self.videoView];
        }
        return self;
    }
    - (instancetype)initWithFrame:(CGRect)frame{
        self = [super initWithFrame:frame];
        if (self) {
            self.contentView.layer.borderColor = [UIColor whiteColor].CGColor;
            self.contentView.layer.borderWidth = 1;
            self.videoView = [[RTCEAGLVideoView alloc] initWithFrame:CGRectMake(0, 0, (kWidth-40)/3, (kWidth-40)/3 + 50)];
        }
        return self;
    }
    
    - (void)setTrack:(RTCVideoTrack *)track{
        if (track != nil) {
            self.contentView.layer.mask = nil;
            [self.contentView addSubview:self.videoView];
            [track addRenderer:self.videoView];
        }else{
            self.contentView.layer.mask = nil;
            for (UIView * view in self.contentView.subviews) {
                [view removeFromSuperview];
            }
            [self setShaperLayer];
        }
    }
    
    
    -(void)setShaperLayer{
        //高亮状态下的imageView
        UIImageView * highlightImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
        highlightImageView.center = self.contentView.center;
        highlightImageView.image = [UIImage imageNamed:@"voice_ highlight"];
        //默认状态下的imageView
        UIImageView * defaultImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
        defaultImageView.image = [UIImage imageNamed:@"voice_default"];
        //先添加highlightImageView,在添加defaultImageview
        defaultImageView.center = self.contentView.center;
        [self.contentView addSubview:defaultImageView];
        [self.contentView addSubview:highlightImageView];
        self.baseLayer = nil;
        if (self.baseLayer == nil) {
            self.baseLayer = [CALayer layer];
            self.baseLayer.frame = highlightImageView.bounds;
        }
        
        //创建左边layer
        CAShapeLayer * leftLayer = [CAShapeLayer layer];
        leftLayer.fillColor = [UIColor greenColor].CGColor;
        leftLayer.position = CGPointMake(-25, 25);
        leftLayer.bounds = highlightImageView.bounds;
        leftLayer.path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 50,50)].CGPath;
        [self.baseLayer addSublayer:leftLayer];
        
        //左边动画
        CABasicAnimation * leftAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
        leftAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(-25, 25)];
        leftAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(5, 25)];
        leftAnimation.duration = 1.0;
        leftAnimation.repeatCount = MAXFLOAT;
        [leftLayer addAnimation:leftAnimation forKey:@"noVoiceLeftAnimation"];
        
    
        //创建右边layer
        CAShapeLayer * rightLayer = [CAShapeLayer layer];
    //    rightLayer.strokeColor = [UIColor greenColor].CGColor;
        rightLayer.bounds = highlightImageView.bounds;
        rightLayer.position = CGPointMake(75, 25);
        rightLayer.fillColor = [UIColor greenColor].CGColor;
        rightLayer.path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 50, 50)].CGPath;
        [self.baseLayer addSublayer:rightLayer];
        //动画
        CABasicAnimation * rightAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
        rightAnimation.duration = 1.0;
        rightAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(75, 25)];
        rightAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(45, 25)];
        rightAnimation.repeatCount = MAXFLOAT;
        [rightLayer addAnimation:rightAnimation forKey:@"noVoiceRightAnimation"];
        
        
        highlightImageView.layer.mask = self.baseLayer;
        
        
    }
    
    @end
    
    
    @interface ChatViewController ()<UICollectionViewDelegate,UICollectionViewDataSource,WebRTCHelperDelegate,WebRTCHelperFrindDelegate,UIGestureRecognizerDelegate>
    {
        RTCMediaStream * _localSteam;
        //判断是显示前摄像头还是显示后摄像头(yes为前摄像头。false为后摄像头)
        BOOL _usingFrontCamera;
        //是否显示我的视频流(默认为yes,显示;no为不显示)
        BOOL _usingCamera;
    }
    @property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
    /*保存远端视频流*/
    @property (nonatomic,strong) NSMutableDictionary *videoTracks;
    /*房间内其他用户*/
    @property (nonatomic,strong) NSMutableArray *members;
    //显示本地视频的view
    @property (weak, nonatomic) IBOutlet RTCCameraPreviewView *localVideoView;
    
    @end
    
    @implementation ChatViewController
    
    /*注释*/
    - (NSMutableArray *)members
    {
        if(!_members){
            _members = [NSMutableArray array];
        }
        return _members;
    }
    
    /*注释*/
    - (NSMutableDictionary *)videoTracks
    {
        if(!_videoTracks){
            _videoTracks = [NSMutableDictionary dictionary];
        }
        return _videoTracks;
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        _usingFrontCamera = YES;
        _usingCamera = YES;
        NSLog(@"uid = %@",[[[UIDevice currentDevice] identifierForVendor] UUIDString]);
        [WebRTCHelper shareInstance].delegate = self;
        [WebRTCHelper shareInstance].friendDelegate = self;
        
        UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc] init];
        layout.minimumLineSpacing = 10;
        layout.minimumInteritemSpacing = 10;
        layout.itemSize = CGSizeMake((kWidth-40)/3, (kWidth-40)/3+50);
        self.collectionView.collectionViewLayout = layout;
        self.collectionView.delegate = self;
        self.collectionView.dataSource = self;
        [self.collectionView registerClass:[ChatCell class] forCellWithReuseIdentifier:@"chatCell"];
        
        [self connect];
        //设置屏幕常亮
        [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
        if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
            self.navigationController.interactivePopGestureRecognizer.enabled = NO;
        }
        self.navigationItem.hidesBackButton = YES;
    }
    -(void)viewWillDisappear:(BOOL)animated{
        [super viewWillDisappear:animated];
        if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
            self.navigationController.interactivePopGestureRecognizer.enabled = YES;
        }
    }
    #pragma mark -按钮点击操作
    /**
     * 关闭按钮
     */
    - (IBAction)closeChatBtnClick:(UIButton *)sender {
        [[WebRTCHelper shareInstance] exitRoom];
        [self.navigationController popViewControllerAnimated:YES];
    }
    
    /**
     * 摄像头转换(前后摄像头)
     */
    - (IBAction)swithVideoBtnClick:(UIButton *)sender {
        _usingFrontCamera = !_usingFrontCamera;
        [[WebRTCHelper shareInstance] swichCamera:_usingFrontCamera];
    
    }
    
    /**
     * 语音是否开启
     */
    - (IBAction)swichAudioBtnClick:(UIButton *)sender {
        [sender setImage:[UIImage imageNamed:@"audioOn"] forState:UIControlStateNormal];
    }
    /**
     是否显示本地摄像头
     */
    - (IBAction)swichLocaolCameraBtnClick:(UIButton *)sender {
        _usingCamera = !_usingCamera;
    //    [sender setImage:[UIImage imageNamed:_usingCamera?@"videoOn":@"videoOff"] forState:UIControlStateNormal];
    //    [[WebRTCHelper shareInstance] showLocaolCamera:_usingCamera];
    }
    
    /**
     * 连接服务器
     */
    -(void)connect{
        [[WebRTCHelper shareInstance] connectServer:@"172.27.104.54" port:@"9090/SocketServer"];
    }
    
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
        NSLog(@"self.members=====%@", self.members);
        return self.members.count;
    }
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
        ChatCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"chatCell" forIndexPath:indexPath];
        NSString * userId = [self.members objectAtIndex:indexPath.item];
        RTCVideoTrack * track = [self.videoTracks objectForKey:userId];
        NSLog(@"%@==6666==%@",track,userId);
        cell.track = track;
        return cell;
    }
    
    #pragma mark -WebRTCHelperFrindDelegate
    - (void)webRTCHelper:(WebRTCHelper *)webRTCHelper gotFriendList:(NSArray *)friendList{
        [self.members removeAllObjects];
        [self.members addObjectsFromArray:friendList];
        [_collectionView reloadData];
    }
    
    - (void)webRTCHelper:(WebRTCHelper *)webRTCHelper gotNewFriend:(NSString *)friendId{
        [self.members addObject:friendId];
        [_collectionView reloadData];
    }
    
    - (void)webRTCHelper:(WebRTCHelper *)webRTCHelper removeFriend:(NSString *)friendId{
        [self.members removeObject:friendId];
        [_collectionView reloadData];
        if (self.members.count == 0) {
    //        [[WebRTCHelper shareInstance] exitRoom];
    //        [self.navigationController popViewControllerAnimated:YES];
        }
    }
    
    #pragma mark -WebRTCHelperDelegate
    - (void)webRTCHelper:(WebRTCHelper *)webRTCHelper receiveMessage:(NSString *)message{
        NSLog(@"messaga = %@",message);
        
    }
    
    /**
     * 旧版本获取本地视频流的代理,在这个代理里面会获取到RTCVideoTrack类,然后添加到RTCEAGLVideoView类型的localVideoView上面
     */
    - (void)webRTCHelper:(WebRTCHelper *)webRTCHelper setLocalStream:(RTCMediaStream *)steam userId:(NSString *)userId{
        if (steam) {
            _localSteam = steam;
            RTCVideoTrack * track = [_localSteam.videoTracks lastObject];
            [track addRenderer:self.localVideoView];
        }
        
    }
    /**
     * 新版获取本地视频流的方法
     * @param captureSession RTCCameraPreviewView类的参数,通过设置这个,就可以达到显示本地视频的功能
     */
    - (void)webRTCHelper:(WebRTCHelper *)webRTCHelper capturerSession:(AVCaptureSession *)captureSession{
        self.localVideoView.captureSession = captureSession;
        
    }
    
    /**
     * 获取远端视频流的方法,主要是获取到RTCVideoTrack类型的数据,然后保存起来,在刷新列表的时候,添加到对应item里面的RTCEAGLVideoView类型的view上面
     */
    - (void)webRTCHelper:(WebRTCHelper *)webRTCHelper addRemoteStream:(RTCMediaStream *)stream userId:(NSString *)userId{
        RTCVideoTrack * track = [stream.videoTracks lastObject];
        NSLog(@"track====%@",track);
        if (track != nil) {
            [self.videoTracks setObject:track forKey:userId];
        }
            [self.collectionView reloadData];
    }
    - (void)webRTCHelper:(WebRTCHelper *)webRTCHelper closeWithUserId:(NSString *)userId{
        [self.videoTracks removeObjectForKey:userId];
        if (self.videoTracks.count >= self.members.count) {
            [self.collectionView reloadData];
        }
    }
    
    - (void)webRTCHelper:(WebRTCHelper *)webRTCHelper socketConnectState:(WebSocketConnectState)connectState{
        if (connectState == WebSocketConnectField) {
            HGAlertViewController * alert = [HGAlertViewController alertControllerWithTitle:@"提示" message:@"连接socket失败" preferredStyle:(UIAlertControllerStyleAlert)];
            alert.addAction(@"取消",^(UIAlertAction *alertAction){
                [[WebRTCHelper shareInstance] exitRoom];
                [self.navigationController popViewControllerAnimated:YES];
            }).addAction(@"确定",^(UIAlertAction *alertAction){
                [[WebRTCHelper shareInstance] exitRoom];
                [self.navigationController popViewControllerAnimated:YES];
            });
            [self presentViewController:alert animated:YES completion:nil];
        }
    }
    -(void)dealloc{
        NSLog(@"移除了");
        //取消设置屏幕常亮
        [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
    }
    
    @end
    
    

    相关文章

      网友评论

          本文标题:WebRTC -ios

          本文链接:https://www.haomeiwen.com/subject/bxbvektx.html