video_windows_webrtc 0.0.4
video_windows_webrtc: ^0.0.4 copied to clipboard
Um plugin sobre video para Windows
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:video_windows_webrtc/video_windows_webrtc.dart';
void main() {
runApp(
const MaterialApp(
home: VMSStressTestApp(),
debugShowCheckedModeBanner: false,
),
);
}
class VMSStressTestApp extends StatefulWidget {
const VMSStressTestApp({super.key});
@override
State<VMSStressTestApp> createState() => _VMSStressTestAppState();
}
class _VMSStressTestAppState extends State<VMSStressTestApp> {
final int rows = 5;
final int cols = 5;
late final List<WebRTCVmsPlayer> _players;
late final List<TextEditingController> _urlControllers;
@override
void initState() {
super.initState();
int total = rows * cols;
_players = List.generate(total, (index) {
return WebRTCVmsPlayer(
onStateChanged: (state) {
if (mounted) {
setState(() {});
}
},
);
});
_urlControllers = List.generate(total, (index) {
return TextEditingController(text: linkVideo(index));
});
}
String linkVideo(int index) {
List<String> links = [
"https://c.vms.tutorsa.cloud/rtc/v1/whep/?app=live&stream=associacaodas02&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://c.vms.tutorsa.cloud/rtc/v1/whep/?app=live&stream=associacaodas03&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live8.protenet.com.br/rtc/v1/whep/?app=live&stream=associacaomor21&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor06&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor07&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor08&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor11&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor12&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor13&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor14&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live9.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor18&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor00&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor01&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor02&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor03&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor04&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live42.analitico.app.br/rtc/v1/whep/?app=live&stream=atacadaolivre02&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live12.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor19&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live23.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor23&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live23.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor24&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live26.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor25&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live12.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor20&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live35.analitico.app.br/rtc/v1/whep/?app=live&stream=homologacaopt00&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live36.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaodas00&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
"https://live36.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaodas01&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
];
if (index >= links.length) return "";
return links[index];
}
@override
void dispose() {
for (var player in _players) {
player.disconnect();
}
for (var urlController in _urlControllers) {
urlController.dispose();
}
super.dispose();
}
void _playAll() {
for (int i = 0; i < _players.length; i++) {
if (_players[i].state == PlayerState.idle ||
_players[i].state == PlayerState.error) {
_players[i].connect(_urlControllers[i].text);
}
}
}
void _stopAll() {
for (int i = 0; i < _players.length; i++) {
_players[i].disconnect();
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'VMS WebRTC Stress Test - ${rows * cols} Cameras (${rows}x${cols})',
),
backgroundColor: Colors.blueGrey[900],
foregroundColor: Colors.white,
actions: [
IconButton(
icon: const Icon(Icons.play_arrow),
onPressed: _playAll,
tooltip: 'Play All',
),
IconButton(
icon: const Icon(Icons.stop),
onPressed: _stopAll,
tooltip: 'Stop All',
),
],
),
backgroundColor: Colors.black,
body: Column(
children: List.generate(rows, (row) {
return Expanded(
child: Row(
children: List.generate(cols, (col) {
int index = row * cols + col;
return Expanded(
child: Padding(
padding: const EdgeInsets.all(1.0),
child: PlayerCell(
player: _players[index],
urlController: _urlControllers[index],
index: index,
),
),
);
}),
),
);
}),
),
);
}
}
class PlayerCell extends StatelessWidget {
final WebRTCVmsPlayer player;
final TextEditingController urlController;
final int index;
const PlayerCell({
super.key,
required this.player,
required this.urlController,
required this.index,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
if (player.state == PlayerState.idle ||
player.state == PlayerState.error) {
print(urlController.text);
player.connect(urlController.text);
} else {
player.disconnect();
}
},
child: Container(
decoration: BoxDecoration(
color: Colors.grey[900],
border: Border.all(color: _getStatusColor(player.state), width: 1),
),
child: Stack(
children: [
ClipRect(
child: SizedBox.expand(
child:
player.textureId != null &&
player.state == PlayerState.playing
? FittedBox(
fit: BoxFit.cover,
child: SizedBox(
width: 1280,
height: 720,
child: Texture(textureId: player.textureId!),
),
)
: Container(color: Colors.black),
),
),
Positioned.fill(child: _buildOverlay()),
Positioned(
top: 2,
left: 2,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
color: Colors.black54,
child: Text(
"CAM ${index + 1}",
style: const TextStyle(color: Colors.white, fontSize: 10),
),
),
),
],
),
),
);
}
Widget _buildOverlay() {
switch (player.state) {
case PlayerState.connecting:
case PlayerState.reconnecting:
return Container(
color: Colors.black38,
child: const Center(
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.orangeAccent),
),
),
),
);
case PlayerState.idle:
return Container(
color: Colors.black26,
child: Center(
child: Icon(
Icons.play_circle_fill,
size: 30,
color: Colors.white.withOpacity(0.8),
),
),
);
case PlayerState.error:
return Container(
color: Colors.black54,
child: const Center(
child: Icon(Icons.error, color: Colors.redAccent, size: 30),
),
);
case PlayerState.playing:
default:
return const SizedBox.shrink();
}
}
Color _getStatusColor(PlayerState state) {
switch (state) {
case PlayerState.playing:
return Colors.greenAccent.withOpacity(0.5);
case PlayerState.connecting:
case PlayerState.reconnecting:
return Colors.orangeAccent.withOpacity(0.5);
case PlayerState.error:
return Colors.redAccent.withOpacity(0.5);
case PlayerState.idle:
default:
return Colors.white24;
}
}
}