IosAv_zh - aopacloud/aopa-rtc GitHub Wiki

实现音视频互动

本文介绍如何集成奥帕实时互动 SDK,通过少量代码从 0 开始实现一个简单的实时互动 App,适用于互动直播和视频通话场景。

首先,你需要了解以下有关音视频实时互动的基础概念:

  • 奥帕实时互动 SDK:由奥帕开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
  • 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
  • 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
  • 观众:可以在频道内订阅音视频,不具备发布音视频权限。

下图展示在 App 中实现音视频互动的基本工作流程:

实现音视频互动

  1. 所有用户调用 joinChannel 方法加入频道,并根据需要设置用户角色:
    • 互动直播:如果用户需要在频道中发流,则设为主播;如果用户只需要收流,则设为观众。
    • 视频通话:将所有的用户角色都为主播。
  2. 加入频道后,不同角色的用户具备不同的行为:
    • 所有用户默认都可以接收频道中的音视频流。
    • 主播可以在频道内发布音视频流。
    • 观众如果需要发流,可在频道内调用 setClientRole 方法修改用户角色,使其具备发流权限。

前提条件

在实现功能以前,请按照以下要求准备开发环境:

  • Xcode 12.0 或以上版本。
  • Apple 开发者账号。
  • 如需使用 Cocoapods 集成 SDK,则确保已安装 Cocoapods,否则请参考 Getting Started with CocoaPods 进行安装。
  • 两台 iOS 9.0 或以上版本的设备。
  • 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考[应对防火墙限制]以正常使用奥帕服务。
  • 一个有效的奥帕账号以及奥帕项目。请参考[开通服务]从奥帕控制台获得以下信息:
    • App ID:奥帕随机生成的字符串,用于识别你的项目。
    • 临时 Token:Token 也称为动态密钥,在客户端加入频道时对用户鉴权。临时 Token 的有效期为 24 小时。

创建项目

按照以下步骤,在 Xcode 中创建一个项目:

  1. 参考 Create a project 创建一个新的项目。Application 选择 AppInterface 选择 StoryboardLanguage 选择 Obk

    信息

    如果你没有添加过开发团队信息,会看到 Add account… 按钮。点击该按钮并按照屏幕提示登入 Apple ID,点击 Next,完成后即可选择你的 Apple 账户作为开发团队。

  2. 为你的项目设置自动签名

  3. 设置部署你的 App 的目标设备

  4. 添加项目的设备权限。

    在项目导航栏中打开 info.plist 文件,编辑属性列表,添加实时互动所需的录音和摄像头权限。

    信息

    • 下表中列出的权限均为可选权限。但如果不添加所列权限,你将无法使用麦克风和摄像头进行实时音视频互动。
    • 如果你的项目中需要添加第三方插件或库(例如第三方摄像头),且该插件或库的签名与项目的签名不一致,你还需勾选 Hardened Runtime > Runtime Exceptions 中的 Disable Library Validation
    • 更多注意事项,可以参考 Preparing Your App for Distribution
    key type value
    Privacy - Microphone Usage Description String 使用麦克风的目的,例如:for a call or live interactive streaming。
    Privacy - Camera Usage Description String 使用摄像头的目的,例如:for a call or live interactive streaming。

集成 SDK

根据实际情况,在以下集成方式中任选一种,在你的项目中集成 SDK。

  • 手动集成
  1. 前往[下载]页面,获取最新版的 SDK,然后解压。

  2. 将 SDK 包内 libs 路径下的文件,拷贝到你的项目路径下。

  3. 打开 Xcode,添加对应动态库,确保添加的动态库 Embed 属性设置为 Embed & Sign

    信息

    奥帕 SDK 默认使用 libc++ (LLVM)。SDK 提供的库是 FAT Image,包含 32/64 位模拟器、32/64 位真机版本。

  4. 在 Xcode 中,进入 File > Swift Packages > Add Package Dependencies...,粘贴如下 URL:

    HTTP

    https://github.com/aopacloud/aopa-rtc
    
  5. Choose Package Options 中指定你想集成的 SDK 版本。你也可以参考 Apple 官方文档进行设置。

创建用户界面

根据使用场景,为你的项目创建一个用户界面,包括本地视频窗口和远端视频窗口。用以下代码替换 ViewController.swift 文件中的内容:

Swift

import UIKit
import AopaRtcKit

class ViewController: UIViewController {
    // 本地视频视图
    var localView: UIView!
    // 远端视频视图
    var remoteView: UIView!
    // RTC 引擎
    var AopaKit: AopaRtcEngineKit!

