Expo AV React Native 本地声音文件问题
Expo AV React Native Local Sound File issue
我正在尝试创建一个具有 React Native 和 Expo AV 的音频播放器。我可以很好地播放在线远程文件(通过 uri),而且我的代码运行良好。但是,每当我尝试播放本地文件时,它都会抛出错误:[Unhandled promise rejection: Error: Cannot load an AV asset from a null playback source]
。我现在的大部分音频处理代码都是通过 handleAudioPlayPause
处理的,它会在按下按钮时调用。我怎样才能让这个程序毫无问题地播放本地文件?谢谢
const audio = {
filename: 'Audio file 1',
uri:
require('../assets/sounds/hello.mp3'), //this does not work
// 'https://www.learningcontainer.com/wp-content/uploads/2020/02/Kalimba.mp3', // this works
};
...
const [isPlaying, setIsPlaying] = useState(false);
const [playbackObject, setPlaybackObject] = useState<any | null>(null);
const [playbackStatus, setPlaybackStatus] = useState<any | null>(null);
useEffect(() => {
if (playbackObject === null) {
setPlaybackObject(new Audio.Sound());
}
}, []);
const handleAudioPlayPause = async () => {
if (playbackObject !== null && playbackStatus === null) {
const status = await playbackObject.loadAsync(
{ uri: audio.uri },
{ shouldPlay: true }
);
setIsPlaying(true);
return setPlaybackStatus(status);
}
// It will pause our audio
if (playbackStatus.isPlaying) {
const status = await playbackObject.pauseAsync();
setIsPlaying(false);
return setPlaybackStatus(status);
}
// It will resume our audio
if (!playbackStatus.isPlaying) {
const status = await playbackObject.playAsync();
console.log(status);
setIsPlaying(true);
return setPlaybackStatus(status);
}
};
查看加载音频文件的不同方法
- 对于远程文件,请像您一样使用它
const status = await playbackObject.loadAsync(
{ uri: audio.uri }, // For remote files we have to place uri like this
{ shouldPlay: true }
);
- 但是对于本地文件,你必须这样使用,
const status = await playbackObject.loadAsync(
audio.uri, // For local files we have to use it like this
{ shouldPlay: true }
);
我认为您应该使用 useRef
而不是 useState
,因为 useState 会导致重新渲染,而 useRef 不会。如果我们想反映 UI 的变化,我们通常使用 useState
。
const soundRef = useRef(null);
useEffect(() => {
#you could have multiple sound files to load
const soundObject = new Audio.Sound();
const loadSounds = async () => {
await soundObject.loadAsync("Your config");
soundRef.current = soundObject;
};
loadSounds();
// ALways clean up running files
return () => {
soundObject && soundObject.unloadAsync();
};
}, []);
只是为了改进 Kartikey 的回答,对于本地文件,以下对我有用。
const { sound } = await Audio.Sound.createAsync(
{ uri: recording.getURI() },
{
shouldPlay: true,
}
);
我正在尝试创建一个具有 React Native 和 Expo AV 的音频播放器。我可以很好地播放在线远程文件(通过 uri),而且我的代码运行良好。但是,每当我尝试播放本地文件时,它都会抛出错误:[Unhandled promise rejection: Error: Cannot load an AV asset from a null playback source]
。我现在的大部分音频处理代码都是通过 handleAudioPlayPause
处理的,它会在按下按钮时调用。我怎样才能让这个程序毫无问题地播放本地文件?谢谢
const audio = {
filename: 'Audio file 1',
uri:
require('../assets/sounds/hello.mp3'), //this does not work
// 'https://www.learningcontainer.com/wp-content/uploads/2020/02/Kalimba.mp3', // this works
};
...
const [isPlaying, setIsPlaying] = useState(false);
const [playbackObject, setPlaybackObject] = useState<any | null>(null);
const [playbackStatus, setPlaybackStatus] = useState<any | null>(null);
useEffect(() => {
if (playbackObject === null) {
setPlaybackObject(new Audio.Sound());
}
}, []);
const handleAudioPlayPause = async () => {
if (playbackObject !== null && playbackStatus === null) {
const status = await playbackObject.loadAsync(
{ uri: audio.uri },
{ shouldPlay: true }
);
setIsPlaying(true);
return setPlaybackStatus(status);
}
// It will pause our audio
if (playbackStatus.isPlaying) {
const status = await playbackObject.pauseAsync();
setIsPlaying(false);
return setPlaybackStatus(status);
}
// It will resume our audio
if (!playbackStatus.isPlaying) {
const status = await playbackObject.playAsync();
console.log(status);
setIsPlaying(true);
return setPlaybackStatus(status);
}
};
查看加载音频文件的不同方法
- 对于远程文件,请像您一样使用它
const status = await playbackObject.loadAsync(
{ uri: audio.uri }, // For remote files we have to place uri like this
{ shouldPlay: true }
);
- 但是对于本地文件,你必须这样使用,
const status = await playbackObject.loadAsync(
audio.uri, // For local files we have to use it like this
{ shouldPlay: true }
);
我认为您应该使用 useRef
而不是 useState
,因为 useState 会导致重新渲染,而 useRef 不会。如果我们想反映 UI 的变化,我们通常使用 useState
。
const soundRef = useRef(null);
useEffect(() => {
#you could have multiple sound files to load
const soundObject = new Audio.Sound();
const loadSounds = async () => {
await soundObject.loadAsync("Your config");
soundRef.current = soundObject;
};
loadSounds();
// ALways clean up running files
return () => {
soundObject && soundObject.unloadAsync();
};
}, []);
只是为了改进 Kartikey 的回答,对于本地文件,以下对我有用。
const { sound } = await Audio.Sound.createAsync(
{ uri: recording.getURI() },
{
shouldPlay: true,
}
);