HarmonyOS开发5.0【声音文件转文本】AI语音

前言

本文主要实现 使用鸿蒙的AI语音功能将声音文件识别并转换成文本

实现流程

  1. 利用AudioCapturer 录制声音,生成录音文件
  2. 利用AI语音功能,实现识别

1

两个录音库介绍

HarmonyOS NEXT 应用开中,实现录音的两个核心库分别为

  1. AudioCapturer
  2. AVRecorder

AVRecorder录制出来的声音封装格式只能是aac,这个文件格式我们的AI语音引擎不支持,AI语音引擎只支持pcm格式,而 AudioCapturer录制的声音封装格式则是pcm。因此我们选择使用 AudioCapturer 来录制声音

AudioCapturer 介绍

AudioCapturer是音频采集器,用于录制PCM(Pulse Code Modulation)音频数据,适合有音频开发经验的开发者实现更灵活的录制功

能。

状态变化示意图

2

能看到使用 AudioCapturer 的主要流程为

  1. 创建 AudioCapturer 实例
  2. 调用 start 方法开始录音
  3. 调用stop方法停止录音
  4. 调用release方法释放实例

创建 AudioCapturer 实例

文末会提供封装好,可以直接使用的代码 下面的代码示例都是基于封装好的代码进行的

我们通过调用 createAudioCapturer方法实现创建 AudioCapturer 实例,其中该方法需要传递相关参数。

3

调用 start 方法开始录音

开始调用 start 方法时,需要准备相关数据。如

  1. 提供录音的文件名,可以自定义
  2. 写入录音数据的回调函数(在录制声音的过程中持续触发)
  3. 调用start方法

4

调用stop方法停止录音

调用stop方法则相对简单,直接调用即可

5

调用release方法释放实例

同理

6

封装好的录音代码

\entry\src\main\ets\utils\AudioCapturerManager.ets 下面是这个类的属性和方法的总结:

属性

  • static audioCapturer:

    • 类型是 audio.AudioCapturer | null,是一个静态属性,用于存储当前的音频捕获器实例。
  • private static recordFilePath:

    • 类型是 string,是一个静态私有属性,用于存储录音文件的路径。

方法

  • static async createAudioCapturer() :

    • 如果 audioCapturer 已经存在,则直接返回该实例;否则创建一个新的音频捕获器实例,并设置其音频流信息和音频捕获信息,然后创建并返回新的实例。
  • static async startRecord(fileName: string) :

    • 异步静态方法,用于启动录音过程。首先调用 createAudioCapturer() 方法确保有一个音频捕获器实例。之后初始化缓冲区大小,并打开或创建一个指定名称的 .wav 录音文件。定义一个读取数据的回调函数,用于将捕获到的数据写入文件中。最后开始录音,并记录下录音文件的路径。
  • static async stopRecord() :

    • 异步静态方法,用于停止录音过程。停止音频捕获器的工作,释放其资源,并清除 audioCapturer 实例。
// 导入音频处理模块
import { audio } from '@kit.AudioKit';
// 导入文件系统模块
import fs from '@ohos.file.fs';


// 定义一个管理音频录制的类
export class AudioCapturerManager {
  // 静态属性,用于存储当前的音频捕获器实例
  static audioCapturer: audio.AudioCapturer | null = null;
  // 静态私有属性,用于存储录音文件的路径
  private static recordFilePath: string = "";

  // 静态异步方法,用于创建音频捕获器实例
  static async createAudioCapturer() {
    if (AudioCapturerManager.audioCapturer) {
      return AudioCapturerManager.audioCapturer
    }
    // 设置音频流信息配置
    let audioStreamInfo: audio.AudioStreamInfo = {
      samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_16000, // 设置采样率为16kHz
      channels: audio.AudioChannel.CHANNEL_1, // 设置单声道
      sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 设置样本格式为16位小端
      encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 设置编码类型为原始数据
    };

    // 设置音频捕获信息配置
    let audioCapturerInfo: audio.AudioCapturerInfo = {
      source: audio.SourceType.SOURCE_TYPE_MIC, // 设置麦克风为音频来源
      capturerFlags: 0 // 捕获器标志,此处为默认值
    };

    // 创建音频捕获选项对象
    let audioCapturerOptions: audio.AudioCapturerOptions = {
      streamInfo: audioStreamInfo, // 使用上面定义的音频流信息
      capturerInfo: audioCapturerInfo // 使用上面定义的音频捕获信息
    };

    // 创建音频捕获器实例
    AudioCapturerManager.audioCapturer = await audio.createAudioCapturer(audioCapturerOptions);

    // 返回创建的音频捕获器实例
    return AudioCapturerManager.audioCapturer;
  }

