@nhanaka/call
v2.0.2
Published
WebRTC call library with group calls, permissions, and realtime chat for Node.js, Next.js, and React
Maintainers
Readme
@nhanaka/call
Thư viện WebRTC call đơn giản và mạnh mẽ cho Node.js, Next.js và React. Hỗ trợ cuộc gọi thoại, video và group call với Socket.IO signaling.
✨ Tính năng
- 🎥 Cuộc gọi video & thoại: Hỗ trợ cả video call và voice call 1-1
- 👥 Group call: Cuộc gọi nhóm nhiều người với phân quyền 3 cấp
- 💬 Chat realtime: Gửi tin nhắn trong cuộc gọi với validation
- 🔐 Phân quyền: HOST, MODERATOR, MEMBER với quyền hạn khác nhau
- ⚛️ React hooks: Tích hợp sẵn với React Context và hooks
- 🔒 Bảo mật: Xác thực token và domain validation
- 🌐 WebRTC: Kết nối peer-to-peer chất lượng cao
- 📡 Socket.IO: Signaling server với rooms support
- 🎛️ Tùy chỉnh: Callbacks linh hoạt cho mọi sự kiện
- 📱 Responsive: Hoạt động tốt trên mọi thiết bị
📦 Cài đặt
npm install @nhanaka/call socket.io socket.io-client react🚀 Quick Start
Server-side
import { createCallServer } from '@nhanaka/call';
import { Server } from 'socket.io';
import { createServer } from 'http';
const httpServer = createServer();
const io = new Server(httpServer, {
cors: { origin: 'http://localhost:3000', credentials: true }
});
const callServer = createCallServer({
io,
callbacks: {
onValidateToken: async (token) => token === 'valid-token',
onCallInitiated: async (data) => {
console.log('New call:', data);
return true;
},
onCallMessage: async (message) => {
await db.messages.create(message);
return true;
}
}
});
httpServer.listen(3001);Client-side (React)
import { CallProvider, useCall, CallType } from '@nhanaka/call';
function App() {
return (
<CallProvider config={{
serverUrl: 'http://localhost:3001',
userId: 'user-123',
token: 'your-token'
}}>
<VideoCall />
</CallProvider>
);
}
function VideoCall() {
const { initiateCall } = useCall();
const handleCall = () => {
initiateCall('user-456', CallType.VIDEO, { audio: true, video: true });
};
const handleGroupCall = () => {
initiateCall(['user-2', 'user-3'], CallType.GROUP, { audio: true, video: true });
};
return <button onClick={handleCall}>Call</button>;
}📞 Group Call
Hệ thống phân quyền 3 cấp
enum ParticipantLevel {
HOST = 0, // Chủ phòng - quyền cao nhất
MODERATOR = 1, // Người điều hành
MEMBER = 2 // Thành viên thường
}| Quyền | HOST | MODERATOR | MEMBER | |-------|------|-----------|--------| | Kick người khác | ✅ | ✅ (chỉ MEMBER) | ❌ | | Mute người khác | ✅ | ✅ (chỉ MEMBER) | ❌ | | Tắt camera người khác | ✅ | ✅ (chỉ MEMBER) | ❌ | | Mời người vào call | ✅ | ✅ | ❌ | | Gửi tin nhắn | ✅ | ✅ | ✅ |
Lưu ý về Force Toggle:
- Khi admin tắt mic/camera với
forced: true, user KHÔNG THỂ tự bật lại - User chỉ có thể bật lại khi admin unmute/unblock họ
- Dùng cho trường hợp cần kiểm soát chặt chẽ (lớp học, hội nghị quan trọng)
Quản lý participants
// Kick participant
await client.kickParticipant(callId, 'user-3', 'Spam');
// Mute participant - user có thể tự bật lại
await client.toggleRemoteMedia(callId, 'user-3', 'audio', false);
// Force mute - user KHÔNG THỂ tự bật lại
await client.toggleRemoteMedia(callId, 'user-3', 'audio', false, true);
// Mời thêm người vào group call
await client.inviteParticipants(callId, ['user-5', 'user-6'], ParticipantLevel.MEMBER);Chat trong cuộc gọi
// Gửi tin nhắn
await client.sendMessage(callId, 'Hello everyone!');
// Nhận tin nhắn
client.on('callMessage', (message) => {
console.log(`: `);
});🎯 API Reference
Server API
createCallServer(config)
io: Socket.IO server instancecallbacks: onValidateToken, onCallInitiated, onCallMessage, etc.
Methods:
getIO(): Lấy Socket.IO instancegetActiveCalls(): Danh sách cuộc gọigetOnlineUsers(): Danh sách user online
Client API
createCallClient(config)
serverUrl: URL serveruserId: ID user hiện tạitoken: Token xác thực
Methods:
connect(): Kết nối serverinitiateCall(to, type, constraints): Tạo cuộc gọijoinCall(callId, constraints, level?): Join group callsendMessage(callId, message): Gửi tin nhắnkickParticipant(callId, userId, reason?): Kick participanttoggleRemoteMedia(callId, userId, type, enabled, forced?): Toggle mediainviteParticipants(callId, userIds, level?): Mời thêm người
React Hooks
useCall()
initiateCall(),acceptCall(),rejectCall(),endCall()toggleAudio(),toggleVideo()localStream,remoteStreams,incomingCall
useVideoElement(stream)
const videoRef = useVideoElement(localStream);
return <video ref={videoRef} autoPlay muted />;📝 Types
enum CallType {
VOICE = 'voice',
VIDEO = 'video',
GROUP = 'group'
}
interface Participant {
userId: string;
level: ParticipantLevel;
isAudioEnabled: boolean;
isVideoEnabled: boolean;
isAudioForcedOff: boolean;
isVideoForcedOff: boolean;
}🎯 Use Cases
Online Class
const callId = await client.initiateCall(
students,
CallType.GROUP,
{ audio: true, video: true }
);
// Force mute all students
for (const student of students) {
await client.toggleRemoteMedia(callId, student, 'audio', false, true);
}
// Cho phép 1 học sinh phát biểu
await client.toggleRemoteMedia(callId, studentId, 'audio', true);📄 License
MIT
🙏 Credits
Built with ❤️ using WebRTC, Socket.IO, and TypeScript
Repository: https://github.com/fo-nhan/call
