在Expo React Native中播放OpenAI TTS API音频遇问题求助
解决Expo中直接播放OpenAI TTS API音频Blob的问题
问题场景
使用Expo开发React Native应用时,调用OpenAI TTS API将文本转为音频后,希望直接播放Blob响应而不本地保存文件。已成功获取正确的Blob,但使用expo-av播放时触发错误:
Error: The AVPlayerItem instance has failed with the error code -1002 and domain "NSURLErrorDomain"
错误原因
错误码-1002对应NSURLErrorUnsupportedURL,因为iOS原生AVPlayer(expo-av的底层依赖)不支持URL.createObjectURL生成的Blob URL,导致无法加载音频资源。
解决方案
将Blob转换为Base64格式的Data URI,expo-av的Audio.Sound支持直接加载Data URI形式的音频源。
修改后的完整代码
import { Audio } from 'expo-av'; const convertTextToSpeech = async (textToConvert) => { const apiKey = 'myKey'; const url = 'https://api.openai.com/v1/audio/speech'; try { const response = await fetch(url, { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'tts-1', input: textToConvert, voice: 'alloy', language: 'da', }) }); if (!response.ok) { throw new Error(`请求失败: ${response.status}`); } const blob = await response.blob(); await playSound(blob); } catch (error) { console.error('请求或播放出错:', error); } }; async function playSound(blob) { // 将Blob转换为Base64 const base64 = await new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result.split(',')[1]); reader.onerror = reject; reader.readAsDataURL(blob); }); // 构建Data URI const audioUri = `data:${blob.type};base64,${base64}`; // 加载并播放音频 const { sound, status } = await Audio.Sound.createAsync( { uri: audioUri }, { shouldPlay: false } ); try { await sound.playAsync(); // 监听播放结束,清理资源 sound.setOnPlaybackStatusUpdate((status) => { if (status.didJustFinish) { sound.unloadAsync(); } }); } catch (playError) { console.error('播放失败:', playError); await sound.unloadAsync(); } }
关键修改点
- 替换
URL.createObjectURL为Blob转Base64的逻辑,生成Data URI适配expo-av的加载要求 - 添加音频播放结束后的资源卸载逻辑,避免内存泄漏
- 统一使用async/await语法,提升代码可读性和错误处理能力
内容的提问来源于stack exchange,提问作者Christoffer Nielsen
相关产品推荐
相关产品推荐

