php 声波图,绘制声波图(获取音频回调)

本文介绍了如何在纯音频连麦场景中,利用SDK提供的音频回调API,如getCurrentTimeDomainData、getCurrentFrequencyData和onAudioBuffer,来获取和分析音频数据。通过获取时域数据并绘制声波图,展示了在用户发言时高亮麦克风图标的功能。文章提供了一个简单的canvas绘制声波图的实现,并强调了不同音频API的适用场景。
摘要由CSDN通过智能技术生成

在纯音频连麦的过程中,我们经常有这种需求,展示当前是谁在发言,比如当某人说话时就在他的麦克风图标上做高亮处理。为了实现这种需求,我们就需要实时地去获取一个媒体流中正在播放的音频数据。在我们的场景中,这种设计可能显得有些多余,但我们仅仅是为了演示这个功能,所以就来绘制一个实时的声波图吧。

在绘制之前,我想先介绍一下我们 SDK 提供的和音频回调相关的 API,它们分别是:

getCurrentTimeDomainData 获取当前音频的时域数据

getCurrentFrequencyData 获取当前音频的频域数据

onAudioBuffer 获取音频 PCM 数据

这 3 个方法的详细说明可以参见 stream 对象。这里我们主要讨论这 3 种音频采集方法的区别,以及在什么情况下使用哪种方法。

我们知道,音频数据是根据采样率的大小在一个数组里按时间顺序填充的采样数据,播放音频时,也会时序地将这个数组中的数据按批次取出并送入声卡中,声卡中正在处理的那一批音频数据,就是我们在那一刻听到的声音。所以这里的第一个方法 getCurrentTimeDomainData,就是实时地去获取当前正在处理的音频数据(实际上这并不是声卡当前正在处理的数据,只是尽量精确的一个离当前播放 buffer 最近的范围为 2048 长度的音频)。不过这里要注意,我们不能通过不断地调用这个方法来收集音频的原始数据,这个方法仅用于一些实时的音频分析和处理(比如我们绘制声波图),如果想要收集音频的原始数据,使用我们的第三个方法 onAudioBuffer,这个函数的返回不能保证实时性,但是会根据播放的进度不断地将之前用于播放的音频数据回调回来。好了,这样我们还剩下最后一个方法没有介绍,其实很简单,第二个方法 getCurrentFrequencyData 就是将当前的时序音频数据做了一次 STFT 变换得到的频域数据,一般可用用来绘制频谱图,或者用来判断某个频段是否有声音(是否有人说话)。

介绍完了我们 SDK 提供的方法,回到我们的场景,这里需要用到的其实就是获取当前的时域数据(getCurrentTimeDomainData) 这个方法。下面看代码吧,首先在 room.html 里创建 2 个 canvas 对象用于绘制我们的声波图。

...

...

在 room.css 中添加相应的 css,注意这里我们固定了 canvas 的宽高,因为 canvas 跟随窗口动态宽高太过复杂,这里就不赘述了。

/* css/room.css */

canvas {

position: absolute;

top: 0;

left: 0;

}

有了 canvas 之后,就可以开始绘制了,绘制的过程设计到本地音频的绘制和远端音频的绘制,所以我们还是先将绘制操作抽成一个公共的函数,在 room.js 一开始加入如下代码。

// js/room.js

// 绘制声波图,stream 为需要实时绘制的媒体流对象

// ctx 为 canvas 的 context 对象,用来区分画在哪个 canvas 上

function drawAudioWave(stream, ctx) {

// 如果没有流或者流被释放了(远端取消发布等情况)就直接返回

if (!stream || stream.isDestoryed) {

return;

}

// 获取当前实时的时域数据

const timeData = stream.getCurrentTimeDomainData();

// 以下为 canvas 相关的绘制代码

const width = ctx.canvas.width;

const height = ctx.canvas.height;

ctx.fillStyle = "#000";

ctx.strokeStyle = "#fff";

ctx.lineWidth = 2;

ctx.fillRect(0, 0, width, height);

ctx.beginPath();

for (let i = 0; i < width; i += 1) {

const dataIndex = Math.round(i * (timeData.length / width));

const data = Math.round(timeData[dataIndex] * (height / 255.0));

if (i === 0) {

ctx.moveTo(i, data);

} else {

ctx.lineTo(i, data);

}

}

ctx.stroke();

// 调用 requestAnimationFrame 逐帧更新

requestAnimationFrame(() => drawAudioWave(stream, ctx));

}

有了绘制函数,接下来就在相应的地方调用它吧

// js/room.js

function subscribeUser(myRTC, user) {

if (!user.published) {

return;

}

myRTC.subscribe(user.userId).then(remoteStream => {

const remotePlayer = document.getElementById('remoteplayer');

remoteStream.play(remotePlayer);

// 修改订阅函数,如果订阅的目标流没有开启视频(纯音频)

// 就绘制声波图

if (!remoteStream.enableVideo) {

const ctx = document.getElementById('remotewave').getContext('2d');

drawAudioWave(remoteStream, ctx);

}

}).catch(e => {

console.log('subscribe error!', e);

});

}

...

...

const localPlayer = document.getElementById('localplayer');

localStream.play(localPlayer, true);

await myRTC.publish(localStream);

// 如果本地发布的流没有开启视频采集

// 就绘制本地的声波图

if (!enableVideo) {

const ctx = document.getElementById('localwave').getContext('2d');

drawAudioWave(localStream, ctx);

}

...

...

好了,现在再使用纯音频连麦进入的话,就可以看到自己和远端的声波图啦。这里是用了最简单的方法绘制的声波图,仅仅展示 API 用,使用频域和一些算法搭配绘制会有更好的效果,这里就不赘述了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在uniapp H5中获取音频率并绘制声波可以通过以下步骤实现: 1. 使用HTML5的Web Audio API获取麦克风输入的音频数据。 2. 将音频数据转换成频率数据,可以使用FFT算法进行频谱分析。 3. 将频率数据绘制声波,可以使用Canvas进行绘制。 以下是一个简单的示例代码: ```html <template> <canvas id="canvas"></canvas> </template> <script> export default { mounted() { this.draw(); }, methods: { draw() { const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); // 获取麦克风输入的音频数据 navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { const audioContext = new AudioContext(); const source = audioContext.createMediaStreamSource(stream); const analyser = audioContext.createAnalyser(); // 配置AnalyserNode,将音频数据转换成频率数据 analyser.fftSize = 2048; const bufferLength = analyser.frequencyBinCount; const dataArray = new Uint8Array(bufferLength); source.connect(analyser); // 每隔16.7毫秒获取一次频率数据,并绘制声波 setInterval(() => { analyser.getByteFrequencyData(dataArray); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.beginPath(); const barWidth = canvas.width / bufferLength; let x = 0; for (let i = 0; i < bufferLength; i++) { const barHeight = dataArray[i] / 2; ctx.fillStyle = `rgb(${barHeight}, 0, 0)`; ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight); x += barWidth + 1; } }, 16.7); }) .catch(err => { console.error(err); }); } } } </script> ``` 在上面的示例代码中,我们使用了HTML5的Web Audio API获取麦克风输入的音频数据,然后将音频数据转换成频率数据,并使用Canvas将频率数据绘制声波。你可以将上面的代码复制到你的uniapp项目中,并根据需要进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值