yourname hace 7 meses
padre
commit
3e97a003f2
Se han modificado 3 ficheros con 423 adiciones y 434 borrados
  1. 423 0
      client/mobile/pages_classroom.tsx
  2. 0 263
      server/room_management.ts
  3. 0 171
      server/routes_live.ts

+ 423 - 0
client/mobile/pages_classroom.tsx

@@ -0,0 +1,423 @@
+import React, { useState, useEffect, useRef, createContext, useContext } from 'react';
+import AliRtcEngine, { AliRtcSubscribeState, AliRtcVideoTrack, AliRtcSdkChannelProfile } from 'aliyun-rtc-sdk';
+import { ToastContainer, toast } from 'react-toastify';
+
+// 从 SDK 中提取需要的类型
+type ImEngine = InstanceType<typeof AliVCInteraction.ImEngine>;
+type ImGroupManager = AliVCInteraction.AliVCIMGroupManager;
+type ImMessageManager = AliVCInteraction.AliVCIMMessageManager;
+type ImLogLevel = AliVCInteraction.ImLogLevel;
+type ImMessageLevel = AliVCInteraction.ImMessageLevel;
+
+interface ImUser {
+  userId: string;
+  userExtension?: string;
+}
+
+interface ImGroupMessage {
+  groupId: string;
+  type: number;
+  data: string;
+  sender?: ImUser;
+  timestamp?: number;
+}
+
+// 课堂上下文类型
+type ClassroomContextType = {
+  userId: string;
+  role: 'teacher' | 'student';
+  isLoggedIn: boolean;
+  isJoinedClass: boolean;
+  messageList: string[];
+  errorMessage: string;
+  setRole: (role: 'teacher' | 'student') => void;
+};
+
+const ClassroomContext = createContext<ClassroomContextType | null>(null);
+
+// 辅助函数
+function hex(buffer: ArrayBuffer): string {
+  const hexCodes = [];
+  const view = new DataView(buffer);
+  for (let i = 0; i < view.byteLength; i += 4) {
+    const value = view.getUint32(i);
+    const stringValue = value.toString(16);
+    const padding = '00000000';
+    const paddedValue = (padding + stringValue).slice(-padding.length);
+    hexCodes.push(paddedValue);
+  }
+  return hexCodes.join('');
+}
+
+async function generateToken(
+  appId: string,
+  appKey: string,
+  channelId: string,
+  userId: string,
+  timestamp: number
+): Promise<string> {
+  const encoder = new TextEncoder();
+  const data = encoder.encode(`${appId}${appKey}${channelId}${userId}${timestamp}`);
+  const hash = await crypto.subtle.digest('SHA-256', data);
+  return hex(hash);
+}
+
+function showToast(type: 'info' | 'success' | 'error', message: string): void {
+  switch(type) {
+    case 'info':
+      toast.info(message);
+      break;
+    case 'success':
+      toast.success(message);
+      break;
+    case 'error':
+      toast.error(message);
+      break;
+  }
+}
+
+// 从SDK获取枚举值
+const { ImLogLevel, ImMessageLevel } = window.AliVCInteraction;
+
+// 配置信息
+const IM_APP_ID = '4c2ab5e1b1b0';
+const IM_APP_KEY = '314bb5eee5b623549e8a41574ba3ff32';
+const IM_APP_SIGN = 'H4sIAAAAAAAE/wCQAG//zguHB+lYCilkv7diSkk4GmcvLuds+InRu9vFOFebMwm/jEgsK5bBT85Z0owObMxG58uXHyPFlPEBEDQm9FswNJ+KmX0VDYkcfdPPWkafA6Hc0B6F+p5De9yJfPEfHzwo/DHMaygbHfLmBgUtmKveq421sJr/gNBz9D04Ewsg39us+ao0NegzLt7xtXvFXXXJAAAA//8BAAD//yoav6aQAAAA';
+const RTC_APP_ID = 'a5842c2a-d94a-43be-81de-1fdb712476e1';
+const RTC_APP_KEY = 'b71d65f4f84c450f6f058f4ad507bd42';
+
+export const ClassroomPage = () => {
+  // 状态管理
+  const [userId, setUserId] = useState<string>('');
+  const [role, setRole] = useState<'teacher' | 'student'>('student');
+  const [classId, setClassId] = useState<string>('');
+  const [isLoggedIn, setIsLoggedIn] = useState<boolean>(false);
+  const [isJoinedClass, setIsJoinedClass] = useState<boolean>(false);
+  const [msgText, setMsgText] = useState<string>('');
+  const [messageList, setMessageList] = useState<string[]>([]);
+  const [errorMessage, setErrorMessage] = useState<string>('');
+
+  // SDK实例
+  const imEngine = useRef<ImEngine | null>(null);
+  const imGroupManager = useRef<ImGroupManager | null>(null);
+  const imMessageManager = useRef<ImMessageManager | null>(null);
+  const aliRtcEngine = useRef<AliRtcEngine | null>(null);
+  const remoteVideoElMap = useRef<Record<string, HTMLVideoElement>>({});
+  const remoteVideoContainer = useRef<HTMLDivElement>(null);
+
+  // 消息管理模块
+  const showMessage = (text: string): void => {
+    setMessageList([...messageList, text]);
+  };
+
+  const listenImEvents = (): void => {
+    if (!imEngine.current) return;
+
+    imEngine.current.on('connectsuccess', () => {
+      showMessage('IM连接成功');
+    });
+
+    imEngine.current.on('disconnect', (code: number) => {
+      showMessage(`IM断开连接: ${code}`);
+    });
+  };
+
+  const listenGroupEvents = (): void => {
+    if (!imGroupManager.current) return;
+
+    imGroupManager.current.on('memberchange', (groupId: string, memberCount: number, joinUsers: ImUser[], leaveUsers: ImUser[]) => {
+      showMessage(`成员变更: 加入${joinUsers.length}人, 离开${leaveUsers.length}人`);
+    });
+  };
+
+  const listenMessageEvents = (): void => {
+    if (!imMessageManager.current) return;
+
+    imMessageManager.current.on('recvgroupmessage', (msg: AliVCInteraction.ImMessage, groupId: string) => {
+      showMessage(`收到消息: ${msg.data}`);
+    });
+  };
+
+  // 音视频模块
+  const removeRemoteVideo = (userId: string, type: 'camera' | 'screen' = 'camera') => {
+    const vid = `${type}_${userId}`;
+    const el = remoteVideoElMap.current[vid];
+    if (el) {
+      aliRtcEngine.current!.setRemoteViewConfig(null, userId, type === 'camera' ? AliRtcVideoTrack.AliRtcVideoTrackCamera : AliRtcVideoTrack.AliRtcVideoTrackScreen);
+      el.pause();
+      remoteVideoContainer.current?.removeChild(el);
+      delete remoteVideoElMap.current[vid];
+    }
+  };
+
+  const listenRtcEvents = () => {
+    if (!aliRtcEngine.current) return;
+
+    aliRtcEngine.current.on('remoteUserOnLineNotify', (userId: string) => {
+      showMessage(`用户 ${userId} 加入课堂`);
+    });
+
+    aliRtcEngine.current.on('remoteUserOffLineNotify', (userId: string) => {
+      showMessage(`用户 ${userId} 离开课堂`);
+      removeRemoteVideo(userId, 'camera');
+      removeRemoteVideo(userId, 'screen');
+    });
+  };
+
+  // 统一登录逻辑
+  const login = async (userId: string): Promise<void> => {
+    try {
+      // 初始化IM
+      const { ImEngine: ImEngineClass } = window.AliVCInteraction;
+      imEngine.current = ImEngineClass.createEngine();
+      await imEngine.current.init({
+        deviceId: 'xxxx',
+        appId: IM_APP_ID,
+        appSign: IM_APP_SIGN,
+        logLevel: ImLogLevel.ERROR,
+      });
+      
+      // 初始化RTC
+      aliRtcEngine.current = AliRtcEngine.getInstance();
+      AliRtcEngine.setLogLevel(0);
+      
+      // 设置事件监听
+      listenImEvents();
+      listenRtcEvents();
+      
+      setIsLoggedIn(true);
+      setErrorMessage('');
+      showToast('success', '登录成功');
+    } catch (err: any) {
+      setErrorMessage(`登录失败: ${err.message}`);
+      showToast('error', '登录失败');
+    }
+  };
+
+  // 加入课堂
+  const joinClass = async (classId: string): Promise<void> => {
+    if (!imEngine.current || !aliRtcEngine.current) return;
+
+    try {
+      // 加入IM群组
+      const gm = imEngine.current.getGroupManager();
+      const mm = imEngine.current.getMessageManager();
+      imGroupManager.current = gm || null;
+      imMessageManager.current = mm || null;
+      await gm!.joinGroup(classId);
+      listenGroupEvents();
+      listenMessageEvents();
+
+      // 加入RTC频道
+      const timestamp = Math.floor(Date.now() / 1000) + 3600 * 3;
+      const token = await generateToken(RTC_APP_ID, RTC_APP_KEY, classId, userId, timestamp);
+      aliRtcEngine.current.setChannelProfile(AliRtcSdkChannelProfile.AliRtcSdkCommunication);
+      await aliRtcEngine.current.joinChannel(
+        {
+          channelId: classId,
+          userId,
+          appId: RTC_APP_ID,
+          token,
+          timestamp,
+        },
+        userId
+      );
+
+      // 设置本地预览
+      aliRtcEngine.current.setLocalViewConfig('localPreviewer', AliRtcVideoTrack.AliRtcVideoTrackCamera);
+      
+      setIsJoinedClass(true);
+      setErrorMessage('');
+      showToast('success', '加入课堂成功');
+    } catch (err: any) {
+      setErrorMessage(`加入课堂失败: ${err.message}`);
+      showToast('error', '加入课堂失败');
+    }
+  };
+
+  // 离开课堂
+  const leaveClass = async (): Promise<void> => {
+    if (imGroupManager.current && classId) {
+      await imGroupManager.current.leaveGroup(classId);
+    }
+    if (aliRtcEngine.current) {
+      await aliRtcEngine.current.leaveChannel();
+    }
+    
+    setIsJoinedClass(false);
+    showToast('info', '已离开课堂');
+  };
+
+  // 发送消息
+  const sendMessage = async (): Promise<void> => {
+    if (!imMessageManager.current || !classId) return;
+
+    try {
+      await imMessageManager.current.sendGroupMessage({
+        groupId: classId,
+        data: msgText,
+        type: 88888,
+        level: ImMessageLevel.NORMAL,
+      });
+      setMsgText('');
+      setErrorMessage('');
+    } catch (err: any) {
+      setErrorMessage(`消息发送失败: ${err.message}`);
+    }
+  };
+
+  // 清理资源
+  useEffect(() => {
+    return () => {
+      if (imGroupManager.current) {
+        imGroupManager.current.removeAllListeners();
+      }
+      if (imMessageManager.current) {
+        imMessageManager.current.removeAllListeners();
+      }
+      if (imEngine.current) {
+        imEngine.current.removeAllListeners();
+      }
+      if (aliRtcEngine.current) {
+        aliRtcEngine.current.destroy();
+      }
+    };
+  }, []);
+
+  return (
+    <ClassroomContext.Provider value={{
+      userId,
+      role,
+      isLoggedIn,
+      isJoinedClass,
+      messageList,
+      errorMessage,
+      setRole,
+    }}>
+      <div className="container mx-auto p-4">
+        <h1 className="text-2xl font-bold mb-4">互动课堂</h1>
+        
+        <ToastContainer
+          position="top-right"
+          autoClose={5000}
+          hideProgressBar={false}
+          newestOnTop={false}
+          closeOnClick
+          rtl={false}
+          pauseOnFocusLoss
+          draggable
+          pauseOnHover
+        />
+
+        <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
+          <div className="md:col-span-1">
+            <form>
+              <div className="mb-2">
+                <label className="block text-sm font-medium text-gray-700">用户ID</label>
+                <input
+                  className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm"
+                  value={userId}
+                  onChange={(e) => setUserId(e.target.value)}
+                />
+              </div>
+              
+              <div className="mb-2">
+                <label className="block text-sm font-medium text-gray-700">课堂ID</label>
+                <input
+                  className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm"
+                  value={classId}
+                  onChange={(e) => setClassId(e.target.value)}
+                />
+              </div>
+              
+              <div className="mb-2">
+                <label className="block text-sm font-medium text-gray-700">角色</label>
+                <select
+                  className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm"
+                  value={role}
+                  onChange={(e) => setRole(e.target.value as 'teacher' | 'student')}
+                >
+                  <option value="student">学生</option>
+                  <option value="teacher">老师</option>
+                </select>
+              </div>
+              
+              <div className="flex space-x-2 mb-2">
+                <button
+                  type="button"
+                  className="px-3 py-2 bg-blue-600 text-white rounded-md"
+                  disabled={isLoggedIn}
+                  onClick={() => login(userId)}
+                >
+                  登录
+                </button>
+                
+                <button
+                  type="button"
+                  className="px-3 py-2 bg-blue-600 text-white rounded-md"
+                  disabled={!isLoggedIn || isJoinedClass}
+                  onClick={() => joinClass(classId)}
+                >
+                  加入课堂
+                </button>
+                
+                <button
+                  type="button"
+                  className="px-3 py-2 bg-gray-600 text-white rounded-md"
+                  disabled={!isJoinedClass}
+                  onClick={leaveClass}
+                >
+                  离开课堂
+                </button>
+              </div>
+            </form>
+            
+            <div className="mt-4">
+              <label className="block text-sm font-medium text-gray-700">消息</label>
+              <input
+                className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm"
+                value={msgText}
+                onChange={(e) => setMsgText(e.target.value)}
+              />
+              <button
+                type="button"
+                className="mt-2 px-3 py-2 bg-blue-600 text-white rounded-md"
+                disabled={!isJoinedClass}
+                onClick={sendMessage}
+              >
+                发送
+              </button>
+            </div>
+          </div>
+          
+          <div className="md:col-span-1">
+            <h4 className="text-lg font-medium mb-2">消息记录</h4>
+            <div className="bg-gray-100 p-2 rounded-md h-64 overflow-y-auto">
+              {messageList.map((msg, i) => (
+                <div key={i} className="mb-1">{msg}</div>
+              ))}
+            </div>
+          </div>
+          
+          <div className="md:col-span-1">
+            <h4 className="text-lg font-medium mb-2">视频区域</h4>
+            <video
+              id="localPreviewer"
+              muted
+              className="w-full h-48 bg-black mb-2"
+            ></video>
+            <div
+              id="remoteVideoContainer"
+              ref={remoteVideoContainer}
+              className="grid grid-cols-2 gap-2"
+            ></div>
+          </div>
+        </div>
+        
+        {errorMessage && (
+          <div className="mt-2 text-red-500">{errorMessage}</div>
+        )}
+      </div>
+    </ClassroomContext.Provider>
+  );
+};

+ 0 - 263
server/room_management.ts

@@ -1,263 +0,0 @@
-import LiveClient, * as $LiveClient from "@alicloud/live20161101";
-import LiveInteractionClient, * as $LiveInteraction from "@alicloud/live-interaction20201214";
-import * as $OpenApi from "@alicloud/openapi-client";
-
-interface RoomOptions {
-  title?: string;
-  templateId?: string;
-  maxUsers?: number;
-}
-
-interface UserInfo {
-  id: string;
-  name?: string;
-  avatar?: string;
-  isAdmin?: boolean;
-}
-
-interface Message {
-  id: string;
-  sender: UserInfo;
-  content: string;
-  timestamp: Date;
-}
-
-export class RoomManagementSystem {
-  private liveClient: LiveClient.default;
-  private liveInteractionClient: LiveInteractionClient.default;
-  private appId: string;
-
-  constructor() {
-    const config = new $OpenApi.Config({
-      accessKeyId: Deno.env.get("ALIYUN_LIVE_ACCESS_KEY_ID") || "",
-      accessKeySecret: Deno.env.get("ALIYUN_LIVE_ACCESS_KEY_SECRET") || "",
-      endpoint: "live.aliyuncs.com"
-    });
-    
-    this.liveClient = new LiveClient.default(config);
-    this.liveInteractionClient = new LiveInteractionClient.default(config);
-    this.appId = Deno.env.get("ALIYUN_CHAT_APP_ID") || "";
-  }
-
-  /**
-   * 创建房间
-   * @param roomId 房间ID
-   * @param options 房间选项
-   * @returns 房间信息
-   */
-  async createRoom(roomId: string, options: RoomOptions = {}): Promise<{
-    roomId: string;
-    pushUrl: string;
-    playUrl: string;
-    chatToken: string;
-  }> {
-    try {
-      // 创建互动直播房间
-      const createRequest = new $LiveInteraction.CreateRoomRequest({
-        AppId: this.appId,
-        RoomId: roomId,
-        Title: options.title || `Room ${roomId}`,
-        TemplateId: options.templateId || "standard"
-      });
-      const createResponse = await this.liveInteractionClient.createRoom(createRequest);
-
-      // 获取推流/播放地址
-      const urlRequest = new $LiveClient.DescribeLiveStreamsOnlineListRequest({
-        AppId: this.appId,
-        RoomId: roomId
-      });
-      const urlResponse = await this.liveClient.describeLiveStreamsOnlineList(urlRequest);
-
-      return {
-        roomId,
-        pushUrl: urlResponse.PushUrl,
-        playUrl: urlResponse.PlayUrl,
-        chatToken: createResponse.Token
-      };
-    } catch (error) {
-      throw new Error(`Failed to create room: ${error instanceof Error ? error.message : "Unknown error"}`);
-    }
-  }
-
-  /**
-   * 销毁房间
-   * @param roomId 房间ID
-   */
-  async destroyRoom(roomId: string): Promise<void> {
-    try {
-      const request = new $LiveInteraction.DestroyRoomRequest({
-        AppId: this.appId,
-        RoomId: roomId
-      });
-      await this.liveInteractionClient.destroyRoom(request); 
-    } catch (error) {
-      throw new Error(`Failed to destroy room: ${error instanceof Error ? error.message : "Unknown error"}`);
-    }
-  }
-
-  /**
-   * 用户加入房间
-   * @param roomId 房间ID
-   * @param user 用户信息
-   * @returns 用户Token和播放地址
-   */
-  async joinRoom(roomId: string, user: UserInfo) {
-    try {
-      const addMemberRequest = new $LiveInteraction.AddGroupMembersRequest({
-        appId:this.appId,
-        requestParams: {
-            groupId: roomId,
-            members: [user.id]
-        }
-      })
-
-      await this.liveInteractionClient.addGroupMembers(addMemberRequest) ;
-
-    } catch (error) {
-      throw new Error(`Failed to join room: ${error instanceof Error ? error.message : "Unknown error"}`);
-    }
-  }
-
-  /**
-   * 用户离开房间
-   * @param roomId 房间ID
-   * @param userId 用户ID
-   */
-  async leaveRoom(roomId: string, userId: string): Promise<void> {
-    try {
-      const request = new $LiveInteraction.RemoveGroupMembersRequest({
-        AppId: this.appId,
-        RoomId: roomId,
-        UserId: userId
-      });
-      await this.liveInteractionClient.leaveRoom(request);
-    } catch (error) {
-      throw new Error(`Failed to leave room: ${error instanceof Error ? error.message : "Unknown error"}`);
-    }
-  }
-
-  /**
-   * 发送消息
-   * @param roomId 房间ID
-   * @param sender 发送者信息
-   * @param content 消息内容
-   * @returns 消息ID
-   */
-  async sendMessage(roomId: string, sender: UserInfo, content: string): Promise<string> {
-    try {
-      const request = new $LiveInteraction.SendMessageRequest({
-        AppId: this.appId,
-        RoomId: roomId,
-        SenderId: sender.id,
-        Content: content
-      });
-      const response = await this.liveInteractionClient.sendMessage(request);
-      return response.MessageId;
-    } catch (error) {
-      throw new Error(`Failed to send message: ${error instanceof Error ? error.message : "Unknown error"}`);
-    }
-  }
-
-  /**
-   * 获取历史消息
-   * @param roomId 房间ID
-   * @param limit 消息数量限制
-   * @returns 消息列表
-   */
-  async getHistoryMessages(roomId: string, limit: number = 50): Promise<Message[]> {
-    try {
-      const request = new $LiveInteraction.GetHistoryMessagesRequest({
-        AppId: this.appId,
-        RoomId: roomId,
-        Limit: limit
-      });
-      const response = await this.liveInteractionClient.getHistoryMessages(request);
-      
-      return response.Messages.map((msg: any) => ({
-        id: msg.MessageId,
-        sender: {
-          id: msg.SenderId,
-          name: msg.SenderName,
-          avatar: msg.SenderAvatar
-        },
-        content: msg.Content,
-        timestamp: new Date(msg.Timestamp)
-      }));
-    } catch (error) {
-      throw new Error(`Failed to get history messages: ${error instanceof Error ? error.message : "Unknown error"}`);
-    }
-  }
-
-  /**
-   * 禁言用户
-   * @param roomId 房间ID
-   * @param userId 用户ID
-   * @param duration 禁言时长(秒)
-   */
-  async muteUser(roomId: string, userId: string, duration: number = 3600): Promise<void> {
-    try {
-      const request = new $LiveInteraction.MuteUserRequest({
-        AppId: this.appId,
-        RoomId: roomId,
-        UserId: userId,
-        Duration: duration
-      });
-      await this.liveInteractionClient.muteUser(request);
-    } catch (error) {
-      throw new Error(`Failed to mute user: ${error instanceof Error ? error.message : "Unknown error"}`);
-    }
-  }
-
-  /**
-   * 踢出用户
-   * @param roomId 房间ID
-   * @param userId 用户ID
-   */
-  async kickUser(roomId: string, userId: string): Promise<void> {
-    try {
-      const request = new $LiveInteraction.KickUserRequest({
-        AppId: this.appId,
-        RoomId: roomId,
-        UserId: userId
-      });
-      await this.liveInteractionClient.kickUser(request);
-    } catch (error) {
-      throw new Error(`Failed to kick user: ${error instanceof Error ? error.message : "Unknown error"}`);
-    }
-  }
-
-  /**
-   * 获取房间信息
-   * @param roomId 房间ID
-   * @returns 房间信息
-   */
-  async getRoomInfo(roomId: string): Promise<{
-    roomId: string;
-    playUrl: string;
-    onlineCount: number;
-  }> {
-    try {
-      // 获取直播间信息
-      const infoRequest = new $LiveClient.DescribeLiveStreamsOnlineListRequest({
-        AppId: this.appId,
-        RoomId: roomId
-      });
-      const infoResponse = await this.liveClient.describeLiveStreamsOnlineList(infoRequest);
-
-      // 获取在线人数
-      const statsRequest = new $LiveClient.DescribeLiveDomainOnlineUserNumRequest({
-        AppId: this.appId,
-        RoomId: roomId
-      });
-      const statsResponse = await this.liveClient.describeLiveDomainOnlineUserNum(statsRequest);
-
-      return {
-        roomId,
-        playUrl: infoResponse.PlayUrl,
-        onlineCount: statsResponse.OnlineCount
-      };
-    } catch (error) {
-      throw new Error(`Failed to get room info: ${error instanceof Error ? error.message : "Unknown error"}`);
-    }
-  }
-}

