3

I use video component from expo. I can play video, but it doesn't sound in iOS. In Android it's okay. How can I fix it.

<Video style={{ width: 340, 
                                height: 220,
                                borderRadius: 10, 
                                overflow: 'hidden' }}
                                posterSource={require('../../assets/loading2.gif')}
                                usePoster={true}
                                rate={1.0}
                                isMuted={false}
                                useNativeControls = {true}
                                volume={1.0}
                                playsInSilentLockedModeIOS ={ true }
                                resizeMode='cover' 
                                shouldPlay={true} 
                                source={{uri : url}} />
manishsharma93
  • 1,039
  • 1
  • 11
  • 26
Anthony
  • 499
  • 4
  • 10

5 Answers5

5

The audio wasn't working because I had my phone on silent. To change this default behaviour, set playsInSilentLockedModeIOS={ true }.

(I know OP already has this in their code, but I'm answering just in case this helps someone).

Irfan434
  • 1,463
  • 14
  • 19
4

Enabling background audio is not the solution (especially if you are using a managed Expo project where messing with Xcode settings is not ideal). I found that the bug exists when you use useNativeControls={true} and do not auto play the video. If you try shouldPlay={true} you should see it working. That's not a great solution (auto playing video is very MySpace circa 2005).

I fixed it by putting an overlay over the video screen with a custom play button. For some reason calling play from the video ref uses the correct sound profile.

  const videoRef = React.useRef<Video>()

  React.useEffect(() => {
    const enableAudio = async () => {
        await Audio.setAudioModeAsync({
        allowsRecordingIOS: false,
        interruptionModeIOS: INTERRUPTION_MODE_IOS_DO_NOT_MIX,
        playsInSilentModeIOS: true,
        staysActiveInBackground: false,
        interruptionModeAndroid: INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
        shouldDuckAndroid: false,
      })
    }
    enableAudio()
  }, [])

  const play = () => videoRef.current && videoRef.current.playAsync()

  const poster = (
      <View position="absolute" flexible="column-center" bg="transparent">
        <IconButton
          name="play"
          onPress={play}
          size={72}
          iconSize={72}
          bg="transparent"
          iconColor="rgba(255,255,255,0.9)"
        />
      </View>
    )

  return (
    <View>
      <VideoPlayer
        ref={videoRef}
        source={R.is(String, props.asset) ? { uri: props.asset } : props.asset}
        shouldPlay={props.autoPlay !== false}
        useNativeControls={true}
        rate={1.0}
        volume={1.0}
        resizeMode={Video.RESIZE_MODE_CONTAIN}
      />
      <View position="absolute" flexible="column-center" bg="transparent">
        <IconButton
          name="play"
          onPress={play}
          size={72}
          iconSize={72}
          bg="transparent"
          iconColor="rgba(255,255,255,0.9)"
        />
      </View>
    </View>
  )

GentryRiggen
  • 788
  • 10
  • 10
4

Here's what worked for me:

  1. Create a reference (ref) to the <Video /> component.
  2. Use a state to listen when the video starts playing.
  3. When it does, call await Audio.setAudioModeAsync({ playsInSilentModeIOS: true });.
  4. Immediately after, re-play the video by calling ref.current.playAsync();

In summary, my component looks like this:

import React, { useState, useEffect, useRef } from 'react';
import { Audio, Video as OriginalVideo } from 'expo-av';

const triggerAudio = async (ref) => {
  await Audio.setAudioModeAsync({ playsInSilentModeIOS: true });
  ref.current.playAsync();
};

const Video = ({ ...props }) => {
  const ref = useRef(null);
  const [status, setStatus] = useState({});

  useEffect(() => {
    if (status.isPlaying) triggerAudio(ref);
  }, [ref, status.isPlaying]);

  return (
    <OriginalVideo
      ref={ref}
      onPlaybackStatusUpdate={(status) => setStatus(status)}
      useNativeControls
      {...props}
    />
  );
};

Tested with Expo SDK v45 and iOS 16.

Hope it helps!

manuelmhtr
  • 326
  • 2
  • 5
0

I was having this issue due to the silent switch on the side of the iPhone being enabled. To have the video player play sound I needed to included the following as a prop to the video component.

ignoreSilentSwitch={'ignore'}
littlebird99
  • 301
  • 3
  • 6
-1

Determine whether the media should continue playing while the app is in the background. This allows customers to continue listening to the audio.

To use this feature on iOS, you must:

  • Enable Background Audio in your Xcode project
  • Set the ignoreSilentSwitch prop to "ignore"
hong developer
  • 13,291
  • 4
  • 38
  • 68