Skip to content

iOS

这页只覆盖客户端单端视角,目标是尽快跑通“引用 SDK -> 初始化 -> 连接并播放”。

前置条件

环境要求

项目要求
iOSiOS 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)")
  }
}

Ti RTC 开发文档