Skip to content

Commit 081974f

Browse files
dmceachernmsftmgamis-msftJamesBurnside
committed
[Bug fix STABLE BLOCKING] Update device behavior on connecting and lobby screens (#3917)
* Fix microphone start issue * fix stream handling issues when joining a call * Change files * Duplicate change files for beta release --------- Co-authored-by: mgamis-msft <79475487+mgamis-msft@users.noreply.github.com> Co-authored-by: James Burnside <2684369+JamesBurnside@users.noreply.github.com>
1 parent be0af52 commit 081974f

4 files changed

Lines changed: 55 additions & 26 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "patch",
3+
"area": "fix",
4+
"workstream": "BugFix",
5+
"comment": "Fix issues with turning camera off and on when joining a call, as well fix microphone button to unmute and mute when joining",
6+
"packageName": "@azure/communication-react",
7+
"email": "94866715+dmceachernmsft@users.noreply.github.com",
8+
"dependentChangeType": "patch"
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "patch",
3+
"area": "fix",
4+
"workstream": "BugFix",
5+
"comment": "Fix issues with turning camera off and on when joining a call, as well fix microphone button to unmute and mute when joining",
6+
"packageName": "@azure/communication-react",
7+
"email": "94866715+dmceachernmsft@users.noreply.github.com",
8+
"dependentChangeType": "patch"
9+
}

packages/calling-component-bindings/src/handlers/createCommonHandlers.ts

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -173,37 +173,48 @@ export const createDefaultCommonCallingHandlers = memoizeOne(
173173
const onToggleCamera = async (options?: VideoStreamOptions): Promise<void> => {
174174
const previewOn = _isPreviewOn(callClient.getState().deviceManager);
175175

176-
if (previewOn && call && call.state === 'Connecting') {
177-
// This is to workaround: https://skype.visualstudio.com/SPOOL/_workitems/edit/3030558.
178-
// The root cause of the issue is caused by never transitioning the unparented view to the
179-
// call object when going from configuration page (disconnected call state) to connecting.
180-
//
181-
// Currently the only time the local video stream is moved from unparented view to the call
182-
// object is when we transition from connecting -> call state. If the camera was on,
183-
// inside the MediaGallery we trigger toggleCamera. This triggers onStartLocalVideo which
184-
// destroys the unparentedView and creates a new stream in the call - so all looks well.
185-
//
186-
// However, if someone turns off their camera during the lobbyOrConnecting screen, the
187-
// call.localVideoStreams will be empty (as the stream is currently stored in the unparented
188-
// views and was never transitioned to the call object) and thus we incorrectly try to create
189-
// a new video stream for the call object, instead of only stopping the unparented view.
190-
//
191-
// The correct fix for this is to ensure that callAgent.onStartCall is called with the
192-
// localvideostream as a videoOption. That will mean call.onLocalVideoStreamsUpdated will
193-
// be triggered when the call is in connecting state, which we can then transition the
194-
// local video stream to the stateful call client and get into a clean state.
195-
await onDisposeLocalStreamView();
196-
return;
197-
}
176+
// the disposal of the unparented views is to workaround: https://skype.visualstudio.com/SPOOL/_workitems/edit/3030558.
177+
// The root cause of the issue is caused by never transitioning the unparented view to the
178+
// call object when going from configuration page (disconnected call state) to connecting.
179+
//
180+
// Currently the only time the local video stream is moved from unparented view to the call
181+
// object is when we transition from connecting -> call state. If the camera was on,
182+
// inside the MediaGallery we trigger toggleCamera. This triggers onStartLocalVideo which
183+
// destroys the unparentedView and creates a new stream in the call - so all looks well.
184+
//
185+
// However, if someone turns off their camera during the lobbyOrConnecting screen, the
186+
// call.localVideoStreams will be empty (as the stream is currently stored in the unparented
187+
// views and was never transitioned to the call object) and thus we incorrectly try to create
188+
// a new video stream for the call object, instead of only stopping the unparented view.
189+
//
190+
// The correct fix for this is to ensure that callAgent.onStartCall is called with the
191+
// localvideostream as a videoOption. That will mean call.onLocalVideoStreamsUpdated will
192+
// be triggered when the call is in connecting state, which we can then transition the
193+
// local video stream to the stateful call client and get into a clean state.
198194

199195
if (call && (_isInCall(call.state) || _isInLobbyOrConnecting(call.state))) {
200196
const stream = call.localVideoStreams.find((stream) => stream.mediaStreamType === 'Video');
201-
if (stream) {
202-
await onStopLocalVideo(stream);
197+
const unparentedViews = callClient.getState().deviceManager.unparentedViews;
198+
if (stream || unparentedViews.length > 0) {
199+
unparentedViews &&
200+
(await unparentedViews.forEach(
201+
(view) => view.mediaStreamType === 'Video' && callClient.disposeView(undefined, undefined, view)
202+
));
203+
stream && (await onStopLocalVideo(stream));
203204
} else {
204205
await onStartLocalVideo();
205206
}
206207
} else {
208+
/**
209+
* This will create a unparented view to be used on the configuration page and the connecting screen
210+
*
211+
* If the device that the stream will come from is not on from permissions checks, then it will take time
212+
* to create the stream since device is off. If we are turn the camera on immedietly on the configuration page we see it is
213+
* fast but that is because the device is already primed to return a stream.
214+
*
215+
* On the connecting page the device has already turned off and the connecting window is so small we do not see the resulting
216+
* unparented view from the code below.
217+
*/
207218
const selectedCamera = callClient.getState().deviceManager.selectedCamera;
208219
if (selectedCamera) {
209220
if (previewOn) {
@@ -292,7 +303,7 @@ export const createDefaultCommonCallingHandlers = memoizeOne(
292303
};
293304

294305
const onToggleMicrophone = async (): Promise<void> => {
295-
if (!call || !_isInCall(call.state)) {
306+
if (!call || !(_isInCall(call.state) || _isInLobbyOrConnecting(call.state))) {
296307
throw new Error(`Please invoke onToggleMicrophone after call is started`);
297308
}
298309
return call.isMuted ? await call.unmute() : await call.mute();

packages/react-composites/src/composites/CallComposite/adapter/AzureCommunicationCallAdapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ export class AzureCommunicationCallAdapter<AgentType extends CallAgent | BetaTea
816816
public async unmute(): Promise<void> {
817817
return await this.asyncTeeErrorToEventEmitter(async () => {
818818
this.context.setIsLocalMicrophoneEnabled(true);
819-
if (_isInCall(this.call?.state) && this.call?.isMuted) {
819+
if ((_isInCall(this.call?.state) || _isInLobbyOrConnecting(this.call?.state)) && this.call?.isMuted) {
820820
await this.handlers.onToggleMicrophone();
821821
}
822822
});

0 commit comments

Comments
 (0)