zoukankan      html  css  js  c++  java
  • 录音 voice record

    参考 : 

    http://air.ghost.io/recording-to-an-audio-file-using-html5-and-js/ (html5 基础)

    https://github.com/muaz-khan/RecordRTC

    https://github.com/webpack-contrib/worker-loader

    https://github.com/webpack-contrib/file-loader

    https://github.com/muaz-khan/RecordRTC/issues/31 (wav 太大的解决方案)

    https://github.com/muaz-khan/Ffmpeg.js/blob/master/wav-to-ogg.html#L209 ( ftmpeg wav to ogg 压缩方案 )

    http://audior.ec/blog/recording-mp3-using-only-html5-and-javascript-recordmp3-js/ (wav to mp3 压缩方案, 超小, 声音也差.., 可以使用 lamejs 比较新)

    使用插件 

    npm install recordrtc
    npm install --save-dev file-loader
    npm install --save-dev worker-loader

    要使用 file,worker loading 需要在 tsconfig.app.json 加上 "node"
      "compilerOptions": {"types": [
          "node"
        ]
      },
    
    
      import * as RecordRTC from 'recordrtc';
     
    startRecord() {
      navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
        let recordRTC = RecordRTC(stream, {
          type: 'audio',
          recorderType: RecordRTC.StereoAudioRecorder,
          disableLogs: true 
          //leftChannel: true,
          //numberOfAudioChannels: 1 // or leftChannel:true
        });
        recordRTC.startRecording();
        this.recordRTC = recordRTC;
        this.stream = stream;
      }).catch(() => {
        console.log('user no allow');
      });
    }

    通过 html5 的 navigator.mediaDevices.getUserMedia 获取用户的 permission, 然后就可以获取到声音了

    通过 RecordRTC 来做录制. 如果是要 to mp3 的话, 可以选择单声道 (不过我试过 to mp3 效果声音效果不好, 所以最好用了 .ogg)

     stop() {
        let recordRTC = this.recordRTC;
        recordRTC.stopRecording(() => {    
          // 关闭 html5 navigator.mediaDevices.getUserMedia
          var track = this.stream.getTracks()[0]; // 0 是因为我们只有一个 track, 是可以 track 2 个的, 声音和影像
          track.stop();
    
          // ff 可以 skip 掉 fileReader, 直接拿 recordRTC.blob new File 也可以, 因为 ff 返回的就是 ogg 了 
          // 下面是针对 chrome 返回的是 wav, 很大, 所以使用 ffmpeg 压缩去 ogg 
          let fileReader = new FileReader();
    
          fileReader.onload = () => {
            recordRTC.clearRecordedData(); // reader 读出来后就可以释放 recordRTC 了. 
    
            //压缩是很慢的, 所以要另开一个线程
            var WorkerConstructor = require("worker-loader!./worker2.js"); 
            var worker = new WorkerConstructor();
    
            worker.onmessage = (e) => {
              var result = e.data[0];
              // edge 不可以跑哦, 只有 chrome and ff ok 
              var blob = new File([result.data], 'whatever.ogg', {
                type: 'audio/ogg'
              });
              
              let formData = new FormData();
              formData.append('uploadFile', blob, 'whatever.ogg');
    
              // 上传
              this.http.post('/api/uploadFile', formData).subscribe(() => {
                console.log('done');
              });
    
              // 做成 audio 
              let audio = new Audio();
              audio.controls = true;
              let url = window.URL.createObjectURL(blob);
              
              audio.src = url;
              let recordMp3Container = document.getElementById('recordmp3-container');
              recordMp3Container.appendChild(audio);
              audio.play();
    
              // 关闭 worker 
              worker.terminate(); 
            };
        
            worker.postMessage(fileReader.result);
          };
    
          fileReader.readAsArrayBuffer(recordRTC.blob); 
        });
      }

    worker2.js 

    let url = require("file-loader!./ffmpeg_asm.js");  
    
    self.importScripts(url);
    
    let print = () => { };
    self.onmessage = (event) => {
        let blob = event.data;
        let result = ffmpeg_run({
            print: print,
            printErr: print,
            files: [
                {
                    data: new Uint8Array(blob),
                    name: "whatever.wav"
                }
            ],
            arguments: '-i whatever.wav -c:a vorbis -b:a 4800k -strict experimental output.ogg'.split(' ')
        });
        self.postMessage(result);
    };

    关键就是调用了 ffmpeg_run

    https://archive.org/download/ffmpeg_asm/ffmpeg_asm.js 

    这个转换器 18mb 非常大哦. 不过只要下载一次, 所以 ok 啦. 

    wav to mp3 

    步骤和上面一下, 使用单声道. 

    然后 worker 用下面这个 

    //var url = require("file-loader!./lame.all.js");
    var url = require("file-loader!lamejs/lame.all.js");  
    
    self.importScripts(url);
    
    self.onmessage = function (e) {
        let stream = e.data.stream;
        let streamArray = new Int16Array(stream);
        streamArray = streamArray.slice(50); //去掉一开始的杂音
        let buffer = [];
        let mp3encoder = new lamejs.Mp3Encoder(1, 44100, 128);
    
        let mp3Data = mp3encoder.encodeBuffer(streamArray);
        buffer.push(mp3Data);
        mp3Data = mp3encoder.flush(); //获取最后一个 part
        buffer.push(mp3Data);
        let blob = new Blob(buffer, { type: 'audio/mp3' });
        var workerResult = {
            stream: blob
        };
        self.postMessage(workerResult);
    }

    调用 lamejs 去压缩.

    最后想说的是... RecordRTC 这个 plugin 是使用原生 MediaRecorder 接口来实现的

    MediaRecorder 只有 chrome and firefox 支持.  chrome 输出的格式是 webm, firefox 则是 ogg, RecordRTC 做了些修改输出的是 wav 

    以上 3 种格式 ios safari 都不支持, 它只支持 mp3... 伤感...

    recordRTC

    import { HttpClient } from '@angular/common/http';
    import { ChangeDetectionStrategy, Component } from '@angular/core';
    import * as RecordRTC from 'recordrtc';
    
    
    declare let MediaRecorder: any;
    
    function invokeSaveAsDialog(file, fileName) {
      if (!file) {
        throw 'Blob object is required.';
      }
    
      if (!file.type) {
        try {
          file.type = 'video/webm';
        } catch (e) { }
      }
    
      var fileExtension = (file.type || 'video/webm').split('/')[1];
    
      if (fileName && fileName.indexOf('.') !== -1) {
        var splitted = fileName.split('.');
        fileName = splitted[0];
        fileExtension = splitted[1];
      }
    
      var fileFullName = (fileName || (Math.round(Math.random() * 9999999999) + 888888888)) + '.' + fileExtension;
    
      if (typeof navigator.msSaveOrOpenBlob !== 'undefined') {
        return navigator.msSaveOrOpenBlob(file, fileFullName);
      } else if (typeof navigator.msSaveBlob !== 'undefined') {
        return navigator.msSaveBlob(file, fileFullName);
      }
    
      var hyperlink = document.createElement('a');
      hyperlink.href = URL.createObjectURL(file);
      hyperlink.download = fileFullName;
    
      (document.body || document.documentElement).appendChild(hyperlink);
    
      if (typeof hyperlink.click === 'function') {
        hyperlink.click();
      } else {
        hyperlink.target = '_blank';
        hyperlink.dispatchEvent(new MouseEvent('click', {
          view: window,
          bubbles: true,
          cancelable: true
        }));
      }
    
      URL.revokeObjectURL(hyperlink.href);
    }
    let mp3 = true;
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css'],
      changeDetection: ChangeDetectionStrategy.OnPush
    })
    export class AppComponent {
    
      constructor(
        private http: HttpClient
      ) { }
      title = 'app';
    
      recordRTC: any;
    
      stop() {
        let recordRTC = this.recordRTC;
        recordRTC.stopRecording(() => {
          // 关闭 html5 navigator.mediaDevices.getUserMedia
          var track = this.stream.getTracks()[0]; // 0 是因为我们只有一个 track, 是可以 track 2 个的, 声音和影像
          track.stop();
    
          // ff 可以 skip 掉 fileReader, 直接拿 recordRTC.blob new File 也可以, 因为 ff 返回的就是 ogg 了 
          // 下面是针对 chrome 返回的是 wav, 很大, 所以使用 ffmpeg 压缩去 ogg 
          let fileReader = new FileReader();
    
          fileReader.onload = () => {
            recordRTC.clearRecordedData(); // reader 读出来后就可以释放 recordRTC 了. 
    
            if (mp3) {
              //压缩是很慢的, 所以要另开一个线程        
              var WorkerConstructor = require("worker-loader!./worker.js");
              var worker = new WorkerConstructor();
            }
            else {
              //压缩是很慢的, 所以要另开一个线程        
              var WorkerConstructor = require("worker-loader!./worker2.js");
              var worker = new WorkerConstructor();
            }
    
            worker.onmessage = (e) => {
    
              if (mp3) {
                console.log(e);
                var result = e.data.stream;        
                invokeSaveAsDialog(result, 'output.mp3');
                // recordRTC.save('dadad');
              }
              else {
                var result = e.data[0];
                // edge 不可以跑哦, 只有 chrome and ff ok 
                var blob = new File([result.data], 'output.ogg', {
                  type: 'audio/ogg'
                });
    
                let formData = new FormData();
                formData.append('uploadFile', blob, 'output.ogg');
    
                // 上传
                // this.http.post('/api/uploadFile', formData).subscribe(() => {
                //   console.log('done');
                // });
    
                invokeSaveAsDialog(blob, 'output.ogg');
                // 做成 audio 
                let audio = new Audio();
                audio.controls = true;
                let url = window.URL.createObjectURL(blob);
    
                audio.src = url;
                let recordMp3Container = document.getElementById('recordmp3-container');
                recordMp3Container.appendChild(audio);
                audio.play();
    
                // 关闭 worker 
                worker.terminate();
              }
            };
    
            worker.postMessage(fileReader.result);
          };
    
          fileReader.readAsArrayBuffer(recordRTC.blob);
        });
      }
    
      stream: any
    
      go() {
    
        navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
    
          let obj = {
            type: 'audio',
            recorderType: RecordRTC.StereoAudioRecorder,
            disableLogs: true,
            // numberOfAudioChannels: 1 // or leftChannel:true
          }
          if(mp3) obj['leftChannel'] = true;
     
          let recordRTC = RecordRTC(stream,obj);
          recordRTC.startRecording();
          this.recordRTC = recordRTC;
          this.stream = stream;
        }).catch(() => {
          console.log('user no allow');
        });
      }
    }
    View Code

    mp3

    //var url = require("file-loader!./lame.all.js");
    var url = require("file-loader!lamejs/lame.all.js");
    
    self.importScripts(url);
    
    self.onmessage = function (e) {
        let stream = e.data;
        let streamArray = new Int16Array(stream);
        streamArray = streamArray.slice(50); //去掉一开始的杂音
        let buffer = [];
        let mp3encoder = new lamejs.Mp3Encoder(1, 44100, 128);
    
        let mp3Data = mp3encoder.encodeBuffer(streamArray);
        buffer.push(mp3Data);
        mp3Data = mp3encoder.flush(); //获取最后一个 part
        buffer.push(mp3Data);
        let blob = new Blob(buffer, { type: 'audio/mp3' });
        var workerResult = {
            stream: blob
        };
        self.postMessage(workerResult);
    }
    View Code

    ogg

    let url = require("file-loader!./ffmpeg_asm.js");
    
    self.importScripts(url);
    
    let print = (text) => {
        console.log(text);
     };
    self.onmessage = (event) => {
        console.log('worker e ', event);
        console.log('worker e.data ', event.data);
        let blob = event.data;
        let result = ffmpeg_run({
            print: print,
            printErr: print,
            files: [
                {
                    data: new Uint8Array(blob),
                    name: "whatever.wav"
                }
            ],
            arguments: '-i whatever.wav -c:a vorbis -b:a 4800k -strict experimental output.ogg'.split(' ')
        });
        self.postMessage(result);
    };
    View Code

    .



  • 相关阅读:
    错误解决mysql
    (一)熟悉执行流程——基于ThinkPHP3.2的内容管理框架OneThink学习
    版权控制之zend guard 6.0使用教程
    IP进制站群原理
    多线程更新已排序的Datagridview数据,造成数据错位
    压缩html 减小存储空间
    DataGridView导入导出excel
    软件下载目录
    java反射
    JTA
  • 原文地址:https://www.cnblogs.com/keatkeat/p/7497227.html
Copyright © 2011-2022 走看看