feat(录音): AmrRecorder AVRecorder(AMR-NB) 封装 start/stop/cancel
This commit is contained in:
@@ -19,6 +19,7 @@ export { ScanProvider } from './src/main/ets/providers/ScanProvider';
|
||||
export { CameraProvider } from './src/main/ets/providers/CameraProvider';
|
||||
export { LocationProvider } from './src/main/ets/providers/LocationProvider';
|
||||
export { AudioProvider } from './src/main/ets/providers/AudioProvider';
|
||||
export { AmrRecorder } from './src/main/ets/providers/AmrRecorder';
|
||||
export { NavProvider } from './src/main/ets/providers/NavProvider';
|
||||
|
||||
// 微信 SDK 封装(EntryAbility 处理回调 want 需用)
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* AVRecorder 录音封装(设计 §6):AMR-NB(CFT_AMR + AUDIO_AMR_NB / 8kHz / 单声道 / 12.2kbps),
|
||||
* 对齐 Android RAW_AMR + AMR_NB。文件落 cacheDir/<uuid>.amr,key=<uuid>.amr。无 UI。
|
||||
*/
|
||||
import { media } from '@kit.MediaKit';
|
||||
import { fileIo } from '@kit.CoreFileKit';
|
||||
import { common } from '@kit.AbilityKit';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import { util } from '@kit.ArkTS';
|
||||
import { Logger } from 'common';
|
||||
|
||||
export class AmrRecorder {
|
||||
private readonly log: Logger = Logger.tag('AmrRecorder');
|
||||
private recorder: media.AVRecorder | undefined = undefined;
|
||||
private fd: number = -1;
|
||||
private filePath: string = '';
|
||||
private fileKey: string = '';
|
||||
|
||||
isActive(): boolean {
|
||||
return this.recorder !== undefined;
|
||||
}
|
||||
|
||||
key(): string {
|
||||
return this.fileKey;
|
||||
}
|
||||
|
||||
async start(context: common.Context): Promise<boolean> {
|
||||
if (this.recorder !== undefined) {
|
||||
return false;
|
||||
}
|
||||
const uuid: string = util.generateRandomUUID(true);
|
||||
this.fileKey = `${uuid}.amr`;
|
||||
this.filePath = `${context.cacheDir}/${this.fileKey}`;
|
||||
try {
|
||||
const file: fileIo.File = fileIo.openSync(this.filePath,
|
||||
fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
|
||||
this.fd = file.fd;
|
||||
const recorder: media.AVRecorder = await media.createAVRecorder();
|
||||
this.recorder = recorder;
|
||||
recorder.on('error', (e: BusinessError) => this.log.w(`recorder error: ${e.code} ${e.message}`));
|
||||
const profile: media.AVRecorderProfile = {
|
||||
audioBitrate: 12200,
|
||||
audioChannels: 1,
|
||||
audioCodec: media.CodecMimeType.AUDIO_AMR_NB,
|
||||
audioSampleRate: 8000,
|
||||
fileFormat: media.ContainerFormatType.CFT_AMR,
|
||||
};
|
||||
const config: media.AVRecorderConfig = {
|
||||
audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC,
|
||||
profile: profile,
|
||||
url: `fd://${this.fd}`,
|
||||
};
|
||||
await recorder.prepare(config);
|
||||
await recorder.start();
|
||||
return true;
|
||||
} catch (e) {
|
||||
this.log.w(`start failed: ${(e as BusinessError).message}`);
|
||||
await this.cleanup(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async stop(): Promise<string> {
|
||||
const path: string = this.filePath;
|
||||
await this.cleanup(false);
|
||||
return path;
|
||||
}
|
||||
|
||||
async cancel(): Promise<void> {
|
||||
await this.cleanup(true);
|
||||
}
|
||||
|
||||
private async cleanup(deleteFile: boolean): Promise<void> {
|
||||
const recorder: media.AVRecorder | undefined = this.recorder;
|
||||
this.recorder = undefined;
|
||||
if (recorder !== undefined) {
|
||||
try {
|
||||
if (recorder.state === 'started' || recorder.state === 'paused') {
|
||||
await recorder.stop();
|
||||
}
|
||||
await recorder.release();
|
||||
} catch (e) {
|
||||
this.log.w(`cleanup recorder failed: ${(e as BusinessError).message}`);
|
||||
}
|
||||
}
|
||||
if (this.fd >= 0) {
|
||||
try {
|
||||
fileIo.closeSync(this.fd);
|
||||
} catch (e) {
|
||||
this.log.w(`close fd failed: ${(e as BusinessError).message}`);
|
||||
}
|
||||
this.fd = -1;
|
||||
}
|
||||
if (deleteFile && this.filePath !== '') {
|
||||
try {
|
||||
fileIo.unlinkSync(this.filePath);
|
||||
} catch (e) {
|
||||
this.log.w(`unlink failed: ${(e as BusinessError).message}`);
|
||||
}
|
||||
this.filePath = '';
|
||||
this.fileKey = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user