Expo录制音频转MP3/M4A及上传FileStack问题排查
问题解决:Expo录制M4A音频并上传至FileStack
一、解决录制M4A格式不生效的问题
你遇到的扩展名仍为.caf的问题,是因为prepareToRecordAsync传入的RECORDING_OPTIONS_PRESET_HIGH_QUALITY预设覆盖了构造器里的自定义配置。正确做法是将格式配置合并到预设选项中,而非分开设置。
修改后的录制代码:
import * as React from "react"; import { Text, View, StyleSheet, Button } from "react-native"; import { Audio } from "expo-av"; export default function App() { const [recording, setRecording] = React.useState(); const [recordedUri, setRecordedUri] = React.useState(); // 保存录制后的URI用于上传 async function startRecording() { try { console.log("请求权限.."); await Audio.requestPermissionsAsync(); await Audio.setAudioModeAsync({ allowsRecordingIOS: true, playsInSilentModeIOS: true, shouldDuckAndroid: true, }); console.log("开始录制.."); // 合并预设与自定义格式配置 const recordingOptions = { ...Audio.RECORDING_OPTIONS_PRESET_HIGH_QUALITY, extension: ".m4a", // iOS指定AAC编码器,确保生成M4A audioEncoder: Audio.RECORDING_OPTION_IOS_AUDIO_ENCODER_AAC, // Android配置对应编码器和输出格式 android: { audioEncoder: Audio.RECORDING_OPTION_ANDROID_AUDIO_ENCODER_AAC, outputFormat: Audio.RECORDING_OPTION_ANDROID_OUTPUT_FORMAT_MPEG_4, }, }; const recording = new Audio.Recording(); await recording.prepareToRecordAsync(recordingOptions); await recording.startAsync(); setRecording(recording); console.log("录制已开始"); } catch (err) { console.error("录制启动失败", err); } } async function stopRecording() { console.log("停止录制.."); setRecording(undefined); await recording.stopAndUnloadAsync(); const uri = recording.getURI(); setRecordedUri(uri); // 保存URI供上传使用 console.log("录制已停止,文件路径:", uri); } return ( <View style={styles.container}> <Button title={recording ? "停止录制" : "开始录制"} onPress={recording ? stopRecording : startRecording} /> {recordedUri && <Text style={{marginTop:16}}>录制文件路径:{recordedUri}</Text>} </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: "center", backgroundColor: "#ecf0f1", padding: 10, }, });
关键修改点:
- 将自定义格式配置合并到预设选项中,避免被覆盖
- 明确指定iOS/Android的音频编码器为AAC,Android输出格式设为MPEG_4,确保生成标准M4A文件
- 添加
recordedUri状态存储文件路径,方便后续上传
二、上传至FileStack的正确实现
直接传递文件URI无法完成上传,Filestack要求接收multipart/form-data格式的文件内容,需用FormData包装文件后发送请求。
修改后的上传代码(整合到App组件内):
import axios from "axios"; // 需先安装:npm install axios // 在App组件内添加上传函数 async function uploadFileAndGetURL() { console.log("开始上传..."); console.log("本地文件路径:", recordedUri); if (!recordedUri) return; try { const formData = new FormData(); const fileName = recordedUri.split("/").pop(); formData.append("file", { uri: recordedUri, name: fileName, type: "audio/m4a", }); const response = await axios.post( `https://www.filestackapi.com/api/store/S3?key=${你的FILESTACKAPI_KEY}`, formData, { headers: { "Content-Type": "multipart/form-data", }, } ); if (response.status === 200) { console.log("上传完成!"); console.log("文件URL:", response.data.url); return response.data.url; } } catch (error) { console.error("上传出错:", error); throw error; } }
在组件return中添加上传按钮:
{recordedUri && ( <Button title="上传至FileStack" onPress={uploadFileAndGetURL} style={{marginTop: 20}} /> )}
关键注意事项:
- 必须用
FormData包装文件,不能直接传递URI - 请求头需设置为
multipart/form-data,而非固定的audio/m4a - 替换
你的FILESTACKAPI_KEY为实际的Filestack API密钥 - 通过
split("/").pop()获取文件名,适配iOS和Android的路径格式
内容的提问来源于stack exchange,提问作者Guidetti
相关产品推荐
相关产品推荐

