Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ios/THEOplayerRCTMainEventHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class THEOplayerRCTMainEventHandler {
// MARK: Members
private weak var player: THEOplayer?
private weak var presentationModeContext: THEOplayerRCTPresentationModeContext?
private var loadedMetadataAndChapterTracksInfo: [[String:Any]] = []
private(set) var loadedMetadataAndChapterTracksInfo: [[String:Any]] = []

// MARK: Events
var onNativePlay: RCTDirectEventBlock?
Expand Down
109 changes: 109 additions & 0 deletions ios/THEOplayerRCTPayloadBuilder.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import Foundation
import THEOplayerSDK

private let PROP_SOURCE = "source"
private let PROP_CURRENT_TIME = "currentTime"
private let PROP_CURRENT_PROGRAM_DATE_TIME = "currentProgramDateTime"
private let PROP_PAUSED = "paused"
private let PROP_PLAYBACK_RATE = "playbackRate"
private let PROP_VOLUME = "volume"
private let PROP_MUTED = "muted"
private let PROP_SEEKABLE = "seekable"
private let PROP_BUFFERED = "buffered"
private let PROP_START = "start"
private let PROP_END = "end"

/**
* This class is used to shape the `state` object for the event `onPlayerReady`
*/
class THEOplayerRCTPayloadBuilder {
private var payload: [String: Any] = [:]

func source(_ source: Any?) -> Self {
if source != nil {
let sourcePayload = NSMutableDictionary()
// Fill in with source fields?
payload[PROP_SOURCE] = sourcePayload
}
return self
}

func currentTime(_ timeInSec: Double) -> Self {
payload[PROP_CURRENT_TIME] = timeInSec * 1e3
return self
}

func currentProgramDateTime(_ date: Date?) -> Self {
if let date = date {
payload[PROP_CURRENT_PROGRAM_DATE_TIME] = date.timeIntervalSince1970 * 1e3
}
return self
}

func paused(_ value: Bool) -> Self {
payload[PROP_PAUSED] = value
return self
}

func playbackRate(_ rate: Double) -> Self {
payload[PROP_PLAYBACK_RATE] = rate
return self
}

func duration(_ durationInSec: Double?) -> Self {
if let durationInSec = durationInSec {
payload[PROP_DURATION] = (durationInSec * 1e3).coerceIfInfOrNan
}
return self
}

func volume(_ volume: Float, muted: Bool) -> Self {
payload[PROP_VOLUME] = Double(volume)
payload[PROP_MUTED] = muted
return self
}

func seekable(_ timeRanges: [THEOplayerSDK.TimeRange]?) -> Self {
payload[PROP_SEEKABLE] = fromTimeRanges(timeRanges)
return self
}

func buffered(_ timeRanges: [THEOplayerSDK.TimeRange]?) -> Self {
payload[PROP_BUFFERED] = fromTimeRanges(timeRanges)
return self
}

func metadataTracksInfo(_ metadataTracksInfo: [String: Any]) -> Self {
payload.merge(metadataTracksInfo) { (current, _) in current }
return self
}

func build() -> [String: Any] {
return payload
}

private func fromTimeRanges(_ ranges: [THEOplayerSDK.TimeRange]?) -> [[String: Double]] {
guard let ranges = ranges else { return [] }
return ranges.map {
[
PROP_START: $0.start * 1000,
PROP_END: $0.end * 1000
]
}
}
}

private extension Double {
// Make sure we do not send INF or NaN double values over the bridge. It might break debug sessions.
var coerceIfInfOrNan: Double {
// The following constants are taken from Android Theo SDK, see PayloadBuilder.kt.
// Looks like some internal convention
if self.isNaN {
return -1.0
}
if self.isInfinite {
return -2.0
}
return self
}
}
36 changes: 29 additions & 7 deletions ios/THEOplayerRCTView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,37 @@ public class THEOplayerRCTView: UIView {
}

private func notifyNativePlayerReady() {
var payload: [String: Any] = [:]

if let player = self.player {
// Get existing tracks info from the player
let metadataTracksInfo = mainEventHandler.loadedMetadataAndChapterTracksInfo
let metadata = THEOplayerRCTTrackMetadataAggregator.aggregateTrackMetadata(player: player, metadataTracksInfo: metadataTracksInfo)
// General player state + source payload
payload["state"] = THEOplayerRCTPayloadBuilder()
.source(player.source)
.currentTime(player.currentTime)
.currentProgramDateTime(player.currentProgramDateTime)
.paused(player.paused)
.playbackRate(player.playbackRate)
.duration(player.duration)
.volume(player.volume, muted: player.muted)
.seekable(player.seekable)
.buffered(player.buffered)
.metadataTracksInfo(metadata)
.build()
}

// Add version info
let versionString = THEOplayer.version
payload["version"] = [
"version": versionString,
"playerSuiteVersion": versionString
]

DispatchQueue.main.async {
let versionString = THEOplayer.version
if let forwardedNativeReady = self.onNativePlayerReady {
forwardedNativeReady([
"version": [
"version" : versionString,
"playerSuiteVersion": versionString
],
])
forwardedNativeReady(payload)
}
}
}
Expand Down
Loading