计算PCM音频数据的音量分贝,需要先获得采样点的幅值,然后使用分贝公式计算,具体步骤如下:
// buffer:AudioCapturer录制的PCM音频数据
private pcm2DB(buffer: ArrayBuffer): number {
const refAmplitude = 32767; // 采样深度为有符号16bit时,参考振幅值为最大正值32767。
const amplitudeArr = new Int16Array(buffer); // 16bit为一个采样点
let sum: number = 0;
for (let i = 0; i < amplitudeArr.length; i++) {
sum += amplitudeArr[i] * amplitudeArr[i]; // 计算平方和
}
let rms = Math.sqrt(sum / amplitudeArr.length); // 计算均方根能量值
let db = 20 * Math.log10(rms / refAmplitude); // 计算音量分贝大小
return db;
} 如果需要获取音频流变化趋势,也可以调用getMaxAmplitudeForInputDevice()获取输入设备音频流的最大电平值,参考示例代码如下:
// 监听最大电平值
async getMaxAmplitude() {
let audioManager = audio.getAudioManager();
let audioVolumeManager: audio.AudioVolumeManager = audioManager.getVolumeManager();
let groupId: number = audio.DEFAULT_VOLUME_GROUP_ID;
let audioVolumeGroupManager: audio.AudioVolumeGroupManager =
await audioVolumeManager.getVolumeGroupManager(groupId);
let deviceDescriptors: audio.AudioDeviceDescriptors | undefined =
this.capturer?.getCurrentInputDevices();
if (deviceDescriptors === undefined) {
return;
}
audioVolumeGroupManager.getMaxAmplitudeForInputDevice(deviceDescriptors[0]).then((value) => {
console.info(`max amplitude is: ${value}`);
}).catch((err: BusinessError) => {
console.error(`getMaxAmplitudeForInputDevice error. Code: ${err.code}, message: ${err.message}`);
});
} 完整代码参考如下:
import { audio } from '@kit.AudioKit';
import { abilityAccessCtrl, common, PermissionRequestResult, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
let audioStreamInfo: audio.AudioStreamInfo = {
channels: audio.AudioChannel.CHANNEL_1,
samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000,
sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW,
};
let audioCapturerInfo: audio.AudioCapturerInfo = {
capturerFlags: 0,
source: audio.SourceType.SOURCE_TYPE_MIC,
};
let audioCapturerOptions: audio.AudioCapturerOptions = {
streamInfo: audioStreamInfo,
capturerInfo: audioCapturerInfo,
};
@Entry
@Component
struct Index {
private capturer?: audio.AudioCapturer;
context = this.getUIContext().getHostContext() as common.UIAbilityContext;
aboutToAppear(): void {
requestPermissions(this.context, ['ohos.permission.MICROPHONE']);
}
aboutToDisappear(): void {
this.stopCapturer();
this.releaseCapturer();
}
build() {
Column({ space: 20 }) {
Row() {
Text('音频分贝大小:');
Button('监听')
.onClick(async () => {
await this.initCapturerGetDb();
await this.startCapturer();
});
Button('取消监听')
.onClick(async () => {
await this.stopCapturer();
await this.releaseCapturer();
});
}
.width('85%')
.justifyContent(FlexAlign.SpaceEvenly);
Row() {
Text('音频振幅大小:');
Button('监听')
.onClick(async () => {
await this.initCapturerGetMaxAmplitude();
await this.startCapturer();
});
Button('取消监听')
.onClick(async () => {
await this.stopCapturer();
await this.releaseCapturer();
});
}
.width('85%')
.justifyContent(FlexAlign.SpaceEvenly);
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center);
}
// buffer:AudioCapturer录制的PCM音频数据
private pcm2DB(buffer: ArrayBuffer): number {
const refAmplitude = 32767; // 采样深度为有符号16bit时,参考振幅值为最大正值32767。
const amplitudeArr = new Int16Array(buffer); // 16bit为一个采样点
let sum: number = 0;
for (let i = 0; i < amplitudeArr.length; i++) {
sum += amplitudeArr[i] * amplitudeArr[i]; // 计算平方和
}
let rms = Math.sqrt(sum / amplitudeArr.length); // 计算均方根能量值
let db = 20 * Math.log10(rms / refAmplitude); // 计算音量分贝大小
return db;
}
async initCapturerGetDb(): Promise<void> {
this.capturer = await audio.createAudioCapturer(audioCapturerOptions);
try {
this.capturer.on('readData', (buffer: ArrayBuffer) => {
let db = this.pcm2DB(buffer);
console.info(`DB Value: ${db}`);
});
} catch (err) {
console.error(`failed to register readData event: ${JSON.stringify(err)}`);
}
}
// 监听最大电平值
async getMaxAmplitude() {
let audioManager = audio.getAudioManager();
let audioVolumeManager: audio.AudioVolumeManager = audioManager.getVolumeManager();
let groupId: number = audio.DEFAULT_VOLUME_GROUP_ID;
let audioVolumeGroupManager: audio.AudioVolumeGroupManager =
await audioVolumeManager.getVolumeGroupManager(groupId);
let deviceDescriptors: audio.AudioDeviceDescriptors | undefined =
this.capturer?.getCurrentInputDevices();
if (deviceDescriptors === undefined) {
return;
}
audioVolumeGroupManager.getMaxAmplitudeForInputDevice(deviceDescriptors[0]).then((value) => {
console.info(`max amplitude is: ${value}`);
}).catch((err: BusinessError) => {
console.error(`getMaxAmplitudeForInputDevice error. Code: ${err.code}, message: ${err.message}`);
});
}
async initCapturerGetMaxAmplitude(): Promise<void> {
this.capturer = await audio.createAudioCapturer(audioCapturerOptions);
try {
this.capturer.on('readData', () => {
this.getMaxAmplitude();
});
} catch (err) {
console.error(`failed to register readData event: ${JSON.stringify(err)}`);
}
}
async startCapturer(): Promise<void> {
if (this.capturer === undefined) {
throw new Error(`AudioCapturer is undefined`);
}
let state = this.capturer.state;
if (state !== audio.AudioState.STATE_PREPARED && state !== audio.AudioState.STATE_STOPPED) {
throw new Error(`AudioCapturer is at wrong state, ${state}`);
}
await this.capturer.start();
}
async stopCapturer(): Promise<void> {
if (this.capturer === undefined) {
throw new Error(`AudioCapturer is undefined`);
}
let state = this.capturer.state;
if (state !== audio.AudioState.STATE_RUNNING) {
throw new Error(`AudioCapturer is at wrong state, ${state}`);
}
await this.capturer.stop();
}
async releaseCapturer(): Promise<void> {
if (this.capturer === undefined) {
throw new Error(`AudioCapturer is undefined`);
}
let state = this.capturer.state;
if (state !== audio.AudioState.STATE_PREPARED && state !== audio.AudioState.STATE_STOPPED) {
throw new Error(`AudioCapturer is at wrong state, ${state}`);
}
try {
this.capturer.off('readData');
} catch (err) {
console.error(`failed to unregister readData event: ${JSON.stringify(err)}`);
}
await this.capturer.release();
this.capturer = undefined;
}
}
function requestPermissions(context: common.UIAbilityContext, permissions: Permissions[]): void {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
atManager.requestPermissionsFromUser(context, permissions)
.then((result: PermissionRequestResult) => {
let grantStatus: number[] = result.authResults;
let length = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] !== 0) {
console.info(`User reject to grant permission: ${permissions[i]}`);
}
}
})
.catch((err: BusinessError) => {
console.error(`Request permissions from user failed, ${JSON.stringify(err)}`);
});
}