Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
358586a
start captions error fix
carocao-msft May 4, 2023
019191b
Change files
carocao-msft May 4, 2023
25ace1e
Duplicate change files for beta release
carocao-msft May 4, 2023
9e10916
Update packages/react-composites CallWithChatComposite browser test s…
github-actions[bot] May 4, 2023
c18077f
Update packages/react-composites CallComposite browser test snapshots
github-actions[bot] May 4, 2023
65a4c08
Merge branch 'carocao/startcaptions' of https://github.com/Azure/comm…
github-actions[bot] May 4, 2023
04da4c7
start captions error fix
carocao-msft May 4, 2023
8590e48
tests
carocao-msft May 4, 2023
2dd6ada
Merge branch 'main' into carocao/startcaptions
carocao-msft May 4, 2023
798913b
Update packages/react-composites CallWithChatComposite browser test s…
github-actions[bot] May 4, 2023
536323c
fixlint
carocao-msft May 4, 2023
849a58f
fixlint
carocao-msft May 4, 2023
d9f1989
Update packages/react-composites CallComposite browser test snapshots
github-actions[bot] May 4, 2023
b05d284
Merge branch 'carocao/startcaptions' of https://github.com/Azure/comm…
github-actions[bot] May 4, 2023
c5bc23f
name change
carocao-msft May 5, 2023
7acb437
test
carocao-msft May 16, 2023
28ca71a
Merge branch 'main' into carocao/startcaptions
carocao-msft May 16, 2023
81bba30
Merge branch 'main' into carocao/startcaptions
carocao-msft May 17, 2023
f9c84db
Update packages/react-composites CallComposite browser test snapshots
github-actions[bot] May 17, 2023
d58df16
captions
carocao-msft May 23, 2023
b7ae704
Merge branch 'main' into carocao/startcaptions
carocao-msft May 23, 2023
65c370e
build fix
carocao-msft May 23, 2023
99accb3
Merge branch 'main' into carocao/startcaptions
dmceachernmsft May 25, 2023
363d460
Merge branch 'main' into carocao/startcaptions
carocao-msft May 25, 2023
5c40739
uprdate
carocao-msft May 25, 2023
0361065
Merge branch 'main' into carocao/startcaptions
carocao-msft May 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Fixed start captions console error and add loading screen ",
"packageName": "@azure/communication-react",
"email": "carolinecao@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Fixed start captions console error and add loading screen ",
"packageName": "@azure/communication-react",
"email": "carolinecao@microsoft.com",
"dependentChangeType": "patch"
}
9 changes: 9 additions & 0 deletions packages/calling-component-bindings/src/baseSelectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,15 @@ export const getCaptionsStatus = (state: CallClientState, props: CallingBaseSele
return state.calls[props.callId]?.captionsFeature.isCaptionsFeatureActive;
};

/* @conditional-compile-remove(close-captions) */
/** @private */
export const getStartCaptionsInProgress = (
state: CallClientState,
props: CallingBaseSelectorProps
): boolean | undefined => {
return state.calls[props.callId]?.captionsFeature.startCaptionsInProgress;
};

/* @conditional-compile-remove(close-captions) */
/** @private */
export const getCurrentCaptionLanguage = (
Expand Down
9 changes: 5 additions & 4 deletions packages/calling-component-bindings/src/captionsSelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/* @conditional-compile-remove(close-captions) */
import { CallClientState, CaptionsInfo } from '@internal/calling-stateful-client';
/* @conditional-compile-remove(close-captions) */
import { CallingBaseSelectorProps } from './baseSelectors';
import { CallingBaseSelectorProps, getStartCaptionsInProgress } from './baseSelectors';
/* @conditional-compile-remove(close-captions) */
import {
getCaptions,
Expand Down Expand Up @@ -99,8 +99,8 @@ export type _CaptionsBannerSelector = (
* @internal
*/
export const _captionsBannerSelector: _CaptionsBannerSelector = reselect.createSelector(
[getCaptions, getCaptionsStatus],
(captions, isCaptionsFeatureActive) => {
[getCaptions, getCaptionsStatus, getStartCaptionsInProgress],
(captions, isCaptionsFeatureActive, startCaptionsInProgress) => {
// Following Teams app logic, no matter how many 'Partial' captions come,
// we only pick first one according to start time, and all the other partial captions will be filtered out
// This will give customers a stable captions experience when others talking over the dominant speaker
Expand All @@ -122,7 +122,8 @@ export const _captionsBannerSelector: _CaptionsBannerSelector = reselect.createS
});
return {
captions: captionsInfo ?? [],
isCaptionsOn: isCaptionsFeatureActive ?? false
isCaptionsOn: isCaptionsFeatureActive ?? false,
startCaptionsInProgress: startCaptionsInProgress ?? false
};
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export interface CaptionsCallFeatureState {
currentCaptionLanguage: string;
currentSpokenLanguage: string;
isCaptionsFeatureActive: boolean;
startCaptionsInProgress: boolean;
supportedCaptionLanguages: string[];
supportedSpokenLanguages: string[];
}
Expand Down
4 changes: 4 additions & 0 deletions packages/calling-stateful-client/src/CallClientState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ export interface CaptionsCallFeatureState {
* whether captions is on/off
*/
isCaptionsFeatureActive: boolean;
/**
* whether start captions button is clicked or now
*/
startCaptionsInProgress: boolean;
/**
* supported caption languages
*/
Expand Down
10 changes: 10 additions & 0 deletions packages/calling-stateful-client/src/CallContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,16 @@ export class CallContext {
}
});
}

/* @conditional-compile-remove(close-captions) */
setStartCaptionsInProgress(callId: string, startCaptionsInProgress: boolean): void {
this.modifyState((draft: CallClientState) => {
const call = draft.calls[this._callIdHistory.latestCallId(callId)];
if (call) {
call.captionsFeature.startCaptionsInProgress = startCaptionsInProgress;
}
});
}
Comment thread
carocao-msft marked this conversation as resolved.
/* @conditional-compile-remove(close-captions) */
setSelectedSpokenLanguage(callId: string, spokenLanguage: string): void {
this.modifyState((draft: CallClientState) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,10 @@ class ProxyTeamsCaptionsFeature implements ProxyHandler<TeamsCaptionsCallFeature
case 'startCaptions':
return this._context.withAsyncErrorTeedToState(
async (...args: Parameters<TeamsCaptionsCallFeature['startCaptions']>) => {
this._context.setStartCaptionsInProgress(this._call.id, true);
const ret = await target.startCaptions(...args);
this._context.setIsCaptionActive(this._call.id, true);
this._context.setSelectedSpokenLanguage(this._call.id, args[0]?.spokenLanguage ?? 'en-us');

return ret;
},
'Call.feature'
Expand All @@ -122,6 +123,7 @@ class ProxyTeamsCaptionsFeature implements ProxyHandler<TeamsCaptionsCallFeature
async (...args: Parameters<TeamsCaptionsCallFeature['stopCaptions']>) => {
const ret = await target.stopCaptions(...args);
this._context.setIsCaptionActive(this._call.id, false);
this._context.setStartCaptionsInProgress(this._call.id, false);
Comment thread
carocao-msft marked this conversation as resolved.
return ret;
},
'Call.feature'
Expand Down
3 changes: 2 additions & 1 deletion packages/calling-stateful-client/src/Converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ export function convertSdkCallToDeclarativeCall(call: CallCommon): CallState {
supportedCaptionLanguages: [],
currentCaptionLanguage: '',
currentSpokenLanguage: '',
isCaptionsFeatureActive: false
isCaptionsFeatureActive: false,
startCaptionsInProgress: false
}
};
}
Expand Down
3 changes: 2 additions & 1 deletion packages/calling-stateful-client/src/StreamUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ function createMockCall(mockCallId: string): CallState {
supportedCaptionLanguages: [],
currentCaptionLanguage: '',
currentSpokenLanguage: '',
isCaptionsFeatureActive: false
isCaptionsFeatureActive: false,
startCaptionsInProgress: false
}
};
return call;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,7 @@ export interface CallCompositeStrings {
captionsAvailableLanguageStrings?: CaptionsAvailableLanguageStrings;
captionsBannerMoreButtonCallingLabel?: string;
captionsBannerMoreButtonTooltip?: string;
captionsBannerSpinnerText?: string;
captionsSettingsCancelButtonLabel?: string;
captionsSettingsCloseModalButtonAriaLabel?: string;
captionsSettingsConfirmButtonLabel?: string;
Expand Down Expand Up @@ -1304,6 +1305,7 @@ export interface CaptionsCallFeatureState {
currentCaptionLanguage: string;
currentSpokenLanguage: string;
isCaptionsFeatureActive: boolean;
startCaptionsInProgress: boolean;
supportedCaptionLanguages: string[];
supportedSpokenLanguages: string[];
}
Expand Down
10 changes: 10 additions & 0 deletions packages/react-components/review/beta/react-components.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,16 @@ export interface _CaptionsBannerProps {
// (undocumented)
isCaptionsOn?: boolean;
onRenderAvatar?: OnRenderAvatarCallback;
// (undocumented)
startCaptionsInProgress?: boolean;
// (undocumented)
strings?: _CaptionsBannerStrings;
}

// @internal
export interface _CaptionsBannerStrings {
// (undocumented)
captionsBannerSpinnerText?: string;
}

// @internal
Expand Down
46 changes: 32 additions & 14 deletions packages/react-components/src/components/CaptionsBanner.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { Stack, FocusZone } from '@fluentui/react';
import { Stack, FocusZone, Spinner } from '@fluentui/react';
import React, { useEffect, useRef, useState, useCallback } from 'react';
import { _FileUploadCardsStrings } from './FileUploadCards';
import { Ref } from '@internal/northstar-wrapper';
import { _Caption } from './Caption';
import {
captionContainerClassName,
captionsBannerClassName,
captionsContainerClassName
captionsContainerClassName,
loadingBannerClassName
} from './styles/Captions.style';
import { OnRenderAvatarCallback } from '../types';

Expand All @@ -23,27 +24,37 @@ export type _CaptionsInfo = {
userId?: string;
};

/**
* @internal
* strings for captions banneer
*/
export interface _CaptionsBannerStrings {
captionsBannerSpinnerText?: string;
}

/**
* @internal
* _CaptionsBanner Component Props.
*/
export interface _CaptionsBannerProps {
captions: _CaptionsInfo[];
isCaptionsOn?: boolean;
startCaptionsInProgress?: boolean;
/**
* Optional callback to override render of the avatar.
*
* @param userId - user Id
*/
onRenderAvatar?: OnRenderAvatarCallback;
strings?: _CaptionsBannerStrings;
}

/**
* @internal
* A component for displaying a CaptionsBanner with user icon, displayName and captions text.
*/
export const _CaptionsBanner = (props: _CaptionsBannerProps): JSX.Element => {
const { captions, isCaptionsOn, onRenderAvatar } = props;
const { captions, isCaptionsOn, startCaptionsInProgress, onRenderAvatar, strings } = props;
const captionsScrollDivRef = useRef<HTMLElement>(null);
const [isAtBottomOfScroll, setIsAtBottomOfScroll] = useState<boolean>(true);

Expand Down Expand Up @@ -82,19 +93,26 @@ export const _CaptionsBanner = (props: _CaptionsBannerProps): JSX.Element => {

return (
<>
{isCaptionsOn && (
{startCaptionsInProgress && (
<FocusZone as="ul" className={captionsContainerClassName}>
<Ref innerRef={captionsScrollDivRef}>
<Stack verticalAlign="start" className={captionsBannerClassName}>
{captions.map((caption) => {
return (
<div key={caption.id} className={captionContainerClassName} data-is-focusable={true}>
<_Caption {...caption} onRenderAvatar={onRenderAvatar} />
</div>
);
})}
{isCaptionsOn && (
<Ref innerRef={captionsScrollDivRef}>
<Stack verticalAlign="start" className={captionsBannerClassName}>
{captions.map((caption) => {
return (
<div key={caption.id} className={captionContainerClassName} data-is-focusable={true}>
<_Caption {...caption} onRenderAvatar={onRenderAvatar} />
</div>
);
})}
</Stack>
</Ref>
)}
{!isCaptionsOn && (
<Stack verticalAlign="center" className={loadingBannerClassName} data-is-focusable={true}>
<Spinner label={strings?.captionsBannerSpinnerText} ariaLive="assertive" labelPosition="right" />
</Stack>
</Ref>
)}
</FocusZone>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import React, { useCallback } from 'react';
import React, { useCallback, useEffect } from 'react';
import { useMemo, useState } from 'react';
import {
IModalStyles,
Expand Down Expand Up @@ -84,21 +84,30 @@ export const _CaptionsSettingsModal = (props: _CaptionsSettingsModalProps): JSX.
text: currentSpokenLanguage !== '' ? currentSpokenLanguage : defaultSpokenLanguage
});

const [hasSetSpokenLanguage, setHasSetSpokenLanguage] = useState(false);

const onDismiss = useCallback((): void => {
if (onDismissCaptionsSettings) {
onDismissCaptionsSettings();
}
}, [onDismissCaptionsSettings]);

useEffect(() => {
Comment thread
carocao-msft marked this conversation as resolved.
// set spoken language when start captions with a spoken language specified.
// this is to fix the bug when a second user starts captions with a new spoken language, captions bot ignore that spoken language
if (isCaptionsFeatureActive && !hasSetSpokenLanguage) {
onSetSpokenLanguage(selectedItem.key.toString());
// we only need to call set spoken language once when first starting captions
setHasSetSpokenLanguage(true);
}
}, [isCaptionsFeatureActive, onSetSpokenLanguage, selectedItem.key, hasSetSpokenLanguage]);

const onConfirm = useCallback(async (): Promise<void> => {
const languageCode = selectedItem.key.toString();
if (isCaptionsFeatureActive) {
onSetSpokenLanguage(languageCode);
} else {
await onStartCaptions({ spokenLanguage: languageCode });
// set spoken language when start captions with a spoken language specified.
// this is to fix the bug when a second user starts captions with a new spoken language, captions bot ignore that spoken language
onSetSpokenLanguage(languageCode);
}
onDismiss();
}, [onDismiss, isCaptionsFeatureActive, onSetSpokenLanguage, onStartCaptions, selectedItem.key]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT license.

import { ControlBarButton, ControlBarButtonProps } from './ControlBarButton';
import React, { useCallback, useMemo } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { _HighContrastAwareIcon } from './HighContrastAwareIcon';
import { defaultSpokenLanguage } from './utils';

Expand Down Expand Up @@ -93,16 +93,25 @@ export const _StartCaptionsButton = (props: _StartCaptionsButtonProps): JSX.Elem
return { spokenLanguage: currentSpokenLanguage === '' ? defaultSpokenLanguage : currentSpokenLanguage };
}, [currentSpokenLanguage]);

const [hasSetSpokenLanguage, setHasSetSpokenLanguage] = useState(false);

const onToggleStartCaptions = useCallback(async (): Promise<void> => {
if (props.checked) {
onStopCaptions();
} else {
await onStartCaptions(options);
}
Comment thread
carocao-msft marked this conversation as resolved.
}, [props.checked, onStartCaptions, onStopCaptions, options]);

useEffect(() => {
if (props.checked && !hasSetSpokenLanguage) {
// set spoken language when start captions with a spoken language specified.
// this is to fix the bug when a second user starts captions with a new spoken language, captions bot ignore that spoken language
onSetSpokenLanguage(options.spokenLanguage);
// we only need to call set spoken language once when first starting captions
setHasSetSpokenLanguage(true);
}
}, [props.checked, onStartCaptions, onStopCaptions, onSetSpokenLanguage, options]);
}, [props.checked, onSetSpokenLanguage, options.spokenLanguage, hasSetSpokenLanguage]);

return (
<ControlBarButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ export const captionsBannerClassName = mergeStyles({
...scrollbarStyles
});

/**
* @private
*/
export const loadingBannerClassName = mergeStyles({
height: _pxToRem(100)
});

/**
* @private
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ export interface CallCompositeStrings {
captionsAvailableLanguageStrings?: CaptionsAvailableLanguageStrings;
captionsBannerMoreButtonCallingLabel?: string;
captionsBannerMoreButtonTooltip?: string;
captionsBannerSpinnerText?: string;
captionsSettingsCancelButtonLabel?: string;
captionsSettingsCloseModalButtonAriaLabel?: string;
captionsSettingsConfirmButtonLabel?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,8 @@ const defaultCallAdapterState: CallAdapterState = {
supportedCaptionLanguages: [],
currentCaptionLanguage: '',
currentSpokenLanguage: '',
isCaptionsFeatureActive: false
isCaptionsFeatureActive: false,
startCaptionsInProgress: false
}
},
userId: { kind: 'communicationUser', communicationUserId: '1' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,4 +511,9 @@ export interface CallCompositeStrings {
* list of key value pairs that pairs language code to language names
*/
captionsAvailableLanguageStrings?: CaptionsAvailableLanguageStrings;
/* @conditional-compile-remove(close-captions) */
/**
* captions banner loading spinner label
*/
captionsBannerSpinnerText?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ function createMockCall(mockCallId: string): CallState {
supportedCaptionLanguages: [],
currentCaptionLanguage: '',
currentSpokenLanguage: '',
isCaptionsFeatureActive: false
isCaptionsFeatureActive: false,
startCaptionsInProgress: false
}
};
return call;
Expand Down
Loading