+ 0 - 171
server/routes_live.ts

@@ -1,171 +0,0 @@
-import { Hono } from "hono";
-import LiveClient, * as $LiveClient from "@alicloud/live20161101";
-import LiveInteractionClient, * as $LiveInteraction from "@alicloud/live-interaction20201214";
-import * as $OpenApi from "@alicloud/openapi-client";
-import type { Variables, WithAuth } from "./app.tsx";
-
-// 阿里云SDK配置
-const liveConfig = new $OpenApi.Config({
-  accessKeyId: Deno.env.get("ALIYUN_LIVE_ACCESS_KEY_ID") || "",
-  accessKeySecret: Deno.env.get("ALIYUN_LIVE_ACCESS_KEY_SECRET") || "",
-  endpoint: "live.aliyuncs.com"
-});
-const liveInteractionClient = new LiveInteractionClient.default(liveConfig);
-const liveClient = new LiveClient.default(liveConfig);
-
-// 创建直播路由
-export function createLiveRoutes(withAuth: WithAuth) {
-  const liveRoutes = new Hono<{ Variables: Variables }>();
-
-  // 创建房间
-  liveRoutes.post("/create-room", withAuth, async (c) => {
-    const { roomId } = await c.req.json();
-    
-    try {
-      // 创建直播间
-      const createRequest = new $LiveInteraction.CreateRoomRequest({
-        AppId: Deno.env.get("ALIYUN_CHAT_APP_ID") || "",
-        RoomId: roomId,
-        Title: `Live Room ${roomId}`,
-        TemplateId: "standard"
-      });
-      const createResponse = await liveInteractionClient.createRoom(createRequest);
-
-      // 获取推流/播放地址
-      const urlRequest = new $LiveClient.DescribeLiveStreamsOnlineListRequest({
-        AppId: Deno.env.get("ALIYUN_CHAT_APP_ID") || "",
-        RoomId: roomId
-      });
-      const urlResponse = await liveClient.describeLiveStreamsOnlineList(urlRequest);
-
-      return c.json({ 
-        success: true,
-        roomId,
-        pushUrl: urlResponse.PushUrl,
-        playUrl: urlResponse.PlayUrl,
-        chatToken: createResponse.Token
-      }, 201);
-    } catch (error) {
-      return c.json({ 
-        success: false,
-        error: error instanceof Error ? error.message : "Unknown error"
-      }, 500);
-    }
-  });
-
-  // 加入房间
-  liveRoutes.post("/join-room", withAuth, async (c) => {
-    const { roomId } = await c.req.json();
-    
-    try {
-      // 获取直播间信息
-      const infoRequest = new $LiveClient.DescribeLiveStreamsOnlineListRequest({
-        AppId: Deno.env.get("ALIYUN_CHAT_APP_ID") || "",
-        RoomId: roomId
-      });
-      const infoResponse = await liveClient.describeLiveStreamsOnlineList(infoRequest);
-
-      // 获取用户Token - 使用正确的API方法
-      const tokenRequest = new $LiveInteraction.CreateTokenRequest({
-        AppId: Deno.env.get("ALIYUN_CHAT_APP_ID") || "",
-        RoomId: roomId,
-        UserId: c.get("user")?.id || "anonymous"
-      });
-      const tokenResponse = await liveInteractionClient.createToken(tokenRequest);
-
-      liveInteractionClient.getLoginToken()
-
-      return c.json({ 
-        success: true,
-        playUrl: infoResponse.PlayUrl,
-        chatToken: tokenResponse.Token
-      });
-    } catch (error) {
-      return c.json({ 
-        success: false,
-        error: error instanceof Error ? error.message : "Unknown error"
-      }, 500);
-    }
-  });
-
-  // 获取房间信息
-  liveRoutes.get("/room-info/:id", withAuth, async (c) => {
-    const roomId = c.req.param("id");
-    
-    try {
-      // 获取直播间信息
-      const infoRequest = new $LiveClient.DescribeLiveStreamsOnlineListRequest({
-        AppId: Deno.env.get("ALIYUN_CHAT_APP_ID") || "",
-        RoomId: roomId
-      });
-      const infoResponse = await liveClient.describeLiveStreamsOnlineList(infoRequest);
-
-      // 获取在线人数
-      const statsRequest = new $LiveClient.DescribeLiveDomainOnlineUserNumRequest({
-        AppId: Deno.env.get("ALIYUN_CHAT_APP_ID") || "",
-        RoomId: roomId
-      });
-      const statsResponse = await liveClient.describeLiveDomainOnlineUserNum(statsRequest);
-
-      return c.json({ 
-        success: true,
-        roomId,
-        playUrl: infoResponse.PlayUrl,
-        onlineCount: statsResponse.OnlineCount
-      });
-    } catch (error) {
-      return c.json({ 
-        success: false,
-        error: error instanceof Error ? error.message : "Unknown error"
-      }, 500);
-    }
-  });
-
-  // 获取推流地址
-  liveRoutes.get("/push-url/:roomId", withAuth, async (c) => {
-    const roomId = c.req.param("roomId");
-    
-    try {
-      const urlRequest = new $LiveClient.DescribeLiveStreamsOnlineListRequest({
-        AppId: Deno.env.get("ALIYUN_CHAT_APP_ID") || "",
-        RoomId: roomId
-      });
-      const urlResponse = await liveClient.describeLiveStreamsOnlineList(urlRequest);
-
-      return c.json({
-        success: true,
-        pushUrl: urlResponse.PushUrl
-      });
-    } catch (error) {
-      return c.json({
-        success: false,
-        error: error instanceof Error ? error.message : "Unknown error"
-      }, 500);
-    }
-  });
-
-  // 获取拉流地址
-  liveRoutes.get("/pull-url/:roomId", withAuth, async (c) => {
-    const roomId = c.req.param("roomId");
-    
-    try {
-      const urlRequest = new $LiveClient.DescribeLiveStreamsOnlineListRequest({
-        AppId: Deno.env.get("ALIYUN_CHAT_APP_ID") || "",
-        RoomId: roomId
-      });
-      const urlResponse = await liveClient.describeLiveStreamsOnlineList(urlRequest);
-
-      return c.json({
-        success: true,
-        pullUrl: urlResponse.PlayUrl
-      });
-    } catch (error) {
-      return c.json({
-        success: false,
-        error: error instanceof Error ? error.message : "Unknown error"
-      }, 500);
-    }
-  });
-
-  return liveRoutes;
-}