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.
Prerequisites
- 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 https://github.com/twilio/twilio-live-player-ios
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
do
codesign --force --deep --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --preserve-metadata=identifier,entitlements --timestamp=none "${framework}"
done
CocoaPods
source 'https://github.com/CocoaPods/Specs'
platform :ios, '11.0'
target 'TARGET_NAME' do
pod 'TwilioLivePlayer', '1.1.0'
pod 'AmazonIVSPlayer', '1.8.0'
end
Then run pod install
to install the dependencies to your project.
Manual
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.
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
Usage
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.
*/
break
case .idle:
/**
* The player has successfully authenticated and is loading the stream. This
* state is also reached as a result of calling player.pause().
*/
break
case .ready:
/**
* The player is ready to playback the stream.
*/
break
case .buffering:
/**
* The player is buffering content.
*/
break
case .playing:
/**
* The player is now playing a stream. This state occurs as a result of calling
* player.play().
*/
break
case .ended:
/**
* The stream has ended.
*/
break
default:
break
}
}
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().
*/
player.play()
/**
* To pause playback, invoke pause(). The player will transition to `.idle`
* until playback is resumed with a subsequent call to play().
*/
player.pause()
/**
* 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.
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
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
}
Telemetry
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 player.play() 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 |
Usage
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
Player.telemetry.subscribe(subscriber)
extension Subscriber: TelemetrySubscriber {
func didReceiveTelemetryData(_ data: TelemetryData) {
os_log("TELEMETRY : %@", log: log, type:.default, "\(data)")
}
}
// .. When your app no longer wants telemetry data, unsubscribe
Player.telemetry.unsubscribe(subscriber)
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) {
yourAppAnalytics.track("high-latency-detected")
}
}
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) {
yourAppAnalytics.track("connection-error-detected")
}
}
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.
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.