From 57ca72dc01b70ea6057f3025e8dc1d306299ea22 Mon Sep 17 00:00:00 2001 From: Olivier Bouillet Date: Fri, 30 Aug 2024 09:24:59 +0200 Subject: [PATCH 1/3] fix(ios): ensure behavior is correct with empty text track list --- examples/basic/src/constants/general.ts | 5 +++++ ios/Video/RCTVideo.swift | 23 +++++++++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/examples/basic/src/constants/general.ts b/examples/basic/src/constants/general.ts index 6331d8a800..609eb5ac19 100644 --- a/examples/basic/src/constants/general.ts +++ b/examples/basic/src/constants/general.ts @@ -78,6 +78,11 @@ export const srcAllPlatformList = [ uri: 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8', startPosition: 50000, }, + { + description: 'mp3 with texttrack', + uri: 'https://traffic.libsyn.com/democracynow/wx2024-0702_SOT_DeadCalm-LucileSmith-FULL-V2.mxf-audio.mp3', // an mp3 file + textTracks: [], // empty text track list + }, { description: 'BigBugBunny sideLoaded subtitles', // sideloaded subtitles wont work for streaming like HLS on ios diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift index f1ca220f17..99615a063a 100644 --- a/ios/Video/RCTVideo.swift +++ b/ios/Video/RCTVideo.swift @@ -42,7 +42,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH private var _repeat = false private var _isPlaying = false private var _allowsExternalPlayback = true - private var _textTracks: [TextTrack]? + private var _textTracks: [TextTrack] = [] private var _selectedTextTrackCriteria: SelectedTrackCriteria? private var _selectedAudioTrackCriteria: SelectedTrackCriteria? private var _playbackStalled = false @@ -598,7 +598,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH } func playerItemPrepareText(asset: AVAsset!, assetOptions: NSDictionary?, uri: String) async -> AVPlayerItem { - if (self._textTracks == nil) || self._textTracks?.isEmpty == true || (uri.hasSuffix(".m3u8")) { + if self._textTracks.isEmpty == true || (uri.hasSuffix(".m3u8")) { return await self.playerItemPropegateMetadata(AVPlayerItem(asset: asset)) } @@ -612,7 +612,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH textTracks: self._textTracks ) - if validTextTracks.count != self._textTracks?.count { + if validTextTracks.count != self._textTracks.count { self.setTextTracks(validTextTracks) } @@ -963,8 +963,8 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH func setSelectedTextTrack(_ selectedTextTrack: SelectedTrackCriteria?) { _selectedTextTrackCriteria = selectedTextTrack - if _textTracks != nil { // sideloaded text tracks - RCTPlayerOperations.setSideloadedText(player: _player, textTracks: _textTracks!, criteria: _selectedTextTrackCriteria) + if !_textTracks.isEmpty { // sideloaded text tracks + RCTPlayerOperations.setSideloadedText(player: _player, textTracks: _textTracks, criteria: _selectedTextTrackCriteria) } else { // text tracks included in the HLS playlist§ Task { await RCTPlayerOperations.setMediaSelectionTrackForCharacteristic(player: _player, characteristic: AVMediaCharacteristic.legible, @@ -979,8 +979,11 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH } func setTextTracks(_ textTracks: [TextTrack]?) { - _textTracks = textTracks - + if (textTracks == nil) { + _textTracks = [] + } else { + _textTracks = textTracks! + } // in case textTracks was set after selectedTextTrack if _selectedTextTrackCriteria != nil { setSelectedTextTrack(_selectedTextTrackCriteria) } } @@ -1294,7 +1297,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH _playerItem = nil _source = nil _chapters = nil - _textTracks = nil + _textTracks = [] _selectedTextTrackCriteria = nil _selectedAudioTrackCriteria = nil _presentingViewController = nil @@ -1448,7 +1451,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH "orientation": orientation, ], "audioTracks": audioTracks, - "textTracks": self._textTracks?.compactMap { $0.json } ?? textTracks.map(\.json), + "textTracks": self._textTracks.compactMap { $0.json } ?? textTracks.map(\.json), "target": self.reactTag as Any]) } @@ -1646,7 +1649,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH if onTextTracks != nil { Task { let textTracks = await RCTVideoUtils.getTextTrackInfo(self._player) - self.onTextTracks?(["textTracks": self._textTracks?.compactMap { $0.json } ?? textTracks.compactMap(\.json)]) + self.onTextTracks?(["textTracks": self._textTracks.compactMap { $0.json } ?? textTracks.compactMap(\.json)]) } } From 3de77b3229f46d92c742dcac9cd1d417bacc356f Mon Sep 17 00:00:00 2001 From: Olivier Bouillet Date: Fri, 30 Aug 2024 10:00:49 +0200 Subject: [PATCH 2/3] chore(ios): fix styling --- ios/Video/RCTVideo.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift index 99615a063a..e735d5d4f2 100644 --- a/ios/Video/RCTVideo.swift +++ b/ios/Video/RCTVideo.swift @@ -979,7 +979,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH } func setTextTracks(_ textTracks: [TextTrack]?) { - if (textTracks == nil) { + if textTracks == nil { _textTracks = [] } else { _textTracks = textTracks! From 50793b8d6ce13bb46ac20325239b1b125b20bb62 Mon Sep 17 00:00:00 2001 From: Olivier Bouillet Date: Fri, 30 Aug 2024 10:05:06 +0200 Subject: [PATCH 3/3] fix(ios): add index to text tracks reported --- ios/Video/RCTVideo.swift | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift index e735d5d4f2..acdb5deb44 100644 --- a/ios/Video/RCTVideo.swift +++ b/ios/Video/RCTVideo.swift @@ -1393,6 +1393,20 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH } } + func extractJsonWithIndex(from tracks: [TextTrack]) -> [NSDictionary]? { + if tracks.isEmpty { + // No tracks, need to return nil to handle + return nil + } + // Map each enumerated pair to include the index in the json dictionary + let mappedTracks = tracks.enumerated().compactMap { index, track -> NSDictionary? in + guard let json = track.json?.mutableCopy() as? NSMutableDictionary else { return nil } + json["index"] = index // Insert the index into the json dictionary + return json + } + return mappedTracks + } + func handleReadyToPlay() { guard let _playerItem else { return } @@ -1451,7 +1465,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH "orientation": orientation, ], "audioTracks": audioTracks, - "textTracks": self._textTracks.compactMap { $0.json } ?? textTracks.map(\.json), + "textTracks": extractJsonWithIndex(from: _textTracks) ?? textTracks.map(\.json), "target": self.reactTag as Any]) } @@ -1649,7 +1663,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH if onTextTracks != nil { Task { let textTracks = await RCTVideoUtils.getTextTrackInfo(self._player) - self.onTextTracks?(["textTracks": self._textTracks.compactMap { $0.json } ?? textTracks.compactMap(\.json)]) + self.onTextTracks?(["textTracks": extractJsonWithIndex(from: _textTracks) ?? textTracks.compactMap(\.json)]) } }