audio标签和audioContext播放

使用audio标签播放音频

  • 使用audio标签播放音频,加载音频文件可以通过直接在标签上的src写好
  • 通过audio.setAttribute('src', path)
<audio id='audio' src='./test.mp3'></audio>
<button onclick='play()'>play</button>
<button onclick='pause()'>pause</button>
var audio = document.getElementById('audio')
function play() {
  audio.play()
}

function pause() {
  audio.pause()
}

限制:Chrome不支持自动播放音频,规定用户与页面交互之后,比如点击页面任何地方之后才能播放。

监听音频播放实现录音效果

使用recordRTC去监听媒体流

  const config = {
      type: 'audio', // video,数据类型
      mimeType: "audio/webm;codecs=opus", // "video/webm;codecs=h264",音视频格式
      getNativeBlob: true, // 获取到的数据类型是否是Blob
      timeSlice: 20, // 多少毫秒取一次数据
      recorderType: RecordRTC.MediaStreamRecorder, // recorder类型
      ondataavailable: async (blob) => {
        const data = await blob.arrayBuffer() // blob转buffer
      }
  }
  const audioStream = audio.captureStream(); //根据dom获取媒体流
  const recordrtc = RecordRTC(audioStream, config);
  recordrtc.startRecording(); // 开始录制
  recordrtc.stopRecording(); // 结束录制

使用audioContext对象播放音频

使用audioContext播放,需要理解audioContext.createBufferSource()
我们可以将音频看成竹子,一段完整的视频,由一个又一个节点相连而成
audioConte上有一个const source = ctx.createBufferSource()方法,用于生成音频头部节点
audioContext有一个属性叫destination,标识音频结束节点
source上的一个方法source.connect(),可以对头尾进行链接source.connect(ctx.destination)
接下来,头尾连接,就成为一根完整的竹子,也就是一个完整的音频。

<button onclick="playAudio()">playAudio</button>
<button onclick="resumeAudio()">resumeAudio</button>
<button onclick="stopAudio()">stopAudio</button>
<script>
  var ctx = new (window.AudioContext || window.webkitAudioContext())();
  let source = ctx.createBufferSource(); // 创建音频源头姐点

  // 播放
  async function playAudio() {
    const audioBuffer = await loadAudio();
    playSound(audioBuffer);
  }
  // 暂停
  async function resumeAudio() {
    if (ctx.state === "running") {
      ctx.suspend();
    } else if (ctx.state === "suspended") {
      ctx.resume();
    }
  }
  // 停止
  async function stopAudio() {
    source.stop();
  }
  async function loadAudio() {
    const audioUrl = "love105.mp3";
    const res = await fetch(audioUrl);
    const arrayBuffer = await res.arrayBuffer(); // byte array字节数组
    const audioBuffer = await ctx.decodeAudioData(arrayBuffer, function(
      decodeData
    ) {
      return decodeData;
    });
    return audioBuffer;
  }
  async function playSound(audioBuffer) {
    source.buffer = audioBuffer; // 设置数据
    source.loop = true; //设置,循环播放
    source.connect(ctx.destination); // 头尾相连
    // 可以对音频做任何控制
    source.start(0); //立即播放
  }
</script>

更新,又遇到了几个新的可以播放音频文件的方法。
会延伸出其他方法的过程是在项目中,遇到了需要播放本地音频文件的需求,然后发现因为浏览器的安全协议,不允许操作绝对路径的文件。报错是这个:
Failed to load because no supported source was found.
然后我就去试验上面的几种方法发现都不行。又去搞了其他的,主要有以下几种:

使用Node.js

本来是想去找一个线上的插件来播放,但是我实在没有找到怎么下载,然后就想自己写了,主要过程在下面(我是用的electron+react):

// 首先在render中,即react中

const audioRef = useRef()

const play = () => {
  const filePath = '本地音频文件的绝对路径'
  const data = electron?.getLocalAudioData({filePath: filePath}) // 假设我已经取到了数据数组
  const url = window.URL.createObjectURL(new Blob(data)) // data返回的是一个数组,里面装的是一个个blob数据, 然后使用createObjectURL方法是根据数据产生一个数据地址,因为本身audio标签拿到一个url地址也需要去解析数据,但是这种可以直接将数据灌进去
  audioRef.current.src = url
  audioRef.current.load()
  audioRef.current.play()
}

const pause = () => {
  audioRef.current.pause()
}

<audio ref={audioRef} />
// 然后在electron中的配置
getLocalAudioData: (params) => ipcRenderer.invoke('get-local-audio-data', params)

ipcMain.handle('get-local-audio-data',async (e, params) => {
  const {filePath} = params
  let datas = []
  return new Promise((resolve, reject) => {
     const fileStream = fs.createReadStream(filePath) // 根据文件地址创建读取流
     fileStream.on('data', (data) => {
      datas.push(data) // 文件读取出来的就是blob类型,blob就是二进制
     })
     fileStream.on('end', () => {
      resolve(datas) // 读取完了就返回数据
     })
     fileStream.on('error', () => {
       resolve(false) // 返回false,如果是reject的话外面收不到的
     })    

   })

})

大概过程就是,node读取文件数据,将文件数据通过window.URL.createObjectURL的方式创建一个新的URL,然后来播放本地音频文件。同理,视频文件也可以这样子做

ffmpeg播放

posted @ 2023-03-14 12:53  卿六  阅读(1924)  评论(0编辑  收藏  举报