Reputation: 177
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
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
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
Reputation: 230
I was on Expo 44, downgrading to Expo 43 did the trick. Run expo upgrade 43
.
Upvotes: -3
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
Reputation:
You're calling loadAsync improperly.
The call should look like this:
await Audio.Sound.createAsync(
{ uri: this.state.file },
{ shouldPlay: true }
);
Upvotes: 2