SpeechSynthesis實現前端消息實時語音播報


用StompJS/SpeechSynthesis實現前端消息實時語音播報


轉發鏈接:https://segmentfault.com/a/1190000022268377

前言

前端消息的實時推送我相信很多人不陌生,我們可以想到利用WebSocket,服務端主動向客戶端推送數據,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創建持久性的連接,並進行雙向數據傳輸。其優點有很多,能更好的節省服務器資源和帶寬,並且能夠更實時地進行通訊等等。語音播報則能夠在人們視覺沒有來的及關注時侯,通過聽覺來獲取需要信息。

這篇文章主要介紹的是基於websocket,利用Stomp.js以及HTML5語音Web Speech API——SpeechSynthesis來實現前端消息的實時推送與語音播報。

StompJS

讓我們先了解一下STOMP(the Simple (or Streaming) Text Orientated Messaging Protocol)——面向消息(或流)的簡單文本協議。它提供了一個可互操作的連接格式,允許STOMP客戶端與任意STOMP消息代理(Broker)進行交互。

WebSocket的實現客戶端看起來比較簡單,但是需要與後臺進行很好的配合和調試才能達到最佳效果。通過SockJS 、Stomp來進行瀏覽器兼容,可以增加消息語義和可用性。簡而言之,WebSocket 是底層協議,SockJS 是WebSocket 的備選方案,也是底層協議,而 STOMP 是基於 WebSocket(SockJS)的上層協議。

創建STOMP客戶端

下面簡單的介紹一下常用的方法。在web瀏覽器中我們可以通過兩種方式進行客戶端的創建:1、使用普通的WebSocket

<code>let url = "ws://localhost:61614/stomp";
let client = Stomp.client(url);/<code>

2、使用定製的WebSocket如果需要使用其他類型的Websocket(例如由SockJS包裝的Websocket),就利用下面的方式創建客戶端

<code>let url = "ws://localhost:61614/stomp";
let socket = new SockJS(url);
let client = Stomp.over(socket);/<code>

除上面的客戶端創建方式不同外,後續的連接等操作都是一樣的。

連接服務端

我們可以用client.connect()方法來連接服務端

<code>client.connect(login,passcode,successCallback,errorCallback);/<code>

其中login和passcode都是字符串,相當於是用戶的登錄名和密碼憑證。successCallback為連接成功的回調函數,errorCallback為連接失敗的回調函數。還可以這樣寫:

<code>client.connect({
login:'name',
passcode:'666',
'token':'2333'
},successCallback,errorCallback);/<code>

斷開連接:

<code>client.disconnect(function(){console.log("再見")})/<code>

Heart-beating(心跳)

heart-beating也就是消息傳送的頻率,incoming是接收頻率,outgoing是發送頻率,其默認值都為10000ms,我們可以手動設置:

<code>client.heartbeat.outgoing = 5000; 
client.heartbeat.incoming = 0;/<code>

發送消息

客戶端向服務端發送消息利用send()方法,此方法有三個參數:第一個參數(string)必需,為發送消息的目的地;第二個參數(object)可選,包含了額外的頭部信息;第三個參數(string)可選,為發送的消息。

<code>client.send(destination, {}, body);/<code>

訂閱消息

訂閱消息也就是客戶端接收服務端發送的消息,訂閱消息可以利用subscribe()方法,此方法有三個參數:第一個參數(string)必需,為接收消息的目的地;第二個參數必需為回調函數;第三個參數{object}為可選,包含額外的頭部信息。

<code>client.subscribe(destination, callback, {});/<code>

取消訂閱消息可以利用unsubscribe()方法:

<code> let mySubscribe =  client.subscribe;
mySubscribe.unsubscribe();/<code>

客戶端訂閱消息可以訂閱廣播,如下所示:

<code>client.subscribe('/topic/msg',function(messages){
console.log(messages);
})/<code>

也可以進行一對一消息的接收:

<code>//第一種方式
const userId = 666;
client.subscribe('/user/' + userId + '/msg',,function(messages){
console.log(messages);
})
//第二種方式
client.subscribe('/msg',function(messages){
console.log(messages);
}, {"userId ": userId })/<code>

客戶端採用的寫法要根據服務端代碼來做選擇。

Web Speech API

在HTML5中,與語音相關的Web Speech API可以分為兩種:一種為語音識別(Speech Recognition),另一種為語音合成(Speech Synthesis)。他們的作用分別為“語音轉文字”和“文字轉語音”。既然是HTML5中的東西,我們還是要先看看他們的兼容性如何:Speech Recognition:

