Twilio Player SDK for iOS
About
The Twilio Player iOS SDK lets you play a stream in your native iOS application.
We want your feedback! Email video-product@twilio.com with suggested improvements, feature requests and general feedback, or feel free to open a GitHub issue. If you need technical support, contact help@twilio.com.
Installation
The SDK can be integrated either manually, or via Swift Package Manager or CocoaPods. Please see more detailed installation instructions here.
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 Programmable Media 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 your application 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 help?
Email help@twilio.com, or open an issue in our GitHub Repository and we’ll give you a hand.