import { ipcMain, BrowserWindow } from "electron"; import { preload, indexHtml, ELECTRON_RENDERER_URL } from "../config"; import { getSessionId, sendMessage } from "../Api/api"; import { showPrompt } from "../utils/tools"; // 直播状态管理 interface LiveState { sessionId: string | null; userId: string | null; isVideoInserted: boolean; isLiveOn: boolean; jobList: any[]; currentJob: any; cameraActive: boolean; audioActive: boolean; liveWindow: BrowserWindow | null; } // 全局直播状态 const liveState: LiveState = { sessionId: null, userId: null, isVideoInserted: false, isLiveOn: false, jobList: [], currentJob: null, cameraActive: false, audioActive: false, liveWindow: null, }; // 直播相关的主进程处理 export function setupLiveHandlers() { // 获取直播状态 ipcMain.handle("get-live-status", async () => { return { success: true, data: { isLiveOn: liveState.isLiveOn, hasLiveWindow: !!liveState.liveWindow, isVideoInserted: liveState.isVideoInserted, cameraActive: liveState.cameraActive, }, }; }); // 切换摄像头插入状态 ipcMain.on("toggle-camera-insert", async () => { if (liveState.liveWindow) { liveState.isVideoInserted = !liveState.isVideoInserted; liveState.liveWindow.webContents.send( "toggle-camera-insert", liveState.isVideoInserted, ); } }); // 插入摄像头视频 ipcMain.on("insert-camera-video", async () => { if (liveState.liveWindow) { liveState.liveWindow.webContents.send("insert-camera-video"); liveState.cameraActive = true; } else { showPrompt("直播窗口未打开", "error"); } }); // 插入音频 ipcMain.on("insert-video-audio", async () => { if (liveState.liveWindow) { liveState.liveWindow.webContents.send("insert-video-audio"); liveState.audioActive = true; } else { showPrompt("直播窗口未打开", "error"); } }); // 开始直播 - 完整的直播启动流程 ipcMain.handle("start-live", async (_, { userId } = {}) => { try { console.log("Starting live stream..."); // 1. 设置用户ID if (userId) { liveState.userId = userId; } // 2. 创建或显示直播窗口 if (!liveState.liveWindow) { await createLiveWindow(); } // 3. 等待网页加载完成 // await waitForPageLoad(); // 4. 获取 sessionId console.log("获取 sessionId"); const sessionResult = await getSessionId({ userId: liveState.userId, }); console.log("sessionid", sessionResult); if (!sessionResult.success) { return { success: false, error: "获取会话ID失败" }; } liveState.sessionId = sessionResult.sessionId; // 5. 设置直播状态 liveState.isLiveOn = true; // 6. 发送欢迎消息 await sendMessage({ sessionid: liveState.sessionId, text: "大家好,欢迎来到我的直播间!", type: "echo", interrupt: true, }); showPrompt("直播已开始", "info"); return { success: true, sessionId: liveState.sessionId }; } catch (error: any) { console.error("Start live error:", error); return { success: false, error: error.message }; } }); // 结束直播 ipcMain.handle("stop-live", async () => { try { liveState.isLiveOn = false; // 关闭直播窗口 if (liveState.liveWindow) { liveState.liveWindow.close(); liveState.liveWindow = null; } // 重置状态 liveState.sessionId = null; liveState.isVideoInserted = false; liveState.cameraActive = false; liveState.audioActive = false; showPrompt("直播已结束", "info"); return { success: true }; } catch (error: any) { return { success: false, error: error.message }; } }); // 强制关闭直播窗口 ipcMain.handle("force-close-live", async () => { try { console.log("Force closing live window..."); // 通知直播窗口清理所有媒体资源 if (liveState.liveWindow) { try { // 发送清理指令到直播窗口 liveState.liveWindow.webContents.send( "force-cleanup-media", ); // 等待一下确保清理指令被处理 await new Promise((resolve) => setTimeout(resolve, 100)); // 强制关闭窗口 liveState.liveWindow.removeAllListeners(); liveState.liveWindow.destroy(); } catch (error) { console.warn("Error destroying window:", error); } liveState.liveWindow = null; } // 强制重置所有状态 liveState.isLiveOn = false; liveState.sessionId = null; liveState.isVideoInserted = false; liveState.cameraActive = false; liveState.audioActive = false; showPrompt("直播窗口已强制关闭", "info"); return { success: true }; } catch (error: any) { console.error("Force close error:", error); return { success: false, error: error.message }; } }); // 提交消息给数字人平台 ipcMain.handle("push-explain-position", async (_, content: string) => { try { if (!liveState.sessionId) { return { success: false, error: "直播未开始,无法发送消息" }; } const params = { sessionid: liveState.sessionId, text: content, type: "echo", interrupt: true, }; await sendMessage(params); return { success: true }; } catch (error: any) { console.error("Send message error:", error); return { success: false, error: error.message }; } }); // 创建直播窗口 async function createLiveWindow() { const width = 375; const height = 690; let liveUrl = `${ELECTRON_RENDERER_URL}/#/live`; if (liveState.userId) { liveUrl += `?userId=${liveState.userId}`; } liveState.liveWindow = new BrowserWindow({ title: "直播窗口", width, height, minimizable: false, maximizable: false, closable: true, alwaysOnTop: true, webPreferences: { preload, nodeIntegration: true, contextIsolation: false, webSecurity: false, // 允许访问本地文件 allowRunningInsecureContent: true, // 允许运行本地内容 }, }); liveState.liveWindow.on("closed", () => { liveState.liveWindow = null; liveState.isLiveOn = false; }); console.log(liveUrl); if (ELECTRON_RENDERER_URL) { await liveState.liveWindow.loadURL(liveUrl); } else { await liveState.liveWindow.loadFile(indexHtml, { hash: "/live" }); } } // 等待页面加载完成 // @ts-ignore - 暂时未使用但保留以备将来使用 async function waitForPageLoad() { if (!liveState.liveWindow) { throw new Error("直播窗口不存在"); } return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error("页面加载超时")); }, 30000); // 30秒超时 // 监听页面加载完成事件 liveState.liveWindow!.webContents.once("did-finish-load", () => { clearTimeout(timeout); console.log("页面加载完成"); // 额外等待一下确保iframe也加载完成 setTimeout(() => { // 通知所有渲染进程状态已更新 const allWindows = BrowserWindow.getAllWindows(); allWindows.forEach((window: BrowserWindow) => { if (window.webContents && !window.isDestroyed()) { window.webContents.send("live-status-updated", { hasLiveWindow: true, windowLoaded: true, }); } }); resolve(true); }, 2000); }); // 监听加载失败事件 liveState.liveWindow!.webContents.once( "did-fail-load", (_, errorCode, errorDesc) => { clearTimeout(timeout); reject( new Error(`页面加载失败: ${errorDesc} (${errorCode})`), ); }, ); }); } // 文件管理处理器 ipcMain.handle("show-files-in-live", async (_, { files }) => { console.log("收到文件", files); try { // 使用当前直播窗口的 webContents if (liveState.liveWindow && !liveState.liveWindow.isDestroyed()) { console.log("发送文件路径到直播窗口:", files.length, "个文件"); // 直接传递文件路径信息,不读取文件内容 const processedFiles = files.map((file) => ({ name: file.name, type: file.type, size: file.size, path: file.path, // 为支持的文件类型生成 file:// URL url: file.path ? `file://${file.path.replace(/\\/g, "/")}` : null, })); console.log( "处理后的文件数据:", processedFiles.map((f) => ({ name: f.name, type: f.type, size: f.size, hasPath: !!f.path, hasUrl: !!f.url, })), ); // 发送文件数据到直播窗口 liveState.liveWindow.webContents.send("show-files-display", { files: processedFiles, timestamp: new Date().toISOString(), }); return { success: true, message: `文件已发送到直播窗口 (${files.length}个文件)`, }; } else { throw new Error("直播窗口未找到或已关闭"); } } catch (error: any) { console.error("展示文件失败:", error); return { success: false, error: error.message || "展示文件失败", }; } }); ipcMain.handle("remove-file-from-live", async (_, { index, fileName }) => { try { if (liveState.liveWindow && !liveState.liveWindow.isDestroyed()) { liveState.liveWindow.webContents.send("remove-file-display", { index, fileName, timestamp: new Date().toISOString(), }); } return { success: true, message: "已通知直播窗口移除文件", }; } catch (error: any) { console.error("移除文件展示失败:", error); return { success: false, error: error.message || "移除文件展示失败", }; } }); ipcMain.handle("clear-all-files-from-live", async () => { try { if (liveState.liveWindow && !liveState.liveWindow.isDestroyed()) { liveState.liveWindow.webContents.send( "clear-all-files-display", { timestamp: new Date().toISOString(), }, ); } return { success: true, message: "已通知直播窗口清空所有文件", }; } catch (error: any) { console.error("清空文件展示失败:", error); return { success: false, error: error.message || "清空文件展示失败", }; } }); } // 导出状态(用于调试) export const getLiveState = () => ({ ...liveState });