• 製品
  • 価格
  • リソース
  • サポート
このページは現在英語版のみで提供されており、日本語版も近日中に提供される予定です。ご利用いただきありがとうございます。

iOS

This document helps you move a Web app from the Twilio Video SDK to the Tencent RTC Engine SDK. It covers key architecture differences, step-by-step migration instructions, practical feature examples, and advanced feature comparisons to help you migrate smoothly.
If you’re starting a new project with Tencent RTC Engine, begin with the Quick Start Guide. For a high-level introduction, see the Product Overview.

Core concepts and architecture differences

Concept Comparison

This section maps key concepts between Tencent RTC Engine and Twilio Video. For Tencent RTC terminology, see Basic Concepts.
Concept
Tencent RTC Engine
Twilio Video
Description
Room
Room
Room
Session space connecting RTC participants. Tencent RTC uses roomId (numeric) or strRoomId (string); Twilio uses roomName (string).
User
User
Participant
User participating in audio/video calls.
Anchor
Anchor
User type with streaming permission; can send and receive audio/video streams to/from the server.
Audience
Audience
User type that only receives audio/video streams.
Application Identifier
SDKAppID
Account SID
Unique application identifier.
Authentication Credential
UserSig
Access Token
Client authentication credential.
User Identifier
userId
Identity
Unique user identifier.
Core Entry Class
TRTCCloud
Video (class)
SDK core entry class.

Technical Architecture Differences

Twilio Video Architecture

Twilio Video uses a track-based architecture:
You explicitly create LocalAudioTrack and LocalVideoTrack.
You publish tracks by passing the track list into ConnectOptions.Builder.
You subscribe to remote tracks via callbacks from RemoteParticipant.Listener.
You render video using a VideoSink or VideoView.

Tencent RTC Engine Architecture

Tencent RTC Engine uses an API-driven architecture:
You capture and publish by calling startLocalPreview() and startLocalAudio() on the TRTCCloud singleton.
You subscribe to remote streams via TRTCCloudListener callbacks and startRemoteView().
You render video with TXCloudVideoView.
You don’t need to manually create or manage track objects.
Tencent RTC Engine APIs are more concise and simplify object management compared to Twilio Video.

Migration Preparation

Step 1. Activate the Service

To use Tencent RTC Engine services, you need to create an application and obtain credentials. Follow these steps to create a Tencent RTC Engine application in the console:
1. Register or sign in to your Tencent RTC account, then access the Tencent RTC Console.
2. Click Create Application.
3. In the popup, enter your application name, select RTC Engine, then click Create.

trtcapplication


After the application is created, view the following credentials under Basic Information:
SDKAppID: Automatically generated application ID that uniquely identifies your Tencent RTC app.
SDKSecretKey: Key used to generate the UserSig, which ensures secure access to Tencent RTC services.
credentials


Note:
Authentication Comparison: Twilio Video uses Access Token for authentication, whereas Tencent RTC uses UserSig. Both are time-limited credentials generated on the server side, but the generation methods differ. See UserSig Authentication Documentation.

Step 2. Import the SDK

Original Twilio Podfile (Reference)

source 'https://github.com/CocoaPods/Specs'

platform :ios, '12.2'

target 'TARGET_NAME' do
pod 'TwilioVideo', '~> 5'
end

Tencent RTC Engine SDK (New Dependency)

CocoaPods (Recommended)
1. If CocoaPods is not installed, install it:
sudo gem install cocoapods
2. In your project root directory, initialize a Podfile:
pod init
3. Add the TRTC SDK dependency to your Podfile:
platform :ios, '9.0'

target 'YourApp' do
pod 'TXLiteAVSDK_TRTC', :podspec => 'https://liteav.sdk.qcloud.com/pod/liteavsdkspec/TXLiteAVSDK_TRTC.podspec'
end
4. Install the SDK:
pod install
5. After pod install finishes, a new .xcworkspace file will be generated. Open the .xcworkspace file to continue development.

Step 3. Project Configuration

1. Open your .xcworkspace project file, click your project name in Xcode’s Project Navigator, and select the correct TARGETS.
2. In Build Settings, search for User Script Sandboxing and set its value to No to allow user scripts broader access.



3. In Info.plist, add Privacy-Microphone Usage Description and Privacy-Camera Usage Description. Fill in appropriate prompts for microphone and camera permissions.



4. Under Signing & Capabilities, add Background Modes and check Audio, AirPlay and Picture in Picture to enable background audio, AirPlay, and Picture in Picture features.




Migration Instructions

Step 4. Initializing SDK Instance and Setting Event Listener

Twilio Video

import TwilioVideo

class TwilioVideoManager {
var room: Room?
var localVideoTrack: LocalVideoTrack?
var localAudioTrack: LocalAudioTrack?

init() {
// Twilio SDK does not require explicit initialization
}
}

Tencent RTC

Swift
Objective-C
import TXLiteAVSDK_TRTC

class TRTCManager: NSObject {
// Obtain TRTCCloud singleton
let trtcCloud = TRTCCloud.sharedInstance()

override init() {
super.init()
// Set event callback delegate
trtcCloud.delegate = self
}
}
#import <TXLiteAVSDK_TRTC/TRTCCloud.h>

@interface TRTCManager : NSObject <TRTCCloudDelegate>
@property (nonatomic, strong) TRTCCloud *trtcCloud;
@end

@implementation TRTCManager

- (instancetype)init {
self = [super init];
if (self) {
// Obtain TRTCCloud singleton
_trtcCloud = [TRTCCloud sharedInstance];
// Set event callback delegate
_trtcCloud.delegate = self;
}
return self;
}
@end

Step 5. Entering a Room

Twilio Video

@IBAction func connectToRoom(sender: AnyObject) {
let connectOptions = ConnectOptions(token: accessToken) { (builder) in
builder.roomName = "my-room"
}
room = TwilioVideoSDK.connect(options: connectOptions, delegate: self)
}

Tencent RTC

Swift
Objective-C
func enterRoom(sdkAppId: UInt32, roomId: UInt32, userId: String, userSig: String) {
// Configure room parameters
let params = TRTCParams()
params.sdkAppId = sdkAppId
params.roomId = roomId
params.userId = userId
params.userSig = userSig
params.role = .anchor // Anchor role can publish streams

// Enter room and specify scene
// .videoCall - video call scene
// .audioCall - audio call scene
// .LIVE - live streaming scene
// .voiceChatRoom - voice chat room scene
trtcCloud.enterRoom(params, appScene: .LIVE)
}
- (void)enterRoomWithSdkAppId:(UInt32)sdkAppId
roomId:(UInt32)roomId
userId:(NSString *)userId
userSig:(NSString *)userSig {
// Configure room parameters
TRTCParams *params = [[TRTCParams alloc] init];
params.sdkAppId = sdkAppId;
params.roomId = roomId;
params.userId = userId;
params.userSig = userSig;
params.role = TRTCRoleAnchor; // Anchor role can publish streams

// Enter room and specify scene
// TRTCAppSceneVideoCall - video call scene
// TRTCAppSceneAudioCall - audio call scene
// TRTCAppSceneLIVE - live streaming scene
// TRTCAppSceneVoiceChatRoom - voice chat room scene
[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];
}

Step 6. Implementing Event Callback Methods

Twilio Video

extension TwilioVideoManager: RoomDelegate {
// Successfully connected to room
func roomDidConnect(room: Room) {
print("Connected to room: \(room.name)")
}

// Disconnected
func roomDidDisconnect(room: Room, error: Error?) {
print("Room connection disconnected")
}

// Connection failed
func roomDidFailToConnect(room: Room, error: Error) {
print("Connection failed: \(error.localizedDescription)")
}

// Remote participant joined
func participantDidConnect(room: Room, participant: RemoteParticipant) {
print("Participant joined: \(participant.identity)")
}

// Remote participant left
func participantDidDisconnect(room: Room, participant: RemoteParticipant) {
print("Participant left: \(participant.identity)")
}
}

Tencent RTC

Swift
Objective-C
extension TRTCManager: TRTCCloudDelegate {
// Room entry result callback
// result > 0: Success (milliseconds)
// result < 0: Failure (error code)
func onEnterRoom(_ result: Int) {
if result > 0 {
print("Entered room successfully, time: \(result)ms")
} else {
print("Failed to enter room, error code: \(result)")
}
}

// Room exit callback
// reason: 0 - voluntary exit, 1 - kicked out, 2 - room dismissed
func onExitRoom(_ reason: Int) {
print("Exited room, reason: \(reason)")
}

// Error callback
func onError(_ errCode: TXLiteAVError, errMsg: String?, extInfo: [AnyHashable: Any]?) {
print("Error: \(errCode.rawValue) - \(errMsg ?? "")")
}

// Remote user entered room
func onRemoteUserEnterRoom(_ userId: String) {
print("Remote user entered: \(userId)")
}

// Remote user left room
func onRemoteUserLeaveRoom(_ userId: String, reason: Int) {
print("Remote user left: \(userId), reason: \(reason)")
}

// Remote user video availability changed
func onUserVideoAvailable(_ userId: String, available: Bool) {
print("User \(userId) video available: \(available)")
}

// Remote user audio availability changed
func onUserAudioAvailable(_ userId: String, available: Bool) {
print("User \(userId) audio available: \(available)")
}
}
#pragma mark - TRTCCloudDelegate

// Room entry result callback
// result > 0: Success (milliseconds)
// result < 0: Failure (error code)
- (void)onEnterRoom:(NSInteger)result {
if (result > 0) {
NSLog(@"Entered room successfully, time: %ldms", (long)result);
} else {
NSLog(@"Failed to enter room, error code: %ld", (long)result);
}
}

// Room exit callback
// reason: 0 - voluntary exit, 1 - kicked out, 2 - room dismissed
- (void)onExitRoom:(NSInteger)reason {
NSLog(@"Exited room, reason: %ld", (long)reason);
}

// Error callback
- (void)onError:(TXLiteAVError)errCode errMsg:(NSString *)errMsg extInfo:(NSDictionary *)extInfo {
NSLog(@"Error: %d - %@", errCode, errMsg);
}

// Remote user entered room
- (void)onRemoteUserEnterRoom:(NSString *)userId {
NSLog(@"Remote user entered: %@", userId);
}

// Remote user left room
- (void)onRemoteUserLeaveRoom:(NSString *)userId reason:(NSInteger)reason {
NSLog(@"Remote user left: %@, reason: %ld", userId, (long)reason);
}

// Remote user video availability changed
- (void)onUserVideoAvailable:(NSString *)userId available:(BOOL)available {
NSLog(@"User %@ video available: %@", userId, available ? @"YES" : @"NO");
}

// Remote user audio availability changed
- (void)onUserAudioAvailable:(NSString *)userId available:(BOOL)available {
NSLog(@"User %@ audio available: %@", userId, available ? @"YES" : @"NO");
}

Step 7. Capturing and Publishing Local Streams

Twilio Video

// MARK: - Local Video

func startPreview() {
// Create camera source
camera = CameraSource(delegate: self)

// Create local video track
localVideoTrack = LocalVideoTrack(source: camera!, enabled: true, name: "camera")

// Add renderer to display preview
localVideoTrack?.addRenderer(previewView)

// Get front camera and start capture
if let frontCamera = CameraSource.captureDevice(position: .front) {
camera?.startCapture(device: frontCamera)
}
}

func stopLocalVideo() {
localVideoTrack?.isEnabled = false
}

// MARK: - Local Audio

func startLocalAudio() {
localAudioTrack = LocalAudioTrack()
}

func stopLocalAudio() {
localAudioTrack?.isEnabled = false
}

func muteAudio(_ mute: Bool) {
localAudioTrack?.isEnabled = !mute
}

Tencent RTC

Swift
Objective-C
// MARK: - Local Video

func startLocalVideo(view: UIView, frontCamera: Bool = true) {
// Set local preview rendering parameters (optional, SDK provides defaults)
let renderParams = TRTCRenderParams()
renderParams.fillMode = .fill // .fill (fill) or .fit (fit)
renderParams.mirrorType = .auto // .auto (front camera), .enable (always mirror), .disable (no mirror)
trtcCloud.setLocalRenderParams(renderParams)

// Start local video preview
// frontCamera: true = front camera, false = rear camera
trtcCloud.startLocalPreview(frontCamera, view: view)
}

func stopLocalVideo() {
trtcCloud.stopLocalPreview()
}

func muteLocalVideo(_ mute: Bool) {
trtcCloud.muteLocalVideo(.big, mute: mute)
}

func switchCamera(_ frontCamera: Bool) {
trtcCloud.getDeviceManager().switchCamera(frontCamera)
}

// MARK: - Local Audio

func startLocalAudio(quality: TRTCAudioQuality = .default) {
// quality options:
// .speech - speech mode
// .default - default mode
// .music - music mode
trtcCloud.startLocalAudio(quality)
}

func stopLocalAudio() {
trtcCloud.stopLocalAudio()
}

func muteLocalAudio(_ mute: Bool) {
trtcCloud.muteLocalAudio(mute)
}
#pragma mark - Local Video

- (void)startLocalVideoWithView:(UIView *)view frontCamera:(BOOL)frontCamera {
// Set local preview rendering parameters (optional, SDK provides defaults)
TRTCRenderParams *renderParams = [[TRTCRenderParams alloc] init];
renderParams.fillMode = TRTCVideoFillMode_Fill;
renderParams.mirrorType = TRTCVideoMirrorTypeAuto;
[self.trtcCloud setLocalRenderParams:renderParams];

// Start local video preview
[self.trtcCloud startLocalPreview:frontCamera view:view];
}

- (void)stopLocalVideo {
[self.trtcCloud stopLocalPreview];
}

- (void)muteLocalVideo:(BOOL)mute {
[self.trtcCloud muteLocalVideo:TRTCVideoStreamTypeBig mute:mute];
}

- (void)switchCamera:(BOOL)frontCamera {
[[self.trtcCloud getDeviceManager] switchCamera:frontCamera];
}

#pragma mark - Local Audio

- (void)startLocalAudioWithQuality:(TRTCAudioQuality)quality {
[self.trtcCloud startLocalAudio:quality];
}

- (void)stopLocalAudio {
[self.trtcCloud stopLocalAudio];
}

- (void)muteLocalAudio:(BOOL)mute {
[self.trtcCloud muteLocalAudio:mute];
}

Step 8. Subscribing to and Playing Remote Streams

Twilio Video

// MARK: - RemoteParticipantDelegate

extension TwilioVideoManager: RemoteParticipantDelegate {
// Track subscribed
func didSubscribeToVideoTrack(videoTrack: RemoteVideoTrack,
publication: RemoteVideoTrackPublication,
participant: RemoteParticipant) {
// Add renderer to display remote video
videoTrack.addRenderer(remoteVideoView)
}

// Track unsubscribed
func didUnsubscribeFromVideoTrack(videoTrack: RemoteVideoTrack,
publication: RemoteVideoTrackPublication,
participant: RemoteParticipant) {
videoTrack.removeRenderer(remoteVideoView)
}
}

Tencent RTC

Swift
Objective-C
extension TRTCManager: TRTCCloudDelegate {
// Remote user video availability changed
func onUserVideoAvailable(_ userId: String, available: Bool) {
if available {
// Subscribe to remote user's video stream
// streamType: .big (main), .small (small), .sub (screen sharing)
trtcCloud.startRemoteView(userId, streamType: .big, view: remoteVideoView)
} else {
// Stop subscription if video becomes unavailable
trtcCloud.stopRemoteView(userId, streamType: .big)
}
}

// Remote user audio availability changed
func onUserAudioAvailable(_ userId: String, available: Bool) {
if available {
// Audio auto-plays, use mute control as needed
trtcCloud.muteRemoteAudio(userId, mute: false)
}
}
}

// Manual control methods
func muteRemoteAudio(userId: String, mute: Bool) {
trtcCloud.muteRemoteAudio(userId, mute: mute)
}

func muteAllRemoteAudio(_ mute: Bool) {
trtcCloud.muteAllRemoteAudio(mute)
#pragma mark - TRTCCloudDelegate

// Remote user video availability changed
- (void)onUserVideoAvailable:(NSString *)userId available:(BOOL)available {
if (available) {
// Subscribe to remote user's video stream
[self.trtcCloud startRemoteView:userId streamType:TRTCVideoStreamTypeBig view:self.remoteVideoView];
} else {
// Stop subscription if video becomes unavailable
[self.trtcCloud stopRemoteView:userId streamType:TRTCVideoStreamTypeBig];
}
}

// Remote user audio availability changed
- (void)onUserAudioAvailable:(NSString *)userId available:(BOOL)available {
if (available) {
[self.trtcCloud muteRemoteAudio:userId mute:NO];
}
}

// Manual control methods
- (void)muteRemoteAudio:(NSString *)userId mute:(BOOL)mute {
[self.trtcCloud muteRemoteAudio:userId mute:mute];
}

- (void)muteAllRemoteAudio:(BOOL)mute {
[self.trtcCloud muteAllRemoteAudio:mute];
}

Step 9. Leaving the Room

Twilio Video

func disconnect() {
// Stop local tracks
localVideoTrack?.isEnabled = false
localAudioTrack?.isEnabled = false

// Disconnect room connection
room?.disconnect()
}

extension TwilioVideoManager: RoomDelegate {
func roomDidDisconnect(room: Room, error: Error?) {
// Clean up resources
localVideoTrack = nil
localAudioTrack = nil
self.room = nil

if let error = error {
print("Disconnected, error: \(error.localizedDescription)")
}
}
}

Tencent RTC

Swift
Objective-C
func exitRoom() {
// Stop local preview and audio first
trtcCloud.stopLocalPreview()
trtcCloud.stopLocalAudio()

// Leave the room
trtcCloud.exitRoom()
}

extension TRTCManager: TRTCCloudDelegate {
func onExitRoom(_ reason: Int) {
// reason: 0 - called exitRoom(), 1 - kicked by server, 2 - room dismissed
switch reason {
case 0:
print("Exited room normally")
case 1:
print("Kicked by server")
case 2:
print("Room dismissed")
default:
break
}
}
}

class TRTCManager: NSObject {
deinit {
// Destroy instance after use
TRTCCloud.destroySharedInstance()
}
}
- (void)exitRoom {
// Stop local preview and audio first
[self.trtcCloud stopLocalPreview];
[self.trtcCloud stopLocalAudio];

// Leave the room
[self.trtcCloud exitRoom];
}

#pragma mark - TRTCCloudDelegate

- (void)onExitRoom:(NSInteger)reason {
// reason: 0 - called exitRoom, 1 - kicked by server, 2 - room dismissed
switch (reason) {
case 0:
NSLog(@"Exited room normally");
break;
case 1:
NSLog(@"Kicked by server");
break;
case 2:
NSLog(@"Room dismissed");
break;
default:
break;
}
}

- (void)dealloc {
// Destroy instance after use
[TRTCCloud destroySharedInstance];
}

Advanced Features

Screen Sharing

Twilio Video

// Using ReplayKitlet
screenCapturer = ReplayKitVideoSource(isScreencast: true)
let screenTrack = LocalVideoTrack(source: screenCapturer)
// Start broadcast
RPScreenRecorder.shared().startCapture { sampleBuffer, bufferType, error in
// Handle sample buffer
}

Tencent RTC

Swift
Objective-C
// Configure screen sharing encoding parameters
let encParam = TRTCVideoEncParam()
encParam.videoResolution = ._1280_720 // Recommended resolution
encParam.videoFps = 10 // Recommended frame rate
encParam.videoBitrate = 1600 // Recommended bitrate (kbps)

// Start system-wide screen sharing (requires Broadcast Extension and App Group)
// streamType: .big (main stream) or .sub (auxiliary stream)
// encParam: video encoding parameters
// appGroup: App Group ID for communication between main app and extension
trtcCloud.startScreenCapture(byReplaykit: .sub,
encParam: encParam,
appGroup: "group.your.app.identifier")

// Stop screen sharing
trtcCloud.stopScreenCapture()
// Configure screen sharing encoding parameters
TRTCVideoEncParam *encParam = [[TRTCVideoEncParam alloc] init];
encParam.videoResolution = TRTCVideoResolution_1280_720;
encParam.videoFps = 10;
encParam.videoBitrate = 1600;

// Start system-wide screen sharing (requires Broadcast Extension and App Group)
- (void)startScreenCapture {
TRTCVideoEncParam *videoEncConfig = [[TRTCVideoEncParam alloc] init];
videoEncConfig.videoResolution = TRTCVideoResolution_1280_720;
videoEncConfig.videoFps = 10;
videoEncConfig.videoBitrate = 2000;
// Replace `APPGROUP` with your App Group Identifier
[[TRTCCloud sharedInstance] startScreenCaptureByReplaykit:videoEncConfig
appGroup:APPGROUP];
}

// Stop screen sharing
- (void)stopScreenCapture {
[[TRTCCloud sharedInstance] stopScreenCapture];
}

Audio/Video Encoding Configuration

Twilio Video

let connectOptions = ConnectOptions(token: token) { builder in
// Video codec preference
builder.preferredVideoCodecs = [Vp8Codec(), H264Codec()]
// Encoding parameters
builder.encodingParameters = EncodingParameters(
audioBitrate: 64,
videoBitrate: 1500
)
}

Tencent RTC

Swift
Objective-C
// Video encoding parameters
let videoEncParam = TRTCVideoEncParam()
videoEncParam.videoResolution = ._960_540 // Resolution
videoEncParam.videoFps = 15 // Frame rate
videoEncParam.videoBitrate = 1200 // Video bitrate (kbps)
videoEncParam.resMode = .portrait // Orientation mode
trtcCloud.setVideoEncoderParam(videoEncParam)

// Audio quality configuration (used in startLocalAudio)
// .speech - speech mode
// .default - default mode
// .music - music mode
trtcCloud.startLocalAudio(.music)
// Video encoding parameters
TRTCVideoEncParam *videoEncParam = [[TRTCVideoEncParam alloc] init];
videoEncParam.videoResolution = TRTCVideoResolution_960_540;
videoEncParam.videoFps = 15;
videoEncParam.videoBitrate = 1200;
videoEncParam.resMode = TRTCVideoResolutionModePortrait;
[self.trtcCloud setVideoEncoderParam:videoEncParam];

// Audio quality configuration (used in startLocalAudio)
[self.trtcCloud startLocalAudio:TRTCAudioQualityMusic];

Device Management

Twilio Video

// Switch camera
if let camera = camera {
let newDevice = CameraSource.captureDevice(position: .back)
camera.selectCaptureDevice(newDevice!) { _, _, error in
// Handle result
}
}

// Mute
localAudioTrack?.isEnabled = false

// Switch to speaker (using AVAudioSession)
do {
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
} catch { }

Tencent RTC

Swift
Objective-C
// Get device manager
let deviceManager = trtcCloud.getDeviceManager()

// Switch front/rear camera
deviceManager.switchCamera(true) // true: front, false: rear

// Check if current camera is front
let isFront = deviceManager.isFrontCamera()

// Set camera zoom ratio (1.0 - 5.0)
deviceManager.setCameraZoomRatio(2.0)

// Set camera focus position
deviceManager.setCameraFocusPosition(CGPoint(x: 100, y: 100))

// Flash control
deviceManager.enableCameraTorch(true)

// Set auto focus
deviceManager.enableCameraAutoFocus(true)

// Mute
trtcCloud.muteLocalAudio(true)

// Switch audio route
trtcCloud.setAudioRoute(.speakerphone) // Speaker
trtcCloud.setAudioRoute(.earpiece) // Earpiece
// Get device manager
TXDeviceManager *deviceManager = [self.trtcCloud getDeviceManager];

// Switch front/rear camera
[deviceManager switchCamera:YES]; // YES: front, NO: rear

// Check if current camera is front
BOOL isFront = [deviceManager isFrontCamera];

// Set camera zoom ratio (1.0 - 5.0)
[deviceManager setCameraZoomRatio:2.0];

// Set camera focus position
[deviceManager setCameraFocusPosition:CGPointMake(100, 100)];

// Flash control
[deviceManager enableCameraTorch:YES];

// Set auto focus
[deviceManager enableCameraAutoFocus:YES];

// Mute
[self.trtcCloud muteLocalAudio:YES];

// Switch audio route
[self.trtcCloud setAudioRoute:TRTCAudioModeSpeakerphone];
[self.trtcCloud setAudioRoute:TRTCAudioModeEarpiece];

Network Quality Monitoring

Twilio Video

extension TwilioVideoManager: RoomDelegate {
// Network quality change callback
func networkQualityLevelDidChange(participant: Participant,
networkQualityLevel: NetworkQualityLevel) {
// NetworkQualityLevel: .zero (unknown) ... .five (excellent)
print("Participant \(participant.identity) network quality: \(networkQualityLevel.rawValue)")
}
}

// Configure network quality monitoring
let connectOptions = ConnectOptions(token: token) { builder in
builder.networkQualityEnabled = true
builder.networkQualityConfiguration = NetworkQualityConfiguration(
localVerbosity: .minimal,
remoteVerbosity: .minimal
)
}

Tencent RTC

Swift
Objective-C
extension TRTCManager: TRTCCloudDelegate {
// Network quality callback (triggered every 2 seconds)
func onNetworkQuality(_ localQuality: TRTCQualityInfo,
remoteQuality: [TRTCQualityInfo]) {
// quality: 0=unknown, 1=excellent, 2=good, 3=average, 4=poor, 5=very poor, 6=unusable
print("Local network quality: \(localQuality.quality.rawValue)")
}

// Statistics callback
func onStatistics(_ statistics: TRTCStatistics) {
print("RTT: \(statistics.rtt)ms")
}
}
// Listen to `onNetworkQuality` callback to monitor current network status
- (void)onNetworkQuality:(TRTCQualityInfo *)localQuality remoteQuality:(NSArray<TRTCQualityInfo *> *)remoteQuality {
switch(localQuality.quality) {
case TRTCQuality_Unknown:
NSLog(@"SDK has not yet detected the current network quality.");
break;
case TRTCQuality_Excellent:
NSLog(@"The network is excellent.");
break;
case TRTCQuality_Good:
NSLog(@"The network is good.");
break;
case TRTCQuality_Poor:
NSLog(@"Network quality barely meets requirements.");
break;
case TRTCQuality_Bad:
NSLog(@"Network is poor; expect significant lag and delays.");
break;
case TRTCQuality_VeryBad:
NSLog(@"Network is very poor; communication quality can't be guaranteed.");
break;
case TRTCQuality_Down:
NSLog(@"Network does not meet minimum requirements.");
break;
default:
break;
}
for (TRTCQualityInfo *info in remoteQuality) {
NSLog(@"remote user: %@, quality = %@", info.userId, @(info.quality));
}
}

Custom Video Capture

Twilio Video

class CustomVideoSource: NSObject, VideoSource {
weak var sink: VideoSink?

func sendFrame(_ pixelBuffer: CVPixelBuffer, timestamp: CMTime) {
let frame = VideoFrame(timestamp: timestamp,
buffer: pixelBuffer.videoFrameBuffer())
sink?.onVideoFrame(frame)
}
}

let customSource = CustomVideoSource()
let videoTrack = LocalVideoTrack(source: customSource, enabled: true, name: "custom")

Tencent RTC

Swift
Objective-C
// Enable custom video capture
trtcCloud.enableCustomVideoCapture(.big, enable: true)

// Send custom video frame (CVPixelBuffer)
func sendCustomVideoFrame(_ pixelBuffer: CVPixelBuffer) {
let videoFrame = TRTCVideoFrame()
videoFrame.pixelFormat = ._NV12
videoFrame.bufferType = .pixelBuffer
videoFrame.pixelBuffer = pixelBuffer

trtcCloud.sendCustomVideoData(.big, frame: videoFrame)
}

// Send custom video frame (texture)
func sendCustomVideoTexture(_ textureId: GLuint, width: Int, height: Int) {
let videoFrame = TRTCVideoFrame()
videoFrame.pixelFormat = ._Texture_2D
videoFrame.bufferType = .texture
videoFrame.textureId = textureId
videoFrame.width = UInt32(width)
videoFrame.height = UInt32(height)

trtcCloud.sendCustomVideoData(.big, frame: videoFrame)
}

// Stop custom capture
trtcCloud.enableCustomVideoCapture(.big, enable: false)
// Enable custom video capture
[self.trtcCloud enableCustomVideoCapture:TRTCVideoStreamTypeBig enable:YES];

// Send custom video frame
- (void)sendCustomVideoFrame:(CVPixelBufferRef)pixelBuffer timestamp:(uint64_t)timestamp {
TRTCVideoFrame *videoFrame = [[TRTCVideoFrame alloc] init];
videoFrame.pixelFormat = TRTCVideoPixelFormat_NV12;
videoFrame.bufferType = TRTCVideoBufferType_PixelBuffer;
videoFrame.pixelBuffer = pixelBuffer;
videoFrame.timestamp = timestamp;
[self.trtcCloud sendCustomVideoData:TRTCVideoStreamTypeBig frame:videoFrame];
}

// Stop custom capture
[self.trtcCloud enableCustomVideoCapture:TRTCVideoStreamTypeBig enable:NO];

Data Channel / Custom Messages

Twilio Video

let localDataTrack = LocalDataTrack(options: dataTrackOptions)
localDataTrack?.send("Hello, World!")

extension ViewController: RemoteDataTrackDelegate {
func remoteDataTrackDidReceiveString(remoteDataTrack: RemoteDataTrack,
message: String) {
print("Received message: \(message)")
}
}

Tencent RTC

Swift
Objective-C
// Send custom message (reliable transmission, to all users in the room)
// cmdID: custom message ID (1-10)
// data: message content, max 1KB
// reliable: true for reliable transmission, false otherwise
// ordered: true for ordered transmission, false otherwise
trtcCloud.sendCustomCmdMsg(1,
data: "Hello, World!".data(using: .utf8)!,
reliable: true,
ordered: true)

// Send SEI message (embedded in video frame, suitable for timestamp sync)
// repeatCount: number of times to send, -1 means continuous
trtcCloud.sendSEIMsg("Timestamp: 12345".data(using: .utf8)!,
repeatCount: 1)

// Receive custom message
extension TRTCManager: TRTCCloudDelegate {
func onRecvCustomCmdMsgUserId(_ userId: String,
cmdID: Int,
seq: UInt32,
message: Data) {
let text = String(data: message, encoding: .utf8) ?? ""
print("Received message from \(userId) [cmdID=\(cmdID)]: \(text)")
}

// Message loss callback
func onMissCustomCmdMsgUserId(_ userId: String,
cmdID: Int,
errCode: Int,
missed: Int) {
print("Lost \(missed) messages from \(userId)")
}

// Receive SEI message
func onRecvSEIMsg(_ userId: String, message: Data) {
let text = String(data: message, encoding: .utf8) ?? ""
print("Received SEI message: \(text)")
}
}
- (void)sendHello {
// Custom message command. Define rules as needed; here, 0x1 sends a text broadcast
NSInteger cmdID = 0x1;
NSData *data = [@"Hello" dataUsingEncoding:NSUTF8StringEncoding];
[trtcCloud sendCustomCmdMsg:cmdID data:data reliable:YES ordered:YES];
}

// Send SEI message (embedded in video frame, suitable for timestamp sync)
// repeatCount: number of times to send, -1 means continuous
[self.trtcCloud sendSEIMsg:[@"Timestamp: 12345" dataUsingEncoding:NSUTF8StringEncoding]
repeatCount:1];

#pragma mark - TRTCCloudDelegate

// Receive custom message
- (void)onRecvCustomCmdMsgUserId:(NSString *)userId
cmdID:(NSInteger)cmdID
seq:(UInt32)seq
message:(NSData *)message {
NSString *text = [[NSString alloc] initWithData:message encoding:NSUTF8StringEncoding];
NSLog(@"Received message from %@ [cmdID=%ld]: %@", userId, (long)cmdID, text);
}

// Message loss callback
- (void)onMissCustomCmdMsgUserId:(NSString *)userId
cmdID:(NSInteger)cmdID
errCode:(NSInteger)errCode
missed:(NSInteger)missed {
NSLog(@"Lost %ld messages from %@", (long)missed, userId);
}

// Receive SEI message
- (void)onRecvSEIMsg:(NSString *)userId message:(NSData *)message {
NSString *text = [[NSString alloc] initWithData:message encoding:NSUTF8StringEncoding];
NSLog(@"Received SEI message: %@", text);
}

FAQs

Q1: What is the difference between Twilio Video's Access Token and TRTC's UserSig?
Both are time-sensitive credentials used for client authentication, but their generation methods differ:
Twilio Access Token: Generated using Account SID, API Key SID, and API Key Secret on the server side with Twilio SDK helper libraries.
TRTC UserSig: Generated with SDKAppID and SDKSecretKey on the server side using HMAC SHA256.

Q2: How does Twilio's Room Name (string) map to TRTC's Room ID?
TRTC supports two types of room identifiers:
Numeric Room ID (roomId): Integer between 1 and 4294967294 (recommended).
String Room ID (strRoomId): Up to 64 bytes, supports letters, numbers, and select special characters.
If your Twilio project uses string room names, map them directly with strRoomId.
Note:
You cannot mix roomId and strRoomId in the same TRTC application; they are not interoperable.

Q3: Why doesn’t TRTC require manual subscription for remote audio?
In Twilio Video, remote audio must be handled via the RemoteParticipant.Listener.onAudioTrackSubscribed callback. In TRTC, remote audio plays automatically after a user enters the room, with no extra action required. If you want to control audio playback for a specific remote user, use muteRemoteAudio(userId, true/false).

Q4: How do Twilio's P2P Room and Group Room map to TRTC's scenarios?
Twilio Room Type
TRTC Application Scene
Applicable Scenario
Peer-to-Peer Room
TRTCAppSceneVideoCall
1v1 Video Call
Peer-to-Peer Room (Audio Only)
TRTCAppSceneAudioCall
1v1 Audio Call
Group Room
TRTCAppSceneLIVE
Interactive Live Streaming, Multi-party Conference
Group Room (Audio Only)
TRTCAppSceneVoiceChatRoom
Voice Chat Room

Q5: How does TRTC handle reconnection?
TRTC SDK features built-in automatic reconnection. When the network connection is lost, the SDK automatically attempts to reconnect. You can monitor reconnection status with these callbacks:
onConnectionLost(): Connection to server lost
onTryToReconnect(): Attempting to reconnect
onConnectionRecovery(): Connection restored
These correspond to Twilio’s onReconnecting and onReconnected callbacks.
For a complete list of functions and descriptions, see the API Reference. If you encounter issues during integration or use, refer to Other Issues.