iOSプレーヤーSDK

クイックスタート - iOSプレーヤーSDK

This guide will walk you through the steps to start a BlendVision One streaming playback using the iOS player SDK.

Before We Start

Before proceeding, ensure that you have prepared your BlendVision One streaming content. You can prepare your content in two ways:

Step 1: Obtain a Playback Token

  • Obtain a valid API token by following the authentication steps
  • Retrieve the resource_id and  resource_type of the streaming content you would like to playback. There are two ways to obtain this information:
    • Retrieve using the API
    • Copy from your BlendVision One console
      • VOD > Publishing Tools > Player SDK > VOD ID
      • Live > Publishing Tools > Player SDK > Event ID

  • Obtain the resource token using the API: /bv/cms/v1/resources/tokens, with the resource_id and  resource_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
  • Obtain the playback token using the API: /bv/playback/v1/tokens, with the resource token as a body parameter.

 

let API_DOMAIN = "https://api.one.blendvision.com"




struct ResourceTokenRequest: Codable {

    let resourceId: String

    let resourceType: String

}




struct ResourceTokenResponse: Codable {

    let resourceToken: String

}




struct PlaybackTokenResponse: Codable {

    let playbackToken: String

}




protocol ApiService {

    func createResourceToken(cmsToken: String, req: ResourceTokenRequest, completion: @escaping (Result<ResourceTokenResponse, Error>) -> Void)

    func getPlaybackToken(resourceToken: String, completion: @escaping (Result<PlaybackTokenResponse, Error>) -> Void)

}




extension ApiService {

    func createResourceToken(cmsToken: String, req: ResourceTokenRequest, completion: @escaping (Result<ResourceTokenResponse, Error>) -> Void) {

        guard let url = URL(string: API_DOMAIN + "/bv/cms/v1/resources/tokens") else {

            // Handle invalid URL error

            return

        }

        

        var request = URLRequest(url: url)

        request.httpMethod = "POST"

        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        request.addValue(cmsToken, forHTTPHeaderField: "Authorization")

        

        do {

            let jsonData = try JSONEncoder().encode(req)

            request.httpBody = jsonData

        } catch {

            // Handle encoding error

            completion(.failure(error))

            return

        }

        

        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(ResourceTokenResponse.self, from: data)

                completion(.success(response))

            } catch {

                // Handle decoding error

                completion(.failure(error))

            }

        }.resume()

    }

    

    func getPlaybackToken(resourceToken: String, completion: @escaping (Result<PlaybackTokenResponse, Error>) -> Void) {

        guard let url = URL(string: API_DOMAIN + "/bv/playback/v1/tokens") else {

            // Handle invalid URL error

            return

        }

        

        var request = URLRequest(url: url)

        request.httpMethod = "POST"

        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        request.addValue(resourceToken, 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(PlaybackTokenResponse.self, from: data)

                completion(.success(response))

            } catch {

                // Handle decoding error

                completion(.failure(error))

            }

        }.resume()

    }

}

Step 2: Start a Playback Session

 

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

  • 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
  • When the user leaves the player, release the session using the end playback session API

 

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

更新