iOS 进阶功能

本文介绍的是音视频通话 API 在 iOS 中的进阶功能。

渲染 View 相关

实现 ARTVCEngineDelegate 中部分和渲染相关的回调接口。

  1. 渲染 View 对象被创建。

    //渲染 View 对象被创建,同时 feed 相关联,业务收到此回调时可将此 view 加入到布局中,//并设置其 frame。
    -(void)didVideoRenderViewInitialized:(UIView*)renderView forFeed:(ARTVCFeed*)feed{
    }
  2. 渲染首帧视频。

    -(void)didFirstVideoFrameRendered:(UIView*)renderView forFeed:(ARTVCFeed*)feed{
    }
  3. 停止渲染视频。

    -(void)didVideoViewRenderStopped:(UIView*)renderView forFeed:(ARTVCFeed*)feed{
    }

统一错误处理

  • 所有错误。通过统一的错误回调接口回调业务,业务根据不同的错误码,进行相应的错误处理。

    -(void)didEncounterError:(NSError *)error forFeed:(ARTVCFeed*)feed{
      //业务根据不同错误码,进行错误处理。
    }
  • 错误定义如下:

    typedef NS_ENUM(int,ARTVCErrorCode){
      /**
      bad parameters passed to API
      */
      ARTVCErrorCodeBadParameters                  = - 103,
      /**
       camera permission is denied by user
       without this permission,video call cann't be continued,please advise user enable camera permission in settings.
       */
      ARTVCErrorCodeCameraPermissionNOtAllowed     = -104,
      /**
      microphone permission is denied by user
      without this permission,video call cann't be continued,please advise user enable camera permission in settings.
      */
      ARTVCErrorCodeMicrophonePermissionNOtAllowed = -105,
      /**
      timeout happened,publish/subscribe cann't be finishied successfully
      */
      ARTVCErrorCodeTimeout                        = -108,
      /**
       you has already published or subsrcibed a feed .
      you cann't publish or subsrcibe the same feed once again when it has NOt been unpublished or unsubscribed.
      */
      ARTVCErrorCodeAlreadyPublishedOrSubsrcibed   = -111,
      /**
       you has NOt published or subsrcibed the feed .so you cann't do unpublish or unsubscribe operation.
      */
      ARTVCErrorCodeFeedHasNOtBeenPublishedOrSubsrcibed   = -119,
      /**
      internal  webrtc-relative error when doing publish/subscribe,for example,setting sdp failed,creating sdp failed,e.g.
      */
      ARTVCErrorCodeInternalError                  = -113,
      /**
       * current room has become invalid .most of all,it's because network's down,heartbeat abNOrmal.
       * if you wanna continue,you MUST call createRoom again to get a new valid room.
       */
      ARTVCErrorCodeCurrentRoomHasBecomeInvalid    = -114,
      /**
      server error hanppened.CreateRoom request failed,it's a server internal error.
      */
      ARTVCErrorCodeProtocolErrorCreateRoomFailed  = -115,
      /**
      server error hanppened.JoinRoom request failed,it's a server internal error.maybe the room you joined has been became invalid yet.
      */
      ARTVCErrorCodeProtocolErrorJoinRoomFailed    = -116,
      /**
      server error hanppened.Publish request failed,it's a server internal error.
      */
      ARTVCErrorCodeProtocolErrorPublishFailed     = -117,
      /**
      server error hanppened.Subscribe request failed,it's a server internal error.maybe the stream you subscribed has been unpunlished yet or some error else.
      */
      ARTVCErrorCodeProtocolErrorSubscribeFailed   = -118,
    };

切换摄像头

切换摄像头代码如下:

[_artvcEgnie switchCamera];

mute 远端视频

mute 远端视频代码如下:

ARTVCFeed* feed = 要 mute 操作的远端 feed;
[_artvcEgnie muteRemoteVideo:YES forFeed:feed];

麦克风静音

麦克风静音代码如下:

[_artvcEgnie muteMicrophone:YES];

mute 远端音频

mute 远端音频代码如下:

ARTVCFeed* feed = 要 mute 操作的远端 feed;
[_artvcEgnie muteRemoteAudio:YES forFeed:feed];

听筒扬声器模式

  • 切换模式:

    [_artvcEgnie switchAudioPlayModeTo:ARTVCAudioPlayModeReceiver complete:nil];
  • 变化通知:

    -(void)didAudioPlayModeChangedTo:(ARTVCAudioPlayMode)audioPlayMode{
      NSString *toast = nil;
      switch (audioPlayMode) {
          case ARTVCAudioPlayModeSpeaker:{
              toast = @"扬声器模式";
          }
              break;
          case ARTVCAudioPlayModeReceiver:{
              toast = @"听筒模式";
          }
              break;
          case ARTVCAudioPlayModeHeadphone:{
              toast = @"耳机模式";
          }
              break;
          case ARTVCAudioPlayModeBluetooth:{
              toast = @"蓝牙设备模式";
          }
              break;
          case ARTVCAudioPlayModeInit:{
              toast = @"未知模式";
          }
              break;
      }
    
      [self showToastWith:toast duration:2.0];
    }

网络变化通知

网络变化通知代码如下,对于移动网络,业务可做弹窗提示用户有流量风险。

-(void)didNetworkChangedTo:(APMNetworkReachabilityStatus)netStatus{
    if(netStatus == APMNetReachabilityStatusReachableViaWiFi){
        return ;
    }
    [self showToastWith:[NSString stringWithFormat:@"网络切换到:%@",[APMNetworkStatusManager stringOfNetworkStatus:netStatus]] duration:2.0];
}

带宽不足通知

带宽不足通知代码如下:

-(void)didAvailabeSendBandwidthBecomeLow:(BOOL)isLow currentBandwidth:(double)bw forFeed:(ARTVCFeed*)feed{
    if(isLow){
        [self showToastWith:@"当前通话质量不佳" duration:2.0];
    }
}

截屏功能

截屏功能代码如下,可对任意流进行截屏。

ARTVCFeed* feed = 要截屏的 feed;
[_artvcEgnie snapshotForFeed:feed  complete:^(UIImage* image){
//根据需要对截屏图片进行处理
}];

获取通话质量的 Debug 信息

通过回调来返回任意流的 Debug 信息。

/**
 brief debug information is generated(including bitrate/cpu/codec,e.g.),you can show this on your debug information view.
 */
- (void)didBriefDebugInformationGenerated:(NSString*)debugInfo forFeed:(ARTVCFeed*)feed{
//如果有需要,可以将 debugInfo 按流展示在 Debug 窗口。
}

获取通话质量的实时监控信息

  • 通过回调可获取任意流的实时监控信息,包括码率、帧率、CPU 等。

    -(void)didRealtimeStatisticGenerated:(ARTVCRealtimeStatisticSummary*)summary forFeed:(ARTVCFeed*)feed{
    }
  • 返回的数据内容如下:

    @interface ARTVCRealtimeStatisticSummary : NSObject
    //connection stats googCandidatePair
    /** 实际总发码率 单位 bps*/
    @property(NOnatomic,copy) NSString* totalSendBitrate;
    /** 实际总的收码率 单位 bps*/
    @property(NOnatomic,copy) NSString* totalRecvBitrate;
    /** 网络延迟(毫秒)*/
    /** 网络延迟(毫秒)*/
    @property(NOnatomic,copy) NSString* rtt;
    //video send
    /** 视频码率发 单位 bps*/
    @property(NOnatomic,copy) NSString* videoSendBitrate;
    /** 实际视频发帧率 */
    @property(NOnatomic,copy) NSString* videoSendFps;
    //video recv
    /** 视频码率收 单位 bps*/
    @property(NOnatomic,copy) NSString* videoRecvBitrate;
    /** 实际视频收帧率 */
    @property(NOnatomic,copy) NSString* videoRecvFps;
    /** 声音码率发 单位 bps*/
    @property(NOnatomic,copy) NSString* audioSendBitrate;
    /** 声音码率收 单位 bps*/
    @property(NOnatomic,copy) NSString* audioRecvBitrate;
    /** 视频发送丢包率*/
    @property(NOnatomic,copy) NSString* videoLossRate;
    //audio send
    /** 音频发送丢包率*/
    @property(NOnatomic,copy) NSString* audioLossRate;
    /** cpu */
    @property(NOnatomic,copy) NSString* cpu;
    @end

