3

Updated: I'm using Expo Managed, expo-av

I’m facing an issue when playing .m3u8 video on IOS device. We are uploading video on s3 bucket and generate .m3u8 video url, at the time we load video, it’s showing as black screen in player and only audio playing. When I tried with android I didn’t have any problem.

This is how I'm doing this:

import React, { Fragment } from 'react'
import { Dimensions, StyleSheet, Text } from 'react-native'
import * as ScreenOrientation from 'expo-screen-orientation'
import { Audio, Video } from 'expo-av'
import PropTypes from 'prop-types'
import isString from 'lodash/isString'
import once from 'lodash/once'
import noop from 'lodash/noop'

import i18n from 'i18n'
import { defaultTextColor, layoutPadding } from 'styles/variables'

const { width: windowWidth } = Dimensions.get('window')

const videoWidth = windowWidth

export default class VideoCard extends React.Component {
  videoRef = React.createRef()
  presentFullscreenOnce = noop

  state = {
    error: false,
    isBuffering: false,
  }

  async componentDidMount() {
    if (this.videoRef.current) {
      this.presentFullscreenOnce = once(this.videoRef.current.presentFullscreenPlayer)
    }

    await Audio.setAudioModeAsync({ playsInSilentModeIOS: true })
  }

  onPlaybackStatusUpdate = playbackStatus => {
    const { didJustFinish, isBuffering } = playbackStatus
    const { shouldPlay } = this.props

    if (shouldPlay && !isBuffering) {
      this.presentFullscreenOnce()
    }

    if (didJustFinish === true) {
      const { onFinish, id } = this.props

      if (this.videoRef.current) {
        this.videoRef.current.stopAsync()
        this.videoRef.current.dismissFullscreenPlayer()
      }

      onFinish(id)
    }
  }

  onFullscreenUpdate = async ({ fullscreenUpdate }) => {
    if (fullscreenUpdate === 0) {
      await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.DEFAULT)
    }

    if (fullscreenUpdate === 2) {
      await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP)
    }
  }

  onError = () => {
    const { onFinish, id } = this.props

    this.setState(() => ({ error: true }))

    onFinish(id)
  }

  render() {
    const {
      video: {
        urls: { hls },
      },
      shouldPlay,
      description,
    } = this.props

    const { error } = this.state

    return error === false && isString(hls) ? (
      <Fragment>
        <Video
          shouldPlay={shouldPlay}
          resizeMode={Video.RESIZE_MODE_CONTAIN}
          source={{ uri: hls }}
          useNativeControls
          style={styles.video}
          onPlaybackStatusUpdate={this.onPlaybackStatusUpdate}
          onFullscreenUpdate={this.onFullscreenUpdate}
          onError={this.onError}
          ref={this.videoRef}
        />
        {description && <Text style={styles.description}>{description}</Text>}
      </Fragment>
    ) : (
      <Text style={styles.description}>
        {i18n.t('content:Unfortunately your device is not capable of playing this video')}.
      </Text>
    )
  }
}

const styles = StyleSheet.create({
  video: {
    width: videoWidth,
    height: (videoWidth * 9) / 16,
  },
  description: {
    color: defaultTextColor,
    textAlign: 'center',
    fontSize: 20,
    marginTop: 5,
    paddingHorizontal: layoutPadding,
  },
})

VideoCard.propTypes = {
  video: PropTypes.object,
  id: PropTypes.string,
  onFinish: PropTypes.func,
  description: PropTypes.string,
}

Hope someone can help. Many thanks!

1 Answers1

-1

In AndroidManifest.xml add below line:

<application android:hardwareAccelerated="true">
  ....
</application>
DhavalR
  • 159
  • 5
  • Sorry, I have updated details. I'm using expo managed flow, so there are no config for android and ios either. And I faced issue on IOS only. – thanhthanchuc Mar 09 '22 at 08:51