用mui混合開發的APP,現有一個功能需求就是語音轉換成文字,並把語音進行保存。對此考慮兩種選擇訊飛和百度。最終選擇了百度語音。html
經過官方文檔咱們大體能夠肯定若是想要實現語音識別,要作到如下幾點:android
1.獲取Access Tokenios
2.獲取錄音 REST API的形式傳給百度服務器,返回文字web
我是把百度信息放到系統中的配置文件中,每次使用的時候調用接口便可。若是有所修改便於維護。ajax
<!--百度人工智能平臺訪問配置--> <add key="BaiduAIPAppID" value="22465672" /> <add key="BaiduAIPAPIKey" value="hUw1j0gFd5k0GVzM3m9dGGnL" /> <add key="BaiduAIPSecretKey" value="YddydGN4NqbzHUGtFu1Gug8jhFXKf7vN" />
ps:以上百度帳號不能正常使用,本身若是要用請自行申請。json
從官網上咱們能夠知道access Token 是有有效期的。但在有效期下屢次提交申請得到Access Token是相同的,因此我在同步到手機緩存是設置了有效期。在判斷是否存在或者是否過時而作出是否從新申請的判斷。api
下載安裝app後,把百度帳號存入手機緩存中,以便於後期直接使用。緩存
/* * 更新百度人工智能平臺訪問配置 */ function UpdateBaiduAipConfig(){ //代用服務器接口獲取百度帳號相應信息保存到手機緩存中 platform.ajax("MBase/GetBaiduAipConfig",null,function(data){ if(data){ var currentAppID = platform.GetData('BaiduAIPAppID') ; console.log(currentAppID) if (currentAppID != data.AppID) {//判斷是否已存在相關數據 console.log("AppID變化,更新配置"); platform.SaveData("BaiduAIPAppID", data.AppID)//此方法是封裝的H5存儲頁面緩存在這再也不過多敘述 platform.SaveData("BaiduAIPAPIKey", data.APIKey) platform.SaveData("BaiduAIPSecretKey", data.SecretKey) // 強制刷新token; platform.SaveData("token_timeout", new Date().getTime()) }else{ console.log("AppID沒有變化,無需更新"); } } },"post"); }
以上把百度帳號存進了到了手機頁面緩存中,一直有效。服務器
判斷是否須要更新獲取Token
//判斷是否須要更新獲取Token function needUpdateToken() { if(access_token == null || access_token == undefined || access_token.length == 0) { console.log("沒有token,須要更新"); return true; } var now = new Date().getTime(); if(token_timeout - now < 86400 * 1000) { console.log("token即將過時,須要更新"); return true; } console.log("token有效,無需更新:" + access_token); return false; }
//獲取token網絡
//獲取token function UpdateBaiduAipToken(entry) { var w = plus.nativeUI.showWaiting("請求中,請稍候..."); var token_url = generateTokenUrl(); mui.ajax(token_url, { data: '', type: 'post', contentType: "application/json; charset=utf-8", timeout: 5000, success: function(resp) { w.close(); access_token = resp.access_token; var expires_in = resp.expires_in; var now = new Date(); token_timeout = now.getTime() + expires_in * 1000; platform.SaveData("access_token", access_token); platform.SaveData("token_timeout", token_timeout); if(entry) { asr(entry); } }, error: function(xhr, type, errorThrown) { w.close(); alert("網絡請求出錯"); } }); }
//獲取百度信息
function get_baidu_api_key() { return platform.GetData("BaiduAIPAPIKey"); } function get_baidu_secret_key() { return platform.GetData("BaiduAIPSecretKey"); } function get_baidu_app_id() { return platform.GetData("BaiduAIPAppID"); }
//獲取token url
var token_url_base = "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id="; var asr_url_base = "http://vop.baidu.com/server_api" var len = 0; var app_id = get_baidu_app_id(); var access_token = platform.GetData("access_token"); var token_timeout = platform.GetData("token_timeout"); function generateTokenUrl() { var api_key = get_baidu_api_key(); var secret_key = get_baidu_secret_key(); console.log(token_url_base + api_key + "&client_secret=" + secret_key) return token_url_base + api_key + "&client_secret=" + secret_key; }
1.首先是獲取錄音
2.傳給百度服務器
3.獲取返回信息賦值
4.保存語音
全局變量
// 開始錄音 var r = null, t = 0, ri = null, rt = null; var rate = 16000; var channel = 1; if(mui.os.android) { var format = "amr"; } else if(mui.os.ios) { var format = "wav"; }
利用MUI H5+獲取錄音 r = plus.audio.getRecorder();
function startRecord() { var bt = $(this).attr("id"); //console.log( "開始錄音:" ); r = plus.audio.getRecorder(); //$$.alert(r.supportedFormats); if(r == null) { //console.log( "錄音對象未獲取" ); return; } r.record({ filename: "_doc/audio/", samplerate: rate }, function(p) { //console.log( "錄音完成:"+p ); plus.io.resolveLocalFileSystemURL(p, function(entry) { showMsic(entry.toLocalURL());//保存語音 doASR(entry);//語音識別轉換 //createItem( entry ); }, function(e) { //console.log( "讀取錄音文件錯誤:"+e.message ); }); }, function(e) { //console.log( "錄音失敗:"+e.message ); }); er.style.display = "block"; t = 0; ri = setInterval(function() { t++; rt.innerText = timeToStr(t); }, 1000); } function doASR(entry) { if(needUpdateToken()) { UpdateBaiduAipToken(entry); } else { asr(entr); } }
//轉換語音編碼 function asr(entry) { var w = plus.nativeUI.showWaiting("請求中,請稍候..."); entry.file(function(file) { len = file.size; console.log("錄音文件長度:" + len); var reader = new plus.io.FileReader(); reader.onload = function(e) { var strResult = e.target.result; console.log("編碼結果:" + strResult); var index = strResult.indexOf('base64,') + 7; var base64Str = strResult.slice(index, strResult.length); w.close(); speech2txt(base64Str); } reader.readAsDataURL(file); }, function(e) { w.close(); console.log("錄音文件處理出錯:" + e); }) } //傳給百度服務器 function speech2txt(base64Str) { var w = plus.nativeUI.showWaiting("請求中,請稍候..."); var data1 = { "format": format, "rate": rate, "dev_pid": 1536, "channel": channel, "token": access_token, "cuid": app_id, "len": len, "speech": base64Str }; var dataStr = JSON.stringify(data1); console.log("json: " + dataStr); mui.ajax(asr_url_base, { data: dataStr, type: 'post', contentType: "application/json", timeout: 5000, success: function(resp) { w.close(); if(resp.result == undefined || resp.result == '') { console.log("轉換失敗:" + resp.err_msg + " err_no: " + resp.err_no); return; } appendVoiceText(resp.result[0]);//賦值 console.log("轉換完成:" + resp.result[0]); }, error: function(xhr, type, errorThrown) { w.close(); if(type == 'timeout') { console.log("錄音超時"); } else { console.log("網絡請求出錯"); } } }); }
function appendVoiceText(voicePath) { cv = $("#HTContent").val()//獲取已有數據 if(cv.length > 0) { cv = cv + " " + voicePath; } else { cv = voicePath; } $("#HTContent").val(cv); }
function showMsic(mic) { //顯示圖片 if(mic) { if($("#image-list ul li").length <= 0) { $("#image-list ul").html(""); } var mcount = $("#image-list ul .muivideo").length + 1; var pname = mic.substring(mic.lastIndexOf('/') + 1); var imgstr = "<li data-path=\"" + mic + "\" >" + "<div class=\"muivideo\">錄音" + mcount + "</div>" + "<span class=\"mui-icon mui-icon-close imgdel\"></span>" + "</li>"; $(imgstr).appendTo("#image-list ul"); $("#sendvideo").focus(); } }
中止錄音,播放相應文件,中止播放,上傳語音長度
// 播放文件相關對象 var p = null, pt = null, pp = null, ps = null, pi = null; // 開始播放 function startPlay(url) { ep.style.display = "block"; var L = pp.clientWidth; p = plus.audio.createPlayer(url); p.play(function() { //console.log("播放完成!" ); // 播放完成 pt.innerText = timeToStr(d) + "/" + timeToStr(d); ps.style.webkitTransition = "all 0.3s linear"; ps.style.width = L + "px"; stopPlay(); }, function(e) { //console.log( "播放音頻文件\""+url+"\"失敗:"+e.message ); }); // 獲取總時長 var d = p.getDuration(); if(!d) { pt.innerText = "00:00:00/" + timeToStr(d); } pi = setInterval(function() { if(!d) { // 兼容沒法及時獲取總時長的狀況 d = p.getDuration(); } var c = p.getPosition(); if(!c) { // 兼容沒法及時獲取當前播放位置的狀況 return; } pt.innerText = timeToStr(c) + "/" + timeToStr(d); var pct = Math.round(L * c / d); if(pct < 8) { pct = 8; } ps.style.width = pct + "px"; }, 1000); } // 中止播放 function stopPlay() { clearInterval(pi); pi = null; setTimeout(resetPlay, 500); // 操做播放對象 if(p) { p.stop(); p = null; } } // 重置播放頁面內容 function resetPlay() { ep.style.display = "none"; ps.style.width = "8px"; ps.style.webkitTransition = "all 1s linear"; pt.innerText = "00:00:00/00:00:00"; } function timeToStr(ts) { if(isNaN(ts)) { return "--:--:--"; } var h = parseInt(ts / 3600); var m = parseInt((ts % 3600) / 60); var s = parseInt(ts % 60); if(s > 20) { stopRecord(); //超過20秒退出 } return(ultZeroize(h) + ":" + ultZeroize(m) + ":" + ultZeroize(s)); }; function ultZeroize(v, l) { var z = ""; l = l || 2; v = String(v); for(var i = 0; i < l - v.length; i++) { z += "0"; } return z + v; };