華為智慧屏分布式語音音樂軟件,可見即可說

??想了解更多關(guān)于開源的內(nèi)容,請訪問:??
在HarmonyOS官方文檔中,有這樣一項功能是只能在智慧屏上使用的,那就是可見即可說。恰好在很久之前參照官方分布式音樂播放器定制了一款自己的播放器,今天將其改造成智慧屏應(yīng)用,并添加可見即可說功能。待真機演示,有設(shè)備的小伙伴可以測試一下!
一、效果演示
- 各設(shè)備

- 手機平板,智慧屏



- 真機待測…(to do 7月7號)
二、可見即可說功能
按照官方文檔的介紹,可見即可說就是將一些熱詞與Component關(guān)聯(lián),達到監(jiān)聽語音熱詞,來執(zhí)行一些相應(yīng)操作。例如,瀏覽圖片的時候,說出圖片的名字或者角標序號,從而實現(xiàn)打開圖片的效果。
那么相應(yīng)的,我們就能將分布式音樂播放器改造成語音控制的,比如將"播放",“暫停”,"上一首"等熱詞綁定到對應(yīng)組件上,監(jiān)測到熱詞的時候執(zhí)行功能即可。
三、可見即可說開發(fā)
1、熱詞注冊
- 創(chuàng)建Component.VoiceEvent對象,設(shè)置相應(yīng)的熱詞,英文和中文都是可以的。
可見即可說的功能的核心就是,Component.VoiceEvent對象,一個對象對應(yīng)一個事件。
// 比如說設(shè)置一個播放事件
Component.VoiceEvent eventplay = new Component.VoiceEvent("播放");
- 一個Component.VoiceEvent對象,可以綁定多個熱詞。
eventplay.addSynonyms("play");
- 綁定完熱詞后,哪個組件需要這個語音事件,哪個組件就需要進行注冊。
//比如分布式音樂播放器里面的播放按鈕,對該語音事件進行注冊。
musicPlayButton.subscribeVoiceEvents(eventplay);
- 如果組件有多個語音事件要響應(yīng),我們就的創(chuàng)建多個Component.VoiceEvent對象,并且都進行注冊。一個對象對應(yīng)一個事件。
2、事件開發(fā)
在前面,我們設(shè)置了語音事件,并且將一個播放按鈕對其進行了注冊。但也僅僅是注冊,然后呢?然后就沒然后了,因為我們還沒有進行事件開發(fā),按鈕要在事件發(fā)生時做出響應(yīng)。
(1)實現(xiàn)SpeechEventListener接口
private Component.SpeechEventListener speechEventListener = new Component.SpeechEventListener(){
public boolean onSpeechEvent(Component v, SpeechEvent event) {
if (event.getActionProperty().equals("播放")) {
... // 檢測注冊的熱詞,進行相應(yīng)的處理
playOrpause();
}
return false;
};
}
(2)通過setSpeechEventListener方法實現(xiàn)回調(diào)注冊
musicplayButton.setSpeechEventListener(speechEventListener);
至此,我們對可見即可說的功能已經(jīng)了解了,那么下面是對分布式音樂播放器案例的改造,感興趣的讀者往下看。
四、案例編寫
1、工程結(jié)構(gòu)

2、UI設(shè)計

3、架構(gòu)簡析
這里簡單剖析一下架構(gòu),詳情見附件工程文件。
- PlayerManager.java
封裝好的播放器類,設(shè)置音樂路徑,播放暫停,上一首下一首的功能。
/**
* 首先播放之前要準備好媒體資源
*/
public void prepareMusic(){...}
/**
* 準備好音頻路徑 準備媒體資源
* @param Uri
*/
public void setResource(String Uri){...}
/**
* 播放
*/
public void play(){...}
/**
* 暫停
*/
public void pause(){...}
/**
* 定時事件通知更新進度條
* DELAY_TIME 延遲1s
* PERIOD 兩個事件間隔1s
*/
private void startTimetask(){...}
//.....
- StateListener
播放器狀態(tài)監(jiān)聽接口,監(jiān)聽播放器狀態(tài)進而進行一些事件通知。
package com.yzj.musicplayer.Player;
public interface StateListener {
void onPlaySuccess(int totalTime);
void onPauseSuccess();
void onPositionChange(int currentTime);
void onMusicFinished();
void onUriSet(String name);
}
- CommonProvider,ViewProvidor
 用來生成dialog,顯示可分布式流轉(zhuǎn)的設(shè)備列表, 對此不贅述,用JAVA做UI體驗不是很好。
- MainAbilitySlice
主頁面
4、綁定可見即可說事件
這里我們有播放,暫停,上一首,下一首,拖動進度條,分布式流轉(zhuǎn)等操作。
我們逐一為其添加語音事件。
//測試
//播放
private Component.VoiceEvent eventplay;
//暫停
private Component.VoiceEvent eventpause;
//下一首
private Component.VoiceEvent eventnext;
//前一首
private Component.VoiceEvent eventpre;
//流轉(zhuǎn)
private Component.VoiceEvent eventremote;
//流轉(zhuǎn)的語音相應(yīng)事件
private Component.SpeechEventListener speech_mShowDeviceListListener = new Component.SpeechEventListener() {
public boolean onSpeechEvent(Component component, SpeechEvent speechEvent) {
if(speechEvent.getActionProperty().equals("流轉(zhuǎn)")){
// 顯示選擇設(shè)備列表
continuationRegisterManager.showDeviceList(abilityToken, null, null);
}
return false;
}
};
void initview(){
//綁定熱詞
eventplay = new Component.VoiceEvent("播放");
eventpause = new Component.VoiceEvent("暫停");
eventnext = new Component.VoiceEvent("下一首");
eventpre = new Component.VoiceEvent("上一首");
eventremote = new Component.VoiceEvent("流轉(zhuǎn)");
//播放按鈕注冊熱詞
musicPlayButton.subscribeVoiceEvents(eventplay);
musicPlayButton.subscribeVoiceEvents(eventpause);
//播放按鈕設(shè)置響應(yīng)事件
musicPlayButton.setSpeechEventListener(new Component.SpeechEventListener() {
public boolean onSpeechEvent(Component component, SpeechEvent speechEvent) {
if(speechEvent.getActionProperty().equals("播放")){
if(playerManager.isPlaying()){
Log.info(TAG,"正在播放");
}
else{
playOrPause();
}
return true;
}
else if(speechEvent.getActionProperty().equals("暫停")){
if(!playerManager.isPlaying()){
Log.info(TAG,"已經(jīng)暫停了");
}
else{
playOrPause();
}
return true;
}
return false;
};
});
//下一首注冊熱詞
playnextButton.subscribeVoiceEvents(eventnext);
//下一首設(shè)置響應(yīng)事件
playnextButton.setSpeechEventListener(new Component.SpeechEventListener() {
public boolean onSpeechEvent(Component component, SpeechEvent speechEvent) {
if(speechEvent.getActionProperty().equals("下一首")){
nextMusic(component);
return true;
}
return false;
}
});
//上一首注冊熱詞
playpreButton.subscribeVoiceEvents(eventpre);
//上一首設(shè)置響應(yīng)事件
playpreButton.setSpeechEventListener(new Component.SpeechEventListener() {
public boolean onSpeechEvent(Component component, SpeechEvent speechEvent) {
if(speechEvent.getActionProperty().equals("上一首")){
prevMusic(component);
return true;
}
return false;
}
});
remotePlay.setClickedListener(mShowDeviceListListener);
//流轉(zhuǎn)按鈕注冊熱詞
remotePlay.subscribeVoiceEvents(eventremote);
//流轉(zhuǎn)按鈕設(shè)置流轉(zhuǎn)彈窗事件
remotePlay.setSpeechEventListener(speech_mShowDeviceListListener);
}
這里只展示了核心部分的代碼,具體含義看名稱即可知,詳情參見附件。
五、關(guān)于分布式流轉(zhuǎn)
關(guān)于流轉(zhuǎn)的部分,這里簡單復習一下。
在本案例里,任何動態(tài)變化的數(shù)據(jù)都是遷移和恢復的內(nèi)容。

六、關(guān)于旋轉(zhuǎn)動畫
- 創(chuàng)建一個屬性動畫
/* 屬性動畫 */
private AnimatorProperty animatorProperty;
- 初始化一個屬性對象
//初始化屬性動畫對象 musicPosters是一個Image組件
animatorProperty = musicPosters.createAnimatorProperty();
animatorProperty.setCurveType(Animator.CurveType.LINEAR);
- 啟動
//讓他一直循環(huán)轉(zhuǎn)下去
animatorProperty.rotate(360+musicPosters.getRotation()).setDuration(100000).setLoopedCount(-1).start();
- 暫停,重置
animatorProperty.stop();
animatorProperty.reset();
各種操作放在合適的位置執(zhí)行就可以了。
七、結(jié)語
本次主要在分布式音樂播放器案例中加入了智慧屏特有的可見即可說的功能,和一些簡單的優(yōu)化和動畫。在手機,平板上也能有類似的操作,可參考分布式語音照相機,但相比之下還是覺得可見即可說的功能更加清楚和好用。




























