quickrtc_flutter_client 1.1.0 copy "quickrtc_flutter_client: ^1.1.0" to clipboard
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: QuickRTCConference includes this automatically when autoRenderAudio: 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:

  1. Stops the local screen share
  2. Emits closeProducer to the server
  3. 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 onMute callback
  • Track muted property 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
  • QuickRTCConference widget - Batteries-included widget that handles socket, controller lifecycle, and audio rendering
  • QuickRTCController.connect() - One-liner to connect and join
  • QuickRTCSocket.connect() - Simplified socket connection
  • toggleScreenShareWithPicker(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