iOS (Objective-C)
本文以实现音视频通话为例,结合 SDK API 和示例代码,介绍如何快速接入。
如需查看完整 SDK API 列表,请点击左侧导航 SDK API 部分。
导入SDK
自动集成
- 请到 下载中心 查看 SDK 最新版本号。
- 通过 CocoaPods 命令
pod search PanoRtc_iOS
查看本地仓库版本信息,确认是否为最新版本,可以通过pod repo update
命令更新本地仓库索引。 - 在 Podfile 文件中添加:
pod PanoRtc_iOS
,执行pod install
命令安装 SDK。 - 通过
#import <PanoRtc/PanoRtcEngineKit.h>
导入 SDK 文件来调用其中接口。
注意:各版本 SDK 对应包名如下,请注意区分:
- macOS SDK (全功能) 对应包名
PanoRtc_macOS
- iOS SDK (全功能) 对应包名
PanoRtc_iOS
- iOS SDK (纯音频) 对应包名
PanoRtc_Audio_iOS
手工集成
- 请到 下载中心 下载 iOS SDK压缩包。
- 将其解压,iOS 目录下有两个子目录:
- Release-iphoneall:支持真机和模拟器的SDK版本
- 1.6.4及之后的版本既可用于开发调试,也可以发布到App Store
- 1.6.3及之前的版本仅用于开发调试,无法发布到App Store
- Release-iphoneos:只支持真机的SDK版本,可以发布到App Store
- Release-iphoneall:支持真机和模拟器的SDK版本
- 按需选择相应的目录,将其中的 PanoRtc.framework 或 PanoRtc.xcframework 复制到项目目录中。
- 打开 Xcode,定位到 TARGETS - General - Frameworks, Libraries, and Embedded Content,添加 PanoRtc.framework 或 PanoRtc.xcframework,将 Embed 属性设置为 Embed & Sign。
- 通过
#import "PanoRtc/PanoRtcEngineKit.h"
导入 SDK 文件来调用其中接口。
配置权限
在 app 的 info.plist 中添加以下两项内容:
- Privacy - Microphone Usage Description: Value 填写 app 需要使用麦克风的提示信息
- Privacy - Camera Usage Description: Value 填写 app 需要使用摄像头的提示信息
注册通知
通过实现 PanoRtcEngineDelegate
协议的回调方法来处理 Pano SDK 返回的通知。
注意:必须尽早注册通知,以免错过某些通知。
@interface ChannelViewController () <PanoRtcEngineDelegate>
...
@end
@implementation ChannelViewController
- (void)onChannelJoinConfirm:(PanoResult)result {
// 自己加入频道的通知
}
- (void)onChannelLeaveIndication:(PanoResult)result {
// 自己被动离开频道的通知
}
...
@end
- 完整的回调方法介绍,请查看 PanoRtcEngineDelegate 协议。
- 为结合介绍 SDK 接口,本文会提供部分 示例代码 中的片段,请开发者注意根据实际情况调整。
初始化
通过 PanoRtcEngineKit
的 + engineWithConfig:delegate:
方法初始化实例。
PanoRtcEngineConfig * engineConfig = [[PanoRtcEngineConfig alloc] init];
engineConfig.appId = @"..."; // 替换为你的应用ID
self.engineKit = [PanoRtcEngineKit engineWithConfig:engineConfig delegate:self];
请登录 Pano控制台,点击左侧导航 应用管理 ,查看应用ID(即
appId
)。
本地预览
通过 PanoRtcEngineKit
实例的 - startPreviewWithView:config:
方法或 - startPreviewWithDelegate:profile:
方法开启本地摄像头预览。
两者的区别在于:前者随带渲染视图,后者随带外置渲染器。后文类似接口不再重复介绍。
PanoRtcRenderConfig * config = [[PanoRtcRenderConfig alloc] init];
config.profileType = kPanoProfileHD720P; // 分辨率:1280 x 720,实际使用请按需配置
config.scalingMode = kPanoScalingCropFill; // 保持宽高比裁剪填充
config.mirror = [self.engineKit isFrontCamera]; // 是否启用镜像,一般前置摄像头需要镜像
[self.engineKit startPreviewWithView:self.previewView config:config];
- 如果设置的分辨率高于摄像头支持的最大分辨率,则自动降低为摄像头支持的最大分辨率。
- 如需切换预览不同的摄像头,先通过
RtcEngine
实例的- stopPreview
方法停止当前预览,再通过- switchCamera
方法切换摄像头,再重新开启新的预览,无需操作 View。- 如果不需要在 加入频道 前进行本地预览,可以忽略本小节的内容。
加入频道
加入频道
通过 PanoRtcEngineKit
实例的 - joinChannelWithToken:channelId:userId:config:
方法加入频道。
PanoRtcChannelConfig * channelConfig = [[PanoRtcChannelConfig alloc] init];
// mode 频道模式:kPanoChannel1v1 一对一模式,kPanoChannelMeeting 多人模式
// 如果有 Web 端参与,或者需要进行直播/录制,请设置为 kPanoChannelMeeting
channelConfig.mode = kPanoChannelMeeting;
/* serviceFlags 频道标志:音视频 | 白板 | 实时消息 (按位或)
channelConfig.serviceFlags =
kPanoChannelServiceMedia | kPanoChannelServiceWhiteboard | kPanoChannelServiceMessage;
*/
channelConfig.serviceFlags = kPanoChannelServiceMedia; // 只使用音视频
channelConfig.subscribeAudioAll = YES; // 自动订阅音频,可以配置为 NO 来主动订阅音频
channelConfig.userName = @""; // 设置用户名
PanoResult result = [self.engineKit joinChannelWithToken:@""
channelId:@""
userId:userId
config:channelConfig];
if (result != kPanoResultOK) {
// 加入失败,请根据 PanoResult 进行处理
}
自己加入频道的通知
调用 - joinChannelWithToken:channelId:userId:config:
方法后,将触发 - onChannelJoinConfirm:
通知。
- (void)onChannelJoinConfirm:(PanoResult)result {
// PanoResult 表示自己加入频道的结果
}
"加入频道"接口返回的
PanoResult
仅表示调用该接口的结果,而"自己加入频道的通知"返回的PanoResult
表示和服务器交互后的结果。
也就是说当"自己加入频道的通知"返回kPanoResultOK
才表示加入频道成功。
其他用户加入频道的通知
其他用户加入频道后,将触发 - onUserJoinIndication:withName:
通知。
- (void)onUserJoinIndication:(UInt64)userId
withName:(NSString * _Nullable)userName {
// 其他用户加入频道的通知。userId 和 userName 都是该用户在 加入频道 时传入的
// 此时可以将其加入到与会者列表中
}
倒计时通知
加入频道后,如果存在倒计时限制,将触发 - onChannelCountDown:
通知。
- (void)onChannelCountDown:(UInt32)remain {
// 频道倒计时通知,单位:秒;请保存用于展示倒计时,此回调仅在加入频道后回调一次
}
- 已实名认证,并且使用正式token,Pano不限制频道时长
- 未实名认证,或者使用临时token,最大频道时长为 30 分钟
操作视频
如果你使用纯音频SDK,请忽略本节,直接跳转到下一节:操作声音。
发送本地视频
通过 PanoRtcEngineKit
实例的以下方法发送本地视频:
- startVideoWithView:config:
(由 SDK 渲染到指定的 View)- startVideoWithDelegate:profile:
(开发者自行渲染,可指定分辨率档位)- startVideoWithDelegate:config:
(开发者自行渲染,可指定分辨率档位等配置)
PanoRtcRenderConfig * renderConfig = [[PanoRtcRenderConfig alloc] init];
renderConfig.profileType = kPanoProfileHD720P; // 分辨率:1280 x 720,实际使用请按需配置
renderConfig.sourceMirror = NO;
renderConfig.scalingMode = kPanoScalingCropFill;
renderConfig.mirror = YES;
/* profileType 和 sourceMirror 会同时影响发送和渲染,scalingMode 和 mirror 只影响渲染不影响发送
sourceMirror 和 mirror 只要其中一个为 true,本地渲染即为镜像模式
*/
// 调用此方法后,其他用户才能看到你的画面;请在 自己加入频道的通知 返回成功后再调用
[self.engineKit startVideoWithView:self.localView config:renderConfig];
- 发送本地视频 接口设置的分辨率表示期望的发送分辨率,实际过程中可能会因硬件支持情况、网络情况和订阅情况触发 SDK 自动调整而降低(后文会介绍订阅)。
- 如果在 发送本地视频 前调用了 本地预览 接口,可以先调用 停止本地预览(
- stopPreview
) 接口再 发送本地视频,避免重复显示。- 如果重复调用 发送本地视频 接口,新参数(
PanoView
,PanoRtcVideoConfig
,PanoRtcRenderDelegate
,PanoVideoProfileType
)立即生效,旧参数立即失效。因此,可以通过重复调用的方式来实现更换视图、更新分辨率等特殊场景。
切换摄像头
通过 PanoRtcEngineKit
实例的 - isFrontCamera
方法判断是否是前置摄像头,通过 - switchCamera
方法切换摄像头。
// 下面代码演示切换到后置摄像头,发送本地视频 前后都可以调用
if ([self.engineKit isFrontCamera] == YES) {
[self.engineKit switchCamera]; // 此方法将切换随后发送出去的摄像头画面,但是不会切换本地预览画面
}
如果前置摄像头需要镜像,而后置摄像头不需要镜像,并且你使用
- startVideoWithView:config:
方法发送本地视频的话,这种场景下,切换前后置摄像头之后,请更改PanoRtcRenderConfig
的mirror
参数值,然后重新调用- startVideoWithView:config:
方法。
停止发送本地视频
通过 PanoRtcEngineKit
实例的 - stopVideo
方法停止发送本地视频。
// 调用此方法后,其他用户将看不到你的画面
// 会同时停止向 发送本地视频 方法设置的渲染视图或外置渲染器传递视频数据
[self.engineKit stopVideo];
其他用户开启视频的通知
当其他用户发送视频时,将触发 - onUserVideoStart:withMaxProfile:
通知。
- (void)onUserVideoStart:(UInt64)userId
withMaxProfile:(PanoVideoProfileType)maxProfile {
// maxProfile 表示该用户的最大可发送分辨率
// 取决于 摄像头支持的最大分辨率 和 设置的发送分辨率 这两个值中的较小值
}
订阅其他用户的视频
通过 PanoRtcEngineKit
实例的 - subscribeVideo:withView:config:
方法或 - subscribeVideo:withDelegate:profile:
方法订阅其他用户的视频。
// 请在收到 其他用户开启视频的通知 后,再调用订阅;返回 kPanoResultOK 表示接口调用成功,否则表示失败
PanoRtcRenderConfig * config = [[PanoRtcRenderConfig alloc] init];
// 可以根据显示窗口的大小来决定订阅分辨率,比如大窗口订阅高分辨率,小窗口订阅低分辨率
// 此处示例订阅 1280 x 720,实际使用请按需配置
config.profileType = kPanoProfileHD720P;
config.scalingMode = kPanoScalingCropFill;
[self.engineKit subscribeVideo:userId withView:view config:config];
- Pano采用订阅模式来接收视频,参与者之间需要相互订阅,才可以看到彼此的视频画面。
- 默认 正式token 最多可以订阅 10 路视频,临时token 最多可以订阅 3 路视频。
- 如果订阅失败,会触发
- onUserVideoSubscribe:withResult:
通知。- 使用
PanoRtcVideoStreamManager
的开发者,请换用其- subscribeVideo:stream:view:config:
或- subscribeVideo:stream:delegate:profile:
方法来订阅其他用户的视频流。
视频首帧的通知
当自己发送或收到其他用户第一个视频帧时,将触发 - onFirstVideoFrameRendered:
通知。
- (void)onFirstVideoFrameRendered:(UInt64)userId {
// 第一个视频帧通知,可以开始显示视频画面
}
取消订阅其他用户的视频
通过 PanoRtcEngineKit
实例的 - unsubscribeVideo:
方法取消订阅其他用户的视频。
[self.engineKit unsubscribeVideo:userId]; // 调用此方法后,你将看不到该用户的画面
- 当其他用户停止视频或者离开频道的时候,将被自动取消订阅。
- 使用
PanoRtcVideoStreamManager
的开发者,请换用其- unsubscribeVideo:stream:
方法来取消订阅。
操作声音
发送本地声音
通过 PanoRtcEngineKit
实例的 - startAudio
方法发送本地声音。
[self.engineKit startAudio]; // 调用此方法后,其他用户才能听到你的声音;请在加入频道成功后再调用
调用此方法,会触发
- onAudioStartResult:
回调。
停止发送本地声音
通过 PanoRtcEngineKit
实例的 - stopAudio
方法停止发送本地声音。
// 调用此方法后,其他用户将听不到你的声音
// 不影响你接收其他用户的声音
// 可以调用 发送本地声音 接口重新发送
[self.engineKit stopAudio];
静音麦克风
通过 PanoRtcEngineKit
实例的 - muteAudio
方法静音本地麦克风。
[self.engineKit muteAudio]; // 调用此方法后,其他用户将听不到你的麦克风的声音
停止发送本地声音(
stopAudio
) 和 静音本地麦克风(muteAudio
) 这两个接口都可以将自己静音(不让其他用户听到你的声音)。它们的区别在于:
1 "停止发送本地声音"会断开音频通道连接(同时停止发送麦克风和伴音的声音,会取消其他用户订阅你的声音,如需重建连接需要消耗时间)
2 "静音本地麦克风"会发送静音包(不影响伴音发送,不影响订阅关系,静音包数据量很小,临时静音建议使用此方式,取消静音能够迅速恢复发送声音)
取消静音麦克风
通过 PanoRtcEngineKit
实例的 - unmuteAudio
方法取消静音本地麦克风。
[self.engineKit unmuteAudio]; // 静音麦克风后,需要取消静音,其他用户才能听到你的麦克风的声音
其他用户开启声音的通知
当其他用户发送声音时,将触发 - onUserAudioStart:
通知。
- (void)onUserAudioStart:(UInt64)userId {
// 其他用户开启声音的通知
}
订阅其他用户的声音
如果在 加入频道 时,配置了自动订阅音频(例如:channelConfig.subscribeAudioAll = YES
),则开发者无需再主动订阅其他用户的声音。否则,需要通过 PanoRtcEngineKit
实例的 - subscribeAudio:
方法订阅其他用户的声音。
// 如果 加入频道 时配置了自动订阅音频,则无需调用此接口
// 请在收到 其他用户开启声音的通知 后,再调用订阅
[self.engineKit subscribeAudio:userId];
- 如果希望在通话过程中,不收听某位与会者,或者不收听所有其他与会者,请在加入频道时,设置不自动订阅音频;随后按需订阅或取消订阅某位或所有其他与会者。
- 如果订阅失败,会触发
- onUserAudioSubscribe:withResult:
通知。
收到其他用户声音的通知
当收到其他用户的声音时,将触发 - onFirstAudioDataReceived:
通知。
- (void)onFirstAudioDataReceived:(UInt64)userId {
// 收到其他用户的首个声音数据包
}
取消订阅其他用户的声音
通过 PanoRtcEngineKit
实例的 - unsubscribeAudio:
方法取消订阅其他用户的声音。
[self.engineKit unsubscribeAudio:userId]; // 调用此方法后,你将听不到该用户的声音
当其他用户停止声音或者离开频道的时候,将被自动取消订阅。
离开频道
离开频道
通过 PanoRtcEngineKit
实例的 - leaveChannel
方法离开频道。
[self.engineKit leaveChannel];
注意:此接口为同步接口;调用此接口主动离开频道,自己不会收到
onChannelLeaveIndication
回调。
其他用户离开频道的通知
其他用户离开频道后,将触发 - onUserLeaveIndication:withReason:
通知。
- (void)onUserLeaveIndication:(UInt64)userId
withReason:(PanoUserLeaveReason)reason {
// 可将其从与会者列表中移除
}
释放资源
通过 - destroy
方法销毁 PanoRtcEngineKit
实例。
[self.engineKit destroy];
反馈问题
我们强烈建议您集成反馈功能,以便用户遇到问题时,可以提交信息给我们分析排查,具体请 点此查看。
SDK API 指南
本文仅介绍接入Pano iOS SDK实现视频通话的基本流程和接口。
实际场景可能需要结合使用更多接口,请 点此查看 API 列表。
示例代码
为方便开发者了解丰富的接口使用方式,我们还提供示例代码,请体验参考: