From 046e2caf7d1213cde2d8cfb5e9653a8b3e8aaf36 Mon Sep 17 00:00:00 2001 From: td Date: Tue, 25 Apr 2023 14:18:45 +0530 Subject: [PATCH] fix: allow passing a WrappedMediaStream to GroupCall.enter() to use as the local user media stream currently in the app we start the group call (but do not enter it), then we use the localStreams provided by it to show the setup page (enable/disable media devices). This causes some issues because the user hasn't joined the group call so the member state events don't update and the group call is killed if they just sit on the setup call page. Also creating a group call, sends notifications in our apps but no one has entered it. With this MR, apps can get their own user media, then edit that stream on setup page add it to GroupCall.enter(stream). This way, a group call doesn't have to be started and we get to do the setup page as well. --- lib/src/voip/group_call.dart | 66 +++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/lib/src/voip/group_call.dart b/lib/src/voip/group_call.dart index 1e61462f..3ca00b56 100644 --- a/lib/src/voip/group_call.dart +++ b/lib/src/voip/group_call.dart @@ -348,44 +348,55 @@ class GroupCall { /// Initializes the local user media stream. /// The media stream must be prepared before the group call enters. - Future initLocalStream() async { + /// if you allow the user to configure their camera and such ahead of time, + /// you can pass that `stream` on to this function. + /// This allows you to configure the camera before joining the call without + /// having to reopen the stream and possibly losing settings. + Future initLocalStream( + {WrappedMediaStream? stream}) async { if (state != GroupCallState.LocalCallFeedUninitialized) { throw Exception('Cannot initialize local call feed in the $state state.'); } setState(GroupCallState.InitializingLocalCallFeed); - MediaStream stream; + WrappedMediaStream localWrappedMediaStream; - try { - stream = await _getUserMedia( - type == GroupCallType.Video ? CallType.kVideo : CallType.kVoice); - } catch (error) { - setState(GroupCallState.LocalCallFeedUninitialized); - rethrow; + if (stream == null) { + MediaStream stream; + + try { + stream = await _getUserMedia( + type == GroupCallType.Video ? CallType.kVideo : CallType.kVoice); + } catch (error) { + setState(GroupCallState.LocalCallFeedUninitialized); + rethrow; + } + + final userId = client.userID; + localWrappedMediaStream = WrappedMediaStream( + renderer: voip.delegate.createRenderer(), + stream: stream, + userId: userId!, + room: room, + client: client, + purpose: SDPStreamMetadataPurpose.Usermedia, + audioMuted: stream.getAudioTracks().isEmpty, + videoMuted: stream.getVideoTracks().isEmpty, + isWeb: voip.delegate.isWeb, + isGroupCall: true, + ); + } else { + localWrappedMediaStream = stream; } - final userId = client.userID; - final newStream = WrappedMediaStream( - renderer: voip.delegate.createRenderer(), - stream: stream, - userId: userId!, - room: room, - client: client, - purpose: SDPStreamMetadataPurpose.Usermedia, - audioMuted: stream.getAudioTracks().isEmpty, - videoMuted: stream.getVideoTracks().isEmpty, - isWeb: voip.delegate.isWeb, - isGroupCall: true, - ); - - localUserMediaStream = newStream; + localUserMediaStream = localWrappedMediaStream; await localUserMediaStream!.initialize(); - await addUserMediaStream(newStream); + await addUserMediaStream(localWrappedMediaStream); setState(GroupCallState.LocalCallFeedInitialized); - return newStream; + return localWrappedMediaStream; } Future updateAudioDevice() async { @@ -406,16 +417,15 @@ class GroupCall { } /// enter the group call. - Future enter() async { + Future enter({WrappedMediaStream? stream}) async { if (!(state == GroupCallState.LocalCallFeedUninitialized || state == GroupCallState.LocalCallFeedInitialized)) { throw Exception('Cannot enter call in the $state state'); } if (state == GroupCallState.LocalCallFeedUninitialized) { - await initLocalStream(); + await initLocalStream(stream: stream); } - await _addParticipant( (await room.requestUser(client.userID!, ignoreErrors: true))!);