【声网】使用 AgoraRTC 实时音频通话以及录音相关方法

306 阅读6分钟

我正在参加「掘金·启航计划」

[Toc]

快速上手

  1. 安装
npm add @netless/fastboard @netless/window-manager white-web-sdk

创建实时音频

采集音视频相关

1. 获取摄像头列表

调用 getMicrophones 获取可用的摄像头列表

getMicrophones 方法会通过 Promise 异步返回一个 MediaDeviceInfo 对象的数组。MediaDeviceInfo 对象复用了 WebRTC API 中的 MediaDeviceInfo 对象。因为是异步方法,你可以使用 then/catch (ES6) 或 async/await (ES7) 获取返回值。

// 获取可用的麦克风设备列表。
// 调用时,如果浏览器还没有获得麦克风访问权限,会在界面上提示你是否允许浏览器访问麦克风。
AgoraRTC.getMicrophones()
.then((deviceInfoArray) => {
    /* 返回 MediaDeviceInfo 数组对象之后的操作*/
})
.catch((e) => {
    console.log("Failed to get microphones!", e);
});

2. 获取摄像头设备信息

在此教程中,我们在 HTML 中创建一个下拉菜单来供用户选择使用的摄像头设备。在用户界面上使用 label 属性显示设备信息。deviceId 属性用于保存设备 ID,用于后续的摄像头访问。

label,即设备标签,返回一个 DOMString,代表描述对应设备的标签。如果浏览器没有获取设备权限,则返回 ""

deviceId,即设备 ID,返回一个 DOMString,代表对应设备。设备 ID 对于应用是唯一的,只要浏览器的 cookie 没有被清除,即使你开启了新的浏览器会话(session),设备 ID 也会保持不变。如果你清除了浏览器 cookie,则设备 ID 会重置。同理,如果你开启了浏览器隐私模式,对于同一个设备,每个浏览器会话的设备 ID 都是不同的。因此,建议每次对设备进行操作时重新获取设备 ID。

HTML

<h1>通过麦克风采集并在本地渲染音频</h1>
<form>
<b> 选择你要使用的麦克风 </b>
<select id = "microphoneList" onchange = "getDeviceId()" >
<option> ---选择麦克风--- </option>
</select>
</form>
<p>你选择设备的 deviceId 是:</p>
<p id="deviceId"></p>

JavaScript

// 定义设备 ID 与标签的映射
let dict = {};

// 获取摄像头列表
AgoraRTC.getMicrophones()
.then((deviceInfoArray) => {
    for (let deviceInfo of deviceInfoArray) {
    let option = document.createElement("option");
    document.getElementById("microphoneList").appendChild(option);
    option.innerHTML = deviceInfo.label;
    dict[deviceInfo.label] = deviceInfo.deviceId;
    }
})
.catch((e) => {
    console.log("Failed to get microphones!", e);
});

// 根据下拉菜单选择的设备标签,显示相应的设备 ID
function getDeviceId() {
    let microphoneList = document.getElementById("microphoneList");
    let deviceLabel = microphoneList.options[microphoneList.selectedIndex].text;
    document.getElementById("deviceId").innerHTML = dict[deviceLabel];
}

3. 创建麦克风音频轨道并渲染

调用 createMicrophoneAudioTrack 创建麦克风音频轨道并调用成员方法 play 通过系统默认扬声器对视频进行渲染。这里轨道的概念和 WebRTC 中的 track 相似。一个轨道代表一路特定的视频源或音频源。声网 SDK 将不同来源的音视频轨道进行抽象,定义了摄像头视频轨道、屏幕采集视频轨道及自定义源视频轨道等。

