This guide will walk you through the steps to start a BlendVision One streaming playback using the iOS player SDK.
Additionally, you can also check out the sample project for an even smoother start:
https://github.com/BlendVision/iOS-Player-SDK/tree/main/Samples
Before We Start
Before proceeding, ensure that you have prepared your BlendVision One streaming content. You can prepare your content in two ways:
- Using BlendVision One Console
- Using BlendVision One API
Step 1: Obtain a Playback Token
- Obtain a valid API token by following the authentication steps
- Retrieve the
resource_id
andresource_type
of the streaming content you would like to playback. There are two ways to obtain this information:
- Retrieve using the API
- VOD: /bv/cms/v1/vods
- Livestream: /bv/cms/v1/lives
- Copy from your BlendVision One console
- Retrieve using the API
-
Obtain the
playback token
using the API: /bv/cms/v1/tokens, with theresource_id
andresource_type
as body parameters-
You can also include
customer_id
in the body parameters if you want to track user playback with your own defined user ID
-
let API_DOMAIN = "https://api.one.blendvision.com" struct PlaybackTokenResponse: Codable { let playbackToken: String } protocol ApiService { func getPlaybackToken(resourceId: String, resourceType: String, customerId: String?, completion: @escaping (Result<PlaybackTokenResponse, Error>) -> Void) } extension ApiService { func getPlaybackToken(resourceId: String, resourceType: String, customerId: String? = nil, completion: @escaping (Result<PlaybackTokenResponse, Error>) -> Void) { guard let url = URL(string: API_DOMAIN + "/bv/cms/v1/tokens") else { // Handle invalid URL error return } var parameters: [String: Any] if let customerId = customerId { parameters = [ "resource_id": resourceId, "resource_type": resourceType, "customer_id": customerId ] } else { parameters = [ "resource_id": resourceId, "resource_type": resourceType ] } var request = URLRequest(url: url) request.httpMethod = "POST" request.httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) request.addValue("application/json", forHTTPHeaderField: "Content-Type") URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { // Handle network error completion(.failure(error)) return } guard let data = data else { // Handle empty response data return } do { let response = try JSONDecoder().decode(PlaybackTokenResponse.self, from: data) completion(.success(response)) } catch { // Handle decoding error completion(.failure(error)) } }.resume() } }
Step 2: Start a Playback Session
- Start a playback session by making a POST request to bv/playback/v1/sessions/<device-id>:start
- Return: drm_server_endpoint
- Obtain stream data from bv/playback/v1/sessions/<device-id>
- Return: protocol, manifest url, resolutions, thumbnail_seeking_url
let API_DOMAIN = "https://api.one.blendvision.com" struct StartSessionResponse: Codable { let endPoint: String } struct GetStreamInfoResponse: Codable { let sources: [Source] } struct Source: Codable { let manifests: [Manifest] let thumbnailSeekingUrl: String } struct Manifest: Codable { let protocal: String let url: String let resolutions: [Resolution] } struct Resolution: Codable { let height: String let width: String } protocol ApiService { func startPlaybackSession(playbackToken: String, deviceId: String, completion: @escaping (Result<StartSessionResponse, Error>) -> Void) func getStreamInfo(playbackToken: String, deviceId: String, completion: @escaping (Result<GetStreamInfoResponse, Error>) -> Void) } extension ApiService { func startPlaybackSession(playbackToken: String, deviceId: String, completion: @escaping (Result<StartSessionResponse, Error>) -> Void) { guard let url = URL(string: "\(API_DOMAIN)/bv/playback/v1/sessions/\(deviceId):start") else { // Handle invalid URL error return } var request = URLRequest(url: url) request.httpMethod = "POST" request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.addValue(playbackToken, forHTTPHeaderField: "Authorization") URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { // Handle network error completion(.failure(error)) return } guard let data = data else { // Handle empty response data return } do { let response = try JSONDecoder().decode(StartSessionResponse.self, from: data) completion(.success(response)) } catch { // Handle decoding error completion(.failure(error)) } }.resume() } func getStreamInfo(playbackToken: String, deviceId: String, completion: @escaping (Result<GetStreamInfoResponse, Error>) -> Void) { guard let url = URL(string: "\(API_DOMAIN)/bv/playback/v1/sessions/\(deviceId)") else { // Handle invalid URL error return } var request = URLRequest(url: url) request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.addValue(playbackToken, forHTTPHeaderField: "Authorization") URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { // Handle network error completion(.failure(error)) return } guard let data = data else { // Handle empty response data return } do { let response = try JSONDecoder().decode(GetStreamInfoResponse.self, from: data) completion(.success(response)) } catch { // Handle decoding error completion(.failure(error)) } }.resume() } }
Step 3: Initialize the Player
Obtain Player License Key
Obtain a valid player license key from your BlendVision One console
Install Player SDK
-
Download and unzip the appropriate dynamic SDK for your project from https://github.com/BlendVision/iOS-Player-SDK/releases.
-
Drag the unzipped .framework or .xcframework into your main project in the Xcode project navigator. Check 'Copy all items if needed', and add to all targets.
-
In your Xcode target, under the General tab, select Embed and Sign for KKSPlayer.framework or KKSPlayer.xcframework and GPUImage_iOS.framework
Create a Player
To play the streaming content, create a player instance with the license key and stream information in the initialization configuration:
How to create your player view, please refer to the following url https://developer.apple.com/documentation/avfoundation/avplayerlayer // Create player configuration let playerConfig = UniPlayerConfig() playerConfig.key = "Your player license key" // Create player based on player config let player = UniPlayerFactory.create(player: playerConfig) // Create player view and pass the player instance to it playerView = UniPlayerView(player: player, frame: .zero) // Add player view into subview and layout your player view view.addSubview(playerView) view.bringSubviewToFront(playerView) // Handle HLS stream guard let hlsUrl = URL(string: "Your HLS URL string") else { debugPrint("The HLS URL not found") return } // Create source config let sourceConfig = UniSourceConfig(url: hlsUrl, type: .hls) sourceConfig.title = "your title" sourceConfig.description = "your description" // Load source config player.load(sourceConfig: sourceConfig)
Step 4: Manage the Lifecycle of a Playback Session
- To keep the playback session alive, periodically invoke the heartbeat API every 10 seconds
func startHeartbeatTimer(deviceId: String, headers: [String: String], player: UniPlayer) { let heartbeatTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { _ in guard let heartbeatURL = URL(string: "https://api.one.blendvision.com/bv/playback/v1/sessions/\(deviceId):heartbeat") else { // Handle invalid URL error return } var heartbeatRequest = URLRequest(url: heartbeatURL) heartbeatRequest.allHTTPHeaderFields = headers URLSession.shared.dataTask(with: heartbeatRequest) { data, response, error in if let error = error { // Handle network error return } guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { // Handle player release player.destroy() return } }.resume() } // Start the timer heartbeatTimer.fire() } func endPlayback(deviceId: String, headers: [String: String]) { guard let endPlaybackURL = URL(string: "https://api.one.blendvision.com/bv/playback/v1/sessions/\(deviceId):end") else { // Handle invalid URL error return } var endPlaybackRequest = URLRequest(url: endPlaybackURL) endPlaybackRequest.allHTTPHeaderFields = headers URLSession.shared.dataTask(with: endPlaybackRequest) { data, response, error in if let error = error { // Handle network error return } // Handle successful end of playback }.resume() }
What's More
- To control the playback, refer to the API Reference documentation.
- To track the playback, refer to the Playback Event documentation.
- To ensure a smooth playback experience, check the compatible operating systems.
- To enable advanced features, refer to the following guides: