import Jessibuca from "../libs/jessibuca"; export enum MessageActionType { TTS = "tts", TTS_End = "tts_end", Interrupt = "interrupt", Load = "load", Start = "start", Heartbeat = "heartbeat", Ping = "ping", } export class WrapSocketSender { jessibuca: Jessibuca; _eventBus: EventTarget; // messageResolveMap: Map; constructor(jessibuca: Jessibuca) { this.jessibuca = jessibuca; this._eventBus = new EventTarget(); this.handleMessage = this.handleMessage.bind(this); } get videoSocket() { if ((this.jessibuca as any).player?.stream) { return (this.jessibuca as any).player.stream.player.stream.socket; } return null; } async handleMessage(event) { if (!(event.data instanceof ArrayBuffer)) { const result = JSON.parse(event.data); switch (result.action) { case MessageActionType.TTS_End: Message.processedReqIds.shift(); if (Message.processedReqIds.length == 0) { this.emit("finished"); await new Promise((resolve) => setTimeout(() => { this.jessibuca?.clearAudioBuffer(); resolve(); }, 500) ); } break; } } } init() { if (!this.videoSocket) { console.warn("socket connect failed"); return; } this.videoSocket.addEventListener("message", this.handleMessage); } private _rawSend(payload: object, raw = false) { if (raw) { this.videoSocket?.send(payload); } else { this.videoSocket.send(JSON.stringify(payload)); } } send(action: MessageActionType, payload?: object) { let message = new Message(action, payload); this._rawSend(message); // const { promise, resolve, reject } = withPromiseResolve(); // this.messageResolveMap.set( // message.req_id, // new MessageResolve(message.req_id, promise, resolve, reject) // ); } addEventListener(eventName: string, callback) { this._eventBus.addEventListener(eventName, callback); return this; } removeEventListener(eventName: string, callback?) { this._eventBus.removeEventListener(eventName, callback); return this; } emit(eventName: string, data?) { this._eventBus.dispatchEvent(new CustomEvent(eventName, { detail: data })); } updateJessibuca(jessibuca: Jessibuca) { this.jessibuca = jessibuca; } detach() { this.videoSocket?.removeEventListener("message", this.handleMessage); } destroy() { this.detach(); this._eventBus = null; this.jessibuca = null; } } class Message { static currentReqId = 0; static processedReqIds = []; static getNextReqId() { return ++Message.currentReqId + ""; } action: MessageActionType; payload: object; req_id: string; constructor(action: MessageActionType, payload: object) { this.action = action; this.payload = payload; if (action == MessageActionType.TTS) { this.req_id = Message.getNextReqId(); Message.processedReqIds.push(this.req_id); } if (action == MessageActionType.Interrupt) { Message.processedReqIds = []; } } } // class MessageResolve { // id: number; // promise: Promise; // resolve: (arg: MessageResolveReturn) => void; // reject: (arg: MessageRejectReturn) => void; // constructor(id, promise, resolve, reject) { // this.id = id; // this.promise = promise; // this.resolve = resolve; // this.reject = reject; // } // } // function withPromiseResolve() { // let resolveFn; // let rejectFn; // // 创建一个 Promise 对象,并将 resolve 和 reject 方法赋值给外部变量 // const promise = new Promise((resolve, reject) => { // resolveFn = resolve; // rejectFn = reject; // }); // // 返回一个对象,包含 Promise 本身以及手动控制的 resolve 和 reject 方法 // return { // promise, // resolve: resolveFn, // reject: rejectFn, // }; // }