2
头图

目录

  • 前言
  • 项目背景
  • 功能概述
  • 技术实现
  • 结束语

前言

在数字化时代浪潮下,智能设备正逐渐成为我们生活中不可或缺的一部分。随着HarmonyOS NEXT的推出,越来越多的开发者开始通过它来为用户提供更加丰富、便捷的应用体验。笔者很荣幸作为一名HarmonyOS NEXT体验官,已经体验使用一年多HarmonyOS NEXT了,那么本文就来向大家展示一个简单易用的基于HarmonyOS NEXT的语音播报demo,它将展示HarmonyOS NEXT在语音交互方面的强大能力和新特性,也方便HarmonyOS NEXT开发的小伙伴学习使用。

项目背景

作为大前端开发者,想必大家都知道语音播报功能在应用开发中的很多场景下都非常实用,比如智能家居控制、新闻资讯播报、语音助手、支付收款等。而HarmonyOS NEXT为开发者提供了丰富的API和工具,使得开发这类功能变得非常简单和快捷,但是由于市面上关于HarmonyOS NEXT的语音播报使用的demo案例较少,所以本文就以这个背景来开发一个任何人都会用的语音播报的demo。

功能概述

本文的这个demo旨在创建一个基础的语音播报应用,开发者可以通过预设文本内容,应用会将文本转换为语音并播放,这个demo将涵盖以下功能:
1.文本设置:用户可以在应用中提前设置想要播报的文本。
2.语音合成:应用将文本转换为语音。
3.播放控制:用户可以点击内容进行多次播放。
image.png

技术实现

1. 环境搭建

先要确保已经安装了DevEco Studio,并且配置了HarmonyOS NEXT的较新版本的开发环境。

2. 语音播报核心功能

HarmonyOS提供了语音合成API,可以在具体使用中调用这些API来实现文本到语音的转换,先创建载体页面及调用,具体代码如下所示:

/**
 * @author 三掌柜
 * @data 2024/9/23 14:56
 */
import  TextToSpeech  from './TextToSpeechUtils';

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  build() {
    Column() {
      RelativeContainer() {
        Text('语音播报demo')
          .height(54)
          .id('title')
          .alignRules({
            middle: {
              anchor: '__container__',
              align: HorizontalAlign.Center
            }
          })
      }
      .width('100%')
      .height(80)
      .padding({ right: 10})

      Column() {

        Text('点击语音播报')
          .fontColor(Color.Red)
          .fontSize(30)
          .margin({ top: 100 })
          .onClick(()=>{
            let speech:string = 'Hello, HarmonyOS'; //语音播报文本内容
            TextToSpeech.createSpeak(speech, 1) //语音播报 此处调用语音播报的方法
          })
      }
      .width('100%')
      .height('100%')
      .hitTestBehavior(HitTestMode.Transparent)
    }.width('100%')
    .height('100%')
  }
}

再来分享一下关于语音播报的工具类文件,具体代码如下所示:

/**
 * @author 三掌柜
 * @data 2024/9/23 14:56
 */
import { textToSpeech } from '@kit.CoreSpeechKit';
import { BusinessError } from '@kit.BasicServicesKit';

let ttsEngine: textToSpeech.TextToSpeechEngine; // 引擎实例
let originalText = ''; // 原始文本
let speed: number = 1 // 语速

class TextToSpeechUtils {
  // 数据回调
  speakListener?: textToSpeech.SpeakListener;

  constructor(originalText: string, speed: number) {
    this.initListener()
    this.createSpeak(originalText, speed)
  }
  //服务初始化
  initListener() {
    this.speakListener = {
      // 开始播报回调
      onStart(requestId: string, response: textToSpeech.StartResponse) {
        console.info(`onStart, requestId: ${requestId} response: ${JSON.stringify(response)}`);
      },
      // 完成播报回调
      onComplete(requestId: string, response: textToSpeech.CompleteResponse) {
        if (response.type === 1) {
          ttsEngine.shutdown();
          console.info(`onComplete, requestId: ${requestId} response: ${JSON.stringify(response)}`);
        }
      },
      // 停止播报完成回调,调用stop方法并完成时会触发此回调
      onStop(requestId: string, response: textToSpeech.StopResponse) {
        console.info(`onStop, requestId: ${requestId} response: ${JSON.stringify(response)}`);
      },
      // 返回音频流
      onData(requestId: string, audio: ArrayBuffer, response: textToSpeech.SynthesisResponse) {
        console.info(`onData, requestId: ${requestId} sequence: ${JSON.stringify(response)} audio: ${JSON.stringify(audio)}`);
      },
      // 错误回调,播报过程发生错误时触发此回调
      // 未创建引擎时调用speak方法时返回错误码1003400007,合成及播报失败
      // 连续调用两次speak,第二次speak会返回错误码1003400006,服务正忙碌
      onError(requestId: string, errorCode: number, errorMessage: string) {
        console.error(`onError, requestId: ${requestId} errorCode: ${errorCode} errorMessage: ${errorMessage}`);
      }
    };
  }

  // 创建引擎,通过callback形式返回
  // 当引擎不存在、引擎资源不存在、初始化超时,返回错误码1003400005,引擎创建失败
  createSpeak(originalText: string, speed: number) {
    // 设置创建引擎参数
    let extraParam: Record<string, Object> = { "style": 'interaction-broadcast', "locate": 'CN', "name": 'EngineName' };
    let initParamsInfo: textToSpeech.CreateEngineParams = {
      language: 'zh-CN',
      person: 0,
      online: 1,
      extraParams: extraParam
    };

    // Promise方式
    // 调用createEngine方法
    textToSpeech.createEngine(initParamsInfo)
      .then((res: textToSpeech.TextToSpeechEngine) => {
        // 获得引擎实例
        ttsEngine = res;
        // 设置回调
        console.info(`Succeeded in creating engine, result: ${JSON.stringify(res)}.`);
        if (res) {
          ttsEngine.setListener(this.speakListener);
          this.speak(originalText, speed)
        }
      }).catch((err: BusinessError) => {
      console.error(`Failed to create engine. Code: ${err.code}, message: ${err.message}.`);
    })
      .finally(() => {
      })
  };

  // 调用speak播报方法
  // 未初始化引擎时调用speak方法,返回错误码1003400007,合成及播报失败
  speak(originalText: string, speed: number) {
    // 设置播报相关参数
    let extraParam: Record<string, Object> = {
      "queueMode": 0,
      "speed": speed, // 语速,取值范围[0.5, 2.0]
      "volume": 2,
      "pitch": 1,
      "languageContext": 'zh-CN',
      "audioType": "pcm",
      "soundChannel": 3,
      "playType": 1
    }
    let speakParams: textToSpeech.SpeakParams = {
      requestId: Date.now().toString(), // requestId在同一实例内仅能用一次,请勿重复设置
      extraParams: extraParam
    };
    // 调用speak播报方法
    ttsEngine?.speak(originalText, speakParams);
  };

  // 停止合成及停止播报
  stop() {
    // 调用stop方法停止播报
    ttsEngine?.stop();
  };

  // 释放引擎,释放成功后,再次调用createEngine方法会重新创建引擎
  shutdown() {
    // 调用release方法释放引擎
    ttsEngine?.shutdown();
  };

  //判断当前是否处于合成或播报中
  isSpeaking() {
    let isSpeaking: boolean = ttsEngine.isBusy();
    console.info(`isSpeaking: ${isSpeaking}`);
    return isSpeaking;
  };
}

export default new TextToSpeechUtils(originalText, speed);

测试与优化

各位小伙伴可以把工具类拖入到自己的项目中,然后在具体想要使用的地方进行引入并调用语音播报的方法,然后运行应用,并测试语音播报功能是否正常工作。大家可以根据需要,调整界面设计和功能逻辑,确保应用的易用性和稳定性,也欢迎大家进行修改和优化,具体的demo链接:https://gitee.com/sanzhanggui/text-speech/tree/bash/

结束语

通过本文内容的分享,结合这个简单的语音播报的demo,我们可以看到HarmonyOS NEXT在语音交互方面提供的健全的API,作为开发者的我们可以利用这些工具和API,快速构建功能丰富、用户体验优秀的鸿蒙原生应用。最后,也要感谢HarmonyOS NEXT提供的平台和工具,让语音播报功能的实现如此简单,希望这个demo能为更多开发者提供学习帮助和参考价值,也欢迎大家进行修改和完善这个demo。


三掌柜
13.5k 声望6k 粉丝

一分耕耘,不一定有一分收获,但十分耕耘,一定会有一分收获!