Package Exports
- quickrtc-client
- quickrtc-client/dist/client.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (quickrtc-client) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
π₯ QuickRTC Client
A powerful yet simple WebRTC client built on MediaSoup for video conferencing applications. Focus on building your UI while we handle the complex WebRTC internals.
π Table of Contents
β¨ Features
- π― Simple API: Just a few lines to join a conference.
- π Conference Management: Easy join/leave operations.
- π₯ Media Handling: Camera, microphone, and screen sharing.
- π Event-Driven: Real-time notifications for all actions.
- π₯ Participant Tracking: Automatic participant management.
- π Media Controls: Toggle audio/video with single method calls.
- π₯οΈ Screen Sharing: Built-in screen share support.
- β‘ Auto-Consumption: Automatically receive remote streams.
- π‘οΈ Error Handling: Comprehensive error management.
- π± TypeScript: Full type safety and IntelliSense.
π¦ Installation
npm install quickrtc_clientBrowser Usage (CDN):
<script src="/quickrtc_client/dist/client.js"></script>
<script>
const client = new ConferenceClient({
conferenceId: "room-123",
participantName: "John Doe",
socket: io(),
});
</script>π Quick Start
Basic Conference Setup (3 Steps)
import { ConferenceClient } from "quickrtc_client";
import io from "socket.io-client";
// 1. Create socket connection
const socket = io("http://localhost:3000");
// 2. Create conference client
const client = new ConferenceClient({
conferenceId: "my-room",
conferenceName: "My Conference",
participantId: "user-123",
participantName: "John Doe",
socket,
});
// 3. Join the meeting
await client.joinMeeting();
// That's it! You're in the conferenceProducing Media (Audio/Video)
// Get user media
const mediaStream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: true,
});
const audioTrack = mediaStream.getAudioTracks()[0];
const videoTrack = mediaStream.getVideoTracks()[0];
// Produce media to the conference
const { audioStreamId, videoStreamId } = await client.produceMedia(
audioTrack,
videoTrack
);
console.log("Media produced:", audioStreamId, videoStreamId);Consuming Remote Streams
// Automatically consume all existing participant streams
await client.consumeExistingStreams();
// Listen for new remote streams
client.addEventListener("remoteStreamAdded", (event) => {
const { participantId, participantName, kind, stream } = event.detail;
// Display the stream in your UI
const videoElement = document.getElementById(`remote-${participantId}`);
videoElement.srcObject = stream;
});π Architecture Flow
Client-Server Integration Flow
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CLIENT APPLICATION β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ConferenceClient β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β Device β β Transport β β Producer β β
β β Setup ββ β Creation ββ β Consumer β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ Socket.IO
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SERVER (QuickRTCServer) β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β Router β β Transport β β Producer β β
β β Creation ββ β Creation ββ β Consumer β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββConference Join Flow
Client Server
β β
βββ1. joinMeeting()βββββββββββββ
β β Create/Get Conference
β β Add Participant
βββ2. routerCapabilitiesββββββββ
β β
βββ3. createTransports()ββββββββ Create Send/Recv Transports
β β
βββ4. transport paramsββββββββββ
β β
β Setup Send Transport β
β Setup Recv Transport β
β β
βββ5. produceMedia()ββββββββββββ
β β Create Producers
βββ6. producer IDsββββββββββββββ
β β
βββ7. consumeExistingStreams()ββ Get Participant List
β β
βββ8. participantsββββββββββββββ
β β
βββ9. consumeParticipantMedia()ββ Create Consumers
β β
βββ10. consumer paramsββββββββββ
β β
β Create Consumers β
β Receive Remote Streams β
β β
βββ11. Event: participantJoinedβ
βββ12. Event: remoteStreamAddedβπ API Reference
Constructor
new ConferenceClient(config: ConferenceClientConfig)Parameters:
interface ConferenceClientConfig {
conferenceId: string; // Unique conference identifier
conferenceName?: string; // Optional conference name
participantId: string; // Unique participant identifier
participantName: string; // Display name
socket: ClientSocket; // Socket.IO client instance
}Methods
joinMeeting(): Promise<void>
Join a conference. Must be called before any other operations.
await client.joinMeeting();produceMedia(audioTrack?, videoTrack?, type?): Promise<{audioStreamId?, videoStreamId?}>
Produce audio/video to the conference.
Parameters:
audioTrack?: MediaStreamTrack- Audio track from getUserMediavideoTrack?: MediaStreamTrack- Video track from getUserMediatype?: "audio" | "video" | "screenshare"- Stream type (default: "video")
Returns: Object with stream IDs for tracking
const { audioStreamId, videoStreamId } = await client.produceMedia(
audioTrack,
videoTrack
);consumeExistingStreams(): Promise<void>
Consume media from all existing participants.
await client.consumeExistingStreams();stopWatchingStream(participantId: string): Promise<void>
Stop receiving streams from a specific participant.
await client.stopWatchingStream("participant-123");toggleAudio(streamId?, mute?): Promise<boolean>
Toggle audio on/off.
Parameters:
streamId?: string- Specific stream ID (uses first audio stream if omitted)mute?: boolean- Explicit mute state (true = mute, false = unmute)
Returns: Current enabled state
const isEnabled = await client.toggleAudio();toggleVideo(streamId?, mute?): Promise<boolean>
Toggle video on/off.
Parameters:
streamId?: string- Specific stream ID (uses first video stream if omitted)mute?: boolean- Explicit mute state (true = mute, false = unmute)
Returns: Current enabled state
const isEnabled = await client.toggleVideo();stopLocalStream(streamId: string): Promise<boolean>
Stop a specific local stream (useful for screen sharing).
await client.stopLocalStream(screenShareId);leaveMeeting(): Promise<void>
Leave the conference and clean up all resources.
await client.leaveMeeting();getParticipants(): Promise<any[]>
Get list of all participants in the conference.
const participants = await client.getParticipants();getRemoteParticipant(participantId: string): RemoteParticipant | undefined
Get a specific remote participant.
const participant = client.getRemoteParticipant("participant-123");getAllRemoteParticipants(): RemoteParticipant[]
Get all remote participants.
const participants = client.getAllRemoteParticipants();getLocalStreams(): LocalStreamInfo[]
Get all local streams.
const streams = client.getLocalStreams();getLocalStream(streamId: string): MediaStream | null
Get a specific local stream.
const stream = client.getLocalStream(streamId);isInMeeting(): boolean
Check if currently in a meeting.
if (client.isInMeeting()) {
console.log("In meeting");
}π Events
The client uses the EventTarget API. Listen to events using addEventListener.
participantJoined
Fired when a new participant joins the conference.
Event Detail:
{
participantId: string;
participantName: string;
}participantLeft
Fired when a participant leaves the conference.
Event Detail:
{
participantId: string;
}remoteStreamAdded
Fired when a remote participant's stream becomes available.
Event Detail:
{
participantId: string;
participantName: string;
kind: "audio" | "video";
stream: MediaStream;
}remoteStreamRemoved
Fired when a remote participant stops their stream.
Event Detail:
{
participantId: string;
kind: "audio" | "video";
}localStreamAdded
Fired when a local stream is added.
Event Detail:
{
streamId: string;
type: "audio" | "video" | "screenshare";
stream: MediaStream;
}localStreamRemoved
Fired when a local stream is removed.
Event Detail:
{
streamId: string;
type: "audio" | "video" | "screenshare";
}localAudioToggled
Fired when local audio is toggled.
Event Detail:
{
streamId: string;
enabled: boolean;
}localVideoToggled
Fired when local video is toggled.
Event Detail:
{
streamId: string;
enabled: boolean;
}error
Fired when an error occurs.
Event Detail:
{
message: string;
error?: any;
}π‘ Usage Examples
Complete Video Conference
import { ConferenceClient } from "quickrtc_client";
import io from "socket.io-client";
// Setup
const socket = io("http://localhost:3000");
const client = new ConferenceClient({
conferenceId: "meeting-123",
participantId: "user-456",
participantName: "John Doe",
socket,
});
// Event listeners
client.addEventListener("participantJoined", (event) => {
const { participantName } = event.detail;
showNotification(`${participantName} joined`);
});
client.addEventListener("remoteStreamAdded", (event) => {
const { participantId, stream, kind } = event.detail;
displayRemoteStream(participantId, stream, kind);
});
client.addEventListener("localStreamAdded", (event) => {
const { stream, type } = event.detail;
if (type === "video") {
document.getElementById("localVideo").srcObject = stream;
}
});
// Join meeting
await client.joinMeeting();
// Produce media
const mediaStream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: true,
});
const audioTrack = mediaStream.getAudioTracks()[0];
const videoTrack = mediaStream.getVideoTracks()[0];
await client.produceMedia(audioTrack, videoTrack);
// Consume existing streams
await client.consumeExistingStreams();Screen Sharing
// Start screen share
async function startScreenShare() {
try {
const screenStream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: false,
});
const screenTrack = screenStream.getVideoTracks()[0];
// Handle when user stops sharing via browser UI
screenTrack.onended = () => {
console.log("Screen share stopped");
screenShareButton.textContent = "Share Screen";
};
const { videoStreamId } = await client.produceMedia(
undefined,
screenTrack,
"screenshare"
);
screenShareButton.textContent = "Stop Sharing";
return videoStreamId;
} catch (error) {
console.error("Screen share error:", error);
}
}
// Stop screen share
async function stopScreenShare(streamId) {
await client.stopLocalStream(streamId);
screenShareButton.textContent = "Share Screen";
}Audio/Video Controls
// Mute/Unmute audio
async function toggleMute() {
const isEnabled = await client.toggleAudio();
muteButton.textContent = isEnabled ? "π Mute" : "π Unmute";
muteButton.classList.toggle("muted", !isEnabled);
}
// Turn video on/off
async function toggleCamera() {
const isEnabled = await client.toggleVideo();
cameraButton.textContent = isEnabled ? "πΉ Camera Off" : "πΉ Camera On";
cameraButton.classList.toggle("off", !isEnabled);
}Participant Management
// Display participant list
async function updateParticipantList() {
const participants = await client.getParticipants();
const listEl = document.getElementById("participants");
listEl.innerHTML = "";
participants.forEach((p) => {
const li = document.createElement("li");
li.textContent = p.participantName;
li.dataset.id = p.participantId;
listEl.appendChild(li);
});
}
// Stop watching a participant
async function stopWatching(participantId) {
await client.stopWatchingStream(participantId);
removeParticipantFromUI(participantId);
}Graceful Cleanup
// Leave meeting
async function leaveMeeting() {
try {
await client.leaveMeeting();
// Clean UI
document.getElementById("localVideo").srcObject = null;
document.getElementById("remoteStreams").innerHTML = "";
console.log("Left meeting successfully");
} catch (error) {
console.error("Error leaving:", error);
}
}
// Handle page unload
window.addEventListener("beforeunload", async () => {
if (client.isInMeeting()) {
await client.leaveMeeting();
}
});π TypeScript Support
Full TypeScript definitions are included.
import {
ConferenceClient,
ConferenceClientConfig,
RemoteParticipant,
LocalStreamInfo,
LocalStreamType,
ConferenceClientEvents,
} from "quickrtc_client";
// Type-safe configuration
const config: ConferenceClientConfig = {
conferenceId: "room-123",
participantId: "user-456",
participantName: "John Doe",
socket: io(),
};
const client = new ConferenceClient(config);
// Type-safe event handling
client.addEventListener("remoteStreamAdded", (event: CustomEvent) => {
const { participantId, stream } = event.detail;
// TypeScript knows the event detail structure
});π License
MIT License - see LICENSE file for details.