123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- import { downloadPCM, downloadWAV, download } from './download/download';
- import { compress, encodePCM, encodeWAV } from './transform/transform';
- import Player from './player/player';
- import Recorder from './recorder/recorder';
- declare let window: any;
- declare let Math: any;
- declare let navigator: any;
- declare let Promise: any;
- // 构造函数参数格式
- interface recorderConfig {
- sampleBits?: number, // 采样位数
- sampleRate?: number, // 采样率
- numChannels?: number, // 声道数
- compiling?: boolean, // 是否边录边播
- }
- class Index extends Recorder {
- private isrecording: boolean = false; // 是否正在录音
- private ispause: boolean = false; // 是否是暂停
- private isplaying: boolean = false; // 是否正在播放
- public onplay: () => void; // 音频播放回调
- public onpauseplay: () => void; // 音频暂停回调
- public onresumeplay: () => void; // 音频恢复播放回调
- public onstopplay: () => void; // 音频停止播放回调
- public onplayend: () => void; // 音频正常播放结束
- /**
- * @param {Object} options 包含以下三个参数:
- * sampleBits,采样位数,一般8,16,默认16
- * sampleRate,采样率,一般 11025、16000、22050、24000、44100、48000,默认为浏览器自带的采样率
- * numChannels,声道,1或2
- */
- constructor(options: recorderConfig = {}) {
- super(options);
- }
- /**
- * 重新修改配置
- *
- * @param {recorderConfig} [options={}]
- * @memberof Recorder
- */
- public setOption(options: recorderConfig = {}) {
- this.setNewOption(options);
- }
- /**
- * Start the recording
- */
- start(): Promise<{}> {
- if (this.isrecording) {
- // 正在录音,则不允许
- return Promise.reject();
- }
- this.isrecording = true;
- return this.startRecord();
- }
- /**
- * Pause the recording
- */
- pause(): void {
- if (this.isrecording && !this.ispause) {
- this.ispause = true;
- // 当前不暂停的时候才可以暂停
- this.pauseRecord();
- }
- }
- /**
- * 继续录音
- */
- resume(): void {
- if (this.isrecording && this.ispause) {
- this.ispause = false;
- this.resumeRecord();
- }
- }
- /**
- * 停止录音
- *
- * @memberof Recorder
- */
- stop(): void {
- if (this.isrecording) {
- this.isrecording = false;
- this.ispause = false;
- this.stopRecord();
- }
- }
- /**
- * 播放录音
- */
- play(): void {
- this.stop();
- // 关闭前一次音频播放
- this.isplaying = true;
- this.onplay && this.onplay();
- Player.addPlayEnd(this.onplayend); // 注册播放完成后的回调事件
- const dataV = this.getWAV();
- if (dataV.byteLength > 44) {
- Player.play(dataV.buffer); // 播放
- }
- }
- /**
- * 获取已经播放了多长时间
- */
- getPlayTime(): number {
- return Player.getPlayTime();
- }
- /**
- * 暂停播放录音
- *
- * @memberof Recorder
- */
- pausePlay(): void {
- if (this.isrecording || !this.isplaying) {
- // 正在录音或没有播放,暂停无效
- return;
- }
- this.isplaying = false;
- this.onpauseplay && this.onpauseplay();
- Player.pausePlay();
- }
- /**
- * 恢复播放录音
- *
- * @memberof Recorder
- */
- resumePlay(): void {
- if (this.isrecording || this.isplaying) {
- // 正在录音或已经播放或没开始播放,恢复无效
- return;
- }
- this.isplaying = true;
- this.onresumeplay && this.onresumeplay();
- Player.resumePlay();
- }
- /**
- * 停止播放
- *
- * @memberof Recorder
- */
- stopPlay(): void {
- if (this.isrecording) {
- // 正在录音,停止录音播放无效
- return;
- }
- this.isplaying = false;
- this.onstopplay && this.onstopplay();
- Player.stopPlay();
- }
- destroy(): Promise<{}> {
- Player.destroyPlay();
- return this.destroyRecord();
- }
- /**
- * 获取当前已经录音的PCM音频数据
- *
- * @returns[DataView]
- * @memberof Recorder
- */
- // getWholeData() {
- // return this.tempPCM;
- // }
- /**
- * 获取余下的新数据,不包括 getNextData 前一次获取的数据
- *
- * @returns [DataView]
- * @memberof Recorder
- */
- // getNextData() {
- // let length = this.tempPCM.length,
- // data = this.tempPCM.slice(this.offset);
- // this.offset = length;
- // return data;
- // }
- /**
- * 获取当前录音的波形数据,
- * 调取频率由外部控制。
- *
- * @memberof Recorder
- */
- getRecordAnalyseData(): any {
- return this.getAnalyseData();
- }
- /**
- * 获取录音播放时的波形数据,
- *
- * @memberof Recorder
- */
- getPlayAnalyseData(): any {
- // 现在录音和播放不允许同时进行,所有复用的录音的analyser节点。
- return Player.getAnalyseData();
- }
- getPCM(): any {
- // 先停止
- this.stop();
- // 获取pcm数据
- let data: any = this.getData();
- // 根据输入输出比例 压缩或扩展
- data = compress(data, this.inputSampleRate, this.outputSampleRate);
- // 按采样位数重新编码
- return encodePCM(data, this.oututSampleBits, this.littleEdian);
- }
- /**
- * 获取PCM格式的blob数据
- *
- * @returns { blob } PCM格式的blob数据
- * @memberof Recorder
- */
- getPCMBlob(): any {
- return new Blob([ this.getPCM() ]);
- }
- /**
- * 下载录音pcm数据
- *
- * @param {string} [name='recorder'] 重命名的名字
- * @memberof Recorder
- */
- downloadPCM(name: string = 'recorder'): void {
- let pcmBlob = this.getPCMBlob();
- downloadPCM(pcmBlob, name);
- }
- /**
- * 获取WAV编码的二进制数据(dataview)
- *
- * @returns {dataview} WAV编码的二进制数据
- * @memberof Recorder
- */
- getWAV(): any {
- let pcmTemp = this.getPCM();
- // PCM增加44字节的头就是WAV格式了
- return encodeWAV(pcmTemp, this.inputSampleRate,
- this.outputSampleRate, this.config.numChannels, this.oututSampleBits, this.littleEdian);;
- }
- /**
- * 获取WAV音频的blob数据
- *
- * @returns { blob } wav格式blob数据
- * @memberof Recorder
- */
- getWAVBlob(): any {
- return new Blob([ this.getWAV() ], { type: 'audio/wav' });
- }
- /**
- * 下载录音的wav数据
- *
- * @param {string} [name='recorder'] 重命名的名字
- * @memberof Recorder
- */
- downloadWAV(name: string = 'recorder'): void {
- let wavBlob = this.getWAVBlob();
- downloadWAV(wavBlob, name);
- }
- /**
- * 通用的下载接口
- */
- download(blob, name: string, type: string): void {
- download(blob, name, type);
- }
- /**
- * 获取左和右声道的数据
- *
- * @returns [DataView]
- */
- getChannelData(): any {
- const all = this.getPCM();
- const length = all.byteLength;
- const littleEdian = this.littleEdian
- const res = { left: null, right: null }
- if (this.config.numChannels === 2) {
- // 双通道,劈开
- const lD = new DataView(new ArrayBuffer(length / 2))
- const rD = new DataView(new ArrayBuffer(length / 2))
- // 双声道,需要拆分下数据
- if (this.config.sampleBits === 16) {
- for (var i = 0; i < length / 2; i += 2) {
- lD.setInt16(i, all.getInt16(i * 2, littleEdian), littleEdian)
- rD.setInt16(i, all.getInt16(i * 2 + 2, littleEdian), littleEdian)
- }
- } else {
- for (var i = 0; i < length / 2; i += 2) {
- lD.setInt8(i, all.getInt8(i * 2))
- rD.setInt8(i, all.getInt8(i * 2 + 1))
- }
- }
- res.left = lD
- res.right = rD
- } else {
- // 单通道
- res.left = all
- }
- return res
- }
- }
- export default Index;
|