When video starts in 'paused' state the onProgress event does not fire on Android
Closed this issue · 10 comments
Bug
onProgress
callback does not fire on Android when video starts paused
.
Platform
Which player are you experiencing the problem on:
- Android ExoPlayer
Environment info
React native info output:
❯ ./node_modules/react-native/cli.js info
info Fetching system and libraries information...
System:
OS: macOS 10.15.3
CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
Memory: 393.53 MB / 16.00 GB
Shell: 5.7.1 - /bin/zsh
Binaries:
Node: 10.17.0 - /var/folders/4n/nd5y3s7x00gbr3mk4fq0jv4c0000gn/T/fnm-shell-2410913/bin/node
Yarn: 1.22.4 - /usr/local/bin/yarn
npm: 6.13.6 - /var/folders/4n/nd5y3s7x00gbr3mk4fq0jv4c0000gn/T/fnm-shell-2410913/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
Managers:
CocoaPods: 1.9.1 - /Users/dylanjhaveri/.rvm/gems/ruby-2.5.1/bin/pod
SDKs:
iOS SDK:
Platforms: iOS 13.4, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
Android SDK: Not Found
IDEs:
Android Studio: 3.6 AI-192.7142.36.36.6241897
Xcode: 11.4/11E146 - /usr/bin/xcodebuild
Languages:
Java: 12.0.2 - /usr/bin/javac
Python: 2.7.17 - /usr/local/bin/python
npmPackages:
@react-native-community/cli: Not Found
react: 16.11.0 => 16.11.0
react-native: 0.62.2 => 0.62.2
npmGlobalPackages:
*react-native*: Not Found
Library version: 5.0.2
Steps To Reproduce
Loom video recording: https://www.loom.com/share/0a903fc33c644ca9a7cb7c9747587997
- Start video in 'paused' state
- Play video
- onProgress callback does not fire on Android (it does fire on iOS)
Expected behaviour
- When video starts out 'paused' the onProgress event should still fire
Reproducible sample code
See simple demo app here:
https://github.com/dylanjha/react-native-video-bugs
@cobarx I was surprised by this bug, any ideas if I'm doing something that is causing it. I thought maybe it was specific to my application but I was able to reproduce it in a sample app (github link above). Any help would be greatly appreciated 🙏
I'm trying to get an SDK out for Video QOS monitoring with his player (https://mux.com/data), but this is a blocker. I'm happy to work on a patch for it it, I started digging through the source code but I wasn't able to find an obvious fix (I'm also new to react-native world so there's a bit of a learning curve there)
@dylanjha : Just find out that it was working fine in my project but I have seen one thing in your repo that paused value is hardcoded in code which is set as true (if you don't provide value to attribute on the component then I will consider as true). But I think that based paused video player play and pause.
So you need to update the paused value with video current playing status in case if you are using custom controls over a player then you need to manage paused value and provide it to the player.
But in your repo, you are using default controls that come with react-native-video which internally handle state so you don't need to pass paused in the first place. But still, you want to manage video state from outside player control then you should provide proper value to the paused attribute. Means false when the video player is playing video and pauses when the video player is not playing a video.
I had clone your bug repo and added two button play and pause which update paused attribute. The default value of paused is set to true. But when you click on play custom button it changes to false and video start playing and you will start receiving progress event. here is your updates code.
import React, {useState} from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
Button,
} from 'react-native';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import Video from 'react-native-video';
const App: () => React$Node = () => {
const [showVideo, setShowVideo] = useState(false);
const [isPause, setPauseStatus] = useState(true); // Added new code
const onProgress = () => {
// iOS - always gets logged
// Android - if video starts in 'paused' state, this does not get logged [BUG]
console.log('debug onProgress');
};
const onSeek = () => {
// iOS - never gets logged
// Android - gets logged [BUG]
console.log('debug onSeek');
};
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={styles.scrollView}>
{global.HermesInternal == null ? null : (
<View style={styles.engine}>
<Text style={styles.footer}>Engine: Hermes</Text>
</View>
)}
<View style={styles.body}>
<Button
title={showVideo ? 'Hide' : 'Show'}
onPress={() => setShowVideo(!showVideo)}
/>
{showVideo && (
<View>
<Video
style={styles.video}
source={{
uri:
'https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8',
}}
onSeek={onSeek}
onProgress={onProgress}
paused={isPause} // value updated with state variable
controls
muted
/>
<Button title="Play" onPress={() => setPauseStatus(false)} />
<Button title="Pause" onPress={() => setPauseStatus(true)} />
</View>
)}
</View>
</ScrollView>
</SafeAreaView>
</>
);
};
const styles = StyleSheet.create({
scrollView: {
backgroundColor: Colors.lighter,
},
video: {
width: 400,
height: 500,
},
engine: {
position: 'absolute',
right: 0,
},
body: {
backgroundColor: Colors.white,
},
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
color: Colors.black,
},
footer: {
color: Colors.dark,
fontSize: 12,
fontWeight: '600',
padding: 4,
paddingRight: 12,
textAlign: 'right',
},
});
export default App;
Interesting, thank you @jariwalabhavesh I can see what this code is doing.
To make sure I understand:
But in your repo, you are using default controls that come with react-native-video which internally handle state so you don't need to pass paused in the first place. But still, you want to manage video state from outside player control then you should provide proper value to the paused attribute. Means false when the video player is playing video and pauses when the video player is not playing a video.
This makes sense, but what is the recommended way if I want to use the default player controls, but start the player off in the paused
state (in other words to not autoplay the video?).
For example, by default this video will autoplay:
<Video source={{uri: "background"}} />
If I want to not autoplay the video it seems like I should be able to do this:
<Video source={{uri: "background"}} paused />
However, based on this explanation it seems like I can only do that if I implement my own custom controls.
Furthermore, since this behavior in inconsistent on iOS vs. Andriod, so should that be considered a bug?
Am I missing something here?
@dylanjha : It looks like a bug if we consider using default player controls and want to keep the paused value as true hardcode.
But my opinion is that default controls are very basic. so the majority of users are using a third party control package. In my case, I had created custom control on a player from react-native.
But as of now, I think the workaround that I had provided in my last comment in your code should be enough to start working on that.
Maybe it will get fixed in future releases.
@jariwalabhavesh Thanks for confirming that you are seeing this bug, leaving this issue open with the hopes it gets some attention
Has this been solved yet?
I would love to have an option to set paused to true or otherwise have an autoplay prop to disable a video from automatically playing.
I also noticed that the video may sometimes keep playing when you set paused = true
right after you used the seek
function. So looks like there's no reliable synchronization between the native player and the RN wrapper.
For me, onEnd event was causing this. It was calling while entering the screen.