    override func viewDidLoad() {
        super.viewDidLoad()

        localView = UIView(frame: UIScreen.main.bounds)
        remoteView = UIView(
            frame: CGRect(x: self.view.bounds.width - 135, y: 50, width: 135, height: 240))
        self.view.addSubview(localView)
        self.view.addSubview(remoteView)
    }
}

实现流程

下图展示了使用奥帕 RTC SDK 实现音视频互动的基本流程。

实现流程

下面列出了一段实现实时互动基本流程的完整代码以供参考。复制以下代码到 ViewController.swift 文件中替换原有内容即可。

信息

appIdtokenchannelName 字段中传入你在控制台获取到的 App ID、临时 Token,以及生成临时 Token 时填入的频道名。

实现音视频互动示例代码

Swift

//  ViewController.swift
import UIKit
import AopaRtcKit

class ViewController: UIViewController {
    // 本地视频视图
    var localView: UIView!
    // 远端视频视图
    var remoteView: UIView!
    // RTC 引擎
    var AopaKit: AopaRtcEngineKit!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        localView = UIView(frame: UIScreen.main.bounds)
        remoteView = UIView(frame: CGRect(x: self.view.bounds.width - 135, y: 50, width: 135, height: 240))
        self.view.addSubview(localView)
        self.view.addSubview(remoteView)
        
        // 初始化 RTC 实例
        AopaKit = AopaRtcEngineKit.sharedEngine(withAppId:<#Your App ID#>, delegate: self)
        
        // 开启视频模块(音频模块默认开启)
        AopaKit.enableVideo()
        
        // 开启本地摄像头预览
        startPreview()
        
        // 加入频道
        joinChannel()
    }
    
    deinit {
        AopaKit.stopPreview()
        AopaKit.leaveChannel(nil)
        AopaRtcEngineKit.destroy()
    }
    
    func startPreview(){
        let videoCanvas = AopaRtcVideoCanvas()
        videoCanvas.view = localView
        videoCanvas.renderMode = .hidden
        AopaKit.setupLocalVideo(videoCanvas)
        AopaKit.startPreview()
    }
    
    func joinChannel(){
        let options = AopaRtcChannelMediaOptions()
        // 设置频道场景为直播
        options.channelProfile = .liveBroadcasting
        // 设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可
        options.clientRoleType = .broadcaster
        // 发布麦克风采集的音频
        options.publishMicrophoneTrack = true
        // 发布摄像头采集的视频
        options.publishCameraTrack = true
        // 自动订阅所有音频流
        options.autoSubscribeAudio = true
        // 自动订阅所有视频流
        options.autoSubscribeVideo = true
        // 使用临时 Token 加入频道,在这里传入你的项目的 Token 和频道名
        // uid 为 0 表示由引擎内部随机生成; 成功后会触发 didJoinChannel 回调
        AopaKit.joinChannel(byToken: <#Your Token#>, channelId: <#Your Channel Name#>, uid: 0, mediaOptions: options)    
    }
}

extension ViewController: AopaRtcEngineDelegate{
    // 成功加入频道回调
    func rtcEngine(_ engine: AopaRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) {
        print("didJoinChannel: \(channel), uid: \(uid)")
    }
    
    // 远端用户或主播加入当前频道回调
    func rtcEngine(_ engine: AopaRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int){
        // 当远端用户加入频道后,显示指定 uid 的远端视频流
        let videoCanvas = AopaRtcVideoCanvas()
        videoCanvas.uid = uid
        videoCanvas.view = remoteView
        videoCanvas.renderMode = .hidden
        AopaKit.setupRemoteVideo(videoCanvas)
    }
    
