TheWidlarzGroup/react-native-video

onSeek is not firing on iOS

Closed this issue · 5 comments

Bug

onSeek event is not firing

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 onSeek = () => {
    // this only gets logged at the end of seek events on Android. It does not get logged on iOS 
    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 && (
              <Video
                style={styles.video}
                source={{
                  uri:
                    'https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8',
                }}
                onSeek={onSeek}
                controls
                muted
              />
            )}
          </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;

Platform

Which player are you experiencing the problem on:

  • iOS: not firing
  • Android ExoPlayer: working ✅

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: 259.19 MB / 16.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 10.17.0 - /var/folders/4n/nd5y3s7x00gbr3mk4fq0jv4c0000gn/T/fnm-shell-8618558/bin/node
    Yarn: 1.22.4 - /usr/local/bin/yarn
    npm: 6.13.6 - /var/folders/4n/nd5y3s7x00gbr3mk4fq0jv4c0000gn/T/fnm-shell-8618558/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  SDKs:
    iOS SDK:
      Platforms: iOS 13.4, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
  IDEs:
    Android Studio: 3.6 AI-192.7142.36.36.6241897
    Xcode: 11.4/11E146 - /usr/bin/xcodebuild
  npmPackages:
    react: 16.9.0 => 16.9.0
    react-native: 0.61.5 => 0.61.5
  npmGlobalPackages:
    react-native-cli: 2.0.1

Library version: x.x.x

react-native-video@^5.0.2:
  resolved "https://registry.yarnpkg.com/react-native-video/-/react-native-video-5.0.2.tgz#8f07da0cd85a1d4b316d115f3786409efc9e39fb"

Steps To Reproduce

  1. Create a simple Demo app like the example above, pass an onSeek callback to the Video element. See that onSeek does not get called when running on iOS app (it does get called when running on Android )
    ...

Expected behaviour

  1. onSeek should be called on iOS. In this example debug onSeek should be printed to the logs like it is on the Android app.

Reproducible sample code

Video sample

If possible, include a link to the video that has the problem that can be streamed or downloaded from.

Are there any updates with this issue? This bug is absolutely killing me

@henryjeff not that I have heard. I'm eager to get this fixed too

The issue here appears to be that the iOS implementation uses a different approach to seeking when the player is scrubbed with the progress bar. The function passed as onVideoSeek is only called when seek is invoked on the ref, and not internally, and therefore the event is never fired. It does, however, get fired when you programmatically seek.

Did a little looking around, and there's really not a good way to detect when the player is being scrubbed (neither AVPlayer nor AVPlayerViewController fire any related events, and the "scrubbing" state isn't explicitly exposed at all).
The best option I've found is what's suggested in this SO thread, which is a pretty heavy-handed workaround and still seems kind of brittle to me.

@garrottkai thanks! Ya I'm not surprised. We (mux.com) have a quality-of-service product as part of our Mux Data offering and with that we have an AVPlayer SDK that tracks everything around video performance on the playback side (including seeking).

The way we do it is by keeping track of the playhead time. While taking into consideration re-buffering events, pause events, we can see if the playhead time jumps forward or backwards in time relative to elapsed wallclock.