123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 |
- import { reactive, ref } from 'vue'
- import { ElMessage } from 'element-plus'
- export default function useAudio(url, playEnd = () => {}) {
- return new Promise((resolve, reject) => {
- const state: any = reactive({
- source: null,
- analyser: null,
- dataArray: null,
- animationId: null,
- pauseTime: 0,
- })
- const volume = ref(0)
- const audioContext = new window.AudioContext()
- let audioDom: any = document.createElement('audio')
- audioDom.setAttribute('src', url)
- audioDom.setAttribute('crossorigin', 'anonymous')
- document.body.appendChild(audioDom)
- // 创建分析器节点
- state.analyser = audioContext.createAnalyser()
- state.analyser.fftSize = 256
- state.dataArray = new Uint8Array(state.analyser.frequencyBinCount)
- // 创建媒体元素源节点
- state.source = audioContext.createMediaElementSource(audioDom)
- // 连接节点:源 -> 分析器 -> 目的地(扬声器)
- state.source.connect(state.analyser)
- state.analyser.connect(audioContext.destination)
- const pause = () => {
- cancelAnimationFrame(state.animationId)
- audioDom.pause()
- volume.value = 0
- }
- const stop = () => {
- pause()
- document.body.removeChild(audioDom)
- audioDom = null
- playEnd()
- }
- audioDom.oncanplay = () => {
- resolve({
- volume,
- play: () => {
- audioDom?.play()
- updateVolume()
- },
- pause,
- stop,
- })
- }
- audioDom.onended = () => {
- stop()
- }
- const updateVolume = () => {
- if (!state.analyser) return
- state.analyser.getByteFrequencyData(state.dataArray)
- // 计算平均音量
- let sum = 0
- for (let i = 0; i < state.dataArray.length; i++) {
- sum += state.dataArray[i]
- }
- const average = sum / state.dataArray.length
- // 将音量映射到0-100范围
- volume.value = Math.min(100, Math.max(0, Math.round(average / 2.55)))
- // 继续动画
- state.animationId = requestAnimationFrame(updateVolume)
- }
- })
- }
|