互动直播 SDK 使用指南

SDK 概述

网易云通信 SDK 为移动提供完善的音视频直播与实时互动开发框架,屏蔽其内部复杂细节,对外提供较为简洁的 API 接口,方便第三方应用快速集成互动直播功能,主要有:

SDK 兼容 iOS 7.0+ ,Demo 兼容 iOS 8.0+ 。

开发准备

互动直播能力作为网易云通信 IM SDK 的 plugin 与 IM SDK 一起发布,并且依赖 IM SDK 的帐号系统。在接入互动直播时,开发者需要参考 IM 即时通讯开发指南 的 以下几个章节:

互动直播相关概念

互动直播接入

云通信提供简单的互动直播和连麦接口,只需要创建并加入互动房间即可以实现直播推流;连麦者使用相同的房间名加入互动房间即可以实现实时连麦互动。

互动直播相关接口都由 NIMNetCallManager 提供。

互动直播房间

用创建接口创建一个互动直播房间:

- (void)reserveMeeting:(NIMNetCallMeeting *)meeting
            completion:(NIMNetCallMeetingHandler)completion

需要先创建房间,本人和其他人才能加入房间。

通过 meetingname 字段做标识;可以通过 meeting 的 扩展字段 ext 在房间的创建和加入之间传递额外信息。

同一个房间名称,只在房间使用完以后才可以重复使用,开发者需要保证不会出现重复预订某房间名称而不使用的情况。

创建房间的结果通过 completion 返回。

房间创建成功后,主播首先使用加入接口进入房间:

- (void)joinMeeting:(NIMNetCallMeeting *)meeting
         completion:(NIMNetCallMeetingHandler)completion

主播加入时需要在 meetingoption 参数中打开互动直播开关 enableBypassStreaming,并指定推流地址 bypassStreamingUrl(指定推流地址的一端被认为是互动的主播)。

option 相关参数说明:

主播可以设置互动直播视频画面混屏模式 bypassStreamingVideoMixMode,在预设的几种直播混频模式 NIMNetCallVideoMixMode 中选择一种,图文介绍

主播可以开启互动直播的服务器录制 bypassStreamingServerRecording。该功能需要开通才能使用。

主播加入房间的 completion 正常返回后,即可以在观众端使用直播拉流播放器观看主播直播。

连麦者使用主播相同的房间名加入房间,需要打开互动直播开关 enableBypassStreaming,不要指定推流地址,调用加入接口 joinMeeting: completion: 进入房间。连麦者成功加入房间后,观众端就可以观看到双人实时连麦互动直播了。

- (void)leaveMeeting:(NIMNetCallMeeting *)meeting

当所有加入的人都离开了某房间以后,该房间对应的名称才可以被重复预订。

- (BOOL)setMeetingRole:(BOOL)actor
- (BOOL)setAudioMute:(BOOL)mute 
             forUser:(NSString *)uid

静音后将听不到该用户的声。

需要在用户加入以后才能进行设置,该接口也可用于点对点双人通话。

- (BOOL)setVideoMute:(BOOL)mute 
             forUser:(NSString *)uid

拒绝后将没有该用户视频数据回调。

需要在用户加入以后才能进行设置,该接口也可用于点对点双人通话。

- (void)onUserJoined:(NSString *)uid
             meeting:(NIMNetCallMeeting *)meeting

通知上层有其他用户加入了房间。

- (void)onUserLeft:(NSString *)uid
           meeting:(NIMNetCallMeeting *)meeting

通知上层有其他用户离开了房间。

- (void)onMeetingError:(NSError *)error
               meeting:(NIMNetCallMeeting *)meeting

一些异常情况可能会引起房间出错,请在收到该回调以后主动离开房间。

视频采集

可以在加入房间时,通过指定 meetingoptionvideoCaptureParam 让 SDK 自动控制视频采集。

SDK 也提供单独的视频采集控制接口,满足开发者需要单独控制视频的采集而不与房间的加入和离开逻辑相关的场景。

开始采集,并指定采集相关的参数:

- (BOOL)startVideoCapture:(NIMNetCallVideoCaptureParam *)param

采集开始以后,通过 onLocalPreviewReady: 回调摄像头预览层画面,也可以通过 param 中的 videoHandler 设置采集画面回调,对画面进行美颜或滤镜等操作以后再给 SDK 发送出去。

视频采集开始以后无法再调用该接口进行更新设置。需要先停止采集以后才能再次开始。

停止采集:

- (void)stopVideoCapture

在加入房间时或单独控制开始视频采集时,通过 NIMNetCallVideoCaptureParam 设置采集相关的参数,其中:

视频采集格式 format 设置采集到的画面的格式。支持 yuv (420f 和 420v) 和 ARGB,如果需要 SDK 回调采集到的视频数据并且对数据格式有要求,可以设置该参数。

期望的发送视频质量 preferredVideoQuality 指定采集的清晰度。SDK 可能会根据具体机型运算性能和协商结果调整为更合适的清晰度,导致该设置无效(该情况通常发生在通话一方有低性能机器时)。

使用后置摄像头开始视频 startWithBackCamera。默认是前置。

初始打开摄像头 startWithCameraOn。如果你希望在开始视频采集以后 SDK 不开始运行摄像头,然后再通过摄像头开关接口单独开启摄像头,可以把该参数指定为 NO。

视频采集方向 videoCaptureOrientation。该设置会改变采集到的视频画面的角度, 主要用于支持互动直播时的横屏直播: 主播以各种角度手持设备直播, 并设置为该角度的 '视频采集方向', 拉流播放器就可以以正常的角度观看直播。

视频采集帧率 videoFrameRate,用于开发者不满足于默认视频帧率时传入更期望的帧率。

视频采集数据回调处理 videoHandler,供上层实现美颜等图像处理相关功能。

动态设置视频采集方向:

- (BOOL)setVideoCaptureOrientation:(NIMVideoOrientation)orientation

动态设置摄像头开关:

- (BOOL)setCameraDisable:(BOOL)disable

动态切换前后摄像头:

- (void)switchCamera:(NIMNetCallCamera)camera

用于在前后摄像头之间切换。

摄像头切换完成后,SDK 通过以下回调通知应用:

- (void)onCameraSwitchedTo:(NIMNetCallCamera)camera

如果应用开启了视频数据回调,需要自己实现处理后的画面的绘制,则需要在该回调中对前置摄像头的画面做水平镜像翻转。

动态切换采集清晰度:

- (BOOL)switchVideoQuality:(NIMNetCallVideoQuality)quality

当前通话信息

- (UInt64)currentCallID

如果没有正在进行中的通话 SDK 返回 0。

- (void)onNetStatus:(NIMNetCallNetStatus)status
               user:(NSString *)user

通常用于在 UI 上展现网络信号。user 表示本端对应于该用户的下行网络状况。如果 user 是自己,表示自己的上行网络状况。

- (NIMNetCallNetStatus)netStatus:(NSString *)user

如果没有正在进行中的通话,则返回值没有参考意义。

- (void)onLocalPreviewReady:(CALayer *)layer

本地摄像头初始化完成时返回 layer,可以用如下示例代码展现本地预览画面:

- (void)onLocalPreviewReady:(CALayer *)layer
{
    if (self.localVideoLayer) {
        [self.localVideoLayer removeFromSuperlayer];
    }
    self.localVideoLayer = layer;
    layer.frame = self.localView.bounds;
    [self.localView.layer addSublayer:layer];
}
- (CALayer *)localPreviewLayer

当摄像头尚未初始化完成时返回 nil。

- (void)onRemoteYUVReady:(NSData *)yuvData
                   width:(NSUInteger)width
                  height:(NSUInteger)height
                    from:(NSString *)user

每获取到一帧对端画面都会回调,其中yuvData是紧凑的 YUV 数据 (stride 与画面宽度相同)。

可以通过user区分不同的对端用户。

将 YUV 数据直接用 OpenGL 渲染,比从 onRemoteImageReady: 得到的 image 贴图节省 CPU 资源。

- (void)onRemoteImageReady:(CGImageRef)image

如果实现了该委托,每获取到一帧对端画面都会回调,可以将 image 转换成 UIImage 后直接在 UIImageView 里面填充。

如果已经使用 onRemoteYUVReady:width:height:from 得到的 YUV 数据渲染画面,不要再实现该委托以优化性能。

- (void)onNetCallRecordingInfo:(NIMNetCallRecordingInfo *)info

提供服务器录制的音频文件和视频文件信息。

-(void)onMyVolumeUpdate:(UInt16)volume
- (void)onSpeakingUsersReport:(nullable NSArray<NIMNetCallUserInfo *> *)report

如果 report 为空,表示没有说话的人。

连麦双方需要实现本地画面和远端画面的渲染:

onLocalPreviewReady: 回调时渲染本地画面;

onRemoteYUVReady:width:height:from: 回调时渲染远端画面。

请参考网络通话相关章节和云通信 Demo 源码的实现。

主播可以调用切换直播推流地址接口,实时切换推流地址,适配某些视频流平台的防盗链机制。

- (BOOL)switchBypassStreamingUrl:(NSString *)url

通话过程控制

- (BOOL)setMute:(BOOL)mute

静音后对端将听不到本端的声音。

- (BOOL)setSpeaker:(BOOL)useSpeaker

用于在扬声器和听筒间切换。

- (void)switchType:(NIMNetCallMediaType)type

用于在语音模式和视频模式之间切换。如果需要对方接受才能切换,请使用 control:typeonConrtol:from:type 进行协商,达成一致后再调用该接口进行切换。

通话中的编解码控制

- (BOOL)setVideoMaxEncodeBitrate:(NSUInteger)bitrate

可以在视频通话过程中实时改变视频编码码率,以满足不同网络状况和使用场景需求。如果用户尚未加入通话,则无法设置。

- (BOOL)switchVideoEncoder:(NIMNetCallVideoCodec)codec
- (BOOL)switchVideoDecoder:(NIMNetCallVideoCodec)codec

可以在视频通话过程中实时切换软硬件编解码器。硬件编解码设置仅在 iOS 8.0 及以上系统有效。如果用户尚未加入通话,则无法设置。

- (BOOL)switchVideoQuality:(NIMNetCallVideoQuality)quality

可以在视频通话过程中实时切换视频质量。如果用户尚未加入通话,则无法设置。

通话中音视频录制

通话建立以后,SDK 支持将本端与对端的音视频图像和声音录制下来,保存成本地 mp4 格式文件。

- (BOOL)startRecording:(nullable NSURL *)filePath
          videoBitrate:(UInt32)videoBitrate
                   uid:(NSString *)userId

只有通话连接建立以后才允许开始录制。

可以指定录制文件的路径 filePath,SDK 不负责创建目录,请确保文件路径的合法性;也可以不指定,由 SDK 自己选择文件路径。

如果对录制文件大小有要求,可以指定录制文件的视频码率 videoBitrate;也可以不指定,由 SDK 自己选择合适的码率。

需要指定开始录制用户的 ID userId

- (BOOL)stopRecordingWithUid:(NSString *)userId

需要指定结束录制用户的 ID userId

- (void)onRecordStarted:(UInt64)callID
                fileURL:(NSURL *)fileURL
                    uid:(NSString *)userId

表示本地录制成功开始,携带录制对应的网络通话 ID 和录制文件路径以及用户 ID 信息。

- (void)onRecordError:(NSError *)error
               callID:(UInt64)callID
                  uid:(NSString *)userId

表示本地录制发生了错误。

- (void)onRecordStopped:(UInt64)callID
                fileURL:(NSURL *)fileURL
                    uid:(NSString *)userId

表示本地录制成功结束,携带录制对应的网络通话 ID 和录制文件路径以及用户 ID 信息。

通话录音

通话建立以后,SDK 支持录制通话中所有参与者的声音,包含混音任务播放的声音,保存成本地 aac 或 wav 格式文件。

- (BOOL)startAudioRecording:(nullable NSURL *)filePath
                      error:(NSError * __nullable *)error

可以指定录音文件的路径 filePath,不包含文件类型后缀。包含文件类型后缀的完整文件路径可以在开始录制以后通过 currentAudioRecordingFilePath 查询。

SDK 不负责创建目录,请确保文件路径的合法性;也可以不指定,由 SDK 自己选择文件路径。

如果开始通话录音失败,error 回填错误码。

- (void)stopAudioRecording
- (nullable NSURL *)currentAudioRecordingFilePath

如果没有进行中的通话录音则返回 nil。

音视频采集数据回调与发送

SDK 支持音视频采集数据回调与发送,可供应用实现美颜和变声等自定义功能。

在开启视频采集时,在 NIMNetCallVideoCaptureParam 中指定视频采集数据回调 block videoHandler,SDK 采集到的视频画面都会通过它回调给应用。videoHandler 的类型声明如下:

typedef void(^NIMNetCallVideoSampleBufferHandler)(CMSampleBufferRef sampleBuffer)

回调的 sampleBuffer 携带时间戳和 NIMNetCallVideoCaptureParam 中指定的 format 格式的 CVPixelBuffer 图像。

应用处理完的视频画面效果无法通过 onLocalPreviewReady: 中的 layer 自动绘制,因为该 layer 只展现摄像头采集的原始画面效果。应用需要自己实现处理后数据的绘制,并在 onCameraSwitchedTo: 回调中处理前置摄像头的镜像翻转问题。

处理完的图像和回调的时间戳一起封装为 CMSampleBufferRef 格式的数据,调用以下接口发送出去:

- (nullable NSError *)sendVideoSampleBuffer:(CMSampleBufferRef)buffer

注意:处理完的画面封装为 CMSampleBufferRef 时,需要填入回调时该画面对应的时间戳,否则对端的视频播放时序会被破坏。

注意:SDK 只接受 sampleBuffer 为封装了 kCVPixelFormatType_32BGRA、kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange 或者 kCVPixelFormatType_420YpCbCr8BiPlanarFullRange 的 CVPixelBuffer 的视频画面发送。

iOS网络通话本地回调画面(美颜)相关的格式转换

在加入互动直播房间时,在 meetingoption 参数中指定视频采集数据回调block audioHandler,SDK 采集到的音频数据都会通过它回调给应用。audioHandler 的类型声明如下:

typedef NSUInteger(^NIMNetCallAudioSamplesHandler)(SInt16 *audioSamples, NSUInteger samplesNumber, Float64 sampleRate)

其中 audioSamples 是麦克风采集到的语音原始 PCM 采样数据,应用处理完的数据也需要通过该字段回填,回填的数据的采样点数通过该回调的返回值告知 SDK。

注意:回填数据采样点数不允许超过回调的数据采样点数;如果需要发送较多数据,可以在每次回调中发送最多 samplesNumber 个采样点数据。

建议异步地处理语音数据,并且在改回调中发送之前已经异步处理完的语音数据。

文件混音

文件混音是在音视频通话和互动直播过程中,将本地的音频文件与本端采集的声音数据混音后发送出去,同时在本端播放出来的功能。

该功能可以处理系统原生支持语音播放的音频文件类型,如 aac、mp3、mp4 和 wav 等。

该功能支持设置文件播放次数、发送音量和播放音量,支持通话中开始、暂停、恢复、更新及停止文件混音。

混音任务的具体设置通过 NIMNetCallAudioFileMixTask 指定。

播放文件的路径通过实例化接口传递:

- (instancetype)initWithFileURL:(NSURL *)url

通过 numberOfLoops 指定该文件循环播放次数,负数表示无限循环,非负数表示总共播放 numberOfLoops + 1 次,可以实时更新,更新后重新计数。

通过 sendVolume 指定混音时的发送语音音量, 接受输入值为 0.0 到 1.0,可以实时更新。

通过 playbackVolume 指定混音时的播放语音音量, 接受输入值为 0.0 到 1.0,可以实时更新。

将实例化的文件混音任务通过以下接口开始任务:

- (nullable NSError *)startAudioMix:(NIMNetCallAudioFileMixTask *)task

如果成功开始混音任务了, 返回 nil。开始新的任务会结束正在进行中的任务。

任务成功开始后,可以实时获取当前任务信息:

- (nullable NIMNetCallAudioFileMixTask *)currentAudioMixTask

如果没有进行中的任务则返回 nil。

可以在任务进行中通过更新接口实时更新文件播放次数、发送音量和播放音量等:

- (nullable NSError *)updateAudioMix:(NIMNetCallAudioFileMixTask *)task

如果成功更新了任务, 返回 nil。更新循环播放次数后,SDK 重新计算播放次数。

- (BOOL)pauseAudioMix

任务暂停以后,通过该接口从暂停处恢复任务:

- (BOOL)resumeAudioMix

通过该接口停止进行中的任务:

- (BOOL)stopAudioMix

混音任务完成后,通过以下接口通知应用:

- (void)onAudioMixTaskCompleted

本地视频截图

本地截图,截取自己下一帧待发送的画面

- (void)snapshotFromLocalVideoCompletion:(void(^)(UIImage * __nullable image))result;

result 为返回的截图结果,如果截图失败 result 中 image 为 nil。

网络探测

网络探测是一个辅助的诊断工具,可探测音视频通话网络的连通性、丢包率和延迟等信息。

网络探测通过 NIMAVChatNetDetectManager 管理类提供服务。

- (UInt64)startDetectTask:(nullable NIMAVChatNetDetectCompleteBlock)completion

该接口返回任务 id,可以用来标识或停止已经开始的任务。

网络探测结果通过 completion 回调给应用。

网络探测结果回调声明如下:

typedef void(^NIMAVChatNetDetectCompleteBlock)(NIMAVChatNetDetectResult *result)

返回的 result 中:

taskId 是任务标识,与开始任务接口返回的 id 对应;

error 是任务执行的结果,如果执行成功为 nil,如果执行失败,result 中的 taskId 以外的其他字段均无意义;

lossRate 是丢包率百分比;

rttMaximal 是 rtt 最大值;

rttMinimal 是 rtt 最小值;

rttAverage 是 rtt 平均值;

rttMeanDeviation 是 rtt 偏差值 mdev;

expandInfo 是 扩展信息。

在上述返回的字段中,lossRate、rttAverage、rttMeanDeviation这三个值最能反应当前客户端的实际网络情况。由这三个值可以计算出当前的网络状况指数:

网络状况指数 = (lossRate/20)*50% +(rttAverage/1200)*25% +(rttMeanDeviation/150)*25%

经过我们的反复测试,现提供三个网络状况指数节点

网络状况指数节点 lossRate(%) rttAverage(ms) rttMeanDeviation(ms) 网络状况指数
A 3 500 50 0.2625
B 10 800 80 0.55
C 20 1200 150 1

备注:

1.当网络状况指数≤0.2625时,网络状况非常好,音视频通话流畅;

2.当0.2625<网络状况指数≤0.55时,网络状况好,音视频通话偶有卡顿;

3.当0.55<网络状况指数≤1时,网络状况差,音频通话流畅;

4.当网络状况指数>1时,网络状况非常差,音频通话偶有卡顿。

可以通过开始任务接口返回的 id 停止一个正在进行的任务:

- (void)stopDetectTask:(UInt64)taskId

网络探测日志记录在单独的文件中,通过以下接口获取该文件路径:

- (NSString *)logFilepath

API 文档