twilio_flutter_video_sdk 1.0.0+2 copy "twilio_flutter_video_sdk: ^1.0.0+2" to clipboard
twilio_flutter_video_sdk: ^1.0.0+2 copied to clipboard

Flutter plugin for Twilio Programmable Video SDK with video conferencing, mute/unmute, camera switching, and meeting management.

Twilio Flutter Video SDK #

A Flutter plugin for integrating Twilio Programmable Video SDK, providing video conferencing capabilities with features like mute/unmute, camera switching, video toggle, and meeting management.

Features #

  • ✅ Join/Leave video rooms
  • ✅ Mute/Unmute audio
  • ✅ Toggle video on/off
  • ✅ Switch between front and back camera
  • ✅ End meeting/disconnect
  • ✅ Real-time participant events
  • ✅ Connection status monitoring
  • ✅ Error handling
  • ✅ Native video rendering via PlatformView
  • ✅ Multiple remote participant support
  • ✅ Video track enabled/disabled handling
  • ✅ Automatic handling of existing participants when joining rooms

Platform Support #

  • ✅ Android (API 24+, Twilio Video SDK 7.9.1)
  • ✅ iOS (13.0+, Twilio Video SDK 5.3.0)

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  twilio_flutter_video_sdk:
    path: ../twilio_flutter_video_sdk

Or if published:

dependencies:
  twilio_flutter_video_sdk: ^1.0.0

Android Setup #

The plugin requires the following permissions in your AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" />

The Twilio Video SDK dependency (version 7.9.1) is automatically included via Maven Central.

iOS Setup #

Add the following permissions to your Info.plist:

<key>NSCameraUsageDescription</key>
<string>This app needs access to the camera for video calls</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs access to the microphone for video calls</string>
<key>io.flutter.embedded_views_preview</key>
<true/>

The Twilio Video SDK dependency (version 5.3.0) is automatically included via CocoaPods.

Run pod install in the ios/ directory after adding the plugin.

Usage #

The easiest way to use the plugin is with the built-in VideoRoomScreen widget:

import 'package:twilio_flutter_video_sdk/twilio_flutter_video_sdk.dart';
import 'package:permission_handler/permission_handler.dart';

// Request permissions first
await [Permission.camera, Permission.microphone].request();

// Navigate to video room screen
Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => VideoRoomScreen(
      options: VideoRoomScreenOptions(
        accessToken: 'YOUR_ACCESS_TOKEN',
        roomName: 'my-room',
        enableAudio: true,
        enableVideo: true,
        enableFrontCamera: true,
        onConnected: () {
          print('Connected to room!');
        },
        onDisconnected: () {
          print('Disconnected from room');
        },
        onConnectionFailure: (error) {
          print('Connection failed: $error');
        },
      ),
    ),
  ),
);

Custom VideoRoomScreen #

You can customize the video room screen with your own widgets:

VideoRoomScreen(
  options: VideoRoomScreenOptions(
    accessToken: 'YOUR_ACCESS_TOKEN',
    roomName: 'my-room',
    // Custom local video widget
    localVideoBuilder: (context) => Container(
      height: 200,
      child: TwilioVideoView(viewId: "0"),
    ),
    // Custom remote video widget
    remoteVideoBuilder: (context, participantSid) => Container(
      height: 150,
      child: TwilioVideoView(viewId: participantSid),
    ),
    // Custom controls
    controlsBuilder: (context, controller) => Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        IconButton(
          icon: Icon(controller.isMuted ? Icons.mic_off : Icons.mic),
          onPressed: controller.toggleMute,
        ),
        IconButton(
          icon: Icon(controller.isVideoEnabled ? Icons.videocam : Icons.videocam_off),
          onPressed: controller.toggleVideo,
        ),
        IconButton(
          icon: Icon(Icons.cameraswitch),
          onPressed: controller.switchCamera,
        ),
        IconButton(
          icon: Icon(Icons.call_end),
          onPressed: controller.disconnect,
        ),
      ],
    ),
  ),
)

Basic Example (Manual Implementation) #

import 'package:twilio_flutter_video_sdk/twilio_flutter_video_sdk.dart';
import 'package:permission_handler/permission_handler.dart';

// Request permissions
await [Permission.camera, Permission.microphone].request();

// Create video controller
final videoController = TwilioVideoController();

// Create a room instance
final room = videoController.createRoom();

// Listen to events
room.events.listen((event) {
  print('Event: $event');
  if (event == TwilioVideoEvent.connected) {
    print('Connected to room');
  }
});

room.errors.listen((error) {
  print('Error: $error');
});

// Listen to participant events
room.participantEvents.listen((participant) {
  print('Participant: ${participant.identity} connected');
});

// Listen to video track events
room.videoTrackEvents.listen((track) {
  print('Video track: ${track.participantSid}, enabled: ${track.isEnabled}');
});

// Join a room
await room.joinRoom(
  RoomOptions(
    accessToken: 'YOUR_ACCESS_TOKEN',
    roomName: 'my-room',
    enableAudio: true,
    enableVideo: true,
    enableFrontCamera: true,
  ),
);

// Mute/Unmute
await room.toggleMute();

// Toggle video
await room.toggleVideo();

// Switch camera
await room.switchCamera();

// Disconnect
await room.disconnect();

Displaying Video Views #

The plugin provides TwilioVideoView widget for rendering native video:

import 'package:twilio_flutter_video_sdk/twilio_flutter_video_sdk.dart';

// Local video view (viewId: 0)
TwilioVideoView(viewId: 0)

// Remote participant video view (viewId: participantSid)
TwilioVideoView(viewId: participantSid)

Complete Example with Video Views #

class VideoRoomScreen extends StatefulWidget {
  @override
  _VideoRoomScreenState createState() => _VideoRoomScreenState();
}

class _VideoRoomScreenState extends State<VideoRoomScreen> {
  TwilioVideoController? _controller;
  TwilioVideoRoom? _room;
  Set<String> _remoteParticipantSids = {};
  bool _isConnected = false;

  @override
  void initState() {
    super.initState();
    _controller = TwilioVideoController();
    _room = _controller!.createRoom();
    
    // Listen to video track events
    _room!.videoTrackEvents.listen((track) {
      setState(() {
        if (track.isEnabled && track.nativeViewReady) {
          _remoteParticipantSids.add(track.participantSid);
        } else {
          _remoteParticipantSids.remove(track.participantSid);
        }
      });
    });
    
    // Listen to connection events
    _room!.events.listen((event) {
      if (event == TwilioVideoEvent.connected) {
        setState(() => _isConnected = true);
      } else if (event == TwilioVideoEvent.disconnected) {
        setState(() {
          _isConnected = false;
          _remoteParticipantSids.clear();
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          // Local video
          SizedBox(
            height: 200,
            child: TwilioVideoView(viewId: 0),
          ),
          
          // Remote videos
          Expanded(
            child: _remoteParticipantSids.isEmpty
                ? Center(child: Text('Waiting for participants...'))
                : GridView.builder(
                    gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                      crossAxisCount: 2,
                    ),
                    itemCount: _remoteParticipantSids.length,
                    itemBuilder: (context, index) {
                      final participantSid = _remoteParticipantSids.elementAt(index);
                      return TwilioVideoView(viewId: participantSid);
                    },
                  ),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    _room?.disconnect();
    _controller?.dispose();
    super.dispose();
  }
}

Complete Example #

See the example/ directory for a complete working example with UI.

API Reference #

TwilioVideoController #

Main controller for managing video rooms.

final controller = TwilioVideoController();
final room = controller.createRoom();
controller.dispose(); // Clean up resources

TwilioVideoRoom #

Represents a video room connection.

Methods

  • Future<void> joinRoom(RoomOptions options) - Join a video room
  • Future<void> disconnect() - Disconnect from the room
  • Future<void> setMuted(bool muted) - Mute or unmute audio
  • Future<void> toggleMute() - Toggle mute state
  • Future<void> setVideoEnabled(bool enabled) - Enable or disable video
  • Future<void> toggleVideo() - Toggle video on/off
  • Future<void> switchCamera() - Switch between front and back camera
  • void dispose() - Dispose resources

Properties

  • bool isConnected - Whether currently connected
  • bool isMuted - Whether audio is muted
  • bool isVideoEnabled - Whether video is enabled
  • bool isFrontCamera - Whether using front camera

Streams

  • Stream<TwilioVideoEvent> events - Video events stream
  • Stream<ParticipantInfo> participantEvents - Participant updates
  • Stream<VideoTrackInfo> videoTrackEvents - Video track updates
  • Stream<String> errors - Error messages

VideoRoomScreen #

Ready-to-use video room screen widget with built-in UI and controls.

VideoRoomScreen({
  required VideoRoomScreenOptions options,
  VideoRoomScreenController? controller,
})

Features:

  • Complete UI with local and remote video views
  • Built-in controls (mute, video toggle, camera switch, disconnect)
  • Automatic handling of video tracks and participants
  • Customizable with builder functions
  • Optional controller for programmatic control

VideoRoomScreenOptions #

Configuration for VideoRoomScreen.

VideoRoomScreenOptions({
  required String accessToken,        // Twilio access token
  required String roomName,           // Room name to join
  bool enableAudio = true,            // Enable audio by default
  bool enableVideo = true,            // Enable video by default
  bool enableFrontCamera = true,      // Use front camera by default
  bool showInputFields = false,      // Show token/room input fields
  String? appBarTitle,                // Custom app bar title
  VoidCallback? onConnected,          // Called when connected
  VoidCallback? onDisconnected,       // Called when disconnected
  Function(String)? onConnectionFailure, // Called on connection failure
  Widget Function(BuildContext)? localVideoBuilder,  // Custom local video widget
  Widget Function(BuildContext, String)? remoteVideoBuilder, // Custom remote video widget
  Widget Function(BuildContext, VideoRoomScreenController)? controlsBuilder, // Custom controls
})

VideoRoomScreenController #

Controller for programmatically controlling VideoRoomScreen.

final controller = VideoRoomScreenController();

// Properties
controller.isConnected      // Whether connected to room
controller.isMuted          // Whether audio is muted
controller.isVideoEnabled   // Whether video is enabled
controller.isFrontCamera   // Whether using front camera
controller.room            // Access to TwilioVideoRoom instance

// Methods
await controller.toggleMute();     // Toggle mute state
await controller.toggleVideo();    // Toggle video on/off
await controller.switchCamera();   // Switch camera
await controller.disconnect();     // Disconnect from room

TwilioVideoView #

Widget for displaying native video views.

TwilioVideoView({
  required String viewId,  // "0" for local, participantSid for remote
})

Important Notes:

  • Local video always uses viewId: "0"
  • Remote participant videos use viewId: participantSid
  • Only create TwilioVideoView widgets when track.isEnabled && track.nativeViewReady is true
  • The widget automatically handles platform-specific rendering (AndroidView on Android, UiKitView on iOS)

RoomOptions #

Configuration for joining a room.

RoomOptions(
  accessToken: 'YOUR_ACCESS_TOKEN',  // Required
  roomName: 'room-name',              // Required
  enableAudio: true,                  // Optional, default: true
  enableVideo: true,                  // Optional, default: true
  enableFrontCamera: true,            // Optional, default: true
)

TwilioVideoEvent #

Video events emitted by the room.

class TwilioVideoEvent {
  final String event;
  final Map<String, dynamic> data;
}

Event types:

  • connected - Successfully connected to room
  • disconnected - Disconnected from room
  • connectionFailure - Failed to connect
  • participantConnected - Remote participant joined
  • participantDisconnected - Remote participant left
  • videoTrackAdded - Video track added (local or remote)
  • videoTrackRemoved - Video track removed
  • audioTrackAdded - Audio track added
  • audioTrackRemoved - Audio track removed

VideoTrackInfo #

Information about a video track.

class VideoTrackInfo {
  final String trackSid;
  final String participantSid;
  final bool isEnabled;
  final bool nativeViewReady;  // Whether native VideoView is ready
}

Important: Only create TwilioVideoView widgets when both isEnabled and nativeViewReady are true. This ensures the native view exists before Flutter tries to access it.

ParticipantInfo #

Information about a participant.

class ParticipantInfo {
  final String sid;
  final String identity;
  final bool isAudioEnabled;
  final bool isVideoEnabled;
  final bool isConnected;
}

Video Track Lifecycle #

The plugin handles video tracks as follows:

  1. When a participant joins with video:

    • videoTrackAdded event is sent with isEnabled: true and nativeViewReady: true
    • Create TwilioVideoView widget with the participant's SID
  2. When a participant disables video:

    • videoTrackAdded event is sent with isEnabled: false
    • Remove the participant from your UI or show a placeholder
    • The native view is kept for reuse when video is enabled again
  3. When a participant enables video again:

    • videoTrackAdded event is sent with isEnabled: true and nativeViewReady: true
    • Re-add the participant to your UI
  4. When a participant leaves:

    • videoTrackRemoved event is sent
    • Remove the participant from your UI

Handling Existing Participants #

When you join a room where other participants are already present:

  • The plugin automatically detects existing participants
  • Video tracks for existing participants are handled automatically
  • videoTrackAdded events are sent for all existing subscribed tracks
  • No special handling needed - just listen to videoTrackEvents and create views as tracks are added

Getting Access Tokens #

To use this plugin, you need Twilio access tokens. You can generate them using the Twilio Video Access Token Generator or by creating a backend service.

Important: Never embed your Twilio credentials in your mobile app. Always use a backend service to generate access tokens.

Example backend endpoint (Node.js):

const express = require('express');
const twilio = require('twilio');

const app = express();
const AccessToken = twilio.jwt.AccessToken;
const VideoGrant = AccessToken.VideoGrant;

app.post('/token', (req, res) => {
  const { identity, roomName } = req.body;
  
  const token = new AccessToken(
    process.env.TWILIO_ACCOUNT_SID,
    process.env.TWILIO_API_KEY,
    process.env.TWILIO_API_SECRET,
    { identity }
  );
  
  const videoGrant = new VideoGrant({ room: roomName });
  token.addGrant(videoGrant);
  
  res.json({ token: token.toJwt() });
});

Permissions #

The plugin requires camera and microphone permissions. Make sure to request these permissions before joining a room:

import 'package:permission_handler/permission_handler.dart';

final statuses = await [
  Permission.camera,
  Permission.microphone,
].request();

if (statuses[Permission.camera]?.isGranted == true &&
    statuses[Permission.microphone]?.isGranted == true) {
  // Permissions granted, proceed to join room
} else {
  // Handle permission denial
}

Troubleshooting #

Android Issues #

  • Build errors with Twilio SDK:

    • Ensure mavenCentral() is in your settings.gradle.kts repositories
    • Verify Twilio Video SDK version 7.9.1 is being used
    • Clean and rebuild: ./gradlew clean build
  • Camera not working:

    • Ensure minSdk is 24 or higher
    • Check that all permissions are declared in AndroidManifest.xml
    • Verify camera permission is granted before joining room
  • Video views not showing:

    • Ensure you're only creating TwilioVideoView when nativeViewReady is true
    • Check that viewId matches the participant SID for remote videos
    • Verify PlatformView is properly registered

iOS Issues #

  • Build errors:

    • Ensure iOS deployment target is 13.0 or higher
    • Run pod install in the iOS directory after adding the plugin
    • Clean build folder in Xcode: Product → Clean Build Folder
  • Camera/Microphone not working:

    • Check that camera and microphone permissions are in Info.plist
    • Verify io.flutter.embedded_views_preview is set to true in Info.plist
    • Request permissions before joining room
  • Video views not showing:

    • Ensure you're only creating TwilioVideoView when nativeViewReady is true
    • Check that viewId matches the participant SID for remote videos
    • Verify PlatformView factory is properly registered

Common Issues #

  • "Waiting for video..." message:

    • This appears when Flutter tries to create a PlatformView before the native view is ready
    • Solution: Only create TwilioVideoView when track.nativeViewReady is true
  • Frozen video when participant turns off video:

    • Fixed in version 1.0.0: The plugin now properly removes renderers when video is disabled
    • Ensure you're handling isEnabled: false events and hiding/showing placeholders
  • Remote videos not appearing when joining active room:

    • Fixed in version 1.0.0: The plugin automatically detects and handles existing participants
    • Just listen to videoTrackEvents and create views as tracks are added

Version History #

1.0.0+1 #

  • Initial release
  • Support for Android (SDK 7.9.1) and iOS (SDK 5.3.0)
  • Native video rendering via PlatformView
  • Multiple remote participant support
  • Video track enabled/disabled handling
  • Automatic handling of existing participants
  • Proper cleanup when video is disabled (prevents frozen frames)
  • VideoRoomScreen widget - Ready-to-use video room screen with built-in UI and controls

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments #

0
likes
0
points
12
downloads

Publisher

verified publishergowthaman.info

Weekly Downloads

Flutter plugin for Twilio Programmable Video SDK with video conferencing, mute/unmute, camera switching, and meeting management.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on twilio_flutter_video_sdk

Packages that implement twilio_flutter_video_sdk