Khaja Nizamuddin
Khaja Nizamuddin

Reputation: 177

Expo AV audio not playing on iOS/ iPhone

I have used Expo AV and developed a screen in my app to play audio files fetched from my server. It works fine on Android, but doesn't play anything on iPhone.

When I play a button to play the audio which loads and plays the file

soundObject.loadAsync({ uri: this.state.file });
soundObject.playAsync();

It returns an error:

This media format is not supported. - The AVPlayerItem instance has failed with the error code -11828 and domain "AVFoundationErrorDomain".

Here is my code that loads and plays the audio :

async loadAudio() {
soundObject = new Audio.Sound();
try {
await soundObject.loadAsync({ uri: this.state.file });
console.log("File loaded: " + this.state.file);
} catch (error) {
console.log(error);
}
}


async playAudio() {
if (!this.state.isPlayingAudio) {
try {
  
  await soundObject.playAsync();
} catch (error) {
  console.log(error);
}

  else {
soundObject.pauseAsync();
  }
  }

I have tried changing the audio format to m4a, wav, caf while recording and fetching the file but that did not help I'm running the app on iPhone 7 plus, iOS 14.2 Any suggestions/ fixes, please? Thanks in advance

Upvotes: 4

Views: 5274

Answers (5)

ykadaru
ykadaru

Reputation: 1144

A combination of @manish's answer up above, other questions, and Expo's own docs helped me.

For playback of an existing audio file specifically...

// uri is a local device URI starting with 'file:///'
const AudioReactComponent = ({ uri }: { uri: string }) => {
  const [sound, setSound] = useState<Sound>(() => new Audio.Sound());
  const [status, setStatus] = useState<AVPlaybackStatusSuccess | undefined>();
  const [error, setError] = useState<unknown>();

  const handlePlay = () => {
    if (!sound) return;

    if (status?.positionMillis === status?.durationMillis) {
      sound.playFromPositionAsync(0);
    } else {
      sound.playAsync();
    }
  };

  const handlePause = () => {
    if (!sound) return;

    sound.pauseAsync();
  };

  const handleScrub = (newValue: number) => {
    if (!sound) return;

    const rounded = Math.round(newValue);

    if (status?.isPlaying) {
      sound.setPositionAsync(rounded);
      handlePause();
    } else {
      sound.playFromPositionAsync(rounded);
    }
  };

  useEffect(function loadAudio() {
    if (!uri) return;

    // TODO: you may have to add a check ^ above to make sure the URI is a device URI. When you type uri here you'll also see a `localUri` prop but I don't think that's relevant here. https://docs.expo.dev/versions/latest/sdk/av/#avplaybacksourceobject

    sound
      .loadAsync({ uri }, { shouldPlay: false })
      .then((data) => {
        if (!data.isLoaded) {
          setError(data.error);
          return;
        }

        setStatus(data);
      })
      .then(() => {
        sound.setOnPlaybackStatusUpdate((newStatus) => {
          if (!newStatus.isLoaded) {
            setError(newStatus.error);
            return;
          }

          setStatus(newStatus);
        });
      })
      .catch((err) => {
        // TODO: handle your exception...
      });
  }, [uri]);

  useEffect(function unloadAudio() {
    return sound
      ? () => {
          sound.unloadAsync();
        }
      : undefined;
  }, [sound]);

  useEffect(function setAudioMode() {
    Audio.setAudioModeAsync({
      playsInSilentModeIOS: true,
      staysActiveInBackground: false,
      interruptionModeAndroid: InterruptionModeAndroid.DoNotMix,
      shouldDuckAndroid: true,
    });
  }, []);

 // excluded for brevity.... the rest of your component code if any and your UI render returns
};

Upvotes: 0

Manish Arora
Manish Arora

Reputation: 597

Please add this method before playing sound view "expo-av"

const enableAudio = async () => {
    await Audio.setAudioModeAsync({
    playsInSilentModeIOS: true,
    staysActiveInBackground: false,
    interruptionModeAndroid: INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
    shouldDuckAndroid: false,
})

Upvotes: 5

Travis Hoki
Travis Hoki

Reputation: 230

I was on Expo 44, downgrading to Expo 43 did the trick. Run expo upgrade 43.

Upvotes: -3

Murdoch Khallz
Murdoch Khallz

Reputation: 21

I'm passing the uri object and a second argument {shouldPlay: true} to the loadAsync method. This plays my mp3 files from amazon server s3

await Audio.Sound.loadAsync( { uri: this.state.file }, { shouldPlay: true } )

Upvotes: 2

user749127
user749127

Reputation:

You're calling loadAsync improperly.

The call should look like this:

await Audio.Sound.createAsync(
  { uri: this.state.file },
  { shouldPlay: true }
);

Upvotes: 2

Related Questions