Gabriel Capella 2 年 前
コミット
e0e7793364
5 ファイル変更184 行追加51 行削除
  1. 44 7
      lib/grid.dart
  2. 78 42
      lib/src/connection/ws.dart
  3. 56 0
      lib/src/square/rtc.dart
  4. 3 1
      lib/src/square/square.dart
  5. 3 1
      lib/src/widget/square.dart

+ 44 - 7
lib/grid.dart

@@ -21,7 +21,7 @@ class _TransformationsDemoState extends State<TransformationsDemo>
   final GlobalKey _targetKey = GlobalKey();
   final Map<Point<int>, Widget> elements = <Point<int>, Widget>{};
   Set<Color> swatches = Colors.primaries.map((e) => Color(e.value)).toSet();
-  final double minScale = 2;
+  final double minScale = 1;
   final ColorRef cc = ColorRef(Colors.blueGrey);
 
   final TransformationController _transformationController =
@@ -35,7 +35,7 @@ class _TransformationsDemoState extends State<TransformationsDemo>
   @override
   void initState() {
     super.initState();
-    WebRTCChannels().connect((x) {});
+    // WebRTCChannels().connect((x) {});
   }
 
   @override
@@ -79,8 +79,11 @@ class _TransformationsDemoState extends State<TransformationsDemo>
                     child: SizedBox(
                       width: 256 * 90,
                       height: 256 * 53,
-                      child: GridPaper(
-                        child: Stack(children: elements.values.toList()),
+                      child: Stack(
+                        children: [
+                          getGrid(),
+                          ...elements.values.toList(),
+                        ],
                       ),
                     ),
                   ),
@@ -111,6 +114,40 @@ class _TransformationsDemoState extends State<TransformationsDemo>
     );
   }
 
+  Widget getGrid() {
+    Widget grid = Container();
+    double scale = _transformationController.value.clone().getMaxScaleOnAxis();
+    if (scale > 10) {
+      double opacity = 1.0;
+      if (scale <= 15) {
+        opacity = 1 - (15 - scale) / 5;
+      }
+      const oneGrid = GridPaper(
+          color: Colors.black12,
+          interval: 256,
+          divisions: 16,
+          subdivisions: 16,
+          child: SizedBox(
+            width: 256,
+            height: 256,
+          ));
+      grid = Opacity(
+          opacity: opacity,
+          child: Stack(
+              children: elements.keys
+                  .toList()
+                  .map((point) => Container(
+                        margin: EdgeInsets.only(
+                          left: 256.0 * point.x,
+                          top: 256.0 * point.y,
+                        ),
+                        child: oneGrid,
+                      ))
+                  .toList()));
+    }
+    return grid;
+  }
+
   @override
   void dispose() {
     // _controllerReset.dispose();
@@ -157,9 +194,9 @@ class _TransformationsDemoState extends State<TransformationsDemo>
           key: Key(point.toString()),
           margin: EdgeInsets.only(left: 256.0 * point.x, top: 256.0 * point.y),
           child: Stack(children: [
-            CustomPaint(
-              painter: OpenPainter(point),
-            ),
+            // CustomPaint(
+            //   painter: OpenPainter(point),
+            // ),
             Text(point.toString()),
             SquareComponent(color: cc, tile: point, key: Key(point.toString())),
           ])

+ 78 - 42
lib/src/connection/ws.dart

@@ -1,19 +1,26 @@
-
 import 'dart:async';
 import 'dart:convert';
+import 'dart:math';
 
 import 'package:the_paint/src/generated/client.pbgrpc.dart';
 import 'package:flutter_webrtc/flutter_webrtc.dart';
 import 'package:web_socket_channel/web_socket_channel.dart';
 
+class WebRTCChannels extends Resolver {
+  WebRTCChannels._internal();
+
+  static final WebRTCChannels _singleton = WebRTCChannels._internal();
+  static final Map<String, Duplex<RTCDataChannelMessage>> mapf = {};
+
+  // RTCPeerConnection? _pc;
+  static bool connected = false;
 
-class WebRTCChannels {
-  bool _inCalling = false;
-  RTCPeerConnection? _pc;
-  RTCDataChannel? _dc;
-  PaintClient? _grpcClient;
+  Stream<RTCData>? _rtcData;
 
-  WebRTCChannels();
+  factory WebRTCChannels() {
+    // _singleton.connect(() {});
+    return _singleton;
+  }
 
   final Map<String, dynamic> _iceServers = {
     'iceServers': [
@@ -42,50 +49,58 @@ class WebRTCChannels {
     Uri.parse('ws://localhost:8081/ws'),
   );
 
-  Future<void> connect(Function callback) async {
+  Future<void> connect() async {
+    if (connected) {
+      return;
+    }
+    connected = true;
     print("Connecting WEBSOCKET...");
 
-    _pc = await createPeerConnection(
+    _rtcData = _channel.stream
+        .map((event) => RTCData.fromBuffer(event))
+        .asBroadcastStream();
+
+    // await waitForData();
+  }
+
+  Future<RTCData> waitForData(String event /*add client id*/) async {
+    await connect();
+    return await _rtcData!.firstWhere((msg) => msg.event == event);
+  }
+
+  Future<Duplex<RTCDataChannelMessage>> createAndSubscribePeer(
+      RTCSessionDescription session) async {
+    Duplex<RTCDataChannelMessage> dup = Duplex();
+    var key = session.type!;
+    if (mapf.containsKey(key)) {
+      return mapf[key]!;
+    }
+    mapf[key] = dup;
+
+    var pc = await createPeerConnection(
       _iceServers,
     );
 
-    _pc!.onIceCandidate = (candidate) async {
-      print('pc2: onIceCandidate: ${candidate.candidate}');
-      await sendCandidate(candidate);
-    };
+    await pc.setRemoteDescription(session);
+    var answer = await pc.createAnswer();
+    await pc.setLocalDescription(answer);
+    await sendLocalDescription(pc);
 
-    _pc!.onDataChannel = (channel) {
-      RTCDataChannel dc = channel;
-      print('\nnew channel');
-      dc.onDataChannelState = (state) {
+    pc.onDataChannel = (channel) {
+      print('\nnew channel ${channel.id} ${channel.label}');
+      channel.onDataChannelState = (state) {
         print('\ndc2: change state: ${state.toString()}');
       };
-      dc.onMessage = (data) {
-        callback(MonitorReply.fromBuffer(data.binary));
-        // dc.send(
-        // RTCDataChannelMessage('(dc2 ==> dc1) Hello from dc2 echo !!!'));
+      channel.onMessage = (data) {
+        dup.streamToUI.add(data);
       };
+      // add future to send message to channel!!!!
     };
-
-    final rtcData = _channel.stream.map((event) => RTCData.fromBuffer(event));
-    await for (var msg in rtcData) {
-      print(msg.event);
-      switch (msg.event) {
-        case "offer":
-          await _pc!
-              .setRemoteDescription(RTCSessionDescription(msg.data, msg.event));
-          var answer = await _pc!.createAnswer();
-          await _pc!.setLocalDescription(answer);
-          await sendLocalDescription();
-          break;
-        default:
-          print("invalid event");
-      }
-    }
+    return dup;
   }
 
-  sendLocalDescription() async {
-    RTCSessionDescription? answer = await _pc!.getLocalDescription();
+  sendLocalDescription(RTCPeerConnection pc) async {
+    RTCSessionDescription? answer = await pc.getLocalDescription();
     if (answer == null) {
       return;
     }
@@ -94,10 +109,31 @@ class WebRTCChannels {
     _channel.sink.add(encodedData);
   }
 
-  sendCandidate(RTCIceCandidate candidate) async {
+  @override
+  Future<Duplex<RTCDataChannelMessage>> dataChannel(Point<int> point) async {
     final encodedData =
-        RTCData(data: jsonEncode(candidate.toMap()), event: "candidate")
-            .writeToBuffer();
+        RTCData(data: point.toString(), event: "req_p").writeToBuffer();
     _channel.sink.add(encodedData);
+    var msg = await waitForData("offer");
+    var session = RTCSessionDescription(msg.data, msg.event);
+    return await createAndSubscribePeer(session);
+  }
+}
+
+class Duplex<T> {
+  StreamController<T> streamToUI = StreamController.broadcast();
+  StreamController<T> streamFromUI = StreamController.broadcast();
+
+  void send(T serialize) {
+    streamFromUI.add(serialize);
+  }
+
+  Stream<T> getStream() {
+    return streamToUI.stream;
   }
 }
+
+/* Return to who we need to connect*/
+abstract class Resolver {
+  Future<Duplex<RTCDataChannelMessage>> dataChannel(Point<int> point);
+}

+ 56 - 0
lib/src/square/rtc.dart

@@ -0,0 +1,56 @@
+import 'dart:async';
+import 'dart:math';
+import 'dart:ui';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_webrtc/flutter_webrtc.dart';
+import 'package:the_paint/src/generated/client.pb.dart';
+import 'package:the_paint/src/square/square.dart';
+
+import '../connection/ws.dart';
+
+class WebRTCSquareData extends SquereData {
+  final Resolver resolver = WebRTCChannels();
+  final StreamController<MonitorReply> streamChannel =
+      StreamController<MonitorReply>();
+      
+  Duplex? _dc;
+
+  WebRTCSquareData(super.tile);
+
+  @override
+  Stream<MonitorReply> getSteam() {
+    resolver.dataChannel(super.tile).then((dc) {
+      _dc = dc;
+      streamChannel.addStream(dc.getStream().map((event) {
+        var point = Point(1, 1);
+        var color = Colors.blueGrey;
+        return MonitorReply(points: [
+          MonitorPoint(
+              point: BPoint(x: point.x, y: point.y), color: fromColor(color))
+        ]);
+      }));
+    });
+    return streamChannel.stream;
+  }
+
+  @override
+  void paint(Point<int> point, Color color) {
+    if (_dc == null ) {
+      return;
+    }
+    _dc!.send(serialize(point, color));
+  }
+
+  RTCDataChannelMessage serialize(Point<int> point, Color color) {
+    final data = MonitorPoint(
+      point: BPoint(x: point.x, y: point.y),
+      color: fromColor(color),
+    ).writeToBuffer();
+    return RTCDataChannelMessage.fromBinary(data);
+  }
+
+  BColor fromColor(Color c) {
+    return BColor(rgba: c.red | c.green << 8 | c.blue << 16 | c.alpha << 24);
+  }
+}

+ 3 - 1
lib/src/square/square.dart

@@ -7,7 +7,9 @@ import '../generated/client.pb.dart';
  * Simple interfaxe to interact with the UI
  */
 abstract class SquereData {
-  SquereData(Point<int> tile);
+  Point<int> tile;
+
+  SquereData(Point<int> this.tile);
   Stream<MonitorReply> getSteam();
   void paint(Point<int> point, Color color);
 }

+ 3 - 1
lib/src/widget/square.dart

@@ -8,6 +8,7 @@ import 'package:the_paint/src/generated/client.pbgrpc.dart';
 import 'dart:ui' as ui;
 import '../color_ref.dart';
 import '../square/in_memory.dart';
+import '../square/rtc.dart';
 import '../square/square.dart';
 
 class SquareComponent extends StatefulWidget {
@@ -20,7 +21,8 @@ class SquareComponent extends StatefulWidget {
 }
 
 class SquareComponentState extends State<SquareComponent> {
-  late final SquereData __serverSquareData = InMemorySquereData(widget.tile);
+  late final SquereData __serverSquareData = WebRTCSquareData(widget.tile);
+  // late final SquereData __serverSquareData = InMemorySquereData(widget.tile);
   final Uint8List data = Uint8List(256 * 256 * 4);
 
   Future<ui.Image> _loadImage() async {