HarmonyOS 鸿蒙Next AVRecorder进行音频录制时,音频的时长与实际的不符(比实际的时长短)
我在使用AVRecorder进行音频录制时,发现录制出来的音频文件放在电脑的播放器上播放,它的时长比实际录制的短几秒,也就是就我本来是录制20秒的音频。但是通过电脑播放器读取出来的确只有17秒。下面是我的配置
//音视频录制的配置文件。
private readonly avProfile: media.AVRecorderProfile = {
audioBitrate: 100000, // 音频比特率
audioChannels: 2, // 音频声道数
audioCodec: media.CodecMimeType.AUDIO_AAC, // 音频编码格式,当前支持ACC,MP3,G711MU
audioSampleRate: 48000, // 音频采样率
fileFormat: media.ContainerFormatType.CFT_MPEG_4A, // 封装格式,当前支持MP4,M4A,MP3,WAV
}
提示一下:我在录制音频的时侯一边念着我用代码计算的得出的录制秒数,和实际在系统中播放时显示的进度是不符合的。但是整个音频文件是没有缺断的。就像是以1.2倍速播放的那样。
更多关于HarmonyOS 鸿蒙Next AVRecorder进行音频录制时,音频的时长与实际的不符(比实际的时长短)的实战教程也可以访问 https://www.itying.com/category-93-b0.html
import { media } from '@kit.MediaKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { abilityAccessCtrl, common } from '@kit.AbilityKit';
import { FileUtil } from '../utils/FileUtil';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
url: string = "";
aboutToAppear() {
let context = getContext() as common.UIAbilityContext;
let path = context.filesDir + "/" + "VIDEO_" + Date.parse(new Date().toString()) + ".mp4";
let file = FileUtil.createOrOpen(path);
this.url = "fd://" + file.fd;
}
private avRecorder: media.AVRecorder | undefined = undefined;
private avProfile: media.AVRecorderProfile = {
audioBitrate: 100000, // 音频比特率
audioChannels: 2, // 音频声道数
audioCodec: media.CodecMimeType.AUDIO_AAC, // 音频编码格式,当前支持ACC,MP3,G711MU
audioSampleRate: 48000, // 音频采样率
fileFormat: media.ContainerFormatType.CFT_MPEG_4A, // 封装格式,当前支持MP4,M4A,MP3,WAV
};
// 注册audioRecorder回调函数
setAudioRecorderCallback() {
if (this.avRecorder != undefined) {
// 状态机变化回调函数
this.avRecorder.on('stateChange', (state: media.AVRecorderState, reason: media.StateChangeReason) => {
console.log(`AudioRecorder current state is ${state}`);
})
// 错误上报回调函数
this.avRecorder.on('error', (err: BusinessError) => {
console.error(`AudioRecorder failed, code is ${err.code}, message is ${err.message}`);
})
}
}
// 开始录制对应的流程
async startRecordingProcess() {
let avConfig: media.AVRecorderConfig = {
audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, // 音频输入源,这里设置为麦克风
profile: this.avProfile,
url: this.url, // 参考应用文件访问与管理开发示例新建并读写一个文件
};
if (this.avRecorder != undefined) {
await this.avRecorder.release();
this.avRecorder = undefined;
}
// 1.创建录制实例
this.avRecorder = await media.createAVRecorder();
this.setAudioRecorderCallback();
// 2.获取录制文件fd赋予avConfig里的url;参考FilePicker文档
// 3.配置录制参数完成准备工作
await this.avRecorder.prepare(avConfig);
// 4.开始录制
await this.avRecorder.start();
}
// 暂停录制对应的流程
async pauseRecordingProcess() {
if (this.avRecorder != undefined && this.avRecorder.state === 'started') { // 仅在started状态下调用pause为合理状态切换
await this.avRecorder.pause();
}
}
// 恢复录制对应的流程
async resumeRecordingProcess() {
if (this.avRecorder != undefined && this.avRecorder.state === 'paused') { // 仅在paused状态下调用resume为合理状态切换
await this.avRecorder.resume();
}
}
// 停止录制对应的流程
async stopRecordingProcess() {
if (this.avRecorder != undefined) {
// 1. 停止录制
if (this.avRecorder.state === 'started'
|| this.avRecorder.state === 'paused') { // 仅在started或者paused状态下调用stop为合理状态切换
await this.avRecorder.stop();
}
// 2.重置
await this.avRecorder.reset();
// 3.释放录制实例
await this.avRecorder.release();
this.avRecorder = undefined;
// 4.关闭录制文件fd
}
}
// 一个完整的【开始录制-暂停录制-恢复录制-停止录制】示例
async audioRecorderDemo() {
await this.startRecordingProcess(); // 开始录制
// 用户此处可以自行设置录制时长,例如通过设置休眠阻止代码执行
await this.pauseRecordingProcess(); //暂停录制
await this.resumeRecordingProcess(); // 恢复录制
await this.stopRecordingProcess(); // 停止录制
}
//请求权限
async requestPermissions() : Promise<boolean>{
return await new Promise((resolve: Function) => {
try {
let context = getContext() as common.UIAbilityContext;
abilityAccessCtrl.createAtManager().requestPermissionsFromUser(context, [
'ohos.permission.CAMERA',
'ohos.permission.MICROPHONE'
])
.then(async () => {
resolve(true)
}).catch(() => {
resolve(false)
});
} catch (err) {
resolve(false)
}
});
}
build() {
Column(){
Button('开始录制')
.onClick(async () => {
let result = await this.requestPermissions();
if(result) {
this.startRecordingProcess();
}
})
Button('停止录制')
.onClick(async () => {
this.stopRecordingProcess();
})
}
.height('100%')
.width('100%')
}
}
更多关于HarmonyOS 鸿蒙Next AVRecorder进行音频录制时,音频的时长与实际的不符(比实际的时长短)的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
好的好的,我先收藏一下,目前暂时不进行下去了,以后要是再搞的话会回来看这个贴子的。我一个包含该功能的笔记App上架被拒了。说功能不够丰富,现在都月底尾赶不上了,软著也要被失效了。所以先迭代已经有的安卓项目。
[@lichengg](/user/lichengg) 这是我项目中录制语音的帮助类,你写几个按钮调用看看。今天试还是存在我说的那个问题的:
const TAG = 'VoiceRecordHelper'
export class VoiceRecordHelper {
private avRecorder: media.AVRecorder | undefined = undefined;
//音视频录制的配置文件。
private readonly avProfile: media.AVRecorderProfile = {
audioBitrate: 100000, // 音频比特率
audioChannels: 2, // 音频声道数
audioCodec: media.CodecMimeType.AUDIO_AAC, // 音频编码格式,当前支持ACC,MP3,G711MU
audioSampleRate: 48000, // 音频采样率
fileFormat: media.ContainerFormatType.CFT_MPEG_4A, // 封装格式,当前支持MP4,M4A,MP3,WAV
}
private voiceFile: fileIo.File
private recordCallback: RecordCallback
private recordDuration: number = 0
private progressIntervalId: number = -1
private startTime: number = 0
constructor(saveVoiceFile: fileIo.File, recordCallback: RecordCallback) {
this.voiceFile = saveVoiceFile
this.recordCallback = recordCallback
this.recordDuration = 0
}
//开始
public start() {
new Promise <void>(async (resolve: Function, reject: Function) => {
let avConfig: media.AVRecorderConfig = {
audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, // 音频输入源,这里设置为麦克风
profile: this.avProfile,
url: ‘fd://’ + this.voiceFile.fd, // 参考应用文件访问与管理开发示例新建并读写一个文件
}
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.avRecorder != <span class="hljs-literal">undefined</span>) {
await <span class="hljs-keyword">this</span>.avRecorder.release();
<span class="hljs-keyword">this</span>.avRecorder = <span class="hljs-literal">undefined</span>;
}
<span class="hljs-comment">// 1.创建录制实例</span>
<span class="hljs-keyword">this</span>.avRecorder = await media.createAVRecorder();
<span class="hljs-comment">//设置error和status回调监听</span>
<span class="hljs-keyword">this</span>.setAudioRecorderCallback();
<span class="hljs-comment">// 2.获取录制文件fd赋予avConfig里的url;参考FilePicker文档</span>
<span class="hljs-comment">// 3.配置录制参数完成准备工作</span>
await <span class="hljs-keyword">this</span>.avRecorder.prepare(avConfig);
<span class="hljs-comment">// 4.开始录制</span>
await <span class="hljs-keyword">this</span>.avRecorder.start();
resolve()
} <span class="hljs-keyword">catch</span> (e) {
reject(e)
}
}).then(() => {
console.log(TAG, <span class="hljs-string">'开始录制'</span>)
}).catch((error: <span class="hljs-built_in">Error</span>) => {
console.log(TAG, <span class="hljs-string">'开始录制出错:'</span>, error)
<span class="hljs-keyword">this</span>.recordCallback.onError(error)
})
}
// 停止录制对应的流程
public stop() {
new Promise <void>(async (resolve: Function, reject: Function) => {
try {
if (this.avRecorder != undefined) {
// 1. 停止录制
if (this.avRecorder.state === ‘started’
|| this.avRecorder.state === ‘paused’) { // 仅在started或者paused状态下调用stop为合理状态切换
await this.avRecorder.stop();
}
// 2.重置
await this.avRecorder.reset();
// 3.释放录制实例
await this.avRecorder.release();
this.avRecorder = undefined;
// 4.关闭录制文件fd
}
resolve()
} catch (e) {
reject(e)
}
}).then(() => {
// don’t have to do anything
}).catch((error: <span class="hljs-built_in">Error</span>) => {
<span class="hljs-keyword">this</span>.recordCallback.onError(error)
})
<span class="hljs-comment">//停止Progress</span>
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.progressIntervalId != -<span class="hljs-number">1</span>) {
clearInterval(<span class="hljs-keyword">this</span>.progressIntervalId)
}
}
//每秒轮询生成一个伪进度
private doIntervalProgress() {
this.progressIntervalId = setInterval(() => {
if (this.startTime != 0) {
this.recordDuration = Math.floor((Date.now() - this.startTime) / 1000)
this.recordCallback.onProgress(this.recordDuration)
}
}, 1000)
}
// 注册audioRecorder回调函数
private setAudioRecorderCallback() {
if (this.avRecorder != undefined) {
// 状态机变化回调函数
this.avRecorder.on(‘stateChange’, (state: media.AVRecorderState, reason: media.StateChangeReason) => {
console.log(TAG, 当前状态 is ${state}
)
if (state == ‘started’) {
//开始
this.startTime = Date.now()
this.recordCallback.onStart()
this.doIntervalProgress()
} else if (state == ‘stopped’) {
//完成
this.recordCallback.onSuccess({
voiceFile: this.voiceFile,
voiceDuration: this.recordDuration
})
}
})
// 错误上报回调函数
this.avRecorder.on(‘error’, (err: BusinessError) => {
console.error(TAG, 出错, code is ${err.code}, message is ${err.message}
);
this.recordCallback.onError(err)
})
}
}
}
export interface RecordCallback {
onStart: () => void
/**
- 录制中时的进度
- @param progress 单是秒
/
onProgress: (progress: number) => void
/*
- 出错
- @param error
/
onError: (error: Error) => void
/*
- 录制成功
- @param result
*/
onSuccess: (result: RecordResult) => void
}
export interface RecordResult {
voiceFile: fileIo.File,
voiceDuration: number
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>
用手机(模拟器)也是一样的,而且我还录歌曲试了一下,那节凑确实是快了
配置是没有问题的,这边本地测试没有复现,可以提供下复现问题的代码继续分析
好的,你看看下面我最新的回复,在这里回复好像不能有插代码片断格式的编辑方式,我就在这贴子下面回了。
HarmonyOS 鸿蒙Next AVRecorder音频录制时长问题,可能是由于以下几个原因导致的:
-
采样率不匹配:检查录制的音频文件的采样率是否与设备实际支持的采样率一致。若采样率设置过高或过低,可能导致录制时长偏差。
-
时间戳处理:在音频录制过程中,时间戳的计算和更新如果不准确,也会导致录制的音频时长与实际不符。检查AVRecorder的时间戳管理逻辑是否正确。
-
缓冲区设置:音频录制时缓冲区的大小和数量设置不当,可能导致数据丢失或录制不完整,从而影响时长。确认缓冲区配置是否适合录制的音频类型和格式。
-
编码效率:音频编码器的效率差异可能导致编码后的音频数据长度与实际录制时长不一致。检查编码器配置和性能。
-
资源竞争:系统中其他应用或服务占用了大量资源,可能影响AVRecorder的性能,导致录制时长不准确。确保在录制过程中系统资源充足。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html