首页 > 其他分享 >使用audio标签播放pcm音频流

使用audio标签播放pcm音频流

时间:2022-12-02 17:13:44浏览次数:46  
标签:const 音频 pcm bytes offset audio true newoffset view

1   首先我们要获取到pcm流  如果已经获取了  就可以直接对其进行操作 我们这边是没有获取的  使用fetch方法远程请求资源,代码如下

fetch(url, { responseType: 'arrayBuffer', headers: {} }).then((res) => {
        return res.arrayBuffer();
      }).then((arrayBuffer) => {
        console.log(arrayBuffer, '加密')
      })

 这边url 就是远程请求的地址  注意返回类型是arrayBuffer,一种原始的二进制数据流 

2  由于我们的arrayBuffer 是加密的  所以需要先对其解密再进行操作  加密库我们使用的是CryptoJS,解密代码如下

decryptFile(wordArray, secret) {
      const key = CryptoJS.enc.Utf8.parse(CryptoJS.MD5(secret)); // secret就是密钥
      const iv = CryptoJS.enc.Utf8.parse(""); // iv里面的值需要和后端确认
      wordArray = CryptoJS.enc.Base64.stringify(wordArray)
      const decrypt = CryptoJS.AES.decrypt(wordArray, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7  //偏移量  
      })
      return this.wordArrayToArrayBuffer(decrypt).buffer // 注意我们要拿到arrayBuffer 进行操作
    },

  注意这里的第一个参数需要我们构建一下,代码如下:

  

 const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer)

  这里的arrayBuffer 就是我们请求的原始数据,同时附上 上面wordArrayToArrayBuffer函数

    

wordArrayToArrayBuffer(wordArray) {
      const { words } = wordArray
      const { sigBytes } = wordArray
      const u8 = new Uint8Array(sigBytes)
      for (let i = 0; i < sigBytes; i += 1) {
        u8[i] = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
      }
      return u8
    },

  这里我们已经完成了解密  然后将这个流转为audio标签可以播放的格式

   

addWavHeader(samples, sampleRateTmp, sampleBits, channelCount) {
      const dataLength = samples.byteLength;
      /* 新的buffer类,预留44bytes的heaer空间 */
      const buffer = new ArrayBuffer(44 + dataLength);
      /* 转为 Dataview, 利用API来填充字节 */
      const view = new DataView(buffer);
      let offset = 0;
      /* ChunkID, 4 bytes,  资源交换文件标识符 */
      this.writeString(view, offset, 'RIFF'); offset += 4;
      /* ChunkSize, 4 bytes, 下个地址开始到文件尾总字节数,即文件大小-8 */
      view.setUint32(offset, /* 32 */ 36 + dataLength, true); offset += 4;
      /* Format, 4 bytes, WAV文件标志 */
      this.writeString(view, offset, 'WAVE'); offset += 4;
      /* Subchunk1 ID, 4 bytes, 波形格式标志 */
      this.writeString(view, offset, 'fmt '); offset += 4;
      /* Subchunk1 Size, 4 bytes, 过滤字节,一般为 0x10 = 16 */
      view.setUint32(offset, 16, true); offset += 4;
      /* Audio Format, 2 bytes, 格式类别 (PCM形式采样数据) */
      view.setUint16(offset, 1, true); offset += 2;
      /* Num Channels, 2 bytes,  通道数 */
      view.setUint16(offset, channelCount, true); offset += 2;
      /* SampleRate, 4 bytes, 采样率,每秒样本数,表示每个通道的播放速度 */
      view.setUint32(offset, sampleRateTmp, true); offset += 4;
      /* ByteRate, 4 bytes, 波形数据传输率 (每秒平均字节数) 通道数×每秒数据位数×每样本数据位/8 */
      view.setUint32(offset, sampleRateTmp * channelCount * (sampleBits / 8), true); offset += 4;
      /* BlockAlign, 2 bytes, 快数据调整数 采样一次占用字节数 通道数×每样本的数据位数/8 */
      view.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2;
      /* BitsPerSample, 2 bytes, 每样本数据位数 */
      view.setUint16(offset, sampleBits, true); offset += 2;
      /* Subchunk2 ID, 4 bytes, 数据标识符 */
      this.writeString(view, offset, 'data'); offset += 4;
      /* Subchunk2 Size, 4 bytes, 采样数据总数,即数据总大小-44 */
      view.setUint32(offset, dataLength, true); offset += 4;
      if (sampleBits === 16) {
        this.floatTo16BitPCM(view, samples);
      } else if (sampleBits === 8) {
        this.floatTo8BitPCM(view, samples);
      } else {
        this.floatTo32BitPCM(view, samples);
      }
      // return view.buffer
      return new Blob([view], { type: 'audio/wav' });
    },
    writeString(view, offset, string) {
      for (let i = 0; i < string.length; i += 1) {
        view.setUint8(offset + i, string.charCodeAt(i));
      }
    },
    floatTo32BitPCM(output, input) {
      const oinput = new Int32Array(input);
      let newoffset = 44;
      for (let i = 0; i < oinput.length; i += 1, newoffset += 4) {
        output.setInt32(newoffset, oinput[i], true);
      }
    },
    floatTo16BitPCM(output, input) {
      const oinput = new Int16Array(input);
      let newoffset = 44;
      for (let i = 0; i < oinput.length; i += 1, newoffset += 2) {
        output.setInt16(newoffset, oinput[i], true);
      }
    },
    floatTo8BitPCM(output, input) {
      const oinput = new Int8Array(input);
      let newoffset = 44;
      for (let i = 0; i < oinput.length; i += 1, newoffset += 1) {
        output.setInt8(newoffset, oinput[i], true);
      }
    },

  总体来说就是给fem格式的加一个头

 

     最后我们将这个流转为blob类型  这样就可以直接播放了

       

readBlobFile(Blobdata, audioRef) {
      const reader = new FileReader();
      reader.readAsArrayBuffer(Blobdata);
      reader.onload = (e) => {
        const bufer = e.target.result;
        const blob = this.addWavHeader(bufer, 16000, 16, 1);
        console.log(blob, "blob")
        this.srcUrl = window.URL.createObjectURL(blob);
        this.$nextTick(() => {
          this.$refs[audioRef].src = this.srcUrl
          this.$refs[audioRef].load()
        })

        console.log(this.srcUrl, 'readBlobFile')
      };
    },

  

标签:const,音频,pcm,bytes,offset,audio,true,newoffset,view
From: https://www.cnblogs.com/jiuxu/p/16944988.html

相关文章