fix: Fix the call function in flutter and dart.
This commit is contained in:
parent
7efe123274
commit
1f519703a8
|
|
@ -11,7 +11,7 @@ abstract class WebRTCDelegate {
|
||||||
MediaDevices get mediaDevices;
|
MediaDevices get mediaDevices;
|
||||||
Future<RTCPeerConnection> createPeerConnection(
|
Future<RTCPeerConnection> createPeerConnection(
|
||||||
Map<String, dynamic> configuration,
|
Map<String, dynamic> configuration,
|
||||||
[Map<String, dynamic> constraints]);
|
[Map<String, dynamic> constraints = const {}]);
|
||||||
VideoRenderer createRenderer();
|
VideoRenderer createRenderer();
|
||||||
void playRingtone();
|
void playRingtone();
|
||||||
void stopRingtone();
|
void stopRingtone();
|
||||||
|
|
@ -40,6 +40,7 @@ class WrappedMediaStream {
|
||||||
bool videoMuted;
|
bool videoMuted;
|
||||||
final Client client;
|
final Client client;
|
||||||
VideoRenderer renderer;
|
VideoRenderer renderer;
|
||||||
|
final bool isWeb;
|
||||||
|
|
||||||
/// for debug
|
/// for debug
|
||||||
String get title => '$displayName:$purpose:a[$audioMuted]:v[$videoMuted]';
|
String get title => '$displayName:$purpose:a[$audioMuted]:v[$videoMuted]';
|
||||||
|
|
@ -55,7 +56,8 @@ class WrappedMediaStream {
|
||||||
required this.purpose,
|
required this.purpose,
|
||||||
required this.client,
|
required this.client,
|
||||||
required this.audioMuted,
|
required this.audioMuted,
|
||||||
required this.videoMuted});
|
required this.videoMuted,
|
||||||
|
required this.isWeb});
|
||||||
|
|
||||||
/// Initialize the video renderer
|
/// Initialize the video renderer
|
||||||
Future<void> initialize() async {
|
Future<void> initialize() async {
|
||||||
|
|
@ -70,6 +72,11 @@ class WrappedMediaStream {
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
renderer.srcObject = null;
|
renderer.srcObject = null;
|
||||||
if (isLocal() && stream != null) {
|
if (isLocal() && stream != null) {
|
||||||
|
if (isWeb) {
|
||||||
|
stream!.getTracks().forEach((element) {
|
||||||
|
element.stop();
|
||||||
|
});
|
||||||
|
}
|
||||||
await stream?.dispose();
|
await stream?.dispose();
|
||||||
stream = null;
|
stream = null;
|
||||||
}
|
}
|
||||||
|
|
@ -289,7 +296,7 @@ class CallSession {
|
||||||
bool makingOffer = false;
|
bool makingOffer = false;
|
||||||
bool ignoreOffer = false;
|
bool ignoreOffer = false;
|
||||||
String facingMode = 'user';
|
String facingMode = 'user';
|
||||||
late Client client;
|
Client get client => opts.room.client;
|
||||||
String? remotePartyId;
|
String? remotePartyId;
|
||||||
late User remoteUser;
|
late User remoteUser;
|
||||||
late CallParty hangupParty;
|
late CallParty hangupParty;
|
||||||
|
|
@ -298,25 +305,48 @@ class CallSession {
|
||||||
SDPStreamMetadata? remoteSDPStreamMetadata;
|
SDPStreamMetadata? remoteSDPStreamMetadata;
|
||||||
List<RTCRtpSender> usermediaSenders = [];
|
List<RTCRtpSender> usermediaSenders = [];
|
||||||
List<RTCRtpSender> screensharingSenders = [];
|
List<RTCRtpSender> screensharingSenders = [];
|
||||||
Map<String, WrappedMediaStream> streams = <String, WrappedMediaStream>{};
|
List<WrappedMediaStream> streams = <WrappedMediaStream>[];
|
||||||
List<WrappedMediaStream> get getLocalStreams =>
|
List<WrappedMediaStream> get getLocalStreams =>
|
||||||
streams.values.where((element) => element.isLocal()).toList();
|
streams.where((element) => element.isLocal()).toList();
|
||||||
List<WrappedMediaStream> get getRemoteStreams =>
|
List<WrappedMediaStream> get getRemoteStreams =>
|
||||||
streams.values.where((element) => !element.isLocal()).toList();
|
streams.where((element) => !element.isLocal()).toList();
|
||||||
WrappedMediaStream? get localUserMediaStream => getLocalStreams.firstWhere(
|
|
||||||
(element) => element.purpose == SDPStreamMetadataPurpose.Usermedia,
|
WrappedMediaStream? get localUserMediaStream {
|
||||||
orElse: () => Null as WrappedMediaStream);
|
final stream = getLocalStreams.where(
|
||||||
WrappedMediaStream? get localScreenSharingStream =>
|
(element) => element.purpose == SDPStreamMetadataPurpose.Usermedia);
|
||||||
getLocalStreams.firstWhere(
|
if (stream.isNotEmpty) {
|
||||||
(element) => element.purpose == SDPStreamMetadataPurpose.Screenshare,
|
return stream.first;
|
||||||
orElse: () => Null as WrappedMediaStream);
|
}
|
||||||
WrappedMediaStream? get remoteUserMediaStream => getRemoteStreams.firstWhere(
|
return null;
|
||||||
(element) => element.purpose == SDPStreamMetadataPurpose.Usermedia,
|
}
|
||||||
orElse: () => Null as WrappedMediaStream);
|
|
||||||
WrappedMediaStream? get remoteScreenSharingStream =>
|
WrappedMediaStream? get localScreenSharingStream {
|
||||||
getRemoteStreams.firstWhere(
|
final stream = getLocalStreams.where(
|
||||||
(element) => element.purpose == SDPStreamMetadataPurpose.Screenshare,
|
(element) => element.purpose == SDPStreamMetadataPurpose.Screenshare);
|
||||||
orElse: () => Null as WrappedMediaStream);
|
if (stream.isNotEmpty) {
|
||||||
|
return stream.first;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
WrappedMediaStream? get remoteUserMediaStream {
|
||||||
|
final stream = getRemoteStreams.where(
|
||||||
|
(element) => element.purpose == SDPStreamMetadataPurpose.Usermedia);
|
||||||
|
if (stream.isNotEmpty) {
|
||||||
|
return stream.first;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
WrappedMediaStream? get remoteScreenSharingStream {
|
||||||
|
final stream = getRemoteStreams.where(
|
||||||
|
(element) => element.purpose == SDPStreamMetadataPurpose.Screenshare);
|
||||||
|
if (stream.isNotEmpty) {
|
||||||
|
return stream.first;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
final _callStateController =
|
final _callStateController =
|
||||||
StreamController<CallState>.broadcast(sync: true);
|
StreamController<CallState>.broadcast(sync: true);
|
||||||
Stream<CallState> get onCallStateChanged => _callStateController.stream;
|
Stream<CallState> get onCallStateChanged => _callStateController.stream;
|
||||||
|
|
@ -520,6 +550,7 @@ class CallSession {
|
||||||
await track.stop();
|
await track.stop();
|
||||||
}
|
}
|
||||||
localScreenSharingStream!.stopped = true;
|
localScreenSharingStream!.stopped = true;
|
||||||
|
_removeStream(localScreenSharingStream!.stream!);
|
||||||
emit(CallEvent.kFeedsChanged, streams);
|
emit(CallEvent.kFeedsChanged, streams);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -527,11 +558,10 @@ class CallSession {
|
||||||
|
|
||||||
void _addLocalStream(MediaStream stream, String purpose,
|
void _addLocalStream(MediaStream stream, String purpose,
|
||||||
{bool addToPeerConnection = true}) async {
|
{bool addToPeerConnection = true}) async {
|
||||||
final WrappedMediaStream? existingStream = getLocalStreams.firstWhere(
|
final existingStream =
|
||||||
(element) => element.purpose == purpose,
|
getLocalStreams.where((element) => element.purpose == purpose);
|
||||||
orElse: () => Null as WrappedMediaStream);
|
if (existingStream.isNotEmpty) {
|
||||||
if (existingStream != null) {
|
existingStream.first.setNewStream(stream);
|
||||||
existingStream.setNewStream(stream);
|
|
||||||
} else {
|
} else {
|
||||||
final newStream = WrappedMediaStream(
|
final newStream = WrappedMediaStream(
|
||||||
renderer: voip.delegate.createRenderer(),
|
renderer: voip.delegate.createRenderer(),
|
||||||
|
|
@ -542,8 +572,10 @@ class CallSession {
|
||||||
client: client,
|
client: client,
|
||||||
audioMuted: stream.getAudioTracks().isEmpty,
|
audioMuted: stream.getAudioTracks().isEmpty,
|
||||||
videoMuted: stream.getVideoTracks().isEmpty,
|
videoMuted: stream.getVideoTracks().isEmpty,
|
||||||
|
isWeb: voip.delegate.isWeb,
|
||||||
);
|
);
|
||||||
streams[stream.id] = newStream;
|
await newStream.initialize();
|
||||||
|
streams.add(newStream);
|
||||||
emit(CallEvent.kFeedsChanged, streams);
|
emit(CallEvent.kFeedsChanged, streams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -564,7 +596,7 @@ class CallSession {
|
||||||
|
|
||||||
if (purpose == SDPStreamMetadataPurpose.Usermedia) {
|
if (purpose == SDPStreamMetadataPurpose.Usermedia) {
|
||||||
speakerOn = type == CallType.kVideo;
|
speakerOn = type == CallType.kVideo;
|
||||||
if (voip.delegate.isWeb && !voip.delegate.isBackgroud) {
|
if (!voip.delegate.isWeb && !voip.delegate.isBackgroud) {
|
||||||
final audioTrack = stream.getAudioTracks()[0];
|
final audioTrack = stream.getAudioTracks()[0];
|
||||||
audioTrack.enableSpeakerphone(speakerOn);
|
audioTrack.enableSpeakerphone(speakerOn);
|
||||||
}
|
}
|
||||||
|
|
@ -586,11 +618,10 @@ class CallSession {
|
||||||
|
|
||||||
// Try to find a feed with the same purpose as the new stream,
|
// Try to find a feed with the same purpose as the new stream,
|
||||||
// if we find it replace the old stream with the new one
|
// if we find it replace the old stream with the new one
|
||||||
final WrappedMediaStream? existingStream = getRemoteStreams.firstWhere(
|
final existingStream =
|
||||||
(element) => element.purpose == purpose,
|
getRemoteStreams.where((element) => element.purpose == purpose);
|
||||||
orElse: () => Null as WrappedMediaStream);
|
if (existingStream.isNotEmpty) {
|
||||||
if (existingStream != null) {
|
existingStream.first.setNewStream(stream);
|
||||||
existingStream.setNewStream(stream);
|
|
||||||
} else {
|
} else {
|
||||||
final newStream = WrappedMediaStream(
|
final newStream = WrappedMediaStream(
|
||||||
renderer: voip.delegate.createRenderer(),
|
renderer: voip.delegate.createRenderer(),
|
||||||
|
|
@ -601,8 +632,10 @@ class CallSession {
|
||||||
client: client,
|
client: client,
|
||||||
audioMuted: audioMuted,
|
audioMuted: audioMuted,
|
||||||
videoMuted: videoMuted,
|
videoMuted: videoMuted,
|
||||||
|
isWeb: voip.delegate.isWeb,
|
||||||
);
|
);
|
||||||
streams[stream.id] = newStream;
|
await newStream.initialize();
|
||||||
|
streams.add(newStream);
|
||||||
}
|
}
|
||||||
emit(CallEvent.kFeedsChanged, streams);
|
emit(CallEvent.kFeedsChanged, streams);
|
||||||
Logs().i('Pushed remote stream (id="${stream.id}", purpose=$purpose)');
|
Logs().i('Pushed remote stream (id="${stream.id}", purpose=$purpose)');
|
||||||
|
|
@ -756,7 +789,8 @@ class CallSession {
|
||||||
setCallState(CallState.kEnded);
|
setCallState(CallState.kEnded);
|
||||||
voip.currentCID = null;
|
voip.currentCID = null;
|
||||||
voip.calls.remove(callId);
|
voip.calls.remove(callId);
|
||||||
|
cleanUp();
|
||||||
|
voip.delegate.handleCallEnded(this);
|
||||||
if (shouldEmit) {
|
if (shouldEmit) {
|
||||||
emit(CallEvent.kHangup, this);
|
emit(CallEvent.kHangup, this);
|
||||||
}
|
}
|
||||||
|
|
@ -883,7 +917,7 @@ class CallSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanUp() async {
|
void cleanUp() async {
|
||||||
streams.forEach((id, stream) {
|
streams.forEach((stream) {
|
||||||
stream.dispose();
|
stream.dispose();
|
||||||
});
|
});
|
||||||
streams.clear();
|
streams.clear();
|
||||||
|
|
@ -992,25 +1026,30 @@ class CallSession {
|
||||||
|
|
||||||
void tryRemoveStopedStreams() {
|
void tryRemoveStopedStreams() {
|
||||||
final removedStreams = <String, WrappedMediaStream>{};
|
final removedStreams = <String, WrappedMediaStream>{};
|
||||||
streams.forEach((id, stream) {
|
streams.forEach((stream) {
|
||||||
if (stream.stopped) {
|
if (stream.stopped) {
|
||||||
removedStreams[id] = stream;
|
removedStreams[stream.stream!.id] = stream;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
streams.removeWhere((id, stream) => removedStreams.containsKey(id));
|
streams
|
||||||
|
.removeWhere((stream) => removedStreams.containsKey(stream.stream!.id));
|
||||||
removedStreams.forEach((id, element) {
|
removedStreams.forEach((id, element) {
|
||||||
_removeStream(id);
|
_removeStream(element.stream!);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _removeStream(String streamId) async {
|
Future<void> _removeStream(MediaStream stream) async {
|
||||||
Logs().v('Removing feed with stream id $streamId');
|
Logs().v('Removing feed with stream id ${stream.id}');
|
||||||
final removedStream = streams.remove(streamId);
|
|
||||||
if (removedStream == null) {
|
final it = streams.where((element) => element.stream!.id == stream.id);
|
||||||
Logs().v('Didn\'t find the feed with stream id $streamId to delete');
|
if (it.isEmpty) {
|
||||||
|
Logs().v('Didn\'t find the feed with stream id ${stream.id} to delete');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await removedStream.dispose();
|
final wpstream = it.first;
|
||||||
|
streams.removeWhere((element) => element.stream!.id == stream.id);
|
||||||
|
emit(CallEvent.kFeedsChanged, streams);
|
||||||
|
await wpstream.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> _getOfferAnswerConstraints({bool iceRestart = false}) {
|
Map<String, dynamic> _getOfferAnswerConstraints({bool iceRestart = false}) {
|
||||||
|
|
@ -1281,7 +1320,6 @@ class VoIP {
|
||||||
// hangup in any case, either if the other party hung up or we did on another device
|
// hangup in any case, either if the other party hung up or we did on another device
|
||||||
call.terminate(CallParty.kRemote,
|
call.terminate(CallParty.kRemote,
|
||||||
event.content['reason'] ?? CallErrorCode.UserHangup, true);
|
event.content['reason'] ?? CallErrorCode.UserHangup, true);
|
||||||
delegate.handleCallEnded(call);
|
|
||||||
} else {
|
} else {
|
||||||
Logs().v('[VOIP] onCallHangup: Session [$callId] not found!');
|
Logs().v('[VOIP] onCallHangup: Session [$callId] not found!');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue