The voice browser into a string of URL format (Base64 encoded bits)

We can in the browser, by calling JSnative API, converts speech to text, to achieve the effect of the voice input. The idea is:

  1. An audio recording;
  2. To convert the audio URLformat string ( base64bit encoding);
  3. Call iFlyTek open interface, the base64transition bit encoded as text.

This article realize the first two steps, the audio is converted to URLthe format string ( base64bit coding).

Here it will be used in many media recording related APIlists it first:

  • MediaDevices( MediaDevicesUse )

    • MediaDevices Interface provides access to the media input device is connected, such as a camera and a microphone, and a screen sharing.
    • MediaDevices.getUserMedia() Users will be prompted to give permission to use the media input.

We will want to visit microphone browser. If the browser supports getUserMedia, you can access the microphone permission.
MediaDevices.getUserMedia()Return to a Promisesubject, get a microphone permission, will be resolvea callback MediaStreamobject. MediaStreamIt contains the input audio tracks.

  • MediaRecorder( MediaRecorderUse )

    • MediaRecorder()The constructor creates a the specified MediaStreamrecord of MediaRecorderthe object.
    • MediaStreamIs to be recorded stream. It can be derived from the use of navigator.mediaDevices.getUserMedia()stream created.
    • Instantiated MediaRecorderobject that provides an interface recording media

MediaRecorder()The constructor accepts MediaDevices.getUserMedia() resolvecallbacks MediaStream, it will be recorded as a stream. And may specify MIMETypethe type and the audio bit rate.
The constructor is instantiated, the object can read the current state of the recording, and select the state of admission, pause, and stop.
MediaRecorder.stop()Starting method will stop the recording, while the trigger dataavailableevent, returns a storage Blobcontents of recorded data, after which no record

  • Blob( BlobUse )

    • Blob() Constructor returns a new Blob object.
    • Blob It represents an immutable objects, the object class of the original data file.
    • FileInterface is based on Blobaccepting Blobthe object API also listed in Filethe document.

Blob()Constructor takes MediaRecorder.ondataavailable()method returns Blobthe type of recorded data, and specify the audio format.
After instantiating the constructor, creates a new immutable, the object class of the original data file.

  • URL.createObjectURL()( URL.createObjectURL()Use )

    • URL.createObjectURL()It creates a static method DOMString, which contains a URL object parameters given representation.
    • This new URLobject representing the specified Fileobject or Blobobjects.

URL.createObjectURL()Accepts a Blobobject, creating a DomStringthe string as <audio>playing address elements.

  • FileReader( FileReaderUse )

    • FileReader()Constructor to create a new FileReaderobject.
    • readAsDataURL()Reads the specified method Blobor Fileobject.
    • When the read operation is completed, readyStateit will become a has been completed DONE, and trigger loadendevents, while the result property will contain a data:URLformat string ( base64coding) to represent the contents of the file read.

Examples of the FileReader()constructor, create a new FileReaderobject.
Using the readAsDataURL()method, a receiving Blobobject after reading is completed, trigger onloadmethod, while the resultproperty will contain a data: URL format string ( base64code)

Use Angularplacing the core code is as follows:

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 {
      width: 70px;
      height: 70px;
      background-color: rgb(24, 144, 255);
    }
    to {
      width: 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;
}

Guess you like

Origin www.cnblogs.com/xinjie-just/p/12228039.html