HarmonyOS AI语音播报、线程间通信和计时器的使用

奶盖
发布于 2021-6-21 11:28
浏览
4收藏

1. 项目介绍

 

HarmonyOS为应用提供了丰富的AI(Artificial Intelligence)能力,支持开箱即用。开发者可以灵活、便捷地选择AI能力,让应用变得更加智能。语音播报(Text to Speech,下文简称TTS),基于华为智慧引擎(HUAWEI HiAI Engine)中的语音识别引擎,向开发者提供人工智能应用层API。该技术提供将文本转换为语音并进行播报的能力。
通过本项目,您将学习到AI语音播报、线程间通信和计时器的使用方法。项目具体示例如下:程序主体部分是一个可输入文本框,您可以在其中输入需要播报的文本文案,点击"语音播报"即可对文本进行播报,程序会同步记录语音播报的耗时。HarmonyOS AI语音播报、线程间通信和计时器的使用-鸿蒙开发者社区

2. 语音播报

 

TTS提供将文本转换为语音并进行播报的能力。TTS的初始化代码如下所示:
步骤 1 - 创建TTS客户端

private void initTtsEngine() { 
    TtsClient.getInstance().create(this, ttsListener); 
}
  • 1.
  • 2.
  • 3.

 

步骤 2 - 实现TTS客户端创建成功的回调函数

public void onEvent(int eventType, PacMap pacMap) { 
    HiLog.info(LABEL_LOG, "onEvent..."); 
    // 定义TTS客户端创建成功的回调函数 
    if (eventType == TtsEvent.CREATE_TTS_CLIENT_SUCCESS) { 
        TtsParams ttsParams = new TtsParams(); 
        ttsParams.setDeviceId(UUID.randomUUID().toString()); 
        initItsResult = TtsClient.getInstance().init(ttsParams); 
    } 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

 

步骤 3 - 调用TtsClient.getInstance().speakText()方法对文本进行播报

private void readText(Component component) { 
    if (initItsResult) { 
        HiLog.info(LABEL_LOG, "initItsResult is true, speakText"); 
        TtsClient.getInstance().speakText(infoText.getText(), null); 
    } else { 
        HiLog.error(LABEL_LOG, "initItsResult is false"); 
    } 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

—-结束

 

3. 计时器和线程间通信

 

EventHandler是HarmonyOS用于处理线程间通信的一种机制,在开发过程中,开发者经常需要处理较为耗时的操作,但是又不希望当前的线程受到阻塞,此时,就可以使用EventHandler机制。例如本例中AI语音播报是在子线程9275中执行的,更新播报耗时是在UI主线程9015中执行的,日志如下所示:

02-20 11:26:56.916 9015-9015/com.huawei.codedemo I 01100/MainAbilitySlice: initItsResult is true, speakText 
02-20 11:26:56.924 9015-9015/com.huawei.codedemo I 01100/MainAbilitySlice: onEvent... 
02-20 11:26:56.926 9015-9864/com.huawei.codedemo I 01100/MainAbilitySlice: onStart... 
02-20 11:26:57.111 9015-9275/com.huawei.codedemo I 01100/MainAbilitySlice: onSpeechStart... 
02-20 11:26:57.117 9015-9015/com.huawei.codedemo I 01100/MainAbilitySlice: 播报耗时:0 s 
... 
02-20 11:27:09.575 9015-9015/com.huawei.codedemo I 01100/MainAbilitySlice: 播报耗时:12 s 
02-20 11:27:09.934 9015-9860/com.huawei.codedemo I 01100/MainAbilitySlice: onSpeechFinish...
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

 

对于这一场景,就需要使用到EventHandler线程间通信机制。例如,本例中开始发音的时候发送EVENT_MSG_TIME_COUNT事件,开始计时并更新UI页面,示例代码如下所示:

@Override 
public void onSpeechStart(String utteranceId) { 
    // 开始计时 
    HiLog.info(LABEL_LOG, "onSpeechStart..."); 
    if (timer == null && timerTask == null) { 
        timer = new Timer(); 
        timerTask = new TimerTask() { 
            public void run() { 
                handler.sendEvent(EVENT_MSG_TIME_COUNT); 
            } 
        }; 
        timer.schedule(timerTask, 0, 1000); 
    } 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

 

EventHandler更新UI页面的代码如下所示:

private EventHandler handler = new EventHandler(EventRunner.current()) { 
    @Override 
    protected void processEvent(InnerEvent event) { 
        switch (event.eventId) { 
            case EVENT_MSG_TIME_COUNT: 
                getUITaskDispatcher().delayDispatch(new Runnable() { 
                    @Override 
                    public void run() { 
                        time = time + 1; 
                        HiLog.info(LABEL_LOG, "播报耗时:" + Integer.toString(time) + " s"); 
                        timeText.setText("播报耗时:" + Integer.toString(time) + " s"); 
                    } 
                }, 0); 
                break; 
            default: 
                break; 
        } 
    } 
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

 

4. 完整示例

 

基于AI能力的语音播报系统完整示例代码如下所示:

package com.huawei.texttospeech.slice; 
 
import com.huawei.texttospeech.ResourceTable; 
import ohos.aafwk.ability.AbilitySlice; 
import ohos.aafwk.content.Intent; 
import ohos.agp.components.Button; 
import ohos.agp.components.Component; 
import ohos.agp.components.Text; 
import ohos.agp.components.TextField; 
import ohos.ai.tts.TtsClient; 
import ohos.ai.tts.TtsListener; 
import ohos.ai.tts.TtsParams; 
import ohos.ai.tts.constants.TtsEvent; 
import ohos.eventhandler.EventHandler; 
import ohos.eventhandler.EventRunner; 
import ohos.eventhandler.InnerEvent; 
import ohos.hiviewdfx.HiLog; 
import ohos.hiviewdfx.HiLogLabel; 
import ohos.utils.PacMap; 
 
import java.util.Timer; 
import java.util.TimerTask; 
import java.util.UUID; 
 
public class MainAbilitySlice extends AbilitySlice { 
    private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "MainAbilitySlice"); 
    private TextField infoText; 
    private Button readBtn; 
    private Text timeText; 
    private boolean initItsResult; 
    private static final int EVENT_MSG_INIT = 0x1000001; 
    private static final int EVENT_MSG_TIME_COUNT = 0x1000002; 
    private int time = 0; 
    private Timer timer = null; 
    private TimerTask timerTask = null; 
 
    private EventHandler handler = new EventHandler(EventRunner.current()) { 
        @Override 
        protected void processEvent(InnerEvent event) { 
            switch (event.eventId) { 
                case EVENT_MSG_TIME_COUNT: 
                    getUITaskDispatcher().delayDispatch(new Runnable() { 
                        @Override 
                        public void run() { 
                            time = time + 1; 
                            HiLog.info(LABEL_LOG, "播报耗时:" + Integer.toString(time) + " s"); 
                            timeText.setText("播报耗时:" + Integer.toString(time) + " s"); 
                        } 
                    }, 0); 
                    break; 
                default: 
                    break; 
            } 
        } 
    }; 
 
    @Override 
    public void onStart(Intent intent) { 
        super.onStart(intent); 
        super.setUIContent(ResourceTable.Layout_ability_main); 
        initView(); 
        initTtsEngine(); 
    } 
 
    private void initView() { 
        infoText = (TextField) findComponentById(ResourceTable.Id_text); 
        readBtn = (Button) findComponentById(ResourceTable.Id_read_btn); 
        timeText = (Text) findComponentById(ResourceTable.Id_time); 
        readBtn.setClickedListener(this::readText); 
    } 
 
    private void initTtsEngine() { 
        TtsClient.getInstance().create(this, ttsListener); 
    } 
 
    private void readText(Component component) { 
        if (initItsResult) { 
            HiLog.info(LABEL_LOG, "initItsResult is true, speakText"); 
            TtsClient.getInstance().speakText(infoText.getText(), null); 
        } else { 
            HiLog.error(LABEL_LOG, "initItsResult is false"); 
        } 
    } 
 
    private TtsListener ttsListener = new TtsListener() { 
        @Override 
        public void onEvent(int eventType, PacMap pacMap) { 
            HiLog.info(LABEL_LOG, "onEvent..."); 
            // 定义TTS客户端创建成功的回调函数 
            if (eventType == TtsEvent.CREATE_TTS_CLIENT_SUCCESS) { 
                TtsParams ttsParams = new TtsParams(); 
                ttsParams.setDeviceId(UUID.randomUUID().toString()); 
                initItsResult = TtsClient.getInstance().init(ttsParams); 
            } 
        } 
 
        @Override 
        public void onStart(String utteranceId) { 
            HiLog.info(LABEL_LOG, "onStart..."); 
        } 
 
        @Override 
        public void onProgress(String utteranceId, byte[] audioData, int progress) { 
        } 
 
        @Override 
        public void onFinish(String utteranceId) { 
            HiLog.info(LABEL_LOG, "onFinish..."); 
        } 
 
        @Override 
        public void onError(String s, String s1) { 
            HiLog.info(LABEL_LOG, "onError..."); 
        } 
 
        @Override 
        public void onSpeechStart(String utteranceId) { 
            // 开始计时 
            HiLog.info(LABEL_LOG, "onSpeechStart..."); 
            if (timer == null && timerTask == null) { 
                timer = new Timer(); 
                timerTask = new TimerTask() { 
                    public void run() { 
                        handler.sendEvent(EVENT_MSG_TIME_COUNT); 
                    } 
                }; 
                timer.schedule(timerTask, 0, 1000); 
            } 
        } 
 
        @Override 
        public void onSpeechProgressChanged(String utteranceId, int progress) { 
        } 
 
        @Override 
        public void onSpeechFinish(String utteranceId) { 
            // 结束计时 
            HiLog.info(LABEL_LOG, "onSpeechFinish..."); 
            timer.cancel(); 
            time = 0; 
            timer = null; 
            timerTask = null; 
        } 
    }; 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.

 

其中,页面布局文件为ability_main.xml,示例代码如下:

<?xml version="1.0" encoding="utf-8"?> 
<DirectionalLayout 
    xmlns:ohos="http://schemas.huawei.com/res/ohos" 
    ohos:height="match_parent" 
    ohos:width="match_parent" 
    ohos:orientation="vertical"> 
 
    <Text 
        ohos:height="match_content" 
        ohos:width="match_content" 
        ohos:margin="15vp" 
        ohos:text="AI语音播报" 
        ohos:text_size="23fp" 
        ohos:top_margin="40vp"/> 
 
    <TextField 
        ohos:id="$+id:text" 
        ohos:height="150vp" 
        ohos:width="match_content" 
        ohos:layout_alignment="horizontal_center" 
        ohos:left_margin="20vp" 
        ohos:multiple_lines="true" 
        ohos:right_margin="20vp" 
        ohos:text="华为创立于1987年,是全球领先的ICT(信息与通信)基础设施和智能终端提供商,我们致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界。" 
        ohos:text_size="50" 
        ohos:top_margin="20vp" 
        /> 
 
    <DirectionalLayout 
        xmlns:ohos="http://schemas.huawei.com/res/ohos" 
        ohos:height="match_parent" 
        ohos:width="match_parent" 
        ohos:orientation="horizontal"> 
 
        <Button 
            ohos:id="$+id:read_btn" 
            ohos:height="35vp" 
            ohos:width="80vp" 
            ohos:background_element="$graphic:background_button" 
            ohos:margin="15vp" 
            ohos:text="语音播报" 
            ohos:text_size="16fp"/> 
 
        <Text 
            ohos:id="$+id:time" 
            ohos:height="35vp" 
            ohos:width="150vp" 
            ohos:margin="15vp" 
            ohos:text="播报耗时:0 s" 
            ohos:text_size="16fp"/> 
    </DirectionalLayout> 
 
</DirectionalLayout>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.

 

此外您还需在resource/base/graphic目录下添加background_button.xml

<?xml version="1.0" encoding="utf-8"?> 
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos" 
       ohos:shape="rectangle"> 
    <corners 
        ohos:radius="40"/> 
    <solid 
        ohos:color="#e9e9e9"/> 
</shape>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

 

 说明:
以上代码仅demo演示参考使用,产品化的代码需要考虑数据校验和国际化。

已于2022-5-5 14:18:56修改
4
收藏 4
回复
举报
4
1
4
1条回复
按时间正序
/
按时间倒序
黑板报呀
黑板报呀

点赞点赞

回复
2021-6-22 08:54:05


回复
    相关推荐