iOS
这页只覆盖客户端单端视角,目标是尽快跑通“引用 SDK -> 初始化 -> 连接并播放”。
前置条件
环境要求
| 项目 | 要求 |
|---|---|
| iOS | iOS 13.0 及以上 |
| 支持架构 | arm64 |
1. 引用 SDK
ruby
target 'YourApp' do
pod 'TiRTC_AV', '<latest-version>'
end版本号从iOS 发布说明获取。
2. 初始化 SDK
swift
import UIKit
import TiRTC_AV
@main
final class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
let config = TiRtcConfig()
TiRtc.initialize(config)
return true
}
}3. 连接并播放
这份 quick start 按“连上就发”策略保持最短路径。如果你的设备端采用“收到订阅再发”,连接进入 .connected 后再调用 conn.subscribeAudio(streamId: audioStreamId)、conn.subscribeVideo(streamId: videoStreamId),页面离开前再调用 conn.unsubscribeAudio(streamId: audioStreamId)、conn.unsubscribeVideo(streamId: videoStreamId)。
先准备一个视频容器:
swift
let videoContainer = UIView()
videoContainer.backgroundColor = .black然后按页面生命周期处理播放。
swift
import OSLog
import TiRTC_AV
import UIKit
final class PlayerViewController: UIViewController, TiRtcConnDelegate,
TiRtcAudioOutputDelegate, TiRtcVideoOutputDelegate {
private static let tag = "TiRtcQuickStart"
private let remoteId = "your-remote-id"
private let token = "v1.xxxxxx" // got from backend
private let audioStreamId = yourAudioStreamId
private let videoStreamId = yourVideoStreamId
private let logger = Logger(subsystem: PlayerViewController.tag, category: "playback")
private lazy var conn = TiRtcConn(delegate: self)
private let audioOutput = TiRtcAudioOutput()
private let videoOutput = TiRtcVideoOutput()
private let videoContainer = UIView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
// 打印基础状态,便于先定位黑屏、无声或断连。
audioOutput.delegate = self
videoOutput.delegate = self
// 绑定画面渲染容器。
videoContainer.backgroundColor = .black
videoContainer.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(videoContainer)
NSLayoutConstraint.activate([
videoContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor),
videoContainer.trailingAnchor.constraint(equalTo: view.trailingAnchor),
videoContainer.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
videoContainer.heightAnchor.constraint(equalToConstant: 240),
])
_ = videoOutput.attachView(videoContainer)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// 绑定要播放的远端音视频流,再发起连接。
audioOutput.attach(to: conn, streamId: audioStreamId)
videoOutput.attach(to: conn, streamId: videoStreamId)
let code = conn.connect(to: remoteId, token: token)
if code != 0 {
logger.error("connect request failed code=\(code)")
}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// 页面不可见时先停播断连。
audioOutput.detach()
videoOutput.detach()
conn.disconnect()
}
deinit {
// 页面销毁时释放对象。
videoOutput.detachView()
audioOutput.invalidate()
videoOutput.invalidate()
conn.invalidate()
}
func conn(_ conn: TiRtcConn, didChangeState state: TiRtcConnState) {
logger.info("conn state=\(String(describing: state))")
}
func conn(_ conn: TiRtcConn, didDisconnectWithCode code: Int32) {
logger.info("conn disconnected code=\(code)")
}
func conn(_ conn: TiRtcConn, didReceiveCommand cmdw: UInt32, data: Data) {
logger.info("conn cmdw=\(cmdw)")
}
func conn(_ conn: TiRtcConn, didReceiveStreamMessage streamId: UInt8, timestampMs: UInt32, data: Data) {
logger.info("conn stream message streamId=\(streamId)")
}
func conn(_ conn: TiRtcConn, didFailWithCode code: Int32, message: String) {
logger.error("conn error code=\(code) message=\(message)")
}
func audioOutput(_ output: TiRtcAudioOutput, didChangeState state: TiRtcAudioOutputState) {
logger.info("audio state=\(String(describing: state))")
}
func audioOutput(_ output: TiRtcAudioOutput, didFailWithCode code: Int32, message: String) {
logger.error("audio error code=\(code) message=\(message)")
}
func videoOutput(_ output: TiRtcVideoOutput, didChangeState state: TiRtcVideoOutputState) {
logger.info("video state=\(String(describing: state))")
}
func videoOutput(_ output: TiRtcVideoOutput, didChangeRenderSize size: CGSize) {
logger.info("video size=\(size.width)x\(size.height)")
}
func videoOutput(_ output: TiRtcVideoOutput, didFailWithCode code: Int32, message: String) {
logger.error("video error code=\(code) message=\(message)")
}
}