• 浏览器端将语音转换为URL格式的字符串(base64 位编码)


    我们可以在浏览器端,通过调用 JS 原生的 API,将语音转换为文字,实现语音输入的效果。思路是:

    1. 录制一段音频;
    2. 将音频转换为 URL 格式的字符串(base64 位编码);
    3. 调用讯飞开放接口,将 base64 位编码转换为文本。

    这篇文章实现前两步,将音频转换为 URL 格式的字符串(base64 位编码)。

    这里将会用到于媒体录制相关的诸多 API,先将其列出:

    • MediaDevices 接口提供访问连接媒体输入的设备,如照相机和麦克风,以及屏幕共享等。
    • MediaDevices.getUserMedia() 会提示用户给予使用媒体输入的许可。

    我们将要访问浏览器的麦克风。若浏览器支持 getUserMedia,就可以访问麦克风权限。
    MediaDevices.getUserMedia(),返回一个 Promise 对象,获得麦克风许可后,会 resolve 回调一个 MediaStream 对象。MediaStream 包含音频轨道的输入。

    • MediaRecorder() 构造函数会创建一个对指定的 MediaStream 进行录制的 MediaRecorder 对象。
    • MediaStream 是将要录制的流. 它可以是来自于使用 navigator.mediaDevices.getUserMedia() 创建的流。
    • 实例化的 MediaRecorder 对象,提供媒体录制的接口

    MediaRecorder() 构造函数接受 MediaDevices.getUserMedia() resolve 回调的 MediaStream, 作为将要录制的流。并且可以指定 MIMEType 类型和音频比特率。
    实例化该构造函数后,可以读取录制对象的当前状态,并根据状态选择录取、暂停和停止。
    MediaRecorder.stop() 方法会出发停止录制,同时触发 dataavailable 事件,返回一个存储 Blob 内容的录制数据,之后不再记录

    • Blob() 构造函数返回一个新的 Blob 对象。
    • Blob 对象表示一个不可变、原始数据的类文件对象。
    • File 接口基于Blob,接受 Blob 对象的API也被列在 File 文档中。

    Blob() 构造函数接受 MediaRecorder.ondataavailable() 方法返回的 Blob 类型的录制数据,并指定音频格式。
    实例化该构造函数后,新创建一个不可变、原始数据的类文件对象。

    • URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。
    • 这个新的 URL 对象表示指定的 File 对象或 Blob 对象。

    URL.createObjectURL() 接受一个 Blob 对象,创建一个 DomString,该字符串作为 <audio> 元素的播放地址。

    • FileReader() 构造函数去创建一个新的 FileReader 对象。
    • readAsDataURL() 方法会读取指定的 BlobFile 对象。
    • 读取操作完成的时候,readyState 会变成已完成 DONE,并触发 loadend 事件,同时 result 属性将包含一个 data:URL 格式的字符串(base64 编码)以表示所读取文件的内容。

    实例化 FileReader() 构造函数,新创建一个 FileReader 对象。
    使用 readAsDataURL() 方法,接受一个 Blob 对象,读取完成后,触发 onload 方法,同时 result 属性将包含一个data:URL格式的字符串(base64 编码)

    使用 Angular 将核心代码放置如下:

    QaComponent

    <div id="voiceIcon" class="iconfont icon-voice"  (click)="showVoice = !showVoice"  [title]="showVoice ? '停止' : '录制'"></div>
    
    <!-- 语音录制动画 -->
    <app-voice [show]="showVoice"></app-voice>
    
    showVoice = false; // 录音动画显示隐藏
    
    /**
     * 初始化完组件视图及其子视图之后,获取麦克风权限
     */
    ngAfterViewInit(): void {
      this.mediaRecorder();
    }
    
    /**
     * 将语音文件转换为 base64 的字符串编码
     */
    mediaRecorder() {
      const voiceIcon = document.getElementById('voiceIcon') as HTMLDivElement;
      // 在用户通过提示允许的情况下,打开系统上的麦克风
      if (navigator.mediaDevices.getUserMedia) {
        let chunks = [];
        const constraints = { audio: true }; // 指定请求的媒体类型
        navigator.mediaDevices.getUserMedia(constraints).then(
          stream => {
            // 成功后会resolve回调一个 MediaStream 对象,包含音频轨道的输入。
            console.log('授权成功!');
    
            const options = {
              audioBitsPerSecond: 22050, // 音频的比特率
            };
            // MediaRecorder 构造函数实例化的 mediaRecorder 对象是用于媒体录制的接口
            // @ts-ignore
            const mediaRecorder = new MediaRecorder(stream, options);
    
            voiceIcon.onclick = () => {
              // 录制对象 MediaRecorder  的当前状态(闲置中 inactive,录制中 recording 或者暂停 paused)
              if (mediaRecorder.state === 'recording') {
                // 停止录制. 同时触发dataavailable事件,之后不再记录
                mediaRecorder.stop();
                console.log('录音结束');
              } else {
                // 开始录制媒体
                mediaRecorder.start();
                console.log('录音中...');
              }
              console.log('录音器状态:', mediaRecorder.state);
            };
    
            mediaRecorder.ondataavailable = (e: { data: any }) => {
              // 返回一个存储Blob内容的录制数据,在事件的 data 属性中会提供一个可用的 Blob 对象
              chunks.push(e.data);
            };
    
            mediaRecorder.onstop = () => {
              // MIME类型 为 audio/wav
              // 实例化 Blob 构造函数,返回的 blob 对象表示一个不可变、原始数据的类文件对象
              const blob = new Blob(chunks, { type: 'audio/wav; codecs=opus' });
              chunks = [];
    
              // 如果作为音频播放,audioURL 是 <audio>元素的地址
              const audioURL = window.URL.createObjectURL(blob);
    
              const reader = new FileReader();
              // 取指定的 Blob 或 File 对象,读取操作完成的时候,readyState 会变成已完成DONE
              reader.readAsDataURL(blob);
              reader.onload = () => {
                // result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容
                console.log(reader.result); // reader.result 为 base64 字符串编码
              };
            };
          },
          () => {
            console.error('授权失败!');
          },
        );
      } else {
        console.error('浏览器不支持 getUserMedia');
      }
    }
    

    VoiceComponent

    <div class="voice-container" *ngIf="_show">
     <i class="iconfont icon-voice"></i>
     <div class="circle"></div>
    </div>
    
    .voice-container {
      position: absolute;
      top: 50%;
      left: 50%;
      z-index: 1;
      transform: translate(-50%, -50%);
    
      .icon-voice {
        position: absolute;
        top: 50%;
        left: 50%;
        z-index: 4;
        display: block;
        color: #fff;
        font-size: 24px;
        transform: translate(-50%, -50%);
      }
    
      .audio {
        position: relative;
        top: 50%;
        left: 50%;
        z-index: 4;
        transform: translate(-50%, -50%);
      }
    
      .circle {
        position: absolute;
        top: 50%;
        left: 50%;
        z-index: 3;
        border-radius: 50%;
        transform: translate(-50%, -50%);
        animation: gradient 1s infinite;
      }
    
      @keyframes gradient {
        from {
           70px;
          height: 70px;
          background-color: rgb(24, 144, 255);
        }
        to {
           160px;
          height: 160px;
          background-color: rgba(24, 144, 255, 0.3);
        }
      }
    }
    
    public _show: boolean;
    @Input()
    set show(val: boolean) {
      this._show = val;
    }
    get show() {
      return this._show;
    }
    
  • 相关阅读:
    oracle连接命令
    oracle Wrap加密
    oracle copy
    oracle loader
    oracle一些常见的问题
    python-cn(华蟒用户组,CPyUG 邮件列表)
    代理服务器验证工具
    多线程中的信号/槽
    【多线程】python界面阻塞,白屏,not responding解决的简单例子
    vi命令
  • 原文地址:https://www.cnblogs.com/xinjie-just/p/12228039.html
Copyright © 2020-2023  润新知