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

发布于 2021-6-21 11:28
浏览
3收藏

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); 
}

 

步骤 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); 
    } 
}

 

步骤 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"); 
    } 
}

—-结束

 

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...

 

对于这一场景,就需要使用到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); 
    } 
}

 

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; 
        } 
    } 
};

 

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; 
        } 
    }; 
}

 

其中,页面布局文件为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>

 

此外您还需在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>

 

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

已于2022-5-5 14:18:56修改
4
收藏 3
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