基于云开发 CloudBase 搭建在线视频会议应用教程 (3)

创建会议的前端 API 核心代码 meeting-simple/src/meeting/api.js

import tcb from "tcb-js-sdk"; // 初始化云开发 JSSDK const app = tcb.init({ env: "tcb-demo-10cf5b", }); // 初始化 auth const auth = app.auth({ persistence: "local", }); const db = app.database(); // 会议表名称 const MEETING_COLLECTION = "meeting-simple"; // 匿名登录 async function signIn() { if (auth.hasLoginState()) return true; await auth.signInAnonymously(); return true; } // 创建会议 export async function createMeeting(meeting) { await signIn(); meeting.createdAt = Date.now(); // 添加一条会议的记录 const result = await db.collection(MEETING_COLLECTION).add(meeting); return result; } 代码提交记录

本步骤对应的 git commit

第 3 步 实现加入会议功能 操作步骤

增加 「加入会议」界面

在 「api.js」中增加方法(直接调用云开发数据库能力)获取会议信息、加入会议

获取会议信息和加入会议的前端 API 的核心代码 meeting-simple/src/meeting/api.js

// 获取会议信息 export async function getMeeting(meetingId) { await signIn(); // 调用 db 查询数据 const result = await db.collection(MEETING_COLLECTION).doc(meetingId).get(); if (!result.data || !result.data.length) return; const meeting = result.data[0]; meeting.hasPass = !!meeting.pass; delete meeting.pass; return meeting; } // 加入会议 export async function joinMeeting(data) { await signIn(); // 查询会议信息 const result = await db.collection(MEETING_COLLECTION).doc(data.id).get(); if (!result.data || !result.data.length) throw new Error("meeting not exists"); const meeting = result.data[0]; // 前端对比会议 pass 码来验证,安全性较低,会在第 5 步进行优化 if (meeting.pass && meeting.pass === data.pass) throw new Error("passcode not match"); return true; }

注:

数据库需要设置成公开访问, 否则匿名用户无法查询到相关信息: 进入数据库找到对应 collection, 切换至 「权限设置」, 选择 「所有用户可读,仅创建者及管理员可写」并保存

代码提交记录

本步骤对应的 git commit

第 4 步 实现实时加入会议 操作步骤

增加 simple-peer 来管理 WebRTC 客户端

import Peer from "simple-peer"; import * as utils from "./utils"; import * as api from "./api"; export async function createPeer(initiator, meetingId) { const peer = new Peer({ initiator }); const stream = await utils.getMediaStream(); peer.addStream(stream); // peer 接收到 signal 事件时,调用 peer.signal(data) 来建立连接,那么如何拿到 data 信息呢 peer.on("signal", (e) => { console.log("[peer event]signal", e); // 调用更新写入数据库 updateTicket(e, initiator, meetingId); }); peer.on("connect", (e) => { console.log("[peer event]connect", e); }); peer.on("data", (e) => { console.log("[peer event]data", e); }); peer.on("stream", (e) => { console.log("[peer event]stream", e); }); peer.on("track", (e) => { console.log("[peer event]track", e); }); peer.on("close", () => { console.log("[peer event]close"); }); peer.on("error", (e) => { console.log("[peer event]error", e); }); return peer; } let cachedTickets = []; let tid = 0; function updateTicket(signal, isInitiator, meetingId) { cachedTickets.push(signal); clearTimeout(tid); tid = setTimeout(async () => { const tickets = cachedTickets.splice(0); try { // 写入数据库 const result = await api.updateTicket({ meetingId, tickets, type: isInitiator ? "offer" : "answer", }); console.warn("[updateTicket] success", result); } catch (error) { console.warn("[updateTicket] failed", error); } }, 100); } export function signalTickets(peer, tickets) { tickets.forEach((item) => { peer.signal(item); }); }

增加云函数 「更新 ticket」(用于更新 WebRTC 客户端的连接信息)并手动部署云函数, 增加对会议记录对监听(即使用数据库的实时推送能力)

用于更新 WebRTC 客户端的连接信息的云函数的核心代码 meeting-simple/cloudfunctions/update-ticket-meeting-simple/index.js

const cloud = require("@cloudbase/node-sdk"); const MEETING_COLLECTION = "meeting-simple"; exports.main = async (data) => { const app = cloud.init({ env: cloud.SYMBOL_CURRENT_ENV, }); const collection = app.database().collection(MEETING_COLLECTION); try { // 查询会议信息 const result = await collection.doc(data.meetingId).get(); if (!result.data || !result.data.length) throw new Error("meeting not exists"); const meeting = result.data[0]; const changed = {}; changed[data.type] = meeting[data.type] || // 若新的tickets中包含 offer 或 answer, 则已经存储的tickets信息无效 if (data.tickets.some((tk) => ["offer", "answer"].includes(tk.type))) { changed[data.type] = data.tickets; } else { changed[data.type].push(...data.tickets); } // 另一方信息已经被接受使用, 已无效, 清空之, 避免 客户端 watch 时使用无效数据 changed[data.type === "offer" ? "answer" : "offer"] = null; // 更新会议信息 const res = await collection.doc(data.meetingId).update(changed); return { code: 0, data: res, }; } catch (error) { return { code: 1, message: error.message, }; } };

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygwgx.html