Skip to content

Quick Start

This guide walks you through integrating @tencent-classroom/sdk — implementing the complete flow of creating an instance, joining a classroom, and leaving.

Requirements

  • Node.js >= 16
  • Modern browser with ES Module support (Chrome 85+ / Edge 86+ / Safari 15+ / Firefox 80+)
  • WebRTC support required for audio/video features

Installation

bash
pnpm add @tencent-classroom/sdk
# or
npm install @tencent-classroom/sdk

Classroom Lifecycle Overview

Basic Usage

Step 1: Import the SDK

typescript
import {
  TencentClassroom,
  TEvent,
  StreamType,
  JoinProgress,
} from '@tencent-classroom/sdk';

Step 2: Create an Instance

typescript
const classroom = new TencentClassroom({
  language: 'en',               // UI language: zh-CN | zh-TW | en | ja | ko | vi | ar | id | es
  debug: true,                  // Enable debug logging
  board: {
    domId: 'board-container',   // Whiteboard mount container DOM ID
  },
  behavior: {
    autoLoadDefaultDocument: true,  // Auto-load default courseware after joining
  },
});

Tip: After new TencentClassroom(), access the instance anywhere via TencentClassroom.instance.

Step 3: Initialize the Engine

typescript
const initResult = await classroom.init();
if (!initResult.ok) {
  console.error('SDK initialization failed:', initResult.message);
  return;
}

Step 4: Join a Classroom

typescript
const joinResult = await classroom.joinClass({
  classId: 123456,           // Classroom ID (required)
  userId: 'user_001',        // User ID (required)
  token: 'biz-token-xxx',    // Business token (required, issued by server)
});

if (!joinResult.ok) {
  console.error('Join failed:', joinResult.message);
  return;
}

Step 5: In-class Interactions (Audio/Video / Remote Streams)

typescript
// Start local camera (pass a DOM container for preview)
await classroom.startCamera(document.getElementById('local-video')!);

// Start microphone
await classroom.startMicrophone();

// Bind a remote user's camera stream to a DOM element
const binding = classroom.bindRemoteView(
  'teacher_001',
  document.getElementById('remote-video')!,
  StreamType.Camera,
);

Step 6: Leave and Destroy

typescript
// Unbind remote streams
classroom.unbindRemoteView(binding);

// Leave the classroom
await classroom.leaveClass();

// Destroy the instance (releases all resources)
await classroom.destroy();

Complete Minimal Example

typescript
import { TencentClassroom, TEvent, StreamType } from '@tencent-classroom/sdk';

async function main() {
  // 1. Create instance
  const classroom = new TencentClassroom({
    language: 'en',
    debug: true,
    board: { domId: 'board-container' },
  });

  // 2. Initialize
  const initResult = await classroom.init();
  if (!initResult.ok) return console.error(initResult.message);

  // 3. Listen to key events (set up before joining)
  classroom.on(TEvent.KICK_OUT, ({ message }) => alert(message));

  // 4. Join classroom
  const joinResult = await classroom.joinClass({
    classId: 123456,
    userId: 'user_001',
    token: 'your-token',
  });
  if (!joinResult.ok) return console.error(joinResult.message);

  // 5. Start local audio/video
  await classroom.startCamera(document.getElementById('local-video')!);
  await classroom.startMicrophone();

  // 6. Render remote stream
  const binding = classroom.bindRemoteView(
    'teacher_001',
    document.getElementById('remote-video')!,
    StreamType.Camera,
  );

  // 7. Leave on page unload
  window.addEventListener('beforeunload', async () => {
    classroom.unbindRemoteView(binding);
    await classroom.leaveClass();
    await classroom.destroy();
  });
}

main();

Advanced: JoinProgress Phases

The SDK executes 10 internal phases sequentially when joining. Subscribe to joinProgress$ to drive a Loading UI:

typescript
classroom.state.joinProgress$.subscribe((progress) => {
  updateLoadingUI(progress);
});
PhaseValueDescription
IdleidleInitial state
FetchingSchoolInfofetchingSchoolInfoFetching school info (package, watermark config)
FetchingClassInfofetchingClassInfoFetching classroom details (type, config, members)
JoiningMemberjoiningMemberRegistering member (member/join)
LoginIMloginIMLogging into IM message channel
JoinIMGroupjoinIMGroupJoining IM group (signaling + chat)
JoinTRTCjoinTRTCJoining TRTC room (audio/video channel)
InitBoardinitBoardInitializing whiteboard
InitPermissioninitPermissionFetching permission list
FetchingHistoryfetchingHistoryFetching history messages
CompletedcompletedJoin complete

Advanced: Runtime Environment Check

checkEnvironment() validates every core capability required by the classroom in a single call: browser environment, secure context (HTTPS / localhost), the mediaDevices API, and WebRTC support. Call it after init() and before joinClass().

typescript
const env = await classroom.checkEnvironment();
if (!env.ok) {
  alert(env.message);
  return;
}
if (!env.data.isSupported) {
  // Use `reasons` to render fine-grained UI prompts
  if (env.data.reasons?.includes('InsecureContext')) {
    alert('Please open this page over HTTPS.');
  } else if (env.data.reasons?.includes('WebRTCUnsupported')) {
    alert('This browser does not support audio/video. Please use Chrome 85+ or Edge 86+.');
  } else if (env.data.reasons?.includes('NoMediaDevices')) {
    alert('mediaDevices API is unavailable in the current runtime.');
  } else {
    alert('The current environment does not support the classroom.');
  }
  return;
}

// env.data.checks exposes per-item results for diagnostics
// { browser: true, secureContext: true, mediaDevices: true, webrtc: true }

Advanced: State Subscriptions & Event Listeners

Reactive State

typescript
// Subscribe to class status
classroom.state.classStatus$.subscribe(status => {
  console.log('Class status:', status); // 'notStarted' | 'started' | 'ended' | 'expired'
});

// Listen for kick-out
classroom.on(TEvent.KICK_OUT, ({ reason, message }) => {
  alert(message);
});

// Listen for member join
classroom.on(TEvent.MEMBER_JOIN, (member) => {
  console.log('Member joined:', member.userId, member.nickName);
});

Advanced Event Usage

typescript
// on returns an unsubscribe function
const off = classroom.on(TEvent.CLASS_START, () => console.log('Class started'));
off(); // Unsubscribe

// once — one-time listener, auto-removed after trigger
classroom.once(TEvent.JOIN_CLASS, (classInfo) => {
  console.log('Joined, class name:', classInfo.className);
});

// waitFor — Promise-based, waits for one occurrence
const classInfo = await classroom.waitFor(TEvent.JOIN_CLASS);

// waitFor with timeout
try {
  await classroom.waitFor(TEvent.BOARD_READY, 10_000);
} catch {
  console.error('Timed out waiting for whiteboard');
}

Advanced: Role-based Flows

Teacher

Student

Assistant

  • Has the same management permissions as the teacher
  • On-stage by default after joining — can open audio/video immediately
  • Not recommended to call startCamera() + startMicrophone() by default
  • Can perform all member management operations (kick, invite on-stage, etc.)

Supervisor

  • Read-only mode: can watch audio/video, view whiteboard, browse member list
  • Cannot send messages or manage members
  • Not visible to other participants (does not appear in member list)

Advanced: Platform Detection

Access runtime environment info via classroom.platform:

typescript
classroom.platform.isMobile     // Mobile (Native + Web)
classroom.platform.isDesktop    // Desktop (Electron + Web desktop)
classroom.platform.isElectron   // Electron desktop app
classroom.platform.isAndroid    // Android
classroom.platform.isIOS        // iOS
classroom.platform.isPad        // Tablet (iPad / Android tablet)
classroom.platform.isWeb        // Pure web browser
classroom.platform.isNative     // Has Bridge injection (Electron / Android / iOS)
classroom.platform.supportTouch // Touch screen supported

// High-level classification
classroom.platform.platform     // 'web' | 'electron' | 'android' | 'ios' | 'mobile-web' | 'server'

// Example: branching by platform
if (classroom.platform.isMobile) {
  // Use mobile layout
} else {
  // Use desktop layout
}

Next Steps