    // 远端用户或主播离开当前频道回调
    func rtcEngine(_ engine: AopaRtcEngineKit, didOfflineOfUid uid: UInt, reason: AopaUserOfflineReason) {

        let videoCanvas = AopaRtcVideoCanvas()
        videoCanvas.uid = uid
        videoCanvas.view = nil
        AopaKit.setupRemoteVideo(videoCanvas)
    }
}

导入奥帕组件

ViewController.swift 文件中引入 AopaRtcKit

Swift

import AopaRtcKit  

初始化引擎

调用 sharedEngineWithConfig 方法,创建并初始化 AopaRtcEngineKit

注意

在初始化 SDK 前,需确保终端用户已经充分了解并同意相关的隐私政策。

Swift

// 在这里输入你在奥帕控制台中获取的 App ID  
AopaKit = AopaRtcEngineKit.sharedEngine(withAppId:<#Your App ID#>, delegate: self)  

启用视频模块

按照以下步骤启用视频模块。

  1. 调用 enableVideo 方法,启用视频模块。
  2. 调用 setupLocalVideo 方法初始化本地视图,同时设置本地的视频显示属性。
  3. 调用 startPreview 方法,开启本地视频预览。

Swift

// 启用视频模块  
AopaKit.enableVideo()  
  
let videoCanvas = AopaRtcVideoCanvas()  
videoCanvas.view = localView  
videoCanvas.renderMode = .hidden  
// 设置本地视图  
AopaKit.setupLocalVideo(videoCanvas)  
// 开始本地视频预览  
AopaKit.startPreview()  

加入频道并发布音视频流

调用 joinChannelByToken方法、填入你在控制台获取的临时 Token,以及获取 Token 时填入的频道名加入频道,并设置用户角色。

Swift

let options = AopaRtcChannelMediaOptions() // 设置频道场景为直播    
options.channelProfile = .liveBroadcasting    // 设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可    
options.clientRoleType = .broadcaster    // 发布麦克风采集的音频    
options.publishMicrophoneTrack = true    // 发布摄像头采集的视频    
options.publishCameraTrack = true    // 自动订阅所有音频流    
options.autoSubscribeAudio = true    // 自动订阅所有视频流    
options.autoSubscribeVideo = true    // 使用临时 Token 加入频道,在这里传入你的项目的 Token 和频道名    // uid 为 0 表示由引擎内部随机生成; 成功后会触发 didJoinChannel 回调    
AopaKit.joinChannel(byToken: <#Your Token#>, channelId: <#Your Channel Name#>, uid: 0, mediaOptions: options)

设置远端用户视图

调用 setupRemoteVideo 方法初始化远端用户视图,同时设置远端用户的视图在本地显示属性。你可以通过 didJoinedOfUid 回调获取远端用户的 uid

Swift

func rtcEngine(_ engine: AopaRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int){  
    // 当远端用户加入频道后,显示指定 uid 的远端视频流    
    let videoCanvas = AopaRtcVideoCanvas()    
    videoCanvas.uid = uid    
    videoCanvas.view = remoteView    
    videoCanvas.renderMode = .hidden    
    AopaKit.setupRemoteVideo(videoCanvas)}  

实现常用回调

根据使用场景,定义必要的回调。以下示例代码展示了如何实现 didJoinChanneldidOfflineOfUid 回调。

Swift

// 成功加入频道回调  
func rtcEngine(_ engine: AopaRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) {  
    print("didJoinChannel: \(channel), uid: \(uid)")}  
    // 远端用户或主播离开当前频道回调  
func rtcEngine(_ engine: AopaRtcEngineKit, didOfflineOfUid uid: UInt, reason: AopaUserOfflineReason) {  
    let videoCanvas = AopaRtcVideoCanvas()    
    videoCanvas.uid = uid    
    videoCanvas.view = nil    
    AopaKit.setupRemoteVideo(videoCanvas)}  

开始音视频互动

当视图加载完成后,在 viewDidLoad 中调用一系列方法加入频道,开始音视频互动。

Swift

override func viewDidLoad() {  
    super.viewDidLoad()    // 当加载视图后,你可以进行其他其他设置    
    // 当调用奥帕 API 时,以下函数会被调用    
    AopaKit.enableVideo()    
    startPreview()    
    joinChannel()}  

结束音视频互动

  1. 调用 leaveChannel 方法离开频道,与会话相关的资源也会被释放。

    Swift

    AopaKit.stopPreview()  
    AopaKit.leaveChannel(nil)  
    
    
  2. 调用 destroy 销毁引擎,并释放奥帕 SDK 中使用的所有资源。

    Swift

    AopaRtcEngineKit.destroy()  
    
    

    警告

    调用该方法后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎

测试 App

参考以下步骤来测试你的 App:

  1. 将 iOS 设备连接至计算机。
  2. 点击 Build 来运行你的项目,需等待几秒至 App 安装完成。
  3. 允许 App 访问设备的麦克风和摄像头权限。
  4. (可选)如果设备上弹出不受信任的开发者提示,则首先点击取消关闭该提示,然后在 iOS 设备上打开设置 > 通用 > VPN 与设备管理,在开发者 APP 中选择信任该开发者。
  5. 使用第二台 iOS 设备,重复以上步骤,在该设备上安装 App,并打开 App 加入频道,观察测试结果:
    • 如果两台设备均作为主播加入频道,则可以看到对方并且听到对方的声音。
    • 如果两台设备分别作为主播和观众加入,则主播可以在本地视频窗口看到自己;观众可以在远端视频窗口看到主播、并听到主播的声音。

图片

后续步骤

  • 本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见[使用 Token 鉴权]
  • 如果你想要实现极速直播场景,可以在互动直播的基础上,通过修改观众端的延时级别为低延时 (AopaAudienceLatencyLevelLowLatency)实现。详见[实现极速直播]

相关信息

示例项目

奥帕提供了开源的实时互动示例项目供你参考,你可以前往下载或查看其中的源代码。