用StompJS/SpeechSynthesis實現前端消息實時語音播報

Speech Synthesis:

用StompJS/SpeechSynthesis實現前端消息實時語音播報

從上面的圖中可以看出:語音識別(Speech Recognition)很慘烈,大部分瀏覽器還不支持。語音合成(Speech Synthesis)除開IE和Opera,基本上都支持了。本文要實現的是語音播報,就是要把文字消息,轉成語音播報出來,而語音合成(Speech Synthesis)就是實現這樣的功能,而且兼容性也是不錯的,所以我們就能拿來使用啦~

SpeechSynthesis

語音識別(Speech Recognition)就不過多介紹了,我們來詳細看看語音合成(Speech Synthesis)。我們可以先把下面這段代碼打到瀏覽器的控制檯上:

<code>let speechInstance = new window.SpeechSynthesisUtterance('你好,可以交個朋友嗎');
window.speechSynthesis.speak(speechInstance);/<code>

不出意外,瀏覽器說話了,說明瀏覽器是支持這個API的。下面簡單介紹一下相關的屬性和方法:SpeechSynthesisUtterance對象的屬性:

屬性類型描述textstring需要要讀的內容langstring使用的語言(比如:"zh-CN")volumenumber音量,值在0-1之間(默認是1)ratenumber語速的倍數,值在0.1-10之間(默認1倍)pitchnumber音高,值在0-2之間,(默認是1)voicestring指定希望使用的聲音

SpeechSynthesisUtterance對象的方法:

方法描述onstart語音開始合成時觸發onpause語音暫停時觸發onresume語音合成重新開始時觸發onend語音結束時觸發

上述定義的speechInstance其實是我們創建的文本實例,而真實的語音是由speechSynthesis來創建的,其常用的方法如下:

方法描述speak()開始合成語音,將對應的實例添加到語音隊列中cancel()停止合成語音,刪除隊列中所有的語音pause()暫停語音合成resume()恢復暫停後的語音getVoices()返回瀏覽器所支持的語音包數組

實戰環節

上面介紹了StompJS和SpeechSynthesis常用的屬性和方法,是時候動手碼一碼了。

前端web頁面消息實時接收

模擬服務端發送消息

想要接收實時消息,我們當先然要有消息的來源對不對。消息是從後臺發來的,一般是利用Java,然後結合ActiveMQ或者RabbitMQ等消息中間件,Java代碼就不多說,我們接下來就利用ActiveMQ來模擬服務端向客戶端發送消息。這裡說一說windows環境下吧,首先要下載ActiveMQ,直接點擊官網:http://activemq.apache.org/do...選擇最新發佈下來的壓縮包,解壓即可,然後進入解壓後的bin目錄,可以看見裡面有兩個文件夾,win32和win64,這個就根據自己電腦的操作系統來選擇,點擊進去,再雙擊activemq.bat啟動,如果看見下面這樣就說明啟動成功:

用StompJS/SpeechSynthesis實現前端消息實時語音播報

如果沒有啟動成功,那多半是因為沒有jdk,點這裡,跟著安裝就歐克啦~安裝完畢後,再雙擊activemq.bat,現在我們就啟動成功了。在瀏覽器中輸入:http://localhost:8161,可以看到:

用StompJS/SpeechSynthesis實現前端消息實時語音播報

點擊Manage ActiveMQ broker,用戶名和密碼都是admin,然後再點擊Topics

用StompJS/SpeechSynthesis實現前端消息實時語音播報

在輸入框中輸入msg,然後點擊create按鈕

用StompJS/SpeechSynthesis實現前端消息實時語音播報

可以看見下方列表中多了一個Name為msg的Topics

用StompJS/SpeechSynthesis實現前端消息實時語音播報

其中需要注意的是下面幾項,以msg為例:

  • Number Of Consumers :消費者數量,相當於連接服務端msg的客戶端的數量;
  • MessagesEnqueued:進入隊列的消息,相當於服務端向客戶端發送的消息數量;
  • MessagesDequeued:出了隊列的消息,相當於客戶端消費(訂閱)掉的消息數量。
  • 其它想要多瞭解的可以搜索一波。

模擬“服務端”準備就緒。

客戶端消息接收

這“服務端”搞好了,接下來就是客戶端的實現,代碼貼出來index.html:

<code>




<title>實時語音播報/<title>





/<code>

在瀏覽器中打開這個HTML文件,然後打開控制檯,可以看見,我們已經連接服務端成功了:

