Skip to content

Instantly share code, notes, and snippets.

@gisborne
Created June 28, 2024 22:37
Show Gist options
  • Save gisborne/7a714c72444d91cbcd7f93a92aab73b3 to your computer and use it in GitHub Desktop.
Save gisborne/7a714c72444d91cbcd7f93a92aab73b3 to your computer and use it in GitHub Desktop.
Failed webrtc connection
import 'package:flutter/material.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('MacOS STUN Test')),
body: const STUNTest(),
),
);
}
}
class STUNTest extends StatefulWidget {
const STUNTest({Key? key}) : super(key: key);
@override
_STUNTestState createState() => _STUNTestState();
}
class _STUNTestState extends State<STUNTest> {
String _status = 'Initializing...';
RTCPeerConnection? _peerConnection;
bool _gatheringComplete = false;
@override
void initState() {
super.initState();
_createPeerConnection();
}
Future<void> _createPeerConnection() async {
_addLog('Creating peer connection...');
final Map<String, dynamic> configuration = {
'iceServers': [
{
'urls': [
'stun:stun1.l.google.com:19302',
'stun:stun2.l.google.com:19302',
]
}
],
'sdpSemantics': 'unified-plan',
'iceTransportPolicy': 'all',
'bundlePolicy': 'max-bundle',
'rtcpMuxPolicy': 'require',
'iceCandidatePoolSize': 0,
'enableDscp': true,
'enableIPv6': true,
};
_peerConnection = await createPeerConnection(configuration);
_peerConnection!.onIceCandidate = (RTCIceCandidate candidate) {
if (candidate.candidate != null) {
_processCandidate(candidate.candidate!);
}
};
_peerConnection!.onIceGatheringState = (RTCIceGatheringState state) {
_addLog('ICE gathering state changed: $state');
if (state == RTCIceGatheringState.RTCIceGatheringStateComplete) {
_gatheringComplete = true;
_checkGatheringComplete();
}
};
_peerConnection!.onConnectionState = (RTCPeerConnectionState state) {
_addLog('Peer connection state changed: $state');
};
_addLog('Creating data channel...');
await _peerConnection!.createDataChannel('trigger', RTCDataChannelInit());
_addLog('Creating offer...');
RTCSessionDescription offer = await _peerConnection!.createOffer();
_addLog('Setting local description...');
await _peerConnection!.setLocalDescription(offer);
// Set a longer timeout for M1 Macs
Future.delayed(const Duration(seconds: 45), () {
_checkGatheringComplete();
});
}
void _processCandidate(String candidateString) {
_addLog('Received candidate: $candidateString');
final parts = candidateString.split(' ');
final type = parts.firstWhere((part) => part.startsWith('typ ')).split(' ')[1];
final ip = parts[4];
final port = parts[5];
_addLog('Candidate type: $type, IP: $ip, Port: $port');
}
void _checkGatheringComplete() {
if (!_gatheringComplete) {
_addLog('Gathering timed out or completed');
}
if (mounted) {
setState(() {
_status += '\nGathering process finished.';
});
}
}
void _addLog(String log) {
print(log);
if (mounted) {
setState(() {
_status += '\n$log';
});
}
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(_status),
),
);
}
@override
void dispose() {
_peerConnection?.close();
super.dispose();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment