react native 实现本地录音、播放录音、删除录音功能,并调用接口上传录音文件

目录:

  1. 思路
  2. 安装中间件
  3. 获取录音权限、实现录音功能
  4. 调用接口,实现上传录音文件

思路

  • 获取用户录音权限;
  • 实现本地录音功能、播放录音(注意点:播放时,需要使用本地路径,而不是服务器地址)、删除录音
  • 实现上传接口的封装,需要 formData 对象的格式
  • 调用上传接口,实现录音上传 (使用的 fetch 请求接口)

具体步骤

1. 安装中间件 react-native-audioreact-native-sound

版本:

"react": "16.8.3",
"react-native": "0.59.9",
"react-native-audio": "4.3.0",
"react-native-sound": "0.11.0"

2. 获取用户录音权限、实现本地录音功能、播放录音、删除录音

  • (注意⚠️点:播放时,需要使用本地路径,而不是服务器地址)
【主要代码如下】

【- 组织中引入中间件 `react-native-audio`(实现录音功能)、`react-native-sound`(实现播放语音功能)】
【- 获取录音授权】
【- 实现本地录音】
【- 本地录音播放、删除】

...
import React, { Component } from 'react';
import { AudioRecorder, AudioUtils } from 'react-native-audio';
import Sound from 'react-native-sound';
import {requestAudio} from './audioAction'; // 此文件内容在下面
...


class Test extends Component {
    constructor(props) {
        super(props);
        this.state = {
            ...
            hasPermission: undefined, //录音 授权状态  
            audioPath: AudioUtils.DocumentDirectoryPath + `/quick_audio_${new Date().getTime()}.aac`, // 文件路径  
            stop: false,     //录音是否停止  
            currentTime: 0,  //录音时长  
            ...
        }
    }
    
    componentDidMount() {
        this.getAudioAuthorize()
    }
    
    // 请求录音授权
    getAudioAuthorize() {
        AudioRecorder.requestAuthorization()
            .then(isAuthor => {
                console.log('是否授权: ' + isAuthor)
                if(!isAuthor) {
                    return alert('APP需要使用录音,请打开录音权限允许APP使用')
                }
                this.setState({hasPermission: isAuthor})
                this.prepareRecordingPath(this.state.audioPath);
                // 录音进展
                AudioRecorder.onProgress = (data) => {
                    this.setState({
                        currentTime: Math.ceil(data.currentTime)
                    });
                };
                // 完成录音
                AudioRecorder.onFinished = (data) => {
                    // data 录音数据,可以在此存储需要传给接口的路径数据
                    console.log(this.state.currentTime)
                };
            }) 
    }
    
    /**
     * AudioRecorder.prepareRecordingAtPath(path,option)
     * 录制路径
     * path 路径
     * option 参数
     */
    prepareRecordingPath = (path) => {
        const option = {
            SampleRate: 44100.0, //采样率
            Channels: 2, //通道
            AudioQuality: 'High', //音质
            AudioEncoding: 'aac', //音频编码 aac
            OutputFormat: 'mpeg_4', //输出格式
            MeteringEnabled: false, //是否计量
            MeasurementMode: false, //测量模式
            AudioEncodingBitRate: 32000, //音频编码比特率
            IncludeBase64: true, //是否是base64格式
            AudioSource: 0, //音频源
        }
        AudioRecorder.prepareRecordingAtPath(path,option)
    }
    
    // 开始录音
    handleStartAudio = async () => {
        if(!this.state.hasPermission) {
            return alert('APP需要使用录音,请打开录音权限允许APP使用')
        }
        show('录音开始')
        if(this.state.stop) {
            // 初始化录音
            this.prepareRecordingPath(this.state.audioPath)
        }
        try {
            await AudioRecorder.startRecording()
        } catch (err) {
            console.error(err)
        }
    }
    
    // 停止录音
    handleStopAudio = async () => {
        show('录音结束')
        try {
            await AudioRecorder.stopRecording();
            this.setState({ stop: true, recording: false });
        } catch (error) {
            console.error(error);
        }
    }
    
    // 播放录音
    handlePlayAudio = async () => {
        let self = this
        show('正在播放')
        self.whoosh = new Sound(this.state.audioPath, '', (err) => {
            if(err) {
                show('加载音频失败')
                return console.warn(err)
            }
            self.whoosh.play(success => {
                if(success) {
                    console.warn('success - 播放成功')
                    show('播放完毕')
                }else {
                    console.warn('fail - 播放失败')
                    show('播放失败')
                }
            })
        })
    }

    // 删除录音
    handleDelAudio = async () => {
        // 初始化录音
        this.prepareRecordingPath(this.state.audioPath)
        let {listOptionData} = this.state
        listOptionData[11].value = ''
        this.setState({
            currentTime: 0,
            stop: false,
            listOptionData
        })
    }
    
    
    // 注意⚠️,在此处调用接口,传递录音
    async handlesubmit() {
        let {stop, audioPath} = this.state
        if(stop) {
            // 有录音
            let params = {
                path: audioPath // 根据自己项目修改参数哈
            }
            
            let audioResult = await requestAudio(params); // requestAudio 是封装的请求接口的函数,具体内容在下面
            
            console.log('audioResult----请求接口后返回的数据:', audioResult)
        }
    }
    
    
    ...
    render() {
        return (
            
                
                     录音 
                
                
                     停止录音 
                
                
                     播放录音 
                
                
                     删除录音 
                
                
                 this.handlesubmit()}
                    >
                     提交录音 
                
            
        
        )
    }
    ...
    
    
    
    
}


3. 封装的录音请求后端接口的函数 requestAudio,需要 formData 对象的格式,即【调用上传接口】,实现录音上传;

【文件 `audioAction` 内容如下:】

import {UploadRequest} from './util'; // 该函数内容在下面哈

...

// 上传语音 
export const requestAudio = async (params) => {
    let { path } = params
    let formData = new FormData()
    let soundPath = `file://${path}`  // 注意需要增加前缀 `file://`
    let fileName = path.substring(path.lastIndexOf('/') + 1, path.length) // 文件名
    let file = { uri: soundPath, type: "multipart/form-data", name: fileName} // 注意 `uri` 表示文件地址,`type` 表示接口接收的类型,一般为这个,跟后端确认一下
    formData.append('file', file)
    return await UploadRequest('自己的接口地址', formData) // `UploadRequest` 上传也是封装过,具体参考下面
}

...

4. 【fetch 上传】文件的封装;

【文件 `util` 内容如下:】

...

// 上传

export const UploadRequest(url, datas) {
    let BaseUrl = 'http://www.baidu.com'  // 域名地址,根据自己的修改
    
    const params = {
        method: 'POST',
        body: datas,
        headers: {
            'Content-Type': 'multipart/form-data'
        },
        timeout: 5000 // 5s超时
    };

    return fetch(`${BaseUrl}${url}`, params)
        .then(response => response.json())
        .then(data => data)
        .catch(error => {
            return {error_code: -3, error_msg:'请求异常,请重试'}
        })
        
}

...

写给自己的随笔,有问题欢迎指出

你可能感兴趣的:(前端)