这个步骤只是为了演示麦克风音频轨道的渲染。实际开发通话应用时,本地不需要播放本地麦克风采集的音频。

  1. HTML

    <h1>通过麦克风采集并在本地渲染音频</h1>
    <form>
    <b> 选择你要使用的麦克风 </b>
    <select id="microphoneList" onchange="getDeviceId()">
        <option> ---选择麦克风--- </option>
    </select>
    </form>
    <p>你选择设备的 deviceId 是:</p>
    <p id="deviceId"></p>
    

    CSS

    body {font-family: system-ui;background: #f06d06;color: white;text-align: center;}
    div {height: 200px;width: 50%;}
    

    JavaScript

    // 全局变量
    let dict = {}; // 使用 dict 映射设备标签和设备 ID
    let selectedDeviceId = ""; // 下选框选择的设备对应的 ID
    let microphoneAudioTrack = null; // 麦克风音频轨道对象
    
    // 获取本地麦克风列表
    AgoraRTC.getMicrophones()
    .then((deviceInfoArray) => {
        for (let deviceInfo of deviceInfoArray) {
        let option = document.createElement("option");
        document.getElementById("microphoneList").appendChild(option);
        option.innerHTML = deviceInfo.label;
        dict[deviceInfo.label] = deviceInfo.deviceId;
        }
    })
    .catch((e) => {
        console.log("Failed to get microphones!", e);
    });
    
    // 创建麦克风音频轨道
    AgoraRTC.createMicrophoneAudioTrack()
    .then((microphoneAudioTrack) => {
        // 渲染音频。SDK 使用系统默认的扬声器播放声音。
        microphoneAudioTrack.play();
    })
    .catch((e) => {
        console.log("Failed to play audio!", e);
    });
    
    // 根据选择的设备标签,返回对应的设备 ID 并传给麦克风音频轨道
    function getDeviceId() {
    let microphoneList = document.getElementById("microphoneList");
    let deviceLabel = microphoneList.options[microphoneList.selectedIndex].text;
    selectedDeviceId = dict[deviceLabel];
    document.getElementById("deviceId").innerHTML = selectedDeviceId;
    
    if (microphoneAudioTrack != null) {
        microphoneAudioTrack.setDevice(selectedDeviceId);
    }
    }
    

#音频回调

setAudioFrameCallback

  • setAudioFrameCallback(audioFrameCallback: null | function, frameSize?: undefined | number): void

设置原始音频数据(PCM)回调。

设置成功后,SDK 会不断地将远端音频轨道的音频帧以 AudioBuffer 的形式通过回调返回。

你可以通过 frameSize 来设置每次回调中音频帧的大小。该设置也会影响回调的间隔,frameSize 越大,每次回调的音频数据越多,回调间隔越长。

track.setAudioFrameCallback((buffer) => {
  for (let channel = 0; channel < buffer.numberOfChannels; channel += 1) {
    // Float32Array with PCM data
    const currentChannelData = buffer.getChannelData(channel);
    console.log("PCM data in channel", channel, currentChannelData);
  }
}, 2048);

// ....
// Stop getting the raw audio data
track.setAudioFrameCallback(null);

音频回调解码

AudioBuffer - Web API 接口参考 | MDN

AudioBuffer 接口表示存在内存里的一段短小的音频资源,利用AudioContext.decodeAudioData()方法从一个音频文件构建,或者利用 AudioContext.createBuffer()从原始数据构建。把音频放入 AudioBuffer 后,可以传入到一个 AudioBufferSourceNode进行播放。

这些类型对象被设计来控制小音频片段,往往短于 45 秒。对于更长的声音,通过 MediaElementAudioSourceNode来实现更为合适。缓存区(buffer)包含以下数据:不间断的 IEEE754 32 位线性 PCM,从-1 到 1 的范围额定,就是说,32 位的浮点缓存区的每个样本在-1.0 到 1.0 之间。如果AudioBuffer有不同的频道,他们通常被保存在独立的缓存区。

1) 属性
2) 方法
3) 例子

以下的例子展示了如何构建一个 AudioBuffer 以及随机用白噪音填充。你可以在 audio-buffer demo库发现完整的源代码;一个running live 的版本也可获得。

// Stereo
var channels = 2;

// Create an empty two second stereo buffer at the
// sample rate of the AudioContext
var frameCount = audioCtx.sampleRate * 2.0;
var myArrayBuffer = audioCtx.createBuffer(channels, frameCount, audioCtx.sampleRate);

button.onclick = function() {
  // Fill the buffer with white noise;
  // just random values between -1.0 and 1.0
  for (var channel = 0; channel < channels; channel++) {
    // This gives us the actual array that contains the data
    var nowBuffering = myArrayBuffer.getChannelData(channel);
    for (var i = 0; i < frameCount; i++) {
      // Math.random() is in [0; 1.0]
      // audio needs to be in [-1.0; 1.0]
      nowBuffering[i] = Math.random() * 2 - 1;
    }
  }

  // Get an AudioBufferSourceNode.
  // This is the AudioNode to use when we want to play an AudioBuffer
  var source = audioCtx.createBufferSource();

  // set the buffer in the AudioBufferSourceNode
  source.buffer = myArrayBuffer;

  // connect the AudioBufferSourceNode to the
  // destination so we can hear the sound
  source.connect(audioCtx.destination);

  // start the source playing
  source.start();

}
4) 规格参数
Specification
Web Audio API # AudioBuffer

录音对象属性

Agora Web API Reference - 语音通话 - 文档中心 - 声网Agora

音频编码

AudioEncoderConfigurationPreset

AudioEncoderConfigurationPreset: keyof typeof AUDIO_ENCODER_CONFIG_SETTINGS

SDK 预设的 [AudioEncoderConfiguration](docs.agora.io/cn/Voice/AP… Reference/web_ng/interfaces/audioencoderconfiguration.html) 配置。

你可以在以下方法中传入预设值来控制本地音频的编码配置:

下表列出了 SDK 所有内置的音频属性配置,SDK 默认使用 "music_standard"

音频属性配置
"speech_low_quality"16 kHz 采样率,单声道,编码码率约 24 Kbps
"speech_standard"32 kHz 采样率,单声道,编码码率约 24 Kbps
"music_standard"48 kHz 采样率,单声道,编码码率约 40 Kbps
"standard_stereo"48 kHz 采样率,双声道,编码码率约 64 Kbps
"high_quality"48 kHz 采样率,单声道, 编码码率约 128 Kbps
"high_quality_stereo"48 kHz 采样率,双声道,编码码率约 192 Kbps

本地音频轨道

Agora Web API Reference - 语音通话 - 文档中心 - 声网Agora

对接

基于声网 Web SDK 实现视频通话场景 - 专栏 - 声网 Agora RTC 开发者社区