js 實現網頁內容語音朗讀功能

案列演示地址

/*!
 * TtsAudioUtils v1.0
 * author dengmengxin
 * date 2019-09-5
 *
 * @example
 * ```
 * // 初始化語音合成配置
 * // 百度語音合成接口參數 請參考https://ai.baidu.com/docs#/TTS-API/0bda9a98
 * ttsAudioUtils.initTts({
 *     tok: 'access token',
 *     spd: 6,
 *     pit: 4,
 *     vol: 15,
 *     per: 0,
 *     lan: "zh"
 * });
 * // 獲取文本數組
 * ttsAudioUtils.obtainTextArrayFunction = function () {
 *     var textArray = [];
 *     textArray.push("語音合成由百度語音技術提供");
 *     return textArray;
 * }
 * ```
 */
var ttsAudioUtils = {
    stopped: true,
    paused: true,
    playing: false,
    param: {},
    audioArray: [],
    audio: new Audio(),
    obtainTextArrayFunction: null,// 獲取要合成播放的文本數組,由於不定性網頁內容,需要在外部實現
    onPlayCallback: null,// 播放回調
    onPauseCallback: null,// 暫停播放回調
    onStopCallback: null,// 停止播放回調
    onAudioErrorCallback: null,// 音頻錯誤回調
    onPlayCompleteCallback: null, // 播放完成回調
    /**
     * 初始化
     * @param {Object} param 合成參數
     */
    initTts: function (param) {
        ttsAudioUtils.param = param;
        ttsAudioUtils.param['ctp'] = 1;
        ttsAudioUtils.param['cuid'] = ttsAudioUtils._getDeviceOs();
    },
    /**
     * 播放
     */
    play: function () {
        if (ttsAudioUtils.playing) {
            return;
        }
        var textArray = ttsAudioUtils.isFunction(ttsAudioUtils.obtainTextArrayFunction) ? ttsAudioUtils.obtainTextArrayFunction() : [];
        if (textArray < 1) {
            console.log('沒有要播放的文本');
            return false;
        }
        if (ttsAudioUtils.stopped) {
            ttsAudioUtils._speak(textArray);
            ttsAudioUtils.stopped = false;
        }
        ttsAudioUtils.isFunction(ttsAudioUtils.onPlayCallback) && ttsAudioUtils.onPlayCallback();
        ttsAudioUtils.audio.play();
        ttsAudioUtils.paused = false;
        ttsAudioUtils.playing = true;
    },
    /**
     * 暫停播放
     */
    pause: function () {
        ttsAudioUtils.isFunction(ttsAudioUtils.onPauseCallback) && ttsAudioUtils.onPauseCallback();
        ttsAudioUtils.audio.pause();
        ttsAudioUtils.paused = true;
        ttsAudioUtils.playing = false;
    },
    /**
     * 停止播放
     */
    stop: function () {
        ttsAudioUtils.isFunction(ttsAudioUtils.onStopCallback) && ttsAudioUtils.onStopCallback();
        ttsAudioUtils.audio.pause();
        ttsAudioUtils.audio.removeEventListener('ended', ttsAudioUtils._playEndedHandler, false);
        ttsAudioUtils.audio.removeEventListener('error', ttsAudioUtils._playErrorHandler, false);
        ttsAudioUtils.stopped = true;
        ttsAudioUtils.paused = true;
        ttsAudioUtils.playing = false;
    },
    /**
     * 準備重讀
     */
    prepareReread: function () {
        ttsAudioUtils.audio.pause();
        ttsAudioUtils.audio.removeEventListener('ended', ttsAudioUtils._playEndedHandler, false);
        ttsAudioUtils.audio.removeEventListener('error', ttsAudioUtils._playErrorHandler, false);
        ttsAudioUtils.stopped = true;
        ttsAudioUtils.play();
    },
    /**
     * 內部播放結束回調
     */
    _playEndedHandler: function () {
        if (ttsAudioUtils.audioArray.length > 0) {
            ttsAudioUtils.audio.src = ttsAudioUtils.audioArray.pop();
            ttsAudioUtils.audio.play();
        } else {
            // 播放完成
            ttsAudioUtils.isFunction(ttsAudioUtils.onPlayCompleteCallback) && ttsAudioUtils.onPlayCompleteCallback();
            ttsAudioUtils.stop();
        }
    },
    /**
     * 內部播放錯誤回調
     */
    _playErrorHandler: function () {
        // 錯誤狀態  
        // Media.error; //null:正常  
        // Media.error.code; //1.用戶終止 2.網絡錯誤 3.解碼錯誤 4.URL無效
        ttsAudioUtils.playing = false;
        ttsAudioUtils.stop();
        ttsAudioUtils.isFunction(ttsAudioUtils.onAudioErrorCallback) && ttsAudioUtils.onAudioErrorCallback(ttsAudioUtils.audio);
        // console.log('合成語音播放出錯,錯誤碼:' + ttsAudioUtils.audio.error.code + ',鏈接:' + ttsAudioUtils.audio.currentSrc);
    },
    /**
     * 內部核心文本處理
     * @param {any[]} textArray 字符串文本數組
     */
    _speak: function (textArray) {
        if (ttsAudioUtils.param) {
            if (textArray < 1) {
                return false;
            }

            // 處理參數
            var urlParameter = [];
            for (var k in ttsAudioUtils.param) {
                urlParameter.push(k + '=' + ttsAudioUtils.param[k]);
            }

            ttsAudioUtils.audioArray = [];
            for (var i = 0; i < textArray.length; i++) {
                var address = 'http://tsn.baidu.com/text2audio?tex=' + encodeURIComponent(textArray[i]) + '&' + urlParameter.join('&');
                ttsAudioUtils.audioArray.unshift(address);

                //var address = 'http://tsn.baidu.com/text2audio?tex=' + encodeURIComponent(textArray[i]) + '&lan=zh&ctp=1&cuid=' + cuid + '&per=' + per + '&spd=' + spd + '&pit=' + pit + '&tok=' + tok;
                //ttsAudioUtils.audioArray.unshift(address);
            }
            ttsAudioUtils.audio.preload = true;
            ttsAudioUtils.audio.controls = true;
            ttsAudioUtils.audio.src = ttsAudioUtils.audioArray.pop();
            ttsAudioUtils.audio.addEventListener('ended', ttsAudioUtils._playEndedHandler, false);
            ttsAudioUtils.audio.addEventListener('error', ttsAudioUtils._playErrorHandler, false);
            ttsAudioUtils.audio.loop = false;
            console.log('語音合成中,請稍後...');
            return true;
        } else {
            return false;
        }
    },
    /**
     * 內部獲取設備系統
     */
    _getDeviceOs: function () {
        var sUserAgent = navigator.userAgent;
        var isWin = (navigator.platform == "Win32") || (navigator.platform == "Windows");
        var isMac = (navigator.platform == "Mac68K") || (navigator.platform == "MacPPC") || (navigator.platform == "Macintosh") || (navigator.platform == "MacIntel");
        if (isMac)
            return "Mac";
        var isUnix = (navigator.platform == "X11") && !isWin && !isMac;
        if (isUnix)
            return "Unix";
        var isLinux = (String(navigator.platform).indexOf("Linux") > -1);
        if (isLinux)
            return "Linux";
        if (isWin) {
            var isWin2K = sUserAgent.indexOf("Windows NT 5.0") > -1 || sUserAgent.indexOf("Windows 2000") > -1;
            if (isWin2K)
                return "Win2000";
            var isWinXP = sUserAgent.indexOf("Windows NT 5.1") > -1 || sUserAgent.indexOf("Windows XP") > -1;
            if (isWinXP)
                return "WinXP";
            var isWin2003 = sUserAgent.indexOf("Windows NT 5.2") > -1 || sUserAgent.indexOf("Windows 2003") > -1;
            if (isWin2003)
                return "Win2003";
            var isWinVista = sUserAgent.indexOf("Windows NT 6.0") > -1 || sUserAgent.indexOf("Windows Vista") > -1;
            if (isWinVista)
                return "WinVista";
            var isWin7 = sUserAgent.indexOf("Windows NT 6.1") > -1 || sUserAgent.indexOf("Windows 7") > -1;
            if (isWin7)
                return "Win7";
        }
        return "other";
    },
    // 判斷是否是函數
    isFunction: function (obj) {
        if (Object.prototype.toString.call(obj) === '[object Function]') {
            return true;
        }
        return false;
    },
    /**
     * 判斷字符是否爲空的方法
     * @param {String} obj - 字符串
     */
    isEmpty: function (obj) {
        if (typeof obj == "undefined" || obj == null || obj == "") {
            return true;
        } else {
            return false;
        }
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章