You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Janus WebRTC创建视频会议应用房间及Node+ReactJS项目房间API开发求助

Hey Tony, let's walk through this clearly—since you're new to this stack, I'll break it down into actionable steps for both room creation with Janus WebRTC and your Node.js/React setup.

1. Core Concepts: Janus VideoRoom Plugin

First, Janus uses plugins to handle specific features, and for video conferencing, you'll rely on the built-in videoroom plugin. Creating a room involves sending a control message to Janus's API endpoint (usually http://your-janus-server:8088/janus) to initialize the room.

2. Node.js Backend: Auth + Room Creation API

Let's start with the backend—you already have signup/signin routes, so we'll add the room creation logic that talks to Janus directly.

Step 2.1: Setup Dependencies

First, install packages to handle HTTP requests to Janus and session management:

npm install axios express jsonwebtoken bcryptjs cors

Step 2.2: Room Creation Endpoint

Here's a simplified example of a /create-room route that authenticates the user (using JWT) and sends a room creation request to Janus:

const express = require('express');
const axios = require('axios');
const jwt = require('jsonwebtoken');
const cors = require('cors');
const router = express.Router();

// Enable CORS for frontend requests
router.use(cors());

// Middleware to verify JWT (protect room creation route)
const authenticateToken = (req, res, next) => {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];
  if (!token) return res.sendStatus(401);

  jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
    if (err) return res.sendStatus(403);
    req.user = user;
    next();
  });
};

// POST /api/create-room
router.post('/create-room', authenticateToken, async (req, res) => {
  const { roomName, description } = req.body;
  const janusUrl = process.env.JANUS_API_URL; // e.g., "http://localhost:8088/janus"

  try {
    // 1. Create a temporary Janus session
    const sessionResponse = await axios.post(`${janusUrl}`, {
      janus: 'create',
      transaction: Date.now().toString()
    });
    const sessionId = sessionResponse.data.data.id;

    // 2. Attach to the videoroom plugin
    const attachResponse = await axios.post(`${janusUrl}`, {
      janus: 'attach',
      plugin: 'janus.plugin.videoroom',
      session_id: sessionId,
      transaction: Date.now().toString()
    });
    const handleId = attachResponse.data.data.id;

    // 3. Send room creation command
    const createRoomResponse = await axios.post(`${janusUrl}`, {
      janus: 'message',
      body: {
        request: 'create',
        room: Math.floor(Math.random() * 9000) + 1000, // Random 4-digit room ID
        description: description,
        name: roomName,
        publishers: 10, // Max number of video publishers
        bitrate: 1024000 // Default bitrate for streams
      },
      session_id: sessionId,
      handle_id: handleId,
      transaction: Date.now().toString()
    });

    // Cleanup: Detach from plugin and destroy session (good practice)
    await axios.post(`${janusUrl}`, {
      janus: 'detach',
      session_id: sessionId,
      handle_id: handleId,
      transaction: Date.now().toString()
    });
    await axios.post(`${janusUrl}`, {
      janus: 'destroy',
      session_id: sessionId,
      transaction: Date.now().toString()
    });

    // Return room details to frontend
    res.status(200).json({
      success: true,
      roomId: createRoomResponse.data.data.room,
      roomName: roomName
    });
  } catch (error) {
    console.error('Error creating Janus room:', error.response?.data || error.message);
    res.status(500).json({ success: false, message: 'Failed to create room' });
  }
});

module.exports = router;

Step 2.3: Quick Note for Auth Routes

Make sure your signup/signin routes generate a JWT with user details—this is what the authenticateToken middleware uses to ensure only logged-in users can create rooms. For example, a basic signin route:

router.post('/signin', async (req, res) => {
  // Fetch user from your database
  const user = await User.findOne({ email: req.body.email });
  if (!user || !await bcrypt.compare(req.body.password, user.password)) {
    return res.status(401).json({ message: 'Invalid credentials' });
  }

  // Generate JWT token
  const token = jwt.sign({ userId: user._id, email: user.email }, process.env.JWT_SECRET, { expiresIn: '24h' });
  res.json({ token });
});
3. React Frontend: Connect to Backend + Janus

On the React side, you'll need to call your backend's /create-room route, then use the Janus JavaScript library to join the room.

Step 3.1: Add Janus JS Library

Include the Janus script in your public/index.html:

<script src="https://janus.conf.meetecho.com/janus.js"></script>

(For production, download the script locally to avoid relying on external CDNs.)

Step 3.2: Component for Creating/Joining Rooms

Here's a simplified React component that handles room creation and joining:

import { useState } from 'react';
import axios from 'axios';

function VideoRoom() {
  const [roomName, setRoomName] = useState('');
  const [description, setDescription] = useState('');
  const [roomId, setRoomId] = useState(null);
  const [janusInstance, setJanusInstance] = useState(null);

  // Get JWT from local storage (after user logs in)
  const token = localStorage.getItem('authToken');

  const createRoom = async () => {
    if (!token) {
      alert('Please log in first!');
      return;
    }
    try {
      const response = await axios.post('/api/create-room', {
        roomName,
        description
      }, {
        headers: { Authorization: `Bearer ${token}` }
      });
      setRoomId(response.data.roomId);
      alert(`Room created successfully! ID: ${response.data.roomId}`);
    } catch (error) {
      console.error('Error creating room:', error);
      alert('Failed to create room. Check console for details.');
    }
  };

  const joinRoom = () => {
    if (!roomId) return;

    // Initialize Janus connection
    const janus = new Janus({
      server: 'http://your-janus-server:8088/janus',
      success: () => {
        // Attach to videoroom plugin
        janus.attach({
          plugin: 'janus.plugin.videoroom',
          success: (handle) => {
            // Send join request as a publisher
            handle.send({
              message: {
                request: 'join',
                room: parseInt(roomId),
                ptype: 'publisher',
                display: 'Your Display Name'
              },
              success: (result) => {
                console.log('Joined room:', result);
                // Handle local video stream
                handle.createOffer({
                  media: { video: true, audio: true },
                  success: (jsep) => {
                    handle.send({ message: { request: 'configure' }, jsep: jsep });
                  }
                });
                // Listen for remote feeds
                handle.on('remotefeed', (feed) => {
                  feed.attach(document.getElementById('remote-video'));
                });
              },
              error: (err) => {
                console.error('Error joining room:', err);
              }
            });
          },
          error: (err) => {
            console.error('Error attaching to plugin:', err);
          }
        });
      },
      error: (err) => {
        console.error('Error connecting to Janus:', err);
      }
    });
    setJanusInstance(janus);
  };

  return (
    <div className="video-room-container">
      <h2>Video Conference Room</h2>
      <div className="create-room-form">
        <input
          type="text"
          placeholder="Room Name"
          value={roomName}
          onChange={(e) => setRoomName(e.target.value)}
        />
        <input
          type="text"
          placeholder="Room Description"
          value={description}
          onChange={(e) => setDescription(e.target.value)}
        />
        <button onClick={createRoom}>Create New Room</button>
      </div>
      {roomId && (
        <div className="room-controls">
          <p>Room ID: <strong>{roomId}</strong></p>
          <button onClick={joinRoom}>Join Room</button>
          <div className="video-container">
            <video id="local-video" autoPlay playsInline muted></video>
            <video id="remote-video" autoPlay playsInline></video>
          </div>
        </div>
      )}
    </div>
  );
}

export default VideoRoom;
4. Common Bottlenecks & Fixes
  • CORS Errors: Janus runs on a different port, so ensure your Node.js backend uses the cors package, and update Janus's config (janus.cfg) to allow cross-origin requests (set cors_allowed_origins to your frontend URL).
  • Janus Plugin Issues: Double-check that the videoroom plugin is enabled in Janus's config folder (look for janus.plugin.videoroom.jcfg).
  • Session Expiry: Janus sessions have a default timeout—for production, consider keeping a persistent session from your backend instead of creating a new one per room.
  • Debugging: Add detailed logging in both backend and frontend to trace failures (e.g., Janus server unreachable, invalid room parameters).

内容的提问来源于stack exchange,提问作者Tony George

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 17:47:32