quickrtc_flutter_client 1.1.0
quickrtc_flutter_client: ^1.1.0 copied to clipboard
A Flutter WebRTC library built on MediaSoup for real-time video conferencing.
QuickRTC Flutter Client #
A Flutter WebRTC library built on MediaSoup for real-time video conferencing.
Features #
- Simple API - High-level methods for common tasks
- Cross-Platform - Android, iOS, macOS, Web
- Screen Sharing - Full support for all platforms
- Auto-Consume - Automatically handles new participant streams
Installation #
dependencies:
quickrtc_flutter_client: ^1.1.0
Quick Start (Simplest Way) #
Use the QuickRTCConference widget for a batteries-included experience:
import 'package:quickrtc_flutter_client/quickrtc_flutter_client.dart';
QuickRTCConference(
serverUrl: 'https://your-server.com:3000',
conferenceId: 'my-room',
participantName: 'John',
onJoined: (controller) => controller.enableMedia(),
builder: (context, state, controller) {
return Column(
children: [
// Video grid
Expanded(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: state.participantList.length + 1,
itemBuilder: (_, index) {
if (index == 0) {
return QuickRTCMediaRenderer(
stream: state.localVideoStream?.stream,
mirror: true,
isLocal: true,
);
}
final p = state.participantList[index - 1];
return QuickRTCMediaRenderer(
remoteStream: p.videoStream,
participantName: p.name,
);
},
),
),
// Controls using new convenience getters
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(state.isLocalAudioActive ? Icons.mic : Icons.mic_off),
onPressed: () => controller.toggleMicrophoneMute(),
),
IconButton(
icon: Icon(state.isLocalVideoActive ? Icons.videocam : Icons.videocam_off),
onPressed: () => controller.toggleCameraPause(),
),
IconButton(
icon: Icon(state.isLocalScreenshareActive ? Icons.stop_screen_share : Icons.screen_share),
onPressed: () => controller.toggleScreenShareWithPicker(context),
),
],
),
],
);
},
)
Quick Start (Controller API) #
For more control, use QuickRTCController.connect():
// Connect and join in one step
final controller = await QuickRTCController.connect(
serverUrl: 'https://your-server.com:3000',
conferenceId: 'my-room',
participantName: 'John',
);
// Enable camera and microphone
await controller.enableMedia();
// Later: leave and cleanup (socket auto-disconnects)
await controller.leaveMeeting();
controller.dispose();
Manual Setup (Full Control) #
import 'package:quickrtc_flutter_client/quickrtc_flutter_client.dart';
import 'package:socket_io_client/socket_io_client.dart' as io;
// Create socket (or use QuickRTCSocket.connect() for simpler setup)
final socket = await QuickRTCSocket.connect('https://your-server.com:3000');
// Create controller
final controller = QuickRTCController(socket: socket, debug: true);
// Wrap your app with QuickRTCProvider
QuickRTCProvider(
controller: controller,
child: const MyApp(),
);
// Join meeting
await controller.joinMeeting(
conferenceId: 'my-room',
participantName: 'John',
);
Builder, Consumer & Listener Patterns #
The SDK provides several widgets to simplify state management and UI updates.
QuickRTCBuilder #
Use this for reactive UI updates. It only rebuilds when the specified condition is met.
QuickRTCBuilder(
buildWhen: (prev, curr) => prev.participantCount != curr.participantCount,
builder: (context, state) {
return Text('Participants: ${state.participantCount}');
},
)
QuickRTCConsumer #
Use this when you need both the controller and the state in your build method.
QuickRTCConsumer(
builder: (context, controller, state, child) {
return IconButton(
icon: Icon(state.isLocalAudioActive ? Icons.mic : Icons.mic_off),
onPressed: () => controller.toggleMicrophoneMute(),
);
},
)
QuickRTCListener #
Use this for occasional side effects like showing notifications or navigation, without rebuilding the UI.
QuickRTCListener(
listenWhen: (prev, curr) => prev.error != curr.error && curr.error != null,
listener: (context, controller) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(controller.state.error!)),
);
},
child: const YourWidget(),
)
Rendering Media #
QuickRTCMediaRenderer #
Powerful widget for rendering local and remote video streams.
// Local video with mirroring
QuickRTCMediaRenderer(
stream: state.localVideoStream?.stream,
mirror: true,
isLocal: true,
participantName: 'You',
)
// Remote video from participant
QuickRTCMediaRenderer(
remoteStream: participant.videoStream,
participantName: participant.name,
isAudioEnabled: participant.hasAudio && !participant.isAudioMuted,
isVideoEnabled: participant.hasVideo && !participant.isVideoMuted,
)
QuickRTCAudioRenderers #
Invisible widget that handles audio playback for all remote participants.
QuickRTCAudioRenderers(participants: state.participantList)
Note:
QuickRTCConferenceincludes this automatically whenautoRenderAudio: true(default).
Screen Sharing #
// Simplest: use toggleScreenShareWithPicker (handles platform detection)
await controller.toggleScreenShareWithPicker(context);
// Or manually:
// 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),
);
Android Screen Share External Stop Detection #
On Android, when screen sharing is stopped via the system notification ("Stop now" button) or when MediaProjection is revoked, the SDK automatically detects this and:
- Stops the local screen share
- Emits
closeProducerto the server - Other participants are notified and remove the screen share tile
This is handled automatically - no additional code is required. The SDK uses multiple detection strategies:
- Track
onMutecallback - Track
mutedproperty monitoring - Producer RTP stats monitoring (detects when no new bytes are being sent)
Leave Meeting #
await controller.leaveMeeting();
controller.dispose();
// If using manual socket setup:
socket.disconnect();
Platform Setup #
Android #
android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- Required for screen sharing on Android 10+ -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- Required for screen sharing on Android 14+ (API 34+) -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
android/app/build.gradle:
android {
defaultConfig {
minSdkVersion 24
}
}
Note: On Android 14+, the SDK handles the foreground service requirement automatically. The service includes a notification with a "Stop" button for users to stop screen sharing.
iOS #
ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera for video calls</string>
<key>NSMicrophoneUsageDescription</key>
<string>Microphone for audio calls</string>
macOS #
macos/Runner/*.entitlements:
<key>com.apple.security.device.camera</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
State Properties #
// Connection
state.isConnected // Connection status
state.participantList // List<RemoteParticipant>
state.participantCount // Number of participants
// Local media presence
state.hasLocalAudio // Mic active
state.hasLocalVideo // Camera active
state.hasLocalScreenshare // Screen share active
// Local media paused state
state.isLocalAudioPaused // Mic muted
state.isLocalVideoPaused // Camera paused
state.isLocalScreensharePaused // Screen share paused
// NEW in 1.1.0: Convenience getters (active = present && not paused)
state.isLocalAudioActive // hasLocalAudio && !isLocalAudioPaused
state.isLocalVideoActive // hasLocalVideo && !isLocalVideoPaused
state.isLocalScreenshareActive // hasLocalScreenshare && !isLocalScreensharePaused
// Streams
state.localVideoStream // LocalStream?
state.localAudioStream // LocalStream?
state.localScreenshareStream // LocalStream?
RemoteParticipant #
participant.id // String
participant.name // String
participant.videoStream // RemoteStream?
participant.audioStream // RemoteStream?
participant.hasVideo // bool
participant.hasAudio // bool
participant.isVideoMuted // bool
participant.isAudioMuted // bool
What's New in 1.1.0 #
- Version consolidation - Single unified version for all components
- Android screen share external stop detection - Automatically detects when screen sharing is stopped via system notification and notifies other participants
- Producer stats monitoring - Reliable detection of stalled screen share streams
QuickRTCConferencewidget - Batteries-included widget that handles socket, controller lifecycle, and audio renderingQuickRTCController.connect()- One-liner to connect and joinQuickRTCSocket.connect()- Simplified socket connectiontoggleScreenShareWithPicker(context)- Platform-aware screen sharing toggle- Convenience getters -
isLocalAudioActive,isLocalVideoActive,isLocalScreenshareActive
Example #
See example/ for code snippets demonstrating basic features. For a complete working application, refer to the QuickRTC Example Repository.
Documentation #
Full documentation: quickrtc-docs.vercel.app/docs/flutter/getting-started