Skip to content

Commit ff4a811

Browse files
committed
Add turn relay support for web.
1 parent 5c8b485 commit ff4a811

File tree

9 files changed

+67
-84
lines changed

9 files changed

+67
-84
lines changed

lib/main.dart

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import 'package:flutter/material.dart';
2-
import 'src/utils/key_value_store.dart'
3-
if (dart.library.js) 'src/utils/key_value_store_web.dart';
41
import 'dart:core';
2+
3+
import 'package:flutter/material.dart';
4+
import 'package:shared_preferences/shared_preferences.dart';
5+
56
import 'src/basic_sample/basic_sample.dart';
67
import 'src/call_sample/call_sample.dart';
78
import 'src/call_sample/data_channel_sample.dart';
@@ -21,8 +22,9 @@ enum DialogDemoAction {
2122

2223
class _MyAppState extends State<MyApp> {
2324
List<RouteItem> items;
24-
String _serverAddress = '';
25-
KeyValueStore keyValueStore = KeyValueStore();
25+
String _server = '';
26+
SharedPreferences _prefs;
27+
2628
bool _datachannel = false;
2729
@override
2830
initState() {
@@ -60,9 +62,9 @@ class _MyAppState extends State<MyApp> {
6062
}
6163

6264
_initData() async {
63-
await keyValueStore.init();
65+
_prefs = await SharedPreferences.getInstance();
6466
setState(() {
65-
_serverAddress = keyValueStore.getString('server') ?? 'demo.cloudwebrtc.com';
67+
_server = _prefs.getString('server') ?? 'demo.cloudwebrtc.com';
6668
});
6769
}
6870

@@ -74,13 +76,13 @@ class _MyAppState extends State<MyApp> {
7476
// The value passed to Navigator.pop() or null.
7577
if (value != null) {
7678
if (value == DialogDemoAction.connect) {
77-
keyValueStore.setString('server', _serverAddress);
79+
_prefs.setString('server', _server);
7880
Navigator.push(
7981
context,
8082
MaterialPageRoute(
8183
builder: (BuildContext context) => _datachannel
82-
? DataChannelSample(ip: _serverAddress)
83-
: CallSample(ip: _serverAddress)));
84+
? DataChannelSample(ip: _server)
85+
: CallSample(ip: _server)));
8486
}
8587
}
8688
});
@@ -94,11 +96,11 @@ class _MyAppState extends State<MyApp> {
9496
content: TextField(
9597
onChanged: (String text) {
9698
setState(() {
97-
_serverAddress = text;
99+
_server = text;
98100
});
99101
},
100102
decoration: InputDecoration(
101-
hintText: _serverAddress,
103+
hintText: _server,
102104
),
103105
textAlign: TextAlign.center,
104106
),

lib/src/call_sample/signaling.dart

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import 'dart:convert';
22
import 'dart:async';
3-
import 'dart:io';
43
import 'package:flutter_webrtc/webrtc.dart';
4+
55
import 'random_string.dart';
66

77
import '../utils/device_info.dart'
88
if (dart.library.js) '../utils/device_info_web.dart';
99
import '../utils/websocket.dart'
1010
if (dart.library.js) '../utils/websocket_web.dart';
11+
import '../utils/turn.dart'
12+
if (dart.library.js) '../utils/turn_web.dart';
1113

1214
enum SignalingState {
1315
CallStateNew,
@@ -37,7 +39,7 @@ class Signaling {
3739
SimpleWebSocket _socket;
3840
var _sessionId;
3941
var _host;
40-
var _port = 4443;
42+
var _port = 8086;
4143
var _peerConnections = new Map<String, RTCPeerConnection>();
4244
var _dataChannels = new Map<String, RTCDataChannel>();
4345
var _remoteCandidates = [];
@@ -104,17 +106,6 @@ class Signaling {
104106
if (_socket != null) _socket.close();
105107
}
106108

107-
getTurnCredential(String host) async {
108-
var httpClient = new HttpClient();
109-
var uri = new Uri.http('$host', '/api/turn',
110-
{'service': 'turn', 'username': 'flutter-webrtc'});
111-
var request = await httpClient.getUrl(uri);
112-
var response = await request.close();
113-
var responseBody = await response.transform(Utf8Decoder()).join();
114-
Map data = _decoder.convert(responseBody);
115-
return data;
116-
}
117-
118109
void switchCamera() {
119110
if (_localStream != null) {
120111
_localStream.getVideoTracks()[0].switchCamera();
@@ -273,14 +264,14 @@ class Signaling {
273264
}
274265

275266
void connect() async {
276-
var url = 'wss://$_host:$_port/ws';
267+
var url = 'https://$_host:$_port/ws';
277268
_socket = SimpleWebSocket(url);
278269

279270
print('connect to $url');
280271

281272
if (_turnCredential == null) {
282273
try {
283-
_turnCredential = await getTurnCredential(_host);
274+
_turnCredential = await getTurnCredential(_host, _port);
284275
/*{
285276
"username": "1584195784:mbzrxpgjys",
286277
"password": "isyl6FF6nqMTB9/ig5MrMRUXqZg",

lib/src/utils/key_value_store.dart

Lines changed: 0 additions & 16 deletions
This file was deleted.

lib/src/utils/key_value_store_web.dart

Lines changed: 0 additions & 28 deletions
This file was deleted.

lib/src/utils/turn.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import 'dart:convert';
2+
import 'dart:async';
3+
import 'dart:io';
4+
5+
Future<Map> getTurnCredential(String host, int port) async {
6+
HttpClient client = HttpClient(context: SecurityContext());
7+
client.badCertificateCallback =
8+
(X509Certificate cert, String host, int port) {
9+
print('getTurnCredential: Allow self-signed certificate => $host:$port. ');
10+
return true;
11+
};
12+
var url = 'https://$host:$port/api/turn?service=turn&username=flutter-webrtc';
13+
var request = await client.getUrl(Uri.parse(url));
14+
var response = await request.close();
15+
var responseBody = await response.transform(Utf8Decoder()).join();
16+
print('getTurnCredential:response => $responseBody.');
17+
Map data = JsonDecoder().convert(responseBody);
18+
return data;
19+
}

lib/src/utils/turn_web.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import 'dart:convert';
2+
import 'package:http/http.dart' as http;
3+
4+
Future<Map> getTurnCredential(String host, int port) async {
5+
var url = 'https://$host:$port/api/turn?service=turn&username=flutter-webrtc';
6+
final res = await http.get(url);
7+
if (res.statusCode == 200) {
8+
var data = json.decode(res.body);
9+
print('getTurnCredential:response => $data.');
10+
return data;
11+
}
12+
return {};
13+
}

lib/src/utils/websocket.dart

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ class SimpleWebSocket {
1717

1818
connect() async {
1919
try {
20-
_socket = await WebSocket.connect(_url);
21-
//socket = await _connectForSelfSignedCert(_host, _port);
20+
//_socket = await WebSocket.connect(_url);
21+
_socket = await _connectForSelfSignedCert(_url);
2222
this?.onOpen();
2323
_socket.listen((data) {
2424
this?.onMessage(data);
@@ -38,23 +38,22 @@ class SimpleWebSocket {
3838
}
3939

4040
close() {
41-
_socket.close();
41+
if (_socket != null)
42+
_socket.close();
4243
}
4344

44-
Future<WebSocket> _connectForSelfSignedCert(String host, int port) async {
45+
Future<WebSocket> _connectForSelfSignedCert(url) async {
4546
try {
4647
Random r = new Random();
4748
String key = base64.encode(List<int>.generate(8, (_) => r.nextInt(255)));
48-
SecurityContext securityContext = new SecurityContext();
49-
HttpClient client = HttpClient(context: securityContext);
49+
HttpClient client = HttpClient(context: SecurityContext());
5050
client.badCertificateCallback =
5151
(X509Certificate cert, String host, int port) {
52-
print('Allow self-signed certificate => $host:$port. ');
52+
print('SimpleWebSocket: Allow self-signed certificate => $host:$port. ');
5353
return true;
5454
};
5555

56-
HttpClientRequest request = await client.getUrl(
57-
Uri.parse('https://$host:$port/ws')); // form the correct url here
56+
HttpClientRequest request = await client.getUrl(Uri.parse(url)); // form the correct url here
5857
request.headers.add('Connection', 'Upgrade');
5958
request.headers.add('Upgrade', 'websocket');
6059
request.headers.add(

lib/src/utils/websocket_web.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ class SimpleWebSocket {
1111
OnMessageCallback onMessage;
1212
OnCloseCallback onClose;
1313

14-
SimpleWebSocket(this._url);
14+
SimpleWebSocket(this._url) {
15+
_url = _url.replaceAll('https:', 'wss:');
16+
}
1517

1618
connect() async {
1719
try {
@@ -28,7 +30,7 @@ class SimpleWebSocket {
2830
this?.onClose(e.code, e.reason);
2931
});
3032
} catch (e) {
31-
this?.onClose(e.code, e.reason);
33+
this?.onClose(500, e.toString());
3234
}
3335
}
3436

@@ -42,6 +44,6 @@ class SimpleWebSocket {
4244
}
4345

4446
close() {
45-
_socket.close();
47+
if (_socket != null) _socket.close();
4648
}
4749
}

pubspec.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ dependencies:
1919
# The following adds the Cupertino Icons font to your application.
2020
# Use with the CupertinoIcons class for iOS style icons.
2121
cupertino_icons: ^0.1.2
22-
flutter_webrtc: ^0.2.2
22+
flutter_webrtc: ^0.2.6
2323
shared_preferences:
2424
shared_preferences_macos:
25+
shared_preferences_web:
2526

2627
# Required for MediaRecorder example
2728
path_provider:

0 commit comments

Comments
 (0)