iOS SDK (Swift)
TgoRTC iOS (Swift) SDK for real-time audio/video communication based on LiveKit.
Installation
Swift Package Manager
- In Xcode, select File → Add Packages...
- Enter the repository URL:
https://github.com/TgoRTC/TgoRTCiOS
- Select Branch: main or a specific version
- Add the TgoRTCSDK product
Dependencies
The SDK automatically includes the LiveKit dependency.
Quick Start
1. Initialize SDK
import TgoRTCSDK
let options = Options()
options.isDebug = true
options.mirror = false
TgoRTC.shared.configure(options: options)
2. Create Room Info and Join
import TgoRTCSDK
let roomInfo = RoomInfo(
roomName: "room-name",
token: "your-token",
url: "wss://your-server",
maxParticipants: 4,
rtcType: .video,
isP2P: true,
uidList: ["local-user-id", "remote-user-id"],
timeout: 30,
creatorUid: "creator-user-id",
loginUID: "local-user-id"
)
TgoRTC.shared.roomManager.join(
roomInfo: roomInfo,
micEnabled: true,
cameraEnabled: true,
screenShareEnabled: false
)
Note:
The current Swift SDK join(...) method is non-blocking.
It returns immediately and connection changes should be observed through addConnectionStatusListener(...).
3. Listen to Connection Status
let connectionToken = TgoRTC.shared.roomManager.addConnectionStatusListener { roomName, status in
print("Room \(roomName) status changed: \(status)")
switch status {
case .connecting:
print("Connecting...")
case .connected:
print("Connected to room")
case .disconnected:
print("Disconnected from room")
}
}
connectionToken.cancel()
Note:
The current iOS SDK only exposes connecting / connected / disconnected.
4. Get Participants
let local = TgoRTC.shared.participantManager.getLocalParticipant()
let remotes = TgoRTC.shared.participantManager.getRemoteParticipants()
let all = TgoRTC.shared.participantManager.getAllParticipants()
let newParticipantToken = TgoRTC.shared.participantManager.addNewParticipantListener { participant in
print("New participant joined: \(participant.uid)")
}
5. Media Control and Events
TgoParticipant uses Combine @Published state and PassthroughSubject event streams.
import Combine
import TgoRTCSDK
var cancellables = Set<AnyCancellable>()
let participant = TgoRTC.shared.participantManager.getLocalParticipant()
Task {
await participant?.setMicrophoneEnabled(true)
await participant?.setCameraEnabled(true)
await participant?.setScreenShareEnabled(true)
await participant?.setSpeakerphoneOn(true)
}
participant?.switchCamera()
participant?.$isMicrophoneOn
.sink { isOn in
print("Microphone: \(isOn)")
}
.store(in: &cancellables)
participant?.$isCameraOn
.sink { isOn in
print("Camera: \(isOn)")
}
.store(in: &cancellables)
participant?.$isSpeaking
.sink { speaking in
print("Speaking: \(speaking)")
}
.store(in: &cancellables)
participant?.$audioLevel
.sink { level in
print("Audio level: \(level)")
}
.store(in: &cancellables)
participant?.$connectionQuality
.sink { quality in
print("Connection quality: \(quality)")
}
.store(in: &cancellables)
participant?.$cameraPosition
.sink { position in
print("Camera position: \(position)")
}
.store(in: &cancellables)
participant?.$videoInfo
.sink { info in
print("Video info: \(info.resolutionString), \(info.bitrateString)")
}
.store(in: &cancellables)
participant?.onJoined
.sink {
print("Participant joined")
}
.store(in: &cancellables)
participant?.onLeave
.sink { reason in
print("Participant left, reason: \(reason)")
}
.store(in: &cancellables)
participant?.onTrackPublished
.sink {
print("Track published")
}
.store(in: &cancellables)
participant?.onTrackUnpublished
.sink {
print("Track unpublished")
}
.store(in: &cancellables)
6. Render Video Track
The SDK provides TgoTrackRenderer (a SwiftUI view) for displaying video.
import SwiftUI
import TgoRTCSDK
struct VideoView: View {
@ObservedObject var participant: TgoParticipant
var body: some View {
TgoTrackRenderer(
participant: participant,
source: .camera,
fit: .fill
)
.frame(width: 200, height: 300)
}
}
7. Audio Management
Task {
await TgoRTC.shared.audioManager.toggleSpeakerphone()
await TgoRTC.shared.audioManager.setSpeakerphoneOn(true)
}
Task {
let devices = await TgoRTC.shared.audioManager.getAudioOutputDevices()
print(devices.map { "\($0.name)-\($0.type.rawValue)" })
if let speaker = devices.first(where: { $0.type == .speaker }) {
let success = await TgoRTC.shared.audioManager.selectAudioOutputDevice(speaker)
print("Switch result: \(success)")
}
}
let deviceToken = TgoRTC.shared.audioManager.addDeviceChangeListener { devices in
print("Audio devices changed: \(devices)")
}
8. Leave Room
Task {
await TgoRTC.shared.roomManager.leaveRoom()
}
API Reference
TgoRTC
| Property | Type | Description |
|---|---|---|
shared | TgoRTC | Singleton instance |
options | Options? | SDK configuration |
roomManager | RoomManager | Room management |
participantManager | ParticipantManager | Participant management |
audioManager | AudioManager | Audio management |
RoomManager
| Method | Description |
|---|---|
join(roomInfo, micEnabled, cameraEnabled, screenShareEnabled) | Join a room |
leaveRoom() | Leave current room |
addConnectionStatusListener(listener) | Add connection status listener |
addVideoInfoListener(listener) | Add local video info listener |
restartTimeoutCheckerIfNeeded() | Restart the timeout checker if needed |
| Property | Type | Description |
|---|---|---|
currentRoomInfo | RoomInfo? | Current room info |
room | Room? | LiveKit room instance |
ParticipantManager
| Method | Description |
|---|---|
getLocalParticipant() | Get local participant |
getRemoteParticipants() | Get remote participants |
getAllParticipants() | Get all participants |
initializePendingParticipants() | Initialize pending participants |
syncExistingRemoteParticipants() | Sync existing remote participants |
inviteParticipant(roomName, uids) | Invite participants |
removePendingParticipants(roomName, uids) | Remove pending participants |
setParticipantJoin(participant) | Mark a participant as joined |
setParticipantLeave(participant) | Mark a participant as left |
addNewParticipantListener(listener) | Listen for new participants |
clear() | Clear participant state |
TgoParticipant
Properties
| Property | Type | Description |
|---|---|---|
uid | String | Participant ID |
createdAt | Date | Creation time |
isLocal | Bool | Whether this is the local participant |
isDisposed | Bool | Whether this participant wrapper is disposed |
@Published Properties
| Property | Type | Description |
|---|---|---|
isMicrophoneOn | Bool | Whether the microphone is on |
isCameraOn | Bool | Whether the camera is on |
isSpeaking | Bool | Whether the participant is speaking |
audioLevel | Float | Audio level |
connectionQuality | TgoConnectionQuality | Connection quality |
cameraPosition | TgoCameraPosition | Camera position |
isJoined | Bool | Whether the participant has joined |
videoInfo | VideoInfo | Current video info |
Events
| Property | Type | Description |
|---|---|---|
onJoined | PassthroughSubject<Void, Never> | Joined event |
onLeave | PassthroughSubject<TgoLeaveReason, Never> | Leave event |
onTrackPublished | PassthroughSubject<Void, Never> | Track published event |
onTrackUnpublished | PassthroughSubject<Void, Never> | Track unpublished event |
Methods
| Method | Description |
|---|---|
getVideoTrack(source) | Get video track for a specific source |
setLocalParticipant(participant) | Bind local participant |
setRemoteParticipant(participant) | Bind remote participant |
notifyLeave(reason) | Notify leave |
setSpeakerphoneOn(enabled) | Set speakerphone |
setMicrophoneEnabled(enabled) | Enable/disable microphone |
setCameraEnabled(enabled) | Enable/disable camera |
setScreenShareEnabled(enabled) | Enable/disable screen share |
switchCamera() | Switch front/back camera |
dispose() | Release resources |
AudioManager
| Method / Property | Description |
|---|---|
isSpeakerOn | Whether speakerphone is currently on |
currentOutputDevice | Currently selected output device |
addDeviceChangeListener(listener) | Listen for device changes |
setSpeakerphoneOn(on, forceSpeakerOutput) | Set speakerphone |
toggleSpeakerphone() | Toggle speakerphone |
getAudioInputDevices() | Get audio input devices |
getAudioOutputDevices() | Get audio output devices |
selectAudioOutputDevice(device) | Select an output device |
dispose() | Clean up resources |
TgoTrackRenderer
TgoTrackRenderer(
participant: participant,
source: .camera,
fit: .fill
)
Enums
ConnectStatus
public enum ConnectStatus {
case connecting
case connected
case disconnected
}
RTCType
public enum RTCType {
case audio
case video
}
TgoCameraPosition
public enum TgoCameraPosition {
case front
case back
}
TgoConnectionQuality
public enum TgoConnectionQuality {
case unknown
case excellent
case good
case poor
case lost
}
TgoLeaveReason
public enum TgoLeaveReason {
case normal
case timeout
}
RoomInfo
public final class RoomInfo {
var roomName: String
var token: String
var url: String
var maxParticipants: Int
var rtcType: RTCType
var isP2P: Bool
var uidList: [String]
var timeout: Int
var creatorUid: String
var loginUID: String
func isCreator() -> Bool
func getP2PToUID() -> String
}
VideoInfo
public struct VideoInfo {
let width: Int
let height: Int
let bitrate: Int
let frameRate: Double
let layerId: String?
let qualityLimitationReason: String?
var isValid: Bool
var resolutionString: String
var bitrateString: String
}
Platform Configuration
Permissions
Add the following descriptions to your Info.plist:
<key>NSCameraUsageDescription</key>
<string>Need camera access for video calls</string>
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for audio calls</string>
To support background audio calls, enable Background Modes in Signing & Capabilities and check Audio, AirPlay, and Picture in Picture.