Skip to main content

Controller API

The QuickRTCController manages video conferences.

Create Controller

Simplest: connect() Factory

import 'package:quickrtc_flutter_client/quickrtc_flutter_client.dart';

// Connect and optionally join in one step
final controller = await QuickRTCController.connect(
serverUrl: 'https://your-server.com:3000',
conferenceId: 'room-123', // Optional: join immediately
participantName: 'Alice', // Required if conferenceId provided
debug: true,
);

// Socket is managed automatically - disposed when controller is disposed

Manual: Injected Socket

import 'package:quickrtc_flutter_client/quickrtc_flutter_client.dart';

// Option 1: Use QuickRTCSocket helper
final socket = await QuickRTCSocket.connect('https://your-server.com:3000');

// Option 2: Manual socket setup
import 'package:socket_io_client/socket_io_client.dart' as io;
final socket = io.io('https://your-server.com:3000',
io.OptionBuilder()
.setTransports(['websocket'])
.disableAutoConnect()
.build());
socket.connect();

// Create controller with injected socket
final controller = QuickRTCController(socket: socket, debug: true);

Meeting Lifecycle

// Join
await controller.joinMeeting(
conferenceId: 'room-123',
participantName: 'Alice',
);

// Leave
await controller.leaveMeeting();

// Dispose
controller.dispose();
// If using manual socket setup:
socket.disconnect();

Media Control

High-Level Methods

// Enable camera + microphone (recommended)
await controller.enableMedia();

// Or individually:
await controller.enableCamera();
await controller.enableMicrophone();

// Disable
await controller.disableCamera();
await controller.disableMicrophone();
await controller.disableMedia(); // Both

Toggle Methods

// Camera
await controller.toggleCamera(); // Start/stop camera
await controller.toggleCameraPause(); // Pause/resume (keeps stream)

// Microphone
await controller.toggleMicrophone(); // Start/stop microphone
await controller.toggleMicrophoneMute(); // Mute/unmute (keeps stream)

Screen Sharing

Simplest: toggleScreenShareWithPicker()

// Handles platform detection automatically:
// - Desktop: shows screen/window picker dialog
// - Mobile: uses system screen capture
// - If already sharing: stops the screen share
await controller.toggleScreenShareWithPicker(context);

Manual Control

// Start
await controller.startScreenShare();

// Stop
await controller.stopScreenShare();

// Toggle (without picker)
await controller.toggleScreenShare();

Low-Level API

// Mobile
final media = await QuickRTCStatic.getLocalMedia(
MediaConfig.screenShareOnly(),
);

// Desktop (with picker)
final media = await QuickRTCStatic.getScreenShareWithPicker(context);

// Publish
await controller.produce(
ProduceInput.fromTrack(
media.screenshareTrack!,
type: StreamType.screenshare,
),
);

// Stop via state
await controller.state.localScreenshareStream?.stop();

Low-Level Media API

For more control, use QuickRTCStatic and produce():

// Get media
final media = await QuickRTCStatic.getLocalMedia(
MediaConfig.audioVideo(),
);

// Publish to meeting
await controller.produce(
ProduceInput.fromTracksWithTypes(media.tracksWithTypes),
);

Media Config Options

MediaConfig.audioOnly()        // Microphone only
MediaConfig.videoOnly() // Camera only
MediaConfig.audioVideo() // Both
MediaConfig.screenShareOnly() // Screen share

Video Config

MediaConfig.videoOnly(config: VideoConfig.frontCamera)  // Front camera
MediaConfig.videoOnly(config: VideoConfig.backCamera) // Back camera
MediaConfig.videoOnly(config: VideoConfig.hd) // 720p
MediaConfig.videoOnly(config: VideoConfig.fullHd) // 1080p

State Access

final state = controller.state;

// Connection
state.isConnected
state.conferenceId
state.participantId

// Local media presence
state.hasLocalAudio
state.hasLocalVideo
state.hasLocalScreenshare

// Local media paused state
state.isLocalAudioPaused
state.isLocalVideoPaused
state.isLocalScreensharePaused

// Convenience getters (active = present AND not paused)
state.isLocalAudioActive // hasLocalAudio && !isLocalAudioPaused
state.isLocalVideoActive // hasLocalVideo && !isLocalVideoPaused
state.isLocalScreenshareActive // hasLocalScreenshare && !isLocalScreensharePaused

// Participants
state.participantList // List<RemoteParticipant>
state.participantCount // int

Listen to State Changes

ListenableBuilder(
listenable: controller,
builder: (context, _) {
final state = controller.state;
return Text('${state.participantCount} participants');
},
)

Error Handling

if (state.hasError) {
print(state.error);
controller.clearError();
}

Constructor Options

// Using connect() factory
final controller = await QuickRTCController.connect(
serverUrl: 'https://...',
conferenceId: 'room-123', // Optional
participantName: 'Alice', // Required if conferenceId provided
conferenceName: 'My Meeting', // Optional
participantId: 'custom-id', // Optional, auto-generated if not provided
participantInfo: {'role': 'host'}, // Optional metadata
debug: false,
maxParticipants: 0, // 0 = unlimited
connectionTimeout: Duration(seconds: 10),
socketTimeout: Duration(seconds: 30),
operationTimeout: Duration(seconds: 30),
extraHeaders: {'Authorization': 'Bearer ...'}, // Optional
query: {'token': '...'}, // Optional query params
);

// Using constructor with socket
final controller = QuickRTCController(
socket: socket,
debug: false,
maxParticipants: 0,
socketTimeout: Duration(seconds: 30),
operationTimeout: Duration(seconds: 30),
);