UNPKG

@minto-ai/huoshan-tts

Version:

借助“火山引擎在线语音合成API”实现浏览器端“文本转语音

340 lines (289 loc) 10.7 kB
import type { InterfaceHandler } from './handler/core' import type { BusinessParams, PrivateCustomEventName, PublicCustomEventName, SsmlConfig, SystemConfig } from './types' import { isIos } from '@minto-ai/tools' import { AudioActuator, ByteBufferNotIos, CreateSsml, DecodeDataBaShanIos, DecodeDataIos, DecodeDataNotIos, TextSplit, TtsRequestBaShanIos, TtsRequestIos, TtsRequestNotIos, } from './process' import { SystemStatus } from './types' import { createEventBus } from './utils/event-bus' class TtsController { private isEqualBaShan: boolean = false private isNeedCreateSsml: boolean = false private textSplitInstance: TextSplit private createSsmlInstance: CreateSsml private audioActuatorInstance!: AudioActuator // iOS 处理器实例 private ttsRequestIosInstance!: TtsRequestIos private decodeDataIosInstance!: DecodeDataIos // 巴山 IOS 处理器实例 private ttsRequestBaShanIosInstance!: TtsRequestBaShanIos private decodeDataShanIosInstance!: DecodeDataBaShanIos // 非iOS 处理器实例 private ttsRequestNotIosInstance!: TtsRequestNotIos private byteBufferNotIosInstance!: ByteBufferNotIos private decodeDataNotIosInstance!: DecodeDataNotIos public systemStatus: SystemStatus = SystemStatus.OFFLINE public $bus = createEventBus<PublicCustomEventName | PrivateCustomEventName>() /** * TTS控制器构造函数 * @param systemConfig - 系统配置 * @param businessParams - 业务参数 * @param ssmlConfig - SSML 配置 */ constructor(systemConfig: SystemConfig, businessParams: BusinessParams, ssmlConfig: SsmlConfig) { this.isEqualBaShan = businessParams.provider === '100' this.textSplitInstance = new TextSplit() if (this.isEqualBaShan) { this.isNeedCreateSsml = false } else { if (businessParams.text_type === 'ssml') { this.isNeedCreateSsml = true } else { this.isNeedCreateSsml = false } } this.createSsmlInstance = new CreateSsml() this.createSsmlInstance.initProperty(ssmlConfig) this.audioActuatorInstance = new AudioActuator() // 根据设备类型初始化对应的处理器 if (isIos()) { if (this.isEqualBaShan) { this.ttsRequestBaShanIosInstance = new TtsRequestBaShanIos() this.decodeDataShanIosInstance = new DecodeDataBaShanIos() this.ttsRequestBaShanIosInstance.initProperty(systemConfig, businessParams) } else { this.ttsRequestIosInstance = new TtsRequestIos() this.decodeDataIosInstance = new DecodeDataIos() this.ttsRequestIosInstance.initProperty(systemConfig, businessParams) } } else { this.ttsRequestNotIosInstance = new TtsRequestNotIos() this.byteBufferNotIosInstance = new ByteBufferNotIos() this.decodeDataNotIosInstance = new DecodeDataNotIos() this.ttsRequestNotIosInstance.initProperty(systemConfig, businessParams) } this.textSplitInstance.setExecuteController(this) this.createSsmlInstance.setExecuteController(this) // 设置处理器控制器 if (isIos()) { if (this.isEqualBaShan) { this.ttsRequestBaShanIosInstance.setExecuteController(this) this.decodeDataShanIosInstance.setExecuteController(this) this.audioActuatorInstance.setExecuteController(this) } else { this.ttsRequestIosInstance.setExecuteController(this) this.decodeDataIosInstance.setExecuteController(this) this.audioActuatorInstance.setExecuteController(this) } } else { this.ttsRequestNotIosInstance.setExecuteController(this) this.byteBufferNotIosInstance.setExecuteController(this) this.decodeDataNotIosInstance.setExecuteController(this) this.audioActuatorInstance.setExecuteController(this) } // 链接处理器 if (isIos()) { if (this.isEqualBaShan) { // 巴山iOS设备:TextSplit -> CreateSsml(可选)-> TtsRequestBaShanIos -> DecodeDataBaShanIos -> AudioActuator if (this.isNeedCreateSsml) { this.textSplitInstance.linkHandler(this.createSsmlInstance as unknown as InterfaceHandler) this.createSsmlInstance.linkHandler(this.ttsRequestBaShanIosInstance as unknown as InterfaceHandler) } else { this.textSplitInstance.linkHandler(this.ttsRequestBaShanIosInstance as unknown as InterfaceHandler) } this.ttsRequestBaShanIosInstance.linkHandler(this.decodeDataShanIosInstance as unknown as InterfaceHandler) this.decodeDataShanIosInstance.linkHandler(this.audioActuatorInstance as unknown as InterfaceHandler) } else { // iOS设备:TextSplit -> CreateSsml (可选)-> TtsRequestIos -> DecodeDataIos -> AudioActuator if (this.isNeedCreateSsml) { this.textSplitInstance.linkHandler(this.createSsmlInstance as unknown as InterfaceHandler) this.createSsmlInstance.linkHandler(this.ttsRequestIosInstance as unknown as InterfaceHandler) } else { this.textSplitInstance.linkHandler(this.ttsRequestIosInstance as unknown as InterfaceHandler) } this.ttsRequestIosInstance.linkHandler(this.decodeDataIosInstance as unknown as InterfaceHandler) this.decodeDataIosInstance.linkHandler(this.audioActuatorInstance as unknown as InterfaceHandler) } } else { // 非iOS设备:TextSplit -> CreateSsml (可选)-> TtsRequestNotIos -> ByteBufferNotIos -> DecodeDataNotIos -> AudioActuator if (this.isNeedCreateSsml) { this.textSplitInstance.linkHandler(this.createSsmlInstance as unknown as InterfaceHandler) this.createSsmlInstance.linkHandler(this.ttsRequestNotIosInstance as unknown as InterfaceHandler) } else { this.textSplitInstance.linkHandler(this.ttsRequestNotIosInstance as unknown as InterfaceHandler) } this.ttsRequestNotIosInstance.linkHandler(this.byteBufferNotIosInstance as unknown as InterfaceHandler) this.byteBufferNotIosInstance.linkHandler(this.decodeDataNotIosInstance as unknown as InterfaceHandler) this.decodeDataNotIosInstance.linkHandler(this.audioActuatorInstance as unknown as InterfaceHandler) } this.bindEvent() } /** * 绑定事件监听器 */ private bindEvent(): void { /** * 音频首次播放 */ this.$bus.on('_audioActuatorBeforeFirstExecute', () => { this.emit('audioFirstStart') }) /** * 应用出错,触发 appFinish 事件 */ this.$bus.on('_appError', (error) => { this.finish() this.emit('appError', error) }) /** * 应用被销毁,触发 appFinish 事件 */ this.$bus.on('_appFinish', () => { this.finish() }) } /** * 进入待机状态,等待传入文本数据 */ public start(): TtsController { if (this.systemStatus === SystemStatus.EXECUTE) { return this } this.textSplitInstance.triggerHandlerActive() this.createSsmlInstance.triggerHandlerActive() if (isIos()) { if (this.isEqualBaShan) { this.ttsRequestBaShanIosInstance.triggerHandlerActive() this.decodeDataShanIosInstance.triggerHandlerActive() this.audioActuatorInstance.triggerHandlerActive() } else { this.ttsRequestIosInstance.triggerHandlerActive() this.decodeDataIosInstance.triggerHandlerActive() this.audioActuatorInstance.triggerHandlerActive() } } else { this.ttsRequestNotIosInstance.triggerHandlerActive() this.byteBufferNotIosInstance.triggerHandlerActive() this.decodeDataNotIosInstance.triggerHandlerActive() this.audioActuatorInstance.triggerHandlerActive() } this.systemStatus = SystemStatus.EXECUTE return this } /** * 传入文本数据 * @param text - 待转换的文本 */ public send(text: string): TtsController { if (this.systemStatus !== SystemStatus.EXECUTE) { return this } this.textSplitInstance.handle(text) return this } /** * 应用停止处理传入的文本,但是并不会停止音频播放 */ public end(): TtsController { if (this.systemStatus !== SystemStatus.EXECUTE) { return this } this.textSplitInstance.handle(null) this.textSplitInstance.isHandleDataAcceptedComplete = true return this } /** * 停止所有处理器,并且重置状态,触发 appFinish 事件 */ public finish(): void { if (this.systemStatus === SystemStatus.OFFLINE) { return } this.textSplitInstance.triggerHandlerFinish() this.createSsmlInstance.triggerHandlerFinish() if (isIos()) { if (this.isEqualBaShan) { this.ttsRequestBaShanIosInstance.triggerHandlerFinish() this.decodeDataShanIosInstance.triggerHandlerFinish() this.audioActuatorInstance.triggerHandlerFinish() } else { this.ttsRequestIosInstance.triggerHandlerFinish() this.decodeDataIosInstance.triggerHandlerFinish() this.audioActuatorInstance.triggerHandlerFinish() } } else { this.ttsRequestNotIosInstance.triggerHandlerFinish() this.byteBufferNotIosInstance.triggerHandlerFinish() this.decodeDataNotIosInstance.triggerHandlerFinish() this.audioActuatorInstance.triggerHandlerFinish() } this.systemStatus = SystemStatus.OFFLINE this.emit('appFinish') } /** * 发射事件 * @param eventName - 事件名称 * @param data - 事件数据 */ private emit<T>(eventName: PublicCustomEventName, data?: T): void { this.$bus.emit(eventName, data) } /** * 监听事件 * @param eventName - 事件名称 * @param callback - 回调函数 */ public on(eventName: PublicCustomEventName, callback: (data?: any) => void): TtsController { this.$bus.on(eventName, callback) return this } /** * 静音 */ public mute(): void { this.audioActuatorInstance.mute() } /** * 取消静音 */ public unmute(): void { this.audioActuatorInstance.unmute() } /** * 暂停播放 */ public pause(): void { this.audioActuatorInstance.pause() } /** * 恢复播放 */ public resume(): void { this.audioActuatorInstance.resume() } } export default TtsController