Skip to main content
Red5WebRTCKit is the native iOS SDK for publishing and subscribing to live streams over WebRTC. It handles ICE negotiation, codec selection, camera and microphone capture, and license validation so you can focus on building your app. The SDK works with both Red5 Cloud (Stream Manager) deployments and standalone Red5 Pro servers, and is compatible with SwiftUI and UIKit.

Requirements

  • iOS 13.0 or later
  • Xcode 14.0 or later
  • Swift 5.5 or later
  • A valid Red5 Pro SDK license key

Installation

Add the SDK to your Xcode project using Swift Package Manager. Package URL: https://github.com/red5pro/red5pro-ios-sdk Or declare it in your Package.swift:
dependencies: [
    .package(url: "https://github.com/red5pro/red5pro-ios-sdk", from: "latest")
]

Permissions

Add the following keys to your Info.plist before publishing. Camera permission is not required for audio-only sessions.
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to stream video</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access to stream audio</string>

License key setup

Pass your license key to the builder with .setLicenseKey(). The SDK validates the key asynchronously when the client is built, and fires onLicenseValidated on your delegate before any streaming can begin.
let client = Red5WebrtcClientBuilder()
    .setLicenseKey("XXXX-XXXX-XXXX-XXXX")
    // ... other configuration
    .build()
Your license key is available on the Dev Resources page in the Red5 Cloud dashboard.

Minimal publish

Publishing requires three steps after the license validates: start a camera preview, then call publish().
1

Build the client

Configure the client with your server details and media settings. Use setStreamManagerHost() for Red5 Cloud or setServerIp() for a standalone server.
import WebRTC
import Red5WebRTCKit

var client: Red5WebrtcClient?
let renderer = RTCMTLVideoView()

client = Red5WebrtcClientBuilder()
    .setStreamManagerHost("userid-xxx.cloud.red5.net") // Red5 Cloud
    // .setServerIp("192.168.1.100")                  // Standalone
    .setPort(443)
    .setAppName("live")
    .setStreamName("myStream")
    .setLicenseKey("XXXX-XXXX-XXXX-XXXX")
    .setVideoEnabled(true)
    .setAudioEnabled(true)
    .setEventListener(self)
    .build()

client?.setVideoRenderer(renderer)
2

Wait for license validation

The SDK fires onLicenseValidated before any other callback. Start the camera preview only after validation succeeds.
extension YourClass: Red5ProWebrtcEventDelegate {
    func onLicenseValidated(validated: Bool, message: String) {
        if validated {
            client?.startPreview()
        } else {
            print("License invalid: \(message)")
        }
    }
}
3

Publish when preview is ready

Enable your publish button in onPreviewStarted, then call publish() when the user taps it.
func onPreviewStarted() {
    // Unlock your UI
    isReady = true
}

// Called from a button tap:
client?.publish()
4

Stop the session

client?.stopPublish()
client?.stopPreview()
Publish lifecycle:
Red5WebrtcClientBuilder.build()

onLicenseValidated(validated: true)

client.startPreview()

onPreviewStarted()          ← enable Publish button here

client.publish()

onPublishStarted()          ← stream is live

Minimal subscribe

Subscribing does not require a preview step. Build the client, attach a renderer for the incoming video, and call subscribe().
client = Red5WebrtcClientBuilder()
    .setStreamManagerHost("userid-xxx.cloud.red5.net")
    .setPort(443)
    .setAppName("live")
    .setStreamName("myStream")
    .setLicenseKey("XXXX-XXXX-XXXX-XXXX")
    .setEventListener(self)
    .build()

client?.setVideoRenderer(renderer)
client?.subscribe()
Show the video renderer once the stream arrives:
func onSubscribeStarted() {
    hasVideo = true  // show RTCMTLVideoView in your UI
}

Audio-only streaming

Set .setVideoEnabled(false) to publish or subscribe without video. No camera permission is required, and no RTCMTLVideoView renderer is needed.
client = Red5WebrtcClientBuilder()
    .setServerIp(Config.serverIP)
    .setPort(Config.port)
    .setAppName(Config.appName)
    .setStreamName(Config.streamName)
    .setLicenseKey(Config.licenseKey)
    .setVideoEnabled(false)  // disable video track
    .setAudioEnabled(true)
    .setEventListener(self)
    .build()

// No setVideoRenderer() call needed
For audio-only publishing, call publish() directly from onLicenseValidated — no preview step is needed:
func onLicenseValidated(validated: Bool, message: String) {
    if validated {
        client?.publish()  // no startPreview() needed
    }
}

Custom video settings

Configure resolution, frame rate, and bitrate on the builder before calling .build(). These settings cannot be changed after the client is created.
client = Red5WebrtcClientBuilder()
    // ... connection config ...
    .setVideoWidth(1280)    // pixels
    .setVideoHeight(720)    // pixels
    .setVideoFps(30)        // frames per second
    .setVideoBitrate(1500)  // kilobits per second
    .build()
Recommended presets:
QualityWidthHeightFPSBitrate
360p64036030400 kbps
480p85448030750 kbps
720p1280720301500 kbps
720p 60fps1280720602500 kbps
1080p19201080303000 kbps
Bitrate is a target, not a guarantee. WebRTC’s congestion control may lower it dynamically if network conditions degrade. To change settings after a session starts, stop and release the client, then rebuild with new parameters.

Camera controls

Call these methods on the client instance any time after startPreview() completes. Switch between front and back camera:
client?.switchCamera()
Mute and unmute video:
client?.setVideoEnabled(false) // viewer sees a black/frozen frame
client?.setVideoEnabled(true)  // live camera resumes
Mute and unmute audio:
client?.setAudioEnabled(false) // viewer hears silence
client?.setAudioEnabled(true)  // microphone resumes
SwiftUI pattern:
@State private var videoMuted = false
@State private var audioMuted = false

Button("Mute Video") {
    videoMuted.toggle()
    client?.setVideoEnabled(!videoMuted)
}

Button("Flip Camera") {
    client?.switchCamera()
}

Event reference

Implement Red5ProWebrtcEventDelegate in your class to receive SDK lifecycle events. All methods have default no-op implementations, so you only need to override the callbacks you care about.
CallbackDescription
onPublishStarted()Publish session started successfully
onPublishStopped()Publish session ended
onPublishFailed(error: String)Publish session failed
CallbackDescription
onSubscribeStarted()Subscribe session started successfully
onSubscribeStopped()Subscribe session ended
onSubscribeFailed(error: String)Subscribe session failed
CallbackDescription
onPreviewStarted()Local camera preview is running
onPreviewStopped()Local camera preview stopped
onLicenseValidated(validated: Bool, message: String)License check completed — always fires first
onIceConnectionStateChanged(state: IceConnectionState)ICE connection state changed
onConnectionStateChanged(state: PeerConnectionState)Peer connection state changed
onError(error: String)An unrecoverable error occurred
CallbackDescription
onChatConnected()Connected to the PubNub chat service
onChatDisconnected()Disconnected from the PubNub chat service
onChatMessageReceived(channel: String, message: Any)Message received on the subscribed channel
onChatSendSuccess(channel: String, timetoken: NSNumber)Message sent successfully
onChatSendError(channel: String, errorMessage: String)Message failed to send

Configuration reference

Key Red5WebrtcClientBuilder methods:
MethodDefaultDescription
setStreamManagerHost(_ host: String)Stream Manager host for Red5 Cloud
setServerIp(_ ip: String)Standalone server IP address
setPort(_ port: Int)443Server port
setAppName(_ name: String)"live"Application scope name
setStreamName(_ name: String)Stream name
setLicenseKey(_ key: String)Red5 Pro license key
setVideoEnabled(_ enabled: Bool)trueEnable or disable video
setAudioEnabled(_ enabled: Bool)trueEnable or disable audio
setVideoWidth(_ width: Int)640Capture width in pixels
setVideoHeight(_ height: Int)480Capture height in pixels
setVideoFps(_ fps: Int)30Frame rate
setVideoBitrate(_ bitrate: Int)500Bitrate in kbps
setEventListener(_ delegate)SDK event delegate

Example apps

Each example is a self-contained Xcode project. Copy Config.swift and the example file into a fresh project, fill in your server details, and run.
  • 01-MinimalPublish — fewest lines needed to go live
  • 02-MinimalSubscribe — fewest lines needed to receive a stream
  • 03-AudioOnly — publish or subscribe with video disabled
  • 04-CustomVideoSettings — configure resolution, frame rate, and bitrate
  • 05-CameraControls — flip camera, mute/unmute video and audio while live
Browse all examples on GitHub