Anthony
Anthony

Reputation: 568

How to fix 'Video play but don't have sound on iOS with expo'

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}} />

Upvotes: 3

Views: 11736

Answers (7)

Judson dunne
Judson dunne

Reputation: 1

CHECK TO SEE IF YOUR PHONE IS ON SILENT! I spent a hour trying to figure out what was wrong and it was just that...

Upvotes: 0

Petros Kyriakou
Petros Kyriakou

Reputation: 5343

One of the latest ways as the syntax changed a bit

await Audio.setAudioModeAsync({
     allowsRecordingIOS: false,
     interruptionModeIOS: InterruptionModeIOS.DuckOthers,
     playsInSilentModeIOS: true,
     shouldDuckAndroid: true,
     interruptionModeAndroid: InterruptionModeAndroid.DuckOthers,
     playThroughEarpieceAndroid: false,
})

Upvotes: 0

manuelmhtr
manuelmhtr

Reputation: 356

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!

Upvotes: 7

littlebird99
littlebird99

Reputation: 371

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'}

Upvotes: 1

Irfan434
Irfan434

Reputation: 1681

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).

Upvotes: 8

GentryRiggen
GentryRiggen

Reputation: 858

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>
  )

Upvotes: 6

hong developer
hong developer

Reputation: 13906

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"

Upvotes: -1

Related Questions