Skip to content
Merged
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
69 changes: 40 additions & 29 deletions ios/Video/NowPlayingInfoCenterManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class NowPlayingInfoCenterManager {
private var togglePlayPauseTarget: Any?

private let remoteCommandCenter = MPRemoteCommandCenter.shared()
private let metadataQueue = DispatchQueue(label: "com.reactnativevideo.nowplayinginfo")

private var receivingRemoveControlEvents = false {
didSet {
Expand Down Expand Up @@ -206,35 +207,45 @@ class NowPlayingInfoCenterManager {
return
}

// commonMetadata is metadata from asset, externalMetadata is custom metadata set by user
// externalMetadata should override commonMetadata to allow override metadata from source
let metadata = {
let common = Dictionary(uniqueKeysWithValues: currentItem.asset.commonMetadata.map { ($0.identifier, $0) })
let external = Dictionary(uniqueKeysWithValues: currentItem.externalMetadata.map { ($0.identifier, $0) })
return Array((common.merging(external) { _, new in new }).values)
}()

let titleItem = AVMetadataItem.metadataItems(from: metadata, filteredByIdentifier: .commonIdentifierTitle).first?.stringValue ?? ""

let artistItem = AVMetadataItem.metadataItems(from: metadata, filteredByIdentifier: .commonIdentifierArtist).first?.stringValue ?? ""

// I have some issue with this - setting artworkItem when it not set dont return nil but also is crashing application
// this is very hacky workaround for it
let imgData = AVMetadataItem.metadataItems(from: metadata, filteredByIdentifier: .commonIdentifierArtwork).first?.dataValue
let image = imgData.flatMap { UIImage(data: $0) } ?? UIImage()
let artworkItem = MPMediaItemArtwork(boundsSize: image.size) { _ in image }

let newNowPlayingInfo: [String: Any] = [
MPMediaItemPropertyTitle: titleItem,
MPMediaItemPropertyArtist: artistItem,
MPMediaItemPropertyArtwork: artworkItem,
MPMediaItemPropertyPlaybackDuration: currentItem.duration.seconds,
MPNowPlayingInfoPropertyElapsedPlaybackTime: currentItem.currentTime().seconds.rounded(),
MPNowPlayingInfoPropertyPlaybackRate: player.rate,
]
let currentNowPlayingInfo = MPNowPlayingInfoCenter.default().nowPlayingInfo ?? [:]

MPNowPlayingInfoCenter.default().nowPlayingInfo = currentNowPlayingInfo.merging(newNowPlayingInfo) { _, new in new }
// Capture lightweight properties synchronously before dispatching
let asset = currentItem.asset
let externalMetadata = currentItem.externalMetadata
let duration = currentItem.duration.seconds
let currentTime = currentItem.currentTime().seconds.rounded()
let rate = player.rate

// Dispatch metadata loading to background queue to avoid blocking the main thread.
metadataQueue.async {
// commonMetadata is metadata from asset, externalMetadata is custom metadata set by user
// externalMetadata should override commonMetadata to allow override metadata from source
let metadata = {
let common = Dictionary(uniqueKeysWithValues: asset.commonMetadata.map { ($0.identifier, $0) })
let external = Dictionary(uniqueKeysWithValues: externalMetadata.map { ($0.identifier, $0) })
return Array((common.merging(external) { _, new in new }).values)
}()

let titleItem = AVMetadataItem.metadataItems(from: metadata, filteredByIdentifier: .commonIdentifierTitle).first?.stringValue ?? ""

let artistItem = AVMetadataItem.metadataItems(from: metadata, filteredByIdentifier: .commonIdentifierArtist).first?.stringValue ?? ""

// I have some issue with this - setting artworkItem when it not set dont return nil but also is crashing application
// this is very hacky workaround for it
let imgData = AVMetadataItem.metadataItems(from: metadata, filteredByIdentifier: .commonIdentifierArtwork).first?.dataValue
let image = imgData.flatMap { UIImage(data: $0) } ?? UIImage()
let artworkItem = MPMediaItemArtwork(boundsSize: image.size) { _ in image }

let newNowPlayingInfo: [String: Any] = [
MPMediaItemPropertyTitle: titleItem,
MPMediaItemPropertyArtist: artistItem,
MPMediaItemPropertyArtwork: artworkItem,
MPMediaItemPropertyPlaybackDuration: duration,
MPNowPlayingInfoPropertyElapsedPlaybackTime: currentTime,
MPNowPlayingInfoPropertyPlaybackRate: rate,
]
let currentNowPlayingInfo = MPNowPlayingInfoCenter.default().nowPlayingInfo ?? [:]

MPNowPlayingInfoCenter.default().nowPlayingInfo = currentNowPlayingInfo.merging(newNowPlayingInfo) { _, new in new }
}
}

private func findNewCurrentPlayer() {
Expand Down
2 changes: 1 addition & 1 deletion ios/Video/RCTVideo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@
if currentTime != nil && _source?.cropStart != nil {
currentTime = CMTimeSubtract(currentTime!, CMTimeMake(value: _source?.cropStart ?? 0, timescale: 1000))
}
let currentPlaybackTime = _player?.currentItem?.currentDate()
let currentPlaybackTime: Date? = nil // currentDate() is only relevant for HLS live streams. For our vidoes it always returns nil, so currentPlaybackTime was always 0.

Check failure on line 427 in ios/Video/RCTVideo.swift

View workflow job for this annotation

GitHub Actions / Swift-Lint

Line Length Violation: Line should be 160 characters or less; currently it has 176 characters (line_length)
let duration = CMTimeGetSeconds(playerDuration)
var currentTimeSecs = CMTimeGetSeconds(currentTime ?? .zero)

Expand Down Expand Up @@ -1177,7 +1177,7 @@
AVPlaybackSpeed(rate: 1.25, localizedName: "1,25x"),
AVPlaybackSpeed(rate: 1.5, localizedName: "1,5x"),
AVPlaybackSpeed(rate: 2.0, localizedName: "2,0x")
];

Check failure on line 1180 in ios/Video/RCTVideo.swift

View workflow job for this annotation

GitHub Actions / Swift-Lint

Trailing Semicolon Violation: Lines should not have trailing semicolons (trailing_semicolon)
}

viewController.showsPlaybackControls = self._controls
Expand Down Expand Up @@ -1686,11 +1686,11 @@
}
}
}

Check failure on line 1689 in ios/Video/RCTVideo.swift

View workflow job for this annotation

GitHub Actions / Swift-Lint

Trailing Whitespace Violation: Lines should not have trailing whitespace (trailing_whitespace)
func handleWillEnterFullScreen() {
self.onVideoFullscreenPlayerWillPresent?(["target": self.reactTag as Any])
}

Check failure on line 1693 in ios/Video/RCTVideo.swift

View workflow job for this annotation

GitHub Actions / Swift-Lint

Trailing Whitespace Violation: Lines should not have trailing whitespace (trailing_whitespace)
func handleDidEnterFullScreen() {
if #available(iOS 16.0, *) {
let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
Expand All @@ -1699,7 +1699,7 @@

self.onVideoFullscreenPlayerDidPresent?(["target": self.reactTag as Any])
}

Check failure on line 1702 in ios/Video/RCTVideo.swift

View workflow job for this annotation

GitHub Actions / Swift-Lint

Trailing Whitespace Violation: Lines should not have trailing whitespace (trailing_whitespace)
func handleWillExitFullScreen() {
if #available(iOS 16.0, *) {
let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
Expand All @@ -1708,11 +1708,11 @@

self.onVideoFullscreenPlayerWillDismiss?(["target": self.reactTag as Any])
}

Check failure on line 1711 in ios/Video/RCTVideo.swift

View workflow job for this annotation

GitHub Actions / Swift-Lint

Trailing Whitespace Violation: Lines should not have trailing whitespace (trailing_whitespace)
func handleDidExitFullScreen() {
self.onVideoFullscreenPlayerDidDismiss?(["target": self.reactTag as Any])
}

Check failure on line 1715 in ios/Video/RCTVideo.swift

View workflow job for this annotation

GitHub Actions / Swift-Lint

Trailing Whitespace Violation: Lines should not have trailing whitespace (trailing_whitespace)
@objc
func handleDidFailToFinishPlaying(notification: NSNotification!) {
guard onVideoError != nil else { return }
Expand Down
Loading