@@ -26,6 +26,11 @@ enum CallState {
26
26
CallStateBye ,
27
27
}
28
28
29
+ enum VideoSource {
30
+ Camera ,
31
+ Screen ,
32
+ }
33
+
29
34
class Session {
30
35
Session ({required this .sid, required this .pid});
31
36
String pid;
@@ -49,6 +54,8 @@ class Signaling {
49
54
Map <String , Session > _sessions = {};
50
55
MediaStream ? _localStream;
51
56
List <MediaStream > _remoteStreams = < MediaStream > [];
57
+ List <RTCRtpSender > _senders = < RTCRtpSender > [];
58
+ VideoSource _videoSource = VideoSource .Camera ;
52
59
53
60
Function (SignalingState state)? onSignalingStateChange;
54
61
Function (Session session, CallState state)? onCallStateChange;
@@ -60,8 +67,7 @@ class Signaling {
60
67
onDataChannelMessage;
61
68
Function (Session session, RTCDataChannel dc)? onDataChannel;
62
69
63
- String get sdpSemantics =>
64
- WebRTC .platformIsWindows ? 'plan-b' : 'unified-plan' ;
70
+ String get sdpSemantics => 'unified-plan' ;
65
71
66
72
Map <String , dynamic > _iceServers = {
67
73
'iceServers' : [
@@ -99,7 +105,29 @@ class Signaling {
99
105
100
106
void switchCamera () {
101
107
if (_localStream != null ) {
102
- Helper .switchCamera (_localStream! .getVideoTracks ()[0 ]);
108
+ if (_videoSource != VideoSource .Camera ) {
109
+ _senders.forEach ((sender) {
110
+ if (sender.track! .kind == 'video' ) {
111
+ sender.replaceTrack (_localStream! .getVideoTracks ()[0 ]);
112
+ }
113
+ });
114
+ _videoSource = VideoSource .Camera ;
115
+ onLocalStream? .call (_localStream! );
116
+ } else {
117
+ Helper .switchCamera (_localStream! .getVideoTracks ()[0 ]);
118
+ }
119
+ }
120
+ }
121
+
122
+ void switchToScreenSharing (MediaStream stream) {
123
+ if (_localStream != null && _videoSource != VideoSource .Screen ) {
124
+ _senders.forEach ((sender) {
125
+ if (sender.track! .kind == 'video' ) {
126
+ sender.replaceTrack (stream.getVideoTracks ()[0 ]);
127
+ }
128
+ });
129
+ onLocalStream? .call (stream);
130
+ _videoSource = VideoSource .Screen ;
103
131
}
104
132
}
105
133
@@ -193,7 +221,6 @@ class Signaling {
193
221
newSession.remoteCandidates.clear ();
194
222
}
195
223
onCallStateChange? .call (newSession, CallState .CallStateNew );
196
-
197
224
onCallStateChange? .call (newSession, CallState .CallStateRinging );
198
225
}
199
226
break ;
@@ -381,8 +408,8 @@ class Signaling {
381
408
onAddRemoteStream? .call (newSession, event.streams[0 ]);
382
409
}
383
410
};
384
- _localStream! .getTracks ().forEach ((track) {
385
- pc.addTrack (track, _localStream! );
411
+ _localStream! .getTracks ().forEach ((track) async {
412
+ _senders. add ( await pc.addTrack (track, _localStream! ) );
386
413
});
387
414
break ;
388
415
}
@@ -492,7 +519,7 @@ class Signaling {
492
519
try {
493
520
RTCSessionDescription s =
494
521
await session.pc! .createOffer (media == 'data' ? _dcConstraints : {});
495
- await session.pc! .setLocalDescription (s );
522
+ await session.pc! .setLocalDescription (_fixSdp (s) );
496
523
_send ('offer' , {
497
524
'to' : session.pid,
498
525
'from' : _selfId,
@@ -505,11 +532,18 @@ class Signaling {
505
532
}
506
533
}
507
534
535
+ RTCSessionDescription _fixSdp (RTCSessionDescription s) {
536
+ var sdp = s.sdp;
537
+ s.sdp =
538
+ sdp! .replaceAll ('profile-level-id=640c1f' , 'profile-level-id=42e032' );
539
+ return s;
540
+ }
541
+
508
542
Future <void > _createAnswer (Session session, String media) async {
509
543
try {
510
544
RTCSessionDescription s =
511
545
await session.pc! .createAnswer (media == 'data' ? _dcConstraints : {});
512
- await session.pc! .setLocalDescription (s );
546
+ await session.pc! .setLocalDescription (_fixSdp (s) );
513
547
_send ('answer' , {
514
548
'to' : session.pid,
515
549
'from' : _selfId,
@@ -565,5 +599,7 @@ class Signaling {
565
599
566
600
await session.pc? .close ();
567
601
await session.dc? .close ();
602
+ _senders.clear ();
603
+ _videoSource = VideoSource .Camera ;
568
604
}
569
605
}
0 commit comments