用StompJS/SpeechSynthesis實現前端消息實時語音播報

連接成功之後呢,我們就可以嘗試在服務端向客戶端發送消息,先切換到ActiveMQ 的頁面:

用StompJS/SpeechSynthesis實現前端消息實時語音播報

可以看見我們的消費者的數量為1了,然後點擊Send To,就可以開始發消息了:

用StompJS/SpeechSynthesis實現前端消息實時語音播報

比如我們發送一個“你好”,然後我們再切到index.html:

用StompJS/SpeechSynthesis實現前端消息實時語音播報

我們收到了來自服務端的問候~

SpeechSynthesis語音播報

消息已經能夠實時接收了,現在就是需要把接收到的消息讀出來,思路很簡單,就是把語音合成相關API封裝成一個函數,然後當我們服務端發送消息到客戶端之後,把消息數據傳到為我們定義好的語音播報函數里面,然後就能讀出我們服務端發出的消息了,說幹就幹:

<code>//語音播報
speechInfo = () => {
let speechInstance = new SpeechSynthesisUtterance();

return {
//語音播報開始
start: function (content) {
let lang = 'zh-CN';
let text = content;
if( text !== '') {
speechInstance.text = text;
speechInstance.lang = lang;
speechInstance.volume = 1;
speechInstance.rate = 1;
speechSynthesis.speak(speechInstance);
speechInstance.onend = function(event){
console.log("語音播報完畢");
}
}
},

//暫停
pause : function () {
speechSynthesis.pause();
},
//重新開始
resume: function() {

speechSynthesis.resume();
},
//取消
cancel: function() {
speechSynthesis.cancel();
}
}
};/<code>

那咱們調用一下,然後在ActiceMQ頁面發送一條新消息,看是不是如我們所願:

<code>...

client.subscribe('/topic/msg', function(message){
if(message.body){
data = message.body;
console.log(message.body);
//調用語音合成函數
speechInfo().start(data);
}
})

.../<code>

如果是火狐,360安全瀏覽器等瀏覽器,我們的消息和聲音都如期而至。

但是如果用的是Chrome的話,很難受,並沒有聲音,難道是Chrome不支持了嗎?但是我們之前那兩行測試代碼說明Chrome是支持SpeechSynthesis的,那是怎麼回事?答案就在下面:

用StompJS/SpeechSynthesis實現前端消息實時語音播報

Chrome不再支持SpeechSynthesis.speak()的自動播放,要想用的話,必須用戶手動去調用它。原因可以看這裡被垃圾廣告濫用後谷歌瀏覽器71將限制語音合成自動播放

垃圾網站出來背鍋!!!

想不到吧,有一天需要去“兼容”Chrome了。語音不能實時的播報出來,我們看看有沒有什麼辦法。我的思路是在頁面加一個按鈕,然後進行模擬人去點擊,完整index.html代碼:

<code>




<title>Document/<title>



<button> 點擊/<button>




/<code>

但是我們能想到,谷歌想不到?這裡又涉及一個知識點:isTrusted

Event接口的isTrusted是一個Boolean類型的只讀屬性.當事件由用戶操作生成時為true,由腳本創建或修改,或通過調用EventTarget.dispatchEvent生成,為false

我們在控制檯代碼中打個斷點,然後在ActiveMQ 發條消息瞧一瞧,是不是與這個有關:

用StompJS/SpeechSynthesis實現前端消息實時語音播報

可以看見isTrusted的值為false,這個模擬點擊事件是不被瀏覽器信任的,然後我們再手動點擊一下我們寫好的按鈕:

用StompJS/SpeechSynthesis實現前端消息實時語音播報

isTrusted的值為true,我們的聲音也出來了,當我們再在ActiveMQ 發送一條消息:

用StompJS/SpeechSynthesis實現前端消息實時語音播報

聲音自動播放出來了。

最後

需要提一點的是,我在實際是在react中開發的,相關方法都和上述的寫法類似,但是卻不會觸發Chrome對於SpeechSynthesis.speak()的限制,這個限制也是我在寫這篇文章的時候,用原生js+HTML的時候發現的。總的來說用原生js+HTML實現的並不算完美,在Chrome下需要在頁面加載完成後進行一次點擊,才能把後續的語音實時的播報出來。如果大家有相關的解決辦法,或者用其它的方式實現了前端消息實時的語音播報,歡迎提出來,先謝過了~

轉發鏈接:https://segmentfault.com/a/1190000022268377


分享到:


相關文章: