flutter_video_call_sdk_plugin 0.1.0
flutter_video_call_sdk_plugin: ^0.1.0 copied to clipboard
High-performance video call SDK with Kalman filter congestion control, Reed-Solomon FEC, and Rate-Distortion Optimization. Built with Rust for maximum performance.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_video_call_sdk_plugin/flutter_video_call_sdk_plugin.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _sdk = FlutterVideoCallSdk.instance;
String? _sessionId;
SessionStats? _stats;
bool _isInitialized = false;
final List<String> _logs = [];
@override
void initState() {
super.initState();
_initializeSDK();
}
Future<void> _initializeSDK() async {
try {
await _sdk.initialize();
setState(() {
_isInitialized = true;
});
_addLog('β
SDK initialized successfully');
} catch (e) {
_addLog('β Failed to initialize SDK: $e');
}
}
void _addLog(String message) {
setState(() {
_logs.insert(0, '${DateTime.now().toString().substring(11, 19)} - $message');
if (_logs.length > 20) {
_logs.removeLast();
}
});
}
Future<void> _createSession() async {
try {
final sessionId = await _sdk.createSession(
initialBitrate: 1000000, // 1 Mbps
minBitrate: 300000, // 300 kbps
maxBitrate: 3000000, // 3 Mbps
enableFec: true,
);
setState(() {
_sessionId = sessionId;
});
_addLog('π Session created: ${sessionId.substring(0, 8)}...');
await _updateStats();
} catch (e) {
_addLog('β Failed to create session: $e');
}
}
Future<void> _simulateGoodNetwork() async {
if (_sessionId == null) {
_addLog('β οΈ No active session');
return;
}
try {
await _sdk.updateNetworkFeedback(
_sessionId!,
rttMs: 20,
lossRate: 0.0,
);
_addLog('πΆ Simulated good network (20ms RTT, 0% loss)');
await _updateStats();
} catch (e) {
_addLog('β Failed to update feedback: $e');
}
}
Future<void> _simulateBadNetwork() async {
if (_sessionId == null) {
_addLog('β οΈ No active session');
return;
}
try {
await _sdk.updateNetworkFeedback(
_sessionId!,
rttMs: 150,
lossRate: 0.08,
);
_addLog('πΆ Simulated bad network (150ms RTT, 8% loss)');
await _updateStats();
} catch (e) {
_addLog('β Failed to update feedback: $e');
}
}
Future<void> _updateStats() async {
if (_sessionId == null) return;
try {
final stats = await _sdk.getSessionStats(_sessionId!);
setState(() {
_stats = stats;
});
_addLog('π Stats updated: ${stats.bitrateMbps.toStringAsFixed(2)} Mbps');
} catch (e) {
_addLog('β Failed to get stats: $e');
}
}
Future<void> _closeSession() async {
if (_sessionId == null) {
_addLog('β οΈ No active session');
return;
}
try {
await _sdk.closeSession(_sessionId!);
setState(() {
_sessionId = null;
_stats = null;
});
_addLog('π΄ Session closed');
} catch (e) {
_addLog('β Failed to close session: $e');
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
useMaterial3: true,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter Video Call SDK'),
centerTitle: true,
elevation: 2,
),
body: !_isInitialized
? const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text('Initializing SDK...'),
],
),
)
: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Session Status Card
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
_sessionId != null
? Icons.check_circle
: Icons.cancel,
color: _sessionId != null
? Colors.green
: Colors.grey,
),
const SizedBox(width: 8),
Text(
_sessionId != null
? 'Session Active'
: 'No Active Session',
style: Theme.of(context).textTheme.titleLarge,
),
],
),
if (_sessionId != null) ...[
const SizedBox(height: 8),
Text(
'ID: ${_sessionId!.substring(0, 16)}...',
style: Theme.of(context).textTheme.bodySmall,
),
],
],
),
),
),
const SizedBox(height: 16),
// Statistics Card
if (_stats != null)
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Session Statistics',
style: Theme.of(context).textTheme.titleLarge,
),
const Divider(),
_buildStatRow(
'State',
_stats!.state.toUpperCase(),
Icons.info_outline,
),
_buildStatRow(
'Bitrate',
'${_stats!.bitrateMbps.toStringAsFixed(2)} Mbps',
Icons.speed,
),
_buildStatRow(
'FEC Overhead',
'${_stats!.fecOverhead.toStringAsFixed(1)}%',
Icons.shield,
),
_buildStatRow(
'Packet Loss',
'${_stats!.lossRatePercent.toStringAsFixed(1)}%',
Icons.warning_amber,
),
],
),
),
),
const SizedBox(height: 16),
// Control Buttons
Text(
'Session Controls',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _sessionId == null ? _createSession : null,
icon: const Icon(Icons.add_call),
label: const Text('Create Session'),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _sessionId != null ? _closeSession : null,
icon: const Icon(Icons.call_end),
label: const Text('Close Session'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
),
),
const SizedBox(height: 24),
// Network Simulation
Text(
'Network Simulation',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _sessionId != null ? _simulateGoodNetwork : null,
icon: const Icon(Icons.signal_cellular_alt),
label: const Text('Good Network (20ms, 0% loss)'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _sessionId != null ? _simulateBadNetwork : null,
icon: const Icon(Icons.signal_cellular_alt_1_bar),
label: const Text('Bad Network (150ms, 8% loss)'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange,
),
),
const SizedBox(height: 24),
// Activity Log
Text(
'Activity Log',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
Card(
child: Container(
height: 200,
padding: const EdgeInsets.all(12),
child: _logs.isEmpty
? const Center(
child: Text('No activity yet'),
)
: ListView.builder(
itemCount: _logs.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Text(
_logs[index],
style: Theme.of(context).textTheme.bodySmall?.copyWith(
fontFamily: 'monospace',
),
),
);
},
),
),
),
],
),
),
),
);
}
Widget _buildStatRow(String label, String value, IconData icon) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
Icon(icon, size: 20, color: Colors.blue),
const SizedBox(width: 12),
Expanded(
child: Text(
label,
style: const TextStyle(fontWeight: FontWeight.w500),
),
),
Text(
value,
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
],
),
);
}
@override
void dispose() {
_sdk.dispose();
super.dispose();
}
}