• JS实时获取录音数据并播放


    一 原生拉起录音授权,实时获取音频的返回的Float32arry数据

    // 声明获取数据的数组

    var getPCMarrayBuffer = []

     // 初始化浏览器录音

      recorderInit() {

        navigator.getUserMedia =

          navigator.getUserMedia ||

          navigator.webkitGetUserMedia ||

          navigator.mozGetUserMedia ||

          navigator.msGetUserMedia

       

        // 创建音频环境

        try {

          this.audioContext = new (window.AudioContext || window.webkitAudioContext)()

          this.audioContext.resume()

          if (!this.audioContext) {

            alert('浏览器不支持webAudioApi相关接口')

            return

          }

        } catch (e) {

          if (!this.audioContext) {

            alert('浏览器不支持webAudioApi相关接口')

            return

          }

        }

        // 获取浏览器录音权限

        if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {

          navigator.mediaDevices

            .getUserMedia({

              audio: {

                volume: 1.0,

              },

              video: false,

            })

            .then(stream => {

              getMediaSuccess(stream)

            })

            .catch(e => {

              getMediaFail(e)

            })

        } else if (navigator.getUserMedia) {

          navigator.getUserMedia(

            {

              audio: {

                volume: 1.0,

              },

              video: false,

            },

            stream => {

              getMediaSuccess(stream)

            },

            function(e) {

              getMediaFail(e)

            }

          )

        } else {

          if (navigator.userAgent.toLowerCase().match(/chrome/) && location.origin.indexOf('https://') < 0) {

            alert('chrome下获取浏览器录音功能,因为安全性问题,需要在localhost或127.0.0.1或https下才能获取权限')

          } else {

            alert('无法获取浏览器录音功能,请升级浏览器或使用chrome')

          }

          this.audioContext && this.audioContext.close()

          return

        }

        // 获取浏览器录音权限成功的回调

        let getMediaSuccess = stream => {

          // 创建一个用于通过JavaScript直接处理音频

          this.scriptProcessor = this.audioContext.createScriptProcessor(0, 1, 1)

          this.scriptProcessor.onaudioprocess = e => {

            // 去处理音频数据

            getPCMarrayBuffer.push(e.inputBuffer.getChannelData(0).slice(0))

          }

          // 创建一个新的MediaStreamAudioSourceNode 对象,使来自MediaStream的音频可以被播放和操作

          this.mediaSource = this.audioContext.createMediaStreamSource(stream)

          // 连接

          this.mediaSource.connect(this.scriptProcessor)

          this.scriptProcessor.connect(this.audioContext.destination)

        }

        let getMediaFail = (e) => {

          alert('请求录音权限失败,打开权限再试~')

          this.audioContext && this.audioContext.close()

          this.audioContext = undefined

        }

      }

     二 新建lamejs,并引入;下载方式

    npm install lamejs

    import lamejs, { Mp3Enc } from 'lamejs'

    /**

     * 音频转换

     */

    export class AudioConvert {

      /**

       * 录音获得的 Float32Array 的数组转换成 Mp3 格式的 Blob 对象

       * @param data

       */

      static float32ArrayToMp3(data: Float32Array[]): Blob {

        const audioData = AudioConvert.mergeArray(data)

        const int16Buffer = AudioConvert.floatArray2Int16(audioData)

        return AudioConvert.encodeMono(1, 44100, int16Buffer)

      }

      /**

       * 合并单个声道的多个片段

       * @param list

       */

      private static mergeArray(list: Float32Array[]) {

        const length = list.length * list[0].length

        let data = new Float32Array(length)

        let offset = 0

        for (let i = 0; i < list.length; i++) {

          console.log(i)

          data.set(list[i], offset)

          offset += list[i].length

        }

        return data

      }

      private static floatArray2Int16(floatBuffer: Float32Array) {

        const int16Buffer = new Int16Array(floatBuffer.length)

        for (let i = 0, len = floatBuffer.length; i < len; i++) {

          if (floatBuffer[i] < 0) {

            int16Buffer[i] = 0x8000 * floatBuffer[i]

          } else {

            int16Buffer[i] = 0x7fff * floatBuffer[i]

          }

        }

        return int16Buffer

      }

      private static encodeMono(channels: number, sampleRate: number, samples: Int16Array) {

        const buffer = []

        const mp3enc: Mp3Enc = new lamejs.Mp3Encoder(channels, sampleRate, 128)

        let remaining = samples.length

        const maxSamples = 1152

        for (let i = 0; remaining >= maxSamples; i += maxSamples) {

          const mono = samples.subarray(i, i + maxSamples)

          const mp3buf = mp3enc.encodeBuffer(mono)

          if (mp3buf.length > 0) {

            buffer.push(new Int8Array(mp3buf))

          }

          remaining -= maxSamples

        }

        const d = mp3enc.flush()

        if (d.length > 0) {

          buffer.push(new Int8Array(d))

        }

        // console.log('done encoding, size=', buffer.length)

        return new Blob(buffer, { type: 'audio/mp3' })

      }

    }

    三 调用float32ArrayToMp3方法,录音获得的 Float32Array 的数组转换成 Mp3 格式的 Blob 对象;并播放

    let blob = float32ArrayToMp3(getPCMarrayBuffer);

      let blobUrl2 = window.URL.createObjectURL(blob)

      document.getElementById("audio").src = blobUrl2;

      setTimeout(()=>{

        document.getElementById("audio").play()

      },100)

     

  • 相关阅读:
    猫狗图像数据集上的深度学习模型性能对比
    基于 Redisson 和 Kafka 的延迟队列设计方案
    命名空间namespace
    java毕业设计游戏社区设计Mybatis+系统+数据库+调试部署
    S32K的JLINK与PE接线方法与刷程序失败问题
    时序数据库选型
    如何提高MES系统的落地成功率?
    久其报表软件基本操作指引
    vscode - 初使用go的常用快捷键及常见错误
    Java 开发必知的规范文档
  • 原文地址:https://blog.csdn.net/qq_40063198/article/details/132812454