通话过程中动态调整编码分辨率和相机 FPS(仅使用于内置 camera)

  • 当前分辨率以及 FPS 分别为 640x360、15 FPS 时,设置如下:

    _artvcEgnine.videoProfileType = ARTVCVideoProfileType_640x360_15Fps;
  • 假设,因业务需求需要将分辨率以及 FPS 临时调高至 960x540、30 FPS,设置如下:

    _artvcEgnine.videoProfileType = ARTVCVideoProfileType_960x540_30Fps;
  • 处理完特定业务需求后,恢复至 640x360,15 FPS。

    _artvcEgnine.videoProfileType = ARTVCVideoProfileType_640x360_15Fps;

通话过程中动态调整编码分辨率(适应于所有 video source)

  • 自定义推流中,当前分辨率为 640x360,若因业务需求需要临时调高至 960x540,设置如下:

    [ _artvcEgnine changeVideoProfileTo:ARTVCVideoProfileType_960x540_15Fps forVideoSource:ARTVCVideoSourceType_Custom];
  • 内置 camera,当前分辨率为 640x360,若因业务需求需要临时调高至 960x540,设置如下:

    [ _artvcEgnine changeVideoProfileTo:ARTVCVideoProfileType_960x540_30Fps forVideoSource:ARTVCVideoSourceType_Camera];

自定义推视频流

自定义推视频流约束

  • 只支持 NV12 格式的视频帧,以 CVPixelBufferRef 格式输入.

  • 调用方目前需要保证 FPS,按照一定的 FPS 来输入。建议使用 15-24FPS。

  • 只支持手动模式推流。

流程

自定义推视频流的流程如下:

//自定义推流中,必须设置为手动推流模式
[ _artvcEgnine setAutoPublish:NO];
 //创建一个自定义推流类
ARTVCCreateCustomVideoCaputurerParams* params = [[ARTVCCreateCustomVideoCaputurerParams alloc] init];
//如果需要 SDK 帮忙渲染,需要设置 provideRenderView 为 YES,SDK 默认不帮业务渲染。
            params.provideRenderView = YES;


            self.customCapturer = [_artvcEgnine createCustomVideoCapturer:params];
            //按照一定的频率喂数据给 SDK,格式是 CVPixelBufferRef,只支持 NV12 格式。
            [self.customCapturer provideCustomVideoFramePeriodlyWith:CVPixelBufferRef];
//主动调用推流
ARTVCPublishConfig* config = [[ARTVCPublishConfig alloc] init];
            config.videoSource = ARTVCVideoSourceType_Custom;
            config.videoProfile = ARTVCVideoProfileType_640x360_15Fps;
            self.customPublishConfig = config;
            [_artvcEgnine publish:config];

屏幕共享

屏幕共享代码如下:

//必须设置为手动推流模式
[ _artvcEgnine setAutoPublish:NO];
 //开始屏幕共享
-(void)startScreenSharing{
    NSLog(@"start screen sharing");
    ARTVCCreateScreenCaputurerParams* screenParams = [[ARTVCCreateScreenCaputurerParams alloc] init];
    screenParams.provideRenderView = YES;
    [_artvcEgnine startScreenCaptureWithParams:screenParams complete:^(NSError* error){
        NSLog(@"start screen sharing finish,error:%@",error);
        if(error){
             //这里的 code 见启动屏幕捕捉的错误码章节

        }else{
           //屏幕捕捉成功后再调用 publish 进行推流
            ARTVCPublishConfig* config = [[ARTVCPublishConfig alloc] init];
            config.videoSource = ARTVCVideoSourceType_Screen;
            config.audioEnable = NO;
            config.videoProfile = ARTVCVideoProfileType_1280x720_30Fps;
            [_artvcEgnine publish:config];
        }
    }];
}
//停止屏幕共享
-(void)stopScreenSharing{
    NSLog(@"stop screen sharing");
    //停止屏幕捕捉
    [_artvcEgnine stopScreenCapture];
    //取消发布屏幕共享流
    ARTVCUnpublishConfig* config = [[ARTVCUnpublishConfig alloc] init];
    config.feed = self.screenLocalFeed;
    [_artvcEgnine unpublish:config];
}

启动屏幕捕捉的错误码

启动屏幕捕捉的错误码如下:

/**
    screen capture alrady under running, you cann't start it again before you call stop
    */
    ARTVCErrorCodeScreenCapturerAlreadyUnderRunning            = -1011,
    /**
    starting screen capture failed
    */
    ARTVCErrorCodeStartScreenCaptureFailed                     = -1012,
    /**
    start screen capture success,but may be encounter errors during the processing of the capure operation.
    */
    ARTVCErrorCodeScreenCaptureFailedInProcessing              = -1013,