Skip to main content

Screen Sharing

Share your screen with meeting participants.

Quick Start

The simplest way to add screen sharing is using toggleScreenShareWithPicker():

// Handles everything automatically:
// - Platform detection (desktop vs mobile)
// - Showing appropriate picker dialog
// - Stopping if already sharing
await controller.toggleScreenShareWithPicker(context);

This method:

  • Desktop (macOS, Windows, Linux): Shows native screen/window picker
  • Mobile (iOS, Android): Uses system screen capture
  • Web: Uses browser's built-in picker
  • Toggle behavior: Stops screen share if already active

Desktop (macOS, Windows, Linux)

IconButton(
icon: Icon(state.isLocalScreenshareActive
? Icons.stop_screen_share
: Icons.screen_share),
onPressed: () => controller.toggleScreenShareWithPicker(context),
)

Manual Approach with Picker

final media = await QuickRTCStatic.getScreenShareWithPicker(context);

if (media.screenshareTrack != null) {
await controller.produce(
ProduceInput.fromTrack(
media.screenshareTrack!,
type: StreamType.screenshare,
),
);
}

macOS Permissions

Users must grant screen recording permission:

System Preferences → Privacy & Security → Screen Recording

To check/request permission:

// Check permission
final hasPermission = await QuickRTCStatic.checkScreenCapturePermission();

// Request permission
await QuickRTCStatic.requestScreenCapturePermission();

// Open settings
await QuickRTCStatic.openScreenCaptureSettings();

Mobile (Android, iOS)

// Same API works on mobile - no context picker needed
await controller.toggleScreenShareWithPicker(context);

Manual Approach

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

if (media.screenshareTrack != null) {
await controller.produce(
ProduceInput.fromTrack(
media.screenshareTrack!,
type: StreamType.screenshare,
),
);
}

Android Permissions

Add to AndroidManifest.xml:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />

Stop Screen Sharing

// Using toggle (if already sharing, stops it)
await controller.toggleScreenShareWithPicker(context);

// Or explicitly stop
await controller.stopScreenShare();

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

Check Screen Share Status

// Is screen share active?
if (state.hasLocalScreenshare) {
// Screen share is being produced
}

// Is it active AND not paused?
if (state.isLocalScreenshareActive) {
// Screen share is being produced and not paused
}

Config Options

// With toggleScreenShareWithPicker
await controller.toggleScreenShareWithPicker(
context,
config: ScreenShareConfig(
width: 1920,
height: 1080,
frameRate: 30,
),
);

// With MediaConfig
MediaConfig.screenShareOnly(
config: ScreenShareConfig(
width: 1920,
height: 1080,
frameRate: 30,
),
)

Presets:

ScreenShareConfig.defaultConfig  // 1080p, 30fps
ScreenShareConfig.highQuality // 1080p, 60fps

Complete Example

class ConferenceControls extends StatelessWidget {
final QuickRTCController controller;
final QuickRTCState state;


Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Mic toggle
IconButton(
icon: Icon(state.isLocalAudioActive ? Icons.mic : Icons.mic_off),
onPressed: () => controller.toggleMicrophoneMute(),
),
// Camera toggle
IconButton(
icon: Icon(state.isLocalVideoActive ? Icons.videocam : Icons.videocam_off),
onPressed: () => controller.toggleCameraPause(),
),
// Screen share toggle - works on all platforms
IconButton(
icon: Icon(
state.isLocalScreenshareActive
? Icons.stop_screen_share
: Icons.screen_share,
),
onPressed: () => controller.toggleScreenShareWithPicker(context),
),
],
);
}
}