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播放
行百里者半九十