在鸿蒙(HarmonyOS)开发中实现音频捕获(录音)功能,需使用 @ohos.multimedia.audio@ohos.multimedia.media 模块。以下是完整实现方案,涵盖权限配置、音频流捕获、实时处理和保存等核心步骤。


一、权限配置

1. 声明权限 (module.json5)
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.MICROPHONE",
        "reason": "需要访问麦克风进行录音"
      },
      {
        "name": "ohos.permission.WRITE_MEDIA",
        "reason": "保存录音文件到设备存储"
      }
    ]
  }
}
2. 动态权限申请
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';

async function requestMicrophonePermission() {
  const atManager = abilityAccessCtrl.createAtManager();
  try {
    const result = await atManager.requestPermissionsFromUser(
      getContext(),
      ['ohos.permission.MICROPHONE', 'ohos.permission.WRITE_MEDIA']
    );
    return result.authResults[0] === 0; // 0 表示权限已授予
  } catch (err) {
    console.error('权限申请失败:', err.code);
    return false;
  }
}

二、音频捕获核心实现

1. 初始化音频参数
import audio from '@ohos.multimedia.audio';

// 配置音频参数
const audioConfig: audio.AudioCapturerOptions = {
  streamInfo: {
    samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100, // 采样率 44.1kHz
    channels: audio.AudioChannel.CHANNEL_1,                 // 单声道
    sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 16位小端PCM
    encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW    // 原始音频数据
  },
  capturerInfo: {
    source: audio.SourceType.SOURCE_TYPE_MIC,               // 麦克风输入
    capturerFlags: 0                                        // 默认标志
  }
};
2. 创建音频捕获器
let audioCapturer: audio.AudioCapturer | null = null;

async function initAudioCapturer() {
  try {
    audioCapturer = await audio.createAudioCapturer(audioConfig);
    console.log('音频捕获器创建成功');
  } catch (err) {
    console.error('创建失败:', err.code);
  }
}
3. 实时音频捕获与处理
async function startCapture() {
  if (!audioCapturer) return;

  // 创建临时文件保存音频
  const filePath = getContext().filesDir + '/recording.pcm';
  const file = await fs.open(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);

  // 启动捕获
  await audioCapturer.start();
  console.log('录音开始');

  // 实时读取音频数据
  while (audioCapturer.state === audio.AudioState.STATE_RUNNING) {
    const buffer = await audioCapturer.read(BufferSize.SIZE_2048, false);
    if (buffer === null) break;

    // 处理音频数据(示例:写入文件)
    await fs.write(file.fd, buffer);
    
    // 可在此处添加实时处理逻辑(如降噪、格式转换)
  }

  // 停止捕获
  await audioCapturer.stop();
  await fs.close(file);
  console.log('录音已保存至:', filePath);
}

三、高级功能扩展

1. 实时音频波形分析
function analyzeWaveform(buffer: ArrayBuffer) {
  const dataView = new DataView(buffer);
  let maxAmplitude = 0;

  // 分析每个采样点的振幅(16位PCM)
  for (let i = 0; i < dataView.byteLength; i += 2) {
    const sample = dataView.getInt16(i, true); // 小端模式读取
    maxAmplitude = Math.max(maxAmplitude, Math.abs(sample));
  }

  // 转换为分贝 (dBFS)
  const dB = 20 * Math.log10(maxAmplitude / 32767);
  console.log(`当前最大音量: ${dB.toFixed(1)} dB`);
}
2. 跨设备音频采集(分布式能力)
import distributedHardware from '@ohos.distributedHardware';

async function captureFromRemoteDevice() {
  // 发现附近设备的麦克风
  const devices = await distributedHardware.getDeviceList(['mic']);
  const remoteMic = devices[0];

  // 连接远程设备
  const capturer = await audio.createAudioCapturer({
    streamInfo: { ... }, // 参数需与远程设备协商一致
    capturerInfo: {
      source: audio.SourceType.SOURCE_TYPE_REMOTE_MIC,
      deviceId: remoteMic.deviceId
    }
  });

  // 使用方式与本地相同
  capturer.start();
}

四、音频格式转换(PCM → WAV)

import fileio from '@ohos.fileio';

async function convertToWav(pcmPath: string, wavPath: string) {
  const pcmStats = fs.statSync(pcmPath);
  const pcmSize = pcmStats.size;

  // WAV文件头结构
  const wavHeader = Buffer.alloc(44);
  wavHeader.write('RIFF', 0);                             // ChunkID
  wavHeader.writeUInt32LE(pcmSize + 36, 4);               // ChunkSize
  wavHeader.write('WAVE', 8);                             // Format
  wavHeader.write('fmt ', 12);                            // Subchunk1ID
  wavHeader.writeUInt32LE(16, 16);                        // Subchunk1Size
  wavHeader.writeUInt16LE(1, 20);                         // AudioFormat (PCM)
  wavHeader.writeUInt16LE(1, 22);                         // NumChannels
  wavHeader.writeUInt32LE(44100, 24);                     // SampleRate
  wavHeader.writeUInt32LE(44100 * 1 * 2, 28);             // ByteRate
  wavHeader.writeUInt16LE(1 * 2, 32);                     // BlockAlign
  wavHeader.writeUInt16LE(16, 34);                        // BitsPerSample
  wavHeader.write('data', 36);                            // Subchunk2ID
  wavHeader.writeUInt32LE(pcmSize, 40);                   // Subchunk2Size

  // 写入文件
  const wavFile = await fs.open(wavPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
  await fs.write(wavFile.fd, wavHeader.buffer);
  
  const pcmFile = await fs.open(pcmPath, fs.OpenMode.READ_ONLY);
  let offset = 0;
  const bufferSize = 4096;

  while (offset < pcmSize) {
    const readSize = Math.min(bufferSize, pcmSize - offset);
    const pcmData = await fs.read(pcmFile.fd, { offset, length: readSize });
    await fs.write(wavFile.fd, pcmData.buffer);
    offset += readSize;
  }

  await fs.close(wavFile);
  await fs.close(pcmFile);
  console.log('WAV 文件已生成:', wavPath);
}

五、常见问题解决

1. 录音无声音
  • 检查权限:确认 MICROPHONEWRITE_MEDIA 权限已授予
  • 验证设备:确认麦克风未被其他应用占用
  • 测试硬件:使用系统录音机验证麦克风是否正常
2. 音频数据错乱
  • 参数匹配:确保采样率、位深与实际硬件支持一致
  • 字节序处理:小端模式(S16LE)与大端模式(S16BE)需正确对应
3. 高延迟问题
  • 优化缓冲区:调整 read() 的缓冲区大小(推荐 2048-8192 字节)
  • 使用低延迟API:选择 AudioCapturerFlag.SOURCE_TYPE_VOICE_RECOGNITION 模式

六、完整调用示例

@Entry
@Component
struct AudioCapturePage {
  @State isRecording: boolean = false;

  async toggleRecording() {
    if (this.isRecording) {
      await audioCapturer?.stop();
    } else {
      const hasPermission = await requestMicrophonePermission();
      if (!hasPermission) return;
      
      await initAudioCapturer();
      this.isRecording = true;
      startCapture(); // 异步执行
    }
    this.isRecording = !this.isRecording;
  }

  build() {
    Column() {
      Button(this.isRecording ? '停止录音' : '开始录音')
        .onClick(() => this.toggleRecording())
        
      Text('文件保存路径: /data/storage/recording.pcm')
        .margin(20)
    }
  }
}

通过以上代码,您可以在鸿蒙系统中实现完整的音频捕获功能。关键点在于正确配置音频参数、处理权限申请以及合理管理音频数据流。对于需要更高性能的场景(如语音识别),可进一步优化缓冲区策略并集成硬件加速能力。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