class VolumeTTS { // 默认TTS参数 static DEFAULT_PARAMS = { lang: "zh-CN", speed: 1, pitch: 1, volume: 1, }; // 数字到中文的映射 static DIGIT_MAP = { 0: "零", 1: "一", 2: "二", 3: "三", 4: "四", 5: "五", 6: "六", 7: "七", 8: "八", 9: "九" }; constructor(opts = {}) { this.ttsParams = this._initializeParams(opts); this.TTSModule = null; this.customOpts = null; this.platform = uni.getSystemInfoSync().platform; this.isInitialized = false; this.isSpeaking = false; // #ifdef APP-PLUS this._initTTS(); // #endif } /** * 初始化TTS参数 * @private */ _initializeParams(opts) { const audioConfig = uni.getStorageSync("audioConfig"); if (opts && Object.keys(opts).length > 0) { return { ...VolumeTTS.DEFAULT_PARAMS, ...opts }; } if (audioConfig) { return { lang: "zh-CN", speed: Math.max(0.1, Math.min(2.0, audioConfig.audioSpeed / 10)), pitch: Math.max(0.1, Math.min(2.0, audioConfig.audioVolume)), volume: 1, }; } return { ...VolumeTTS.DEFAULT_PARAMS }; } /** * 初始化TTS模块 * @private */ _initTTS() { try { this.TTSModule = uni.requireNativePlugin("nrb-tts-plugin"); if (!this.TTSModule) { console.warn('TTS模块加载失败'); return; } this.TTSModule.init( { lang: "zh", country: "CN", }, (res) => { if (res.success === 0) { this.isInitialized = true; console.log('TTS初始化成功'); // 移除调试弹窗,改为控制台日志 } else { console.error('TTS初始化失败:', res); } } ); } catch (error) { console.error('TTS模块初始化异常:', error); } } /** * 预处理文本,将数字转换为中文 * @param {string} text - 待处理的文本 * @returns {string} 处理后的文本 */ preprocessText(text) { if (!text || typeof text !== 'string') { return ''; } return text.replace(/\d+/g, (match) => { return match .split("") .map((digit) => VolumeTTS.DIGIT_MAP[digit] || digit) .join(""); }); } /** * 设置自定义的opts参数 * @param {Object} opts - 自定义的opts参数 */ setCustomOpts(opts) { if (opts && typeof opts === 'object') { this.customOpts = { ...opts }; } } /** * 获取当前的自定义opts参数 * @returns {Object|null} 当前的自定义opts参数 */ getCustomOpts() { return this.customOpts ? { ...this.customOpts } : null; } /** * 清除自定义的opts参数,恢复默认行为 */ clearCustomOpts() { this.customOpts = null; } /** * 获取平台特定的TTS选项 * @private */ _getPlatformOpts() { if (this.platform === "ios") { return { rate: this.ttsParams.speed, lang: "zh-CN", volume: this.ttsParams.volume, }; } else { return { pitch: this.ttsParams.pitch, speechRate: this.ttsParams.speed, queueMode: 1, }; } } /** * 语音合成 * @param {string} text - 要合成的文本 * @param {Object} customOpts - 自定义选项 * @returns {Promise} 是否成功开始合成 */ async speak(text, customOpts = null) { if (!text || typeof text !== 'string') { console.warn('TTS: 无效的文本输入'); return false; } if (this.isSpeaking) { console.log('TTS: 正在播放中,停止当前播放'); this.stop(); } const processedText = this.preprocessText(text); console.log('TTS: 开始合成文本:', processedText); // #ifdef H5 return this._speakH5(processedText); // #endif // #ifdef APP-PLUS return this._speakApp(processedText, customOpts); // #endif return false; } /** * H5端语音合成 * @private */ _speakH5(text) { if ("speechSynthesis" in window) { try { const utterance = new SpeechSynthesisUtterance(text); utterance.lang = this.ttsParams.lang; utterance.rate = this.ttsParams.speed; utterance.pitch = this.ttsParams.pitch; utterance.volume = this.ttsParams.volume; utterance.onstart = () => { this.isSpeaking = true; console.log('TTS: H5开始播放'); }; utterance.onend = () => { this.isSpeaking = false; console.log('TTS: H5播放完成'); }; utterance.onerror = (error) => { this.isSpeaking = false; console.error('TTS: H5播放错误:', error); }; speechSynthesis.speak(utterance); return true; } catch (error) { console.error('TTS: H5播放异常:', error); return false; } } return false; } /** * APP端语音合成 * @private */ _speakApp(text, customOpts) { if (!this.TTSModule || Object.keys(this.TTSModule).length === 0) { console.log('TTS: 重新初始化模块'); this._initTTS(); return false; } try { let opts; // 优先级:方法参数传入的customOpts > setCustomOpts设置的customOpts > 默认opts if (customOpts && typeof customOpts === 'object') { opts = customOpts; } else if (this.customOpts) { opts = this.customOpts; } else { opts = this._getPlatformOpts(); } this.TTSModule.speak(text, opts, (result) => { if (result && result.success === 0) { this.isSpeaking = true; console.log('TTS: APP开始播放'); } else { console.error('TTS: APP播放失败:', result); } }); return true; } catch (error) { console.error('TTS: APP播放异常:', error); return false; } } /** * 停止语音合成 */ stop() { this.isSpeaking = false; // #ifdef H5 if ("speechSynthesis" in window) { speechSynthesis.cancel(); } // #endif // #ifdef APP-PLUS if (this.TTSModule && typeof this.TTSModule.stop === 'function') { try { this.TTSModule.stop(); } catch (error) { console.error('TTS: 停止播放异常:', error); } } // #endif console.log('TTS: 已停止播放'); } /** * 暂停语音合成 */ pause() { // #ifdef H5 if ("speechSynthesis" in window) { speechSynthesis.pause(); } // #endif console.log('TTS: 已暂停播放'); } /** * 恢复语音合成 */ resume() { // #ifdef H5 if ("speechSynthesis" in window) { speechSynthesis.resume(); } // #endif console.log('TTS: 已恢复播放'); } /** * 检查是否正在播放 * @returns {boolean} 是否正在播放 */ isPlaying() { return this.isSpeaking; } /** * 检查TTS是否已初始化 * @returns {boolean} 是否已初始化 */ isReady() { return this.isInitialized; } /** * 销毁TTS实例 */ destroy() { this.stop(); this.isInitialized = false; this.TTSModule = null; this.customOpts = null; this.ttsParams = { ...VolumeTTS.DEFAULT_PARAMS }; console.log('TTS: 实例已销毁'); } /** * 更新TTS参数 * @param {Object} newParams - 新的参数 */ updateParams(newParams) { if (newParams && typeof newParams === 'object') { this.ttsParams = { ...this.ttsParams, ...newParams }; console.log('TTS: 参数已更新:', this.ttsParams); } } /** * 获取当前TTS参数 * @returns {Object} 当前TTS参数 */ getParams() { return { ...this.ttsParams }; } } export default VolumeTTS;