  // 静态异步方法,用于启动录音过程
  static async startRecord(fileName: string) {
    await AudioCapturerManager.createAudioCapturer()
    // 初始化缓冲区大小
    let bufferSize: number = 0;

    // 定义一个内部类来设置写入文件时的选项
    class Options {
      offset?: number; // 文件写入位置偏移量
      length?: number; // 写入数据的长度
    }

    // 获取应用的文件目录路径
    let path = getContext().filesDir;

    // 设置录音文件的完整路径
    let filePath = `${path}/${fileName}.wav`;


    // 打开或创建录音文件
    let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);

    // 定义一个读取数据的回调函数
    let readDataCallback = (buffer: ArrayBuffer) => {
      // 创建一个写入文件的选项对象
      let options: Options = {
        offset: bufferSize, // 文件当前位置偏移量
        length: buffer.byteLength // 数据长度
      };
      // 将数据写入文件
      fs.writeSync(file.fd, buffer, options);
      // 更新缓冲区大小
      bufferSize += buffer.byteLength;
    };

    // 给音频捕获器实例注册读取数据的事件监听器
    AudioCapturerManager.audioCapturer?.on('readData', readDataCallback);

    // 开始录音
    AudioCapturerManager.audioCapturer?.start();

    AudioCapturerManager.recordFilePath = filePath;
    // 返回录音文件的路径
    return filePath;

  }

  // 静态异步方法,用于停止录音过程
  static async stopRecord() {
    // 停止音频捕获器的工作
    await AudioCapturerManager.audioCapturer?.stop();
    // 释放音频捕获器的资源
    await AudioCapturerManager.audioCapturer?.release();
    // 清除音频捕获器实例
    AudioCapturerManager.audioCapturer = null;
  }
}

页面中开始录音

7

可以通过以下路径查看录音文件是否真实生成

/data/app/el2/100/base/你的项目的boundle名称/haps/entry/files

8

页面代码

Index.ets

import { PermissionManager } from '../utils/permissionMananger'
import { Permissions } from '@kit.AbilityKit'
import SpeechRecognizerManager from '../utils/SpeechRecognizerManager'
import { AudioCapturerManager } from '../utils/AudioCapturerManager'

@Entry
@Component
struct Index {
  @State
  text: string = ""
  fileName: string = ""
  // 1 申请权限
  fn1 = async () => {
    // 准备好需要申请的权限 麦克风权限
    const permissions: Permissions[] = ["ohos.permission.MICROPHONE"]
    // 检查是否拥有权限
    const isPermission = await PermissionManager.checkPermission(permissions)
    if (!isPermission) {
      //   如果没权限,就主动申请
      PermissionManager.requestPermission(permissions)
    }
  }
  // 2 实时语音识别
  fn2 = () => {
    SpeechRecognizerManager.init(res => {
      console.log("实时语音识别", JSON.stringify(res))
      this.text = res.result
    })
  }
  // 3 开始录音
  fn3 = () => {
    this.fileName = Date.now().toString()
    AudioCapturerManager.startRecord(this.fileName)
  }
  // 4 接收录音
  fn4 = () => {
    AudioCapturerManager.stopRecord()
  }

  build() {
    Column({ space: 10 }) {
      Text(this.text)

      Button("申请权限")
        .onClick(this.fn1)
      Button("实时语音识别")
        .onClick(this.fn2)

      Button("开始录音")
        .onClick(this.fn3)
      Button("结束录音")
        .onClick(this.fn4)
    }
    .width("100%")
    .height("100%")
    .justifyContent(FlexAlign.Center)
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值