iOS 播放器 SDK

快速入門: BlendVision One 串流播放

(以下內容均翻譯自英文版文件,最新資訊及內容敬請切換至英文語系參考原文)

 

本指南將指導您完成使用 iOS 播放器 SDK 啟動 BlendVision One 串流播放的步驟。

 

此外,您還可以查看範例專案,以便更順利地開始工作:
https://github.com/BlendVision/iOS-Player-SDK/tree/main/Samples

 

開始之前

在實施步驟之前,請確保您已準備好 BlendVision One 的串流內容。您可以通過兩種方式準備您的內容:

步驟 1:取得播放令牌

  • 按照 驗證步驟 取得有效的 API 令牌
  • 取得預期要播放的串流內容的 resource_id 和 resource_type 。
    有兩種方法可以取得此資訊:

    •  

 

  • 使用 API 取得 playback token  /bv/cms/v1/tokens ,並將 resource_id  resource_type 設為主體參數
    • 您也可以在主體參數中加入 customer_id  ,以使用自定義的使用者 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()
    }
}

 

步驟 2:開始播放工作階段

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()
    }
}

 

步驟 3:初始化播放器

  • 為了播放串流內容,請在初始化配置中使用許可證密鑰和串流資訊建立播放器實例:
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)

 

步驟 4:管理播放工作階段的生命週期

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()
}

 

了解更多

  •  

更新於