Rate this page:

iOS Player SDK Overview

We are no longer allowing new customers to onboard to Twilio Live. Effective November 30, 2023, Twilio Live will End of Life. We have created this Migration Guide to help you identify an alternative solution for your use case.

The Twilio Player iOS SDK lets you play a stream in your native iOS application.


  • Xcode 13.0+
  • Swift projects must use Swift 4.0 or higher
  • Support for iOS 11.0+

Try the live interactive apps

The quickest way to try out the Player SDK for iOS is to run one of our interactive apps:

Add the SDK

The Twilio Player iOS SDK dynamic framework can be installed using Swift Package Manager, CocoaPods, or manually, as you prefer.

Swift Package Manager

You can add Player SDK for iOS by adding the repository as a Swift Package.

As of the latest release of Xcode, there is a known issue with consuming binary frameworks distributed via Swift Package Manager. The current workaround to this issue is to add a Run Script Phase to the Build Phases of your Xcode project. This Run Script Phase should come after the Embed Frameworks build phase. This new Run Script Phase should contain the following code:

find "${CODESIGNING_FOLDER_PATH}" -name '*.framework' -print0 | while read -d $'\0' framework
    codesign --force --deep --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --preserve-metadata=identifier,entitlements --timestamp=none "${framework}"


source ''

platform :ios, '11.0'

target 'TARGET_NAME' do
    pod 'TwilioLivePlayer', '1.1.0'
    pod 'AmazonIVSPlayer', '1.8.0'

Then run pod install to install the dependencies to your project.


TwilioLivePlayer.xcframework is distributed as a dynamic iOS framework that you can drag and drop into your existing projects.

View all Player iOS Releases here or just download the latest Player dynamic framework here.

Once you've downloaded and unpacked the XCFramework, navigate to your Xcode project's General settings page. Drag and drop TwilioLivePlayer.xcframework onto the Frameworks, Libraries, and Embedded Content section. Ensure that "Copy items if needed" is checked and press Finish. Ensure that "Embed & Sign" is selected.

Similarly download and install Twilio Player SDK's dependency AmazonIVSPlayer.xcframework from here.

Carthage Integration

Carthage is not currently a supported distribution mechanism for Twilio Player. Carthage does not currently work with .xcframeworks as documented here. Once Carthage supports binary .xcframeworks, Carthage distribution will be re-added.

Background Modes

To allow playback to be persisted while an application is running in the background, you must select the Audio, AirPlay, and Picture in Picture background mode from the Capabilities project settings page.

Background modes

Xcode and iOS Version Support

SDK Version Minimum Xcode Requirement Minimum iOS Version Supported Architectures Supported Devices
1.x Xcode 13.0 iOS 11.0 arm64, x86_64 iPhone 5s and later, iPad (5th generation) and later, iPad Air and later, iPad mini 2 and later

Getting help

We love feedback and questions, especially those with helpful debugging information so we can diagnose and respond quickly. When submitting issues or support tickets, it would be great if you add the following:

  • Description - A description of the issue
  • Steps to reproduce - List the steps necessary to reproduce the issue
  • Code - Include any applicable code snippets that would assist in reproduction and troubleshooting
  • Expected Behavior - What you expect to happen
  • Actual Behavior - What actually happens
  • Reproduces How Often - What percentage of the time does it reproduce?
  • Logs - Any log output when the issue occurs. See below for enabling debug level logging.
  • Player iOS SDK - The version(s) of the Player iOS SDK where this issue is apparent
  • Xcode - The version(s) of Xcode where this issue is apparent
  • iOS Version - The version(s) of iOS where this issue is apparent
  • iOS Device - The iOS device(s) where this issue is apparent
  • Player SID - Player SIDs can be useful for tracing backend issues

After gathering the above information, you can get help in a few ways:

For issues related to the Twilio Player iOS SDK itself:

Enabling Debug Logging

To enable debug level logging, add the following code in your application:

player.logLevel = .debug


The following snippets provide demonstrations on how to use the Player iOS SDK in an app. Get up and running with our demo app. For more details about streaming content, visit the Twilio Live documentation.

Connecting a Player and Handling Events

You can connect to a stream with an Access Token using the Player.connect(accessToken:delegate:) API. The connect API returns a Player object in connecting state. You can receive the Player events by passing a PlayerDelegate to the connect API.

AVAudioSession Configuration

Before connecting to a stream, set the AVAudioSession.category to playback and activate the AVAudioSession.

do {
    try AVAudioSession.sharedInstance().setCategory(.playback)
    try AVAudioSession.sharedInstance().setActive(true)
} catch {
    print("!!️ Could not setup AVAudioSession: \(error)")

Connect to a stream

Once your app acquires a Twilio access token, you can connect to a stream.

let player = Player.connect(accessToken: "access token", delegate: self)

extension ViewController: PlayerDelegate {

    func playerDidChangePlayerState(player: Player, playerState state: Player.State) {
        XCTAssertEqual(player.state, state)
        switch state {
        case .connecting:
                 * The player is connecting to to Twilio Media Service.

        case .idle:
                 * The player has successfully authenticated and is loading the stream. This
                 * state is also reached as a result of calling player.pause().

        case .ready:
                 * The player is ready to playback the stream.

        case .buffering:
                 * The player is buffering content.

        case .playing:
                 * The player is now playing a stream. This state occurs as a result of calling

        case .ended:
                 * The stream has ended.


    func playerDidFailWithError(player: Player, error: Error) {
         * An error occurred connecting the player or loading a stream.

Managing Playback

The following snippets demonstrate how to manage playback in your app.

 * Once the Player reaches the `.ready` state after initially calling 
 * Player.connect(...), an application can invoke play(). The player will then transition to 
 * the `.playing` state once playback successfully begins.
 * play() can also be called during the `.idle` state only after transitioning as a result
 * of calling pause().

 * To pause playback, invoke pause(). The player will transition to `.idle`
 * until playback is resumed with a subsequent call to play().

 * Playback audio can be muted by updating the muted property.
player.muted = true

 * The playback volume can also be adjusted. Updating the muted property has no effect
 * on the volume property. Once a stream is un-muted, playback will ensue with the last set
 * player volume.
player.volume = 0.25

Using TimedMetadata

When a Media Extension inserts TimedMetadata into a stream, the player will emit the playerDidReceiveTimedMetadata callback if the player is in the .playing state. TimedMetadata will not be received if the player is paused and any data inserted while a player is paused will not be received once the player is resumed.

func playerDidReceiveTimedMetadata(player: Player, metadata: TimedMetadata) {
    print("Received time metadata = \(metadata)")

Playing a stream in background

When the SDK is playing a stream, the Player SDK will continue playing audio when the app backgrounded if the app's .plist file supports audio background mode.


If you are rendering a stream using PlayerView, to continue audio in when the app is backgrounded you should reset player.playerView when the app goes to background.

@objc private func applicationDidEnterBackground(notification: Notification) {
    player.playerView = nil

@objc private func applicationDidBecomeActive(notification: Notification) {
    player.playerView = playerView


The Telemetry API enables applications to subscribe to event and metric data collected by the Player SDK. Telemetry data emitted by the Player SDK can be used to track stream quality, triage issues, and better understand your application's Player SDK usage.

Typed Data Events

The Player SDK represents telemetry data as strongly typed classes. Reference the table below for a summary of the currently reported events.

Telemetry Data Reporting Details
TelemetryDataConnectionConnecting Reported when Player.connect(...) is called
TelemetryDataConnectionConnected Reported when the Player has a playback token
TelemetryDataConnectionNetworkUnavailable Reported when playerNetworkDidBecomeUnavailable is invoked
TelemetryDataConnectionDisconnected Reported when is Player.dealloc() is called
TelemetryDataConnectionError Reported when playerDidFailWithError is invoked in the .connecting state
TelemetryDataPlaybackPlayed Reported when is called
TelemetryDataPlaybackPaused Reported when player.pause() is called
TelemetryDataPlaybackVolumeSet Reported when player.volume is set
TelemetryDataPlaybackMuted Reported when player.muted is set to true
TelemetryDataPlaybackUnmuted Reported when player.muted is set to false
TelemetryDataPlaybackError Reported when playerDidFailWithError is invoked in the following states: .idle, .ready, .buffering, .playing
TelemetryDataPlaybackRebuffering Reported when playerWillRebuffer is invoked
TelemetryDataPlaybackQualitySummary Reported every three seconds while the player is .buffering or .playing state
TelemetryDataPlaybackQualitySet Reported when player.quality is set
TelemetryDataPlaybackQualityChanged Reported when playerdidChangeQuality is invoked
TelemetryDataPlaybackQualityVideoSizeChanged Reported when playerVideoSizeChanged is invoked
TelemetryDataPlaybackQualityHighLatencyReductionApplied Reported when the SDK applies the low latency reduction strategy.
TelemetryDataPlaybackQualityHighLatencyReductionReverted Reported when the SDK reverts the low latency reduction strategy.
TelemetryDataPlaybackStateChanged ``
TelemetryDataTimedMetadataReceived Reported when playerDidReceiveTimedMetadata is invoked

The following snippets demonstrate a few examples of how to use the Telemetry API.

Telemetry Logger

The following snippet demonstrates the simplest Telemetry example: Logging all Telemetry events emitted by the Player SDK

let log: OSLog = OSLog.init(subsystem: "com.example.logger", category: "CodeSnippet")

// Subscribe the logger to events

extension Subscriber: TelemetrySubscriber {
    func didReceiveTelemetryData(_ data: TelemetryData) {
        os_log("TELEMETRY : %@", log: log,  type:.default, "\(data)")

// .. When your app no longer wants telemetry data, unsubscribe

Track High Latency

The following snippet demonstrates an example of checking experience quality by tracking any instances of high latency.

Player.telemetry.subscribe(subscriber, predicate: { data in
    if let summary = data as? TelemetryDataPlaybackQualitySummary {
        return summary.playerLiveLatency.value > 3_000_000
    return false;

extension Subscriber: TelemetrySubscriber {
    func didReceiveTelemetryData(_ data: TelemetryData) {

Track Connection Errors

The following snippet demonstrates an example of using TelemetryPredicate's to filter on specific Telemetry events.

Player.telemetry.subscribe(subscriber, predicate: { data in
    return data is TelemetryDataConnectionError 

extension Subscriber: TelemetrySubscriber {
    func didReceiveTelemetryData(_ data: TelemetryData) {

Threading Contract

The Player iOS SDK does not provide thread safety. Developers should use a Player instance from the main thread. All callbacks will be emitted on the main thread.

Rate this page:

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd by visiting Twilio's Stack Overflow Collective or browsing the Twilio tag on Stack Overflow.

Loading Code Sample...

        Thank you for your feedback!

        Please select the reason(s) for your feedback. The additional information you provide helps us improve our documentation:

        Sending your feedback...
        🎉 Thank you for your feedback!
        Something went wrong. Please try again.

        Thanks for your feedback!