@granite-js/video 3.0.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @granite-js/video
|
|
2
2
|
|
|
3
|
+
## 3.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f7bd69b: Forward iOS video playback options before source loading and restore them when Fabric reuses a view. The default iOS video provider now honors the progress update interval.
|
|
8
|
+
|
|
9
|
+
## 3.0.1
|
|
10
|
+
|
|
3
11
|
## 3.0.0
|
|
4
12
|
|
|
5
13
|
## 2.5.5
|
package/GraniteVideo.podspec
CHANGED
|
@@ -67,6 +67,16 @@ Pod::Spec.new do |s|
|
|
|
67
67
|
|
|
68
68
|
s.frameworks = ["AVFoundation", "AVKit", "CoreMedia"]
|
|
69
69
|
|
|
70
|
+
s.test_spec 'ProviderTests' do |test_spec|
|
|
71
|
+
test_spec.source_files = 'native-tests/ios/**/*.{m,mm,swift}'
|
|
72
|
+
test_spec.requires_app_host = true
|
|
73
|
+
test_spec.frameworks = ['XCTest']
|
|
74
|
+
test_spec.pod_target_xcconfig = {
|
|
75
|
+
'HEADER_SEARCH_PATHS' => '$(inherited) "$(PODS_CONFIGURATION_BUILD_DIR)/ReactCodegen/ReactCodegen.framework/Headers"',
|
|
76
|
+
'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => use_default_provider ? '$(inherited) GRANITE_VIDEO_DEFAULT_PROVIDER' : '$(inherited)'
|
|
77
|
+
}
|
|
78
|
+
end
|
|
79
|
+
|
|
70
80
|
# React Native modules dependencies (Fabric/TurboModule)
|
|
71
81
|
install_modules_dependencies(s)
|
|
72
82
|
end
|
|
@@ -176,6 +176,10 @@ import AVFoundation
|
|
|
176
176
|
@objc var duration: Double { get }
|
|
177
177
|
@objc var isPlaying: Bool { get }
|
|
178
178
|
|
|
179
|
+
// Optional - Progress
|
|
180
|
+
/// Progress callback interval in milliseconds. Non-positive values use the provider default.
|
|
181
|
+
@objc optional func setProgressUpdateInterval(_ interval: Double)
|
|
182
|
+
|
|
179
183
|
// Optional - Volume
|
|
180
184
|
@objc optional func setVolume(_ volume: Float)
|
|
181
185
|
@objc optional func setMuted(_ muted: Bool)
|
package/ios/GraniteVideoView.mm
CHANGED
|
@@ -36,6 +36,8 @@ using namespace facebook::react;
|
|
|
36
36
|
BOOL _muted;
|
|
37
37
|
BOOL _repeat;
|
|
38
38
|
NSString *_resizeMode;
|
|
39
|
+
BOOL _needsPlaybackPropsReapply;
|
|
40
|
+
BOOL _needsMixWithOthersReapply;
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
@@ -56,6 +58,8 @@ using namespace facebook::react;
|
|
|
56
58
|
_muted = NO;
|
|
57
59
|
_repeat = NO;
|
|
58
60
|
_resizeMode = @"contain";
|
|
61
|
+
_needsPlaybackPropsReapply = YES;
|
|
62
|
+
_needsMixWithOthersReapply = NO;
|
|
59
63
|
|
|
60
64
|
// Create provider from registry
|
|
61
65
|
_provider = [[GraniteVideoRegistry shared] createProvider];
|
|
@@ -95,6 +99,23 @@ using namespace facebook::react;
|
|
|
95
99
|
const auto &oldViewProps = *std::static_pointer_cast<GraniteVideoViewProps const>(_props);
|
|
96
100
|
const auto &newViewProps = *std::static_pointer_cast<GraniteVideoViewProps const>(props);
|
|
97
101
|
|
|
102
|
+
// Apply options before loading: providers may configure audio, observers and playback in loadSource.
|
|
103
|
+
if (_needsMixWithOthersReapply || newViewProps.mixWithOthers != oldViewProps.mixWithOthers) {
|
|
104
|
+
[self updateMixWithOthers:[NSString stringWithUTF8String:newViewProps.mixWithOthers.c_str()]];
|
|
105
|
+
}
|
|
106
|
+
if (_needsPlaybackPropsReapply || newViewProps.progressUpdateInterval != oldViewProps.progressUpdateInterval) {
|
|
107
|
+
if ([_provider respondsToSelector:@selector(setProgressUpdateInterval:)]) {
|
|
108
|
+
[_provider setProgressUpdateInterval:newViewProps.progressUpdateInterval];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (_needsPlaybackPropsReapply || newViewProps.automaticallyWaitsToMinimizeStalling != oldViewProps.automaticallyWaitsToMinimizeStalling) {
|
|
112
|
+
if ([_provider respondsToSelector:@selector(setAutomaticallyWaitsToMinimizeStalling:)]) {
|
|
113
|
+
[_provider setAutomaticallyWaitsToMinimizeStalling:newViewProps.automaticallyWaitsToMinimizeStalling];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
_needsPlaybackPropsReapply = NO;
|
|
117
|
+
_needsMixWithOthersReapply = NO;
|
|
118
|
+
|
|
98
119
|
// Source
|
|
99
120
|
if (newViewProps.source.uri != oldViewProps.source.uri ||
|
|
100
121
|
newViewProps.source.type != oldViewProps.source.type) {
|
|
@@ -198,13 +219,6 @@ using namespace facebook::react;
|
|
|
198
219
|
}
|
|
199
220
|
}
|
|
200
221
|
|
|
201
|
-
// Automatically Waits to Minimize Stalling
|
|
202
|
-
if (newViewProps.automaticallyWaitsToMinimizeStalling != oldViewProps.automaticallyWaitsToMinimizeStalling) {
|
|
203
|
-
if ([_provider respondsToSelector:@selector(setAutomaticallyWaitsToMinimizeStalling:)]) {
|
|
204
|
-
[_provider setAutomaticallyWaitsToMinimizeStalling:newViewProps.automaticallyWaitsToMinimizeStalling];
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
222
|
// Allows External Playback
|
|
209
223
|
if (newViewProps.allowsExternalPlayback != oldViewProps.allowsExternalPlayback) {
|
|
210
224
|
if ([_provider respondsToSelector:@selector(setAllowsExternalPlayback:)]) {
|
|
@@ -281,6 +295,19 @@ using namespace facebook::react;
|
|
|
281
295
|
}
|
|
282
296
|
}
|
|
283
297
|
|
|
298
|
+
- (void)updateMixWithOthers:(NSString *)mode
|
|
299
|
+
{
|
|
300
|
+
if ([_provider respondsToSelector:@selector(setMixWithOthers:)]) {
|
|
301
|
+
GraniteVideoMixWithOthers value = GraniteVideoMixWithOthersInherit;
|
|
302
|
+
if ([mode isEqualToString:@"mix"]) {
|
|
303
|
+
value = GraniteVideoMixWithOthersMix;
|
|
304
|
+
} else if ([mode isEqualToString:@"duck"]) {
|
|
305
|
+
value = GraniteVideoMixWithOthersDuck;
|
|
306
|
+
}
|
|
307
|
+
[_provider setMixWithOthers:value];
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
284
311
|
- (void)updateDrmConfig:(const GraniteVideoViewDrmStruct &)drm
|
|
285
312
|
{
|
|
286
313
|
if (drm.type.empty()) {
|
|
@@ -665,6 +692,9 @@ using namespace facebook::react;
|
|
|
665
692
|
{
|
|
666
693
|
[super prepareForRecycle];
|
|
667
694
|
[_provider unload];
|
|
695
|
+
// The provider survives recycling, while Fabric resets the old props to defaults.
|
|
696
|
+
_needsPlaybackPropsReapply = YES;
|
|
697
|
+
_needsMixWithOthersReapply = YES;
|
|
668
698
|
_props = std::make_shared<const GraniteVideoViewProps>();
|
|
669
699
|
}
|
|
670
700
|
|
|
@@ -34,6 +34,7 @@ private class AVPlayerContainerView: UIView {
|
|
|
34
34
|
private var playerView: AVPlayerContainerView?
|
|
35
35
|
private var playerItem: AVPlayerItem?
|
|
36
36
|
private var timeObserver: Any?
|
|
37
|
+
private var progressInterval: Double = 0.25
|
|
37
38
|
private var pipController: AVPictureInPictureController?
|
|
38
39
|
|
|
39
40
|
private var shouldRepeat: Bool = false
|
|
@@ -242,11 +243,7 @@ private class AVPlayerContainerView: UIView {
|
|
|
242
243
|
player.seek(to: seekTime)
|
|
243
244
|
}
|
|
244
245
|
|
|
245
|
-
|
|
246
|
-
let interval = CMTime(seconds: 0.25, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
|
|
247
|
-
timeObserver = player.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] _ in
|
|
248
|
-
self?.handleProgressUpdate()
|
|
249
|
-
}
|
|
246
|
+
updateProgressObserver()
|
|
250
247
|
|
|
251
248
|
// Apply settings
|
|
252
249
|
player.isMuted = isMuted
|
|
@@ -375,6 +372,11 @@ private class AVPlayerContainerView: UIView {
|
|
|
375
372
|
playerItem?.preferredForwardBufferDuration = duration
|
|
376
373
|
}
|
|
377
374
|
|
|
375
|
+
@objc public func setProgressUpdateInterval(_ interval: Double) {
|
|
376
|
+
progressInterval = interval.isFinite && interval > 0 ? interval / 1000.0 : 0.25
|
|
377
|
+
updateProgressObserver()
|
|
378
|
+
}
|
|
379
|
+
|
|
378
380
|
@objc public func setAutomaticallyWaitsToMinimizeStalling(_ waits: Bool) {
|
|
379
381
|
automaticallyWaits = waits
|
|
380
382
|
player.automaticallyWaitsToMinimizeStalling = waits
|
|
@@ -400,6 +402,17 @@ private class AVPlayerContainerView: UIView {
|
|
|
400
402
|
|
|
401
403
|
// MARK: - Private Methods
|
|
402
404
|
|
|
405
|
+
private func updateProgressObserver() {
|
|
406
|
+
guard playerItem != nil else { return }
|
|
407
|
+
if let observer = timeObserver {
|
|
408
|
+
player.removeTimeObserver(observer)
|
|
409
|
+
}
|
|
410
|
+
let interval = CMTime(seconds: progressInterval, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
|
|
411
|
+
timeObserver = player.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] _ in
|
|
412
|
+
self?.handleProgressUpdate()
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
403
416
|
private func unloadPlayerItem() {
|
|
404
417
|
if let observer = timeObserver {
|
|
405
418
|
player.removeTimeObserver(observer)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@granite-js/video",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "Pluggable video component for React Native with provider selection",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/module/index.js",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"dist",
|
|
20
20
|
"android",
|
|
21
21
|
"ios",
|
|
22
|
+
"native-tests/ios",
|
|
22
23
|
"*.podspec",
|
|
23
24
|
"react-native.config.js",
|
|
24
25
|
"!example/**",
|