移动端H5录音组件开发(react版本)
时间:2020-05-20
本文章向大家介绍移动端H5录音组件开发(react版本),主要包括移动端H5录音组件开发(react版本)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
基于AudioContext
和mediaDevices
实现的原生js的录音功能
// recorder.js,这个是在网上找的,具体地址不记得了,这个存在一个问题就是,他分段之后会把audioData清空,导致最后结束的时候,audioData是一个空值,如果需要把整段的录音转化成一个音频文件,不考虑分片的话,可以把onaudioprocess里面的sendData注释掉,没错,我就是这样搞的,只需要一个完整的音频,如果需要分段传送,就把注释打开,然后作出对应的处理
const Recorder = function (stream, callback) {
const sampleBits = 16; //输出采样数位 8, 16
const sampleRate = 8000; //输出采样率
const context = new AudioContext();
const audioInput = context.createMediaStreamSource(stream);
const recorder = context.createScriptProcessor(4096, 1, 1);
const audioData = {
size: 0, //录音文件长度
buffer: [], //录音缓存
inputSampleRate: 48000, //输入采样率
inputSampleBits: 16, //输入采样数位 8, 16
outputSampleRate: sampleRate, //输出采样数位
oututSampleBits: sampleBits, //输出采样率
clear: function () {
this.buffer = [];
this.size = 0;
},
input: function (data) {
this.buffer.push(new Float32Array(data));
this.size += data.length;
},
compress: function () { //合并压缩
//合并
const data = new Float32Array(this.size);
let offset = 0;
for (let i = 0; i < this.buffer.length; i++) {
data.set(this.buffer[i], offset);
offset += this.buffer[i].length;
}
//压缩
const compression = parseInt(this.inputSampleRate / this.outputSampleRate);
const length = data.length / compression;
const result = new Float32Array(length);
let index = 0,
j = 0;
while (index < length) {
result[index] = data[j];
j += compression;
index++;
}
return result;
},
encodePCM: function () { //这里不对采集到的数据进行其他格式处理,如有需要均交给服务器端处理。
const sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate);
const sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits);
const bytes = this.compress();
const dataLength = bytes.length * (sampleBits / 8);
const buffer = new ArrayBuffer(dataLength);
const data = new DataView(buffer);
let offset = 0;
for (let i = 0; i < bytes.length; i++, offset += 2) {
const s = Math.max(-1, Math.min(1, bytes[i]));
data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
return new Blob([data], { 'type': 'audio/pcm' });
}
};
const sendData = function () { //对以获取的数据进行处理(分包)
const reader = new FileReader();
reader.onload = e => {
const outbuffer = e.target.result;
// callback && callback(outbuffer);
const arr = new Int8Array(outbuffer);
if (arr.length > 0) {
let tmparr = new Int8Array(1024);
let j = 0;
for (let i = 0; i < arr.byteLength; i++) {
tmparr[j++] = arr[i];
if (((i + 1) % 1024) == 0) {
callback && callback(tmparr);
if (arr.byteLength - i - 1 >= 1024) {
tmparr = new Int8Array(1024);
} else {
tmparr = new Int8Array(arr.byteLength - i - 1);
}
j = 0;
}
if ((i + 1 == arr.byteLength) && ((i + 1) % 1024) != 0) {
callback && callback(tmparr);
}
}
}
};
reader.readAsArrayBuffer(audioData.encodePCM());
audioData.clear();//每次发送完成则清理掉旧数据
};
this.start = function () {
audioInput.connect(recorder);
recorder.connect(context.destination);
}
this.stop = function () {
recorder.disconnect();
}
this.getBlob = function () {
return audioData.encodePCM();
}
this.clear = function () {
audioData.clear();
}
recorder.onaudioprocess = function (e) {
const inputBuffer = e.inputBuffer.getChannelData(0);
audioData.input(inputBuffer);
// sendData();
}
}
export default Recorder;
/**
* 录音组件
*/
// RecordItem.js
import React, { Component } from 'react';
import { Icon } from 'antd';
import { Toast } from 'antd-mobile';
import Recorder from './Recorder';
import './RecordItem.less';
class RecordItem extends Component {
state = {
isRecording: false, // 是否正在录音
}
timer = null; // 判断长按的定时器
handleTouchStart = () => {
this.timer = setTimeout(() => {
this.recorder.start();
this.setState({
isRecording: true
});
}, 300);
}
handleTouchEnd = () => {
if (this.timer) {
clearTimeout(this.timer);
}
this.recorder.stop();
this.setState({
isRecording: false
}, () => {
const { onEnd } = this.props;
onEnd && onEnd(this.recorder.getBlob());
});
}
// 处理录音的回调
handleMsg = (data) => {
const { onProgress } = this.props;
onProgress && onProgress(data);
}
componentDidMount() {
const constraints = { audio: true };
navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
this.recorder = new Recorder(stream, this.handleMsg);
}, err => {
switch (err.message || err.name) {
case 'PERMISSION_DENIED':
case 'PermissionDeniedError':
Toast.info('用户拒绝提供信息。');
break;
case 'NOT_SUPPORTED_ERROR':
case 'NotSupportedError':
Toast.info('浏览器不支持硬件设备。');
break;
case 'MANDATORY_UNSATISFIED_ERROR':
case 'MandatoryUnsatisfiedError':
Toast.info('无法发现指定的硬件设备。');
break;
default:
Toast.info('无法打开麦克风。异常信息:' + (err.code || err.name));
break;
}
});
// this.recorder = new Recorder({
// callback: this.handleMsg
// });
}
render() {
const { isRecording } = this.state;
return (
<div
className={`RecordItem ${isRecording ? 'recording' : ''}`}
onTouchStart={this.handleTouchStart}
onTouchEnd={this.handleTouchEnd}
>
<Icon type="audio" />
</div>
);
}
}
export default RecordItem;
// RecordItem.less
.RecordItem {
color: #333333;
&.recording {
color: #10C0DC;
}
.anticon {
font-size: 1.5rem;
}
}
原文地址:https://www.cnblogs.com/aloneMing/p/12924678.html
- Android6.0蓝牙协议之OPP
- 简单直白教你理解Java中四大引用强引用,软引用,弱引用,虚引用
- ubuntu系统上配置git
- Android源码编译出错No rule to make...
- Android中资源各种引用方式?,@,@*等等
- git撤销修改各种情况
- Android中ContentProvider简介
- 利用Androidstudio开发Java工程图文详解
- 小程序学习笔记分享(含1-tabBar、轮播图和九宫格)
- Android中ViewStub控件分析及使用
- 如何实现微信小程序的滚动加载功能
- 分享微信小程序推送消息步骤
- 实例分享微信小程序项目搭建(下)
- 实例分享微信小程序项目搭建(上)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- python学习笔记(7)——远程主机强迫关闭了一个现有的连接
- 【带你成为pyq最靓的仔】朋友圈九宫格(一)之图片切割篇
- Material Design Compoents 1.1.0
- 【第19期】HTTP请求头referer
- Sentinel流控日志与索引
- Next.js + TypeScript 搭建一个简易的博客系统
- 【redis】02-redis持久化存储以及对象存储
- Kubernetes 集群可视化监控之 Weave Scope 入门
- h5 与原生 app 交互的原理
- 怎么在Openresty中REST?
- 【redis】04-redis 根据监听key的失效事件实现订单超时关闭
- 搭建分布式任务调度平台
- 微信小程序根据线上版本 Source Map 文件定位错误代码
- 全解系列:内存泄漏定位工具LeakCanary!
- 【Java反射】触手可及