Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cnwankwo/together mode stream impl #5391

Draft
wants to merge 43 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
43a8827
Change files
cn0151 Oct 25, 2024
0280dd8
Included a common util method that set call features renderer info
cn0151 Oct 25, 2024
92f7122
Merge branch 'main' into cnwankwo/CallFeatureStream
cn0151 Oct 25, 2024
984e927
Merge branch 'main' into cnwankwo/CallFeatureStream
cn0151 Oct 29, 2024
37710d7
Merge branch 'main' into cnwankwo/CallFeatureStream
cn0151 Oct 31, 2024
4abe027
Addressed comments
cn0151 Oct 31, 2024
592cff1
Together Mode APIs
cn0151 Nov 1, 2024
aa77cda
Update @azure-communication-react-c495d5e5-3d35-4714-a329-a839d316e76…
cn0151 Nov 1, 2024
2a3a676
TogetherModeTypes interface update
cn0151 Nov 3, 2024
a647145
Merge branch 'cnwankwo/together_mode_api' of https://github.com/Azure…
cn0151 Nov 3, 2024
e3220c7
Together Mode Stream Implementation
cn0151 Nov 4, 2024
1fece80
Merge branch 'main' of https://github.com/Azure/communication-ui-libr…
cn0151 Nov 9, 2024
8f2a758
Base changes for together Mode stream and reactions
cn0151 Nov 11, 2024
8fd022a
Merge branch 'main' into cnwankwo/TogetherModeStream_Impl
cn0151 Nov 11, 2024
1abe026
API cleanup
cn0151 Nov 12, 2024
1478855
Merge branch 'cnwankwo/TogetherModeStream_Impl' of https://github.com…
cn0151 Nov 12, 2024
52843b5
Updated together mode reactions
cn0151 Nov 12, 2024
32769bc
Merge branch 'main' into cnwankwo/TogetherModeStream_Impl
cn0151 Nov 12, 2024
a4a2ddc
Merge branch 'main' into cnwankwo/TogetherModeStream_Impl
cn0151 Nov 13, 2024
99faf6b
Merge branch 'main' of https://github.com/Azure/communication-ui-libr…
cn0151 Nov 13, 2024
848574b
Merge branch 'main' into cnwankwo/TogetherModeStream_Impl
cn0151 Nov 16, 2024
514f5e0
make together mode button disabled for ACS user if its not started by…
cn0151 Nov 16, 2024
a9e71f3
Merge branch 'main' into cnwankwo/TogetherModeStream_Impl
cn0151 Nov 18, 2024
fb69100
Together mode with raiseHand, spotlight and mute particpant Implement…
cn0151 Nov 27, 2024
e44d697
Merge branch 'main' into cnwankwo/TogetherModeStream_Impl
cn0151 Nov 27, 2024
0abd7d3
clean up imports
cn0151 Dec 2, 2024
3f1c601
Updated API and cleaned up reactions overlay
cn0151 Dec 4, 2024
d4c3c07
Merge branch 'main' into cnwankwo/TogetherModeStream_Impl
cn0151 Dec 4, 2024
2f643e7
Implementation of together mode notification when started or ended
cn0151 Dec 6, 2024
6a3f326
Logic to switch back to default view if together mode is no longer ac…
cn0151 Dec 6, 2024
db77af3
Logic to switch back to default view if together mode is no longer ac…
cn0151 Dec 6, 2024
4dab149
Merge branch 'main' into cnwankwo/TogetherModeStream_Impl
cn0151 Dec 6, 2024
8c1cdc7
Merge branch 'cnwankwo/TogetherModeStream_Impl' of https://github.com…
cn0151 Dec 6, 2024
08cc53f
fixed merge conflicts
cn0151 Dec 6, 2024
03e5eac
Merge branch 'main' into cnwankwo/TogetherModeStream_Impl
cn0151 Dec 6, 2024
ccded9c
Updated API
cn0151 Dec 7, 2024
c10ef0b
Hover effect on together mode
cn0151 Dec 8, 2024
a3a8e28
reaction animation
cn0151 Dec 8, 2024
aaa380b
Display name auto expand
cn0151 Dec 9, 2024
d75e27b
Merge branch 'main' of https://github.com/Azure/communication-ui-libr…
cn0151 Dec 10, 2024
ea3bfd3
cn0151 Dec 18, 2024
c809c0f
12/19 - demo commit
cn0151 Dec 18, 2024
9cfea5c
Merge https://github.com/Azure/communication-ui-library into cnwankwo…
cn0151 Dec 18, 2024
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,8 @@
{
"type": "prerelease",
"area": "feature",
"workstream": "togetherMode",
"comment": "TogetherMode Stream view implementation",
"packageName": "@azure/communication-react",
"dependentChangeType": "patch"
}
12 changes: 11 additions & 1 deletion packages/calling-component-bindings/src/baseSelectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import { ConferencePhoneInfo } from '@internal/calling-stateful-client';
import { CallNotifications } from '@internal/calling-stateful-client';
/* @conditional-compile-remove(media-access) */
import { CapabilitiesChangeInfo } from '@azure/communication-calling';

/* @conditional-compile-remove(together-mode) */
import { TogetherModeCallFeatureState } from '@internal/calling-stateful-client';
/**
* Common props used to reference calling declarative client state.
*
Expand Down Expand Up @@ -306,3 +307,12 @@ export const getAssignedBreakoutRoom = (
): BreakoutRoom | undefined => {
return state.calls[props.callId]?.breakoutRooms?.assignedBreakoutRoom;
};

/* @conditional-compile-remove(together-mode) */
/**
* @private
*/
export const getTogetherModeCallFeature = (
state: CallClientState,
props: CallingBaseSelectorProps
): TogetherModeCallFeatureState | undefined => state.calls[props.callId]?.togetherMode;
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,6 @@ export const createDefaultCommonCallingHandlers = memoizeOne(
? { view: createViewResult?.view }
: undefined;
}

return togetherModeCreateViewResult;
};

Expand All @@ -831,6 +830,7 @@ export const createDefaultCommonCallingHandlers = memoizeOne(
}

const togetherModeStreams = callState.togetherMode.streams;

if (!togetherModeStreams.mainVideoStream) {
return;
}
Expand Down Expand Up @@ -938,9 +938,9 @@ export const createDefaultCommonCallingHandlers = memoizeOne(
/* @conditional-compile-remove(together-mode) */
onStartTogetherMode: notImplemented,
/* @conditional-compile-remove(together-mode) */
onDisposeTogetherModeStreamView,
/* @conditional-compile-remove(together-mode) */
onSetTogetherModeSceneSize,
/* @conditional-compile-remove(together-mode) */
onDisposeTogetherModeStreamView,
/* @conditional-compile-remove(media-access) */
onForbidAudio,
/* @conditional-compile-remove(media-access) */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,6 @@ export const notificationStackSelector: NotificationStackSelector = createSelect
autoDismiss: true
});
}

/* @conditional-compile-remove(together-mode) */
if (latestNotifications['togetherModeEnded']) {
activeNotifications.push({
Expand Down
43 changes: 39 additions & 4 deletions packages/calling-component-bindings/src/videoGallerySelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
import { toFlatCommunicationIdentifier } from '@internal/acs-ui-common';
import { CallClientState, RemoteParticipantState } from '@internal/calling-stateful-client';
import { VideoGalleryRemoteParticipant, VideoGalleryLocalParticipant } from '@internal/react-components';
/* @conditional-compile-remove(together-mode) */
import {
VideoGalleryTogetherModeStreams,
VideoGalleryTogetherModeParticipantPosition
} from '@internal/react-components';
import { createSelector } from 'reselect';
import {
CallingBaseSelectorProps,
Expand All @@ -16,6 +21,8 @@ import {
getRole,
getScreenShareRemoteParticipant
} from './baseSelectors';
/* @conditional-compile-remove(together-mode) */
import { getTogetherModeCallFeature } from './baseSelectors';
import { isHideAttendeeNamesEnabled } from './baseSelectors';
import { getOptimalVideoCount } from './baseSelectors';
import { _updateUserDisplayNames } from './utils/callUtils';
Expand Down Expand Up @@ -49,6 +56,14 @@ export type VideoGallerySelector = (
optimalVideoCount?: number;
spotlightedParticipants?: string[];
maxParticipantsToSpotlight?: number;
/* @conditional-compile-remove(together-mode) */
isTogetherModeActive?: boolean;
/* @conditional-compile-remove(together-mode) */
startTogetherModeEnabled?: boolean;
/* @conditional-compile-remove(together-mode) */
togetherModeStreams?: VideoGalleryTogetherModeStreams;
/* @conditional-compile-remove(together-mode) */
togetherModeSeatingCoordinates?: VideoGalleryTogetherModeParticipantPosition;
};

/**
Expand All @@ -71,7 +86,9 @@ export const videoGallerySelector: VideoGallerySelector = createSelector(
isHideAttendeeNamesEnabled,
getLocalParticipantReactionState,
getSpotlightCallFeature,
getCapabilities
getCapabilities,
/* @conditional-compile-remove(together-mode) */
getTogetherModeCallFeature
],
(
screenShareRemoteParticipantId,
Expand All @@ -88,7 +105,9 @@ export const videoGallerySelector: VideoGallerySelector = createSelector(
isHideAttendeeNamesEnabled,
localParticipantReaction,
spotlightCallFeature,
capabilities
capabilities,
/* @conditional-compile-remove(together-mode) */
togetherModeCallFeature
) => {
const screenShareRemoteParticipant =
screenShareRemoteParticipantId && remoteParticipants
Expand All @@ -102,7 +121,15 @@ export const videoGallerySelector: VideoGallerySelector = createSelector(
const noRemoteParticipants: RemoteParticipantState[] = [];
const localParticipantReactionState = memoizedConvertToVideoTileReaction(localParticipantReaction);
const spotlightedParticipantIds = memoizeSpotlightedParticipantIds(spotlightCallFeature?.spotlightedParticipants);

/* @conditional-compile-remove(together-mode) */
const togetherModeStreams = {
mainVideoStream: {
isReceiving: togetherModeCallFeature?.streams?.mainVideoStream?.isReceiving,
isAvailable: togetherModeCallFeature?.streams?.mainVideoStream?.isAvailable,
renderElement: togetherModeCallFeature?.streams?.mainVideoStream?.view?.target,
streamSize: togetherModeCallFeature?.streams?.mainVideoStream?.streamSize
}
};
return {
screenShareParticipant: screenShareRemoteParticipant
? convertRemoteParticipantToVideoGalleryRemoteParticipant(
Expand Down Expand Up @@ -145,7 +172,15 @@ export const videoGallerySelector: VideoGallerySelector = createSelector(
dominantSpeakers: dominantSpeakerIds,
maxRemoteVideoStreams: optimalVideoCount,
spotlightedParticipants: spotlightedParticipantIds,
maxParticipantsToSpotlight: spotlightCallFeature?.maxParticipantsToSpotlight
maxParticipantsToSpotlight: spotlightCallFeature?.maxParticipantsToSpotlight,
/* @conditional-compile-remove(together-mode) */
togetherModeStreams: togetherModeStreams,
/* @conditional-compile-remove(together-mode) */
togetherModeSeatingCoordinates: togetherModeCallFeature?.seatingPositions,
/* @conditional-compile-remove(together-mode) */
isTogetherModeActive: togetherModeCallFeature?.isActive,
/* @conditional-compile-remove(together-mode) */
startTogetherModeEnabled: capabilities?.startTogetherMode.isPresent
};
}
);
4 changes: 3 additions & 1 deletion packages/calling-stateful-client/src/CallContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,9 @@ export class CallContext {
for (const [userId, seatingPosition] of seatingMap.entries()) {
seatingPositions[userId] = seatingPosition;
}
call.togetherMode.seatingPositions = seatingPositions;
if (Object.keys(seatingPositions).length > 0) {
call.togetherMode.seatingPositions = seatingPositions;
}
}
});
}
Expand Down
1 change: 1 addition & 0 deletions packages/calling-stateful-client/src/index-public.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export type { CreateViewResult } from './StreamUtils';
export type { RaiseHandCallFeatureState as RaiseHandCallFeature } from './CallClientState';
/* @conditional-compile-remove(together-mode) */
export type {
TogetherModeCallFeatureState,
CallFeatureStreamState,
TogetherModeSeatingPositionState,
CallFeatureStreamName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,8 @@ export interface CallCompositeStrings {
tagsSurveyTextFieldDefaultText: string;
threeParticipantJoinedNoticeString: string;
threeParticipantLeftNoticeString: string;
togetherModeEnded?: string;
togetherModeStarted?: string;
transferPageNoticeString: string;
transferPageTransferorText: string;
transferPageTransferTargetText: string;
Expand Down Expand Up @@ -4927,7 +4929,7 @@ export type SpotlightChangedListener = (args: {

// @public
export interface SpotlightPromptStrings {
closeSpotlightPromptButtonLabel: string;
closeSpotlightPromptButtonLabel?: string;
startSpotlightCancelButtonLabel: string;
startSpotlightConfirmButtonLabel: string;
startSpotlightHeading: string;
Expand Down Expand Up @@ -5443,7 +5445,7 @@ export interface VideoBackgroundReplacementEffect extends BackgroundReplacementC
export const VideoGallery: (props: VideoGalleryProps) => JSX.Element;

// @public (undocumented)
export type VideoGalleryLayout = 'default' | 'floatingLocalVideo' | 'speaker' | /* @conditional-compile-remove(large-gallery) */ 'largeGallery' | 'focusedContent';
export type VideoGalleryLayout = 'default' | 'floatingLocalVideo' | 'speaker' | /* @conditional-compile-remove(large-gallery) */ 'largeGallery' | /* @conditional-compile-remove(together-mode) */ 'togetherMode' | 'focusedContent';

// @public
export interface VideoGalleryLocalParticipant extends VideoGalleryParticipant {
Expand All @@ -5468,6 +5470,8 @@ export type VideoGalleryParticipant = {
// @public
export interface VideoGalleryProps {
dominantSpeakers?: string[];
// (undocumented)
isTogetherModeActive?: boolean;
layout?: VideoGalleryLayout;
localParticipant: VideoGalleryLocalParticipant;
localVideoCameraCycleButtonProps?: LocalVideoCameraCycleButtonProps;
Expand All @@ -5477,19 +5481,26 @@ export interface VideoGalleryProps {
maxRemoteVideoStreams?: number;
onCreateLocalStreamView?: (options?: VideoStreamOptions) => Promise<void | CreateVideoStreamViewResult>;
onCreateRemoteStreamView?: (userId: string, options?: VideoStreamOptions) => Promise<void | CreateVideoStreamViewResult>;
// (undocumented)
onCreateTogetherModeStreamView?: (options?: VideoStreamOptions) => Promise<void | TogetherModeStreamViewResult>;
onDisposeLocalScreenShareStreamView?: () => Promise<void>;
onDisposeLocalStreamView?: () => void;
onDisposeRemoteScreenShareStreamView?: (userId: string) => Promise<void>;
// @deprecated (undocumented)
onDisposeRemoteStreamView?: (userId: string) => Promise<void>;
onDisposeRemoteVideoStreamView?: (userId: string) => Promise<void>;
// (undocumented)
onDisposeTogetherModeStreamView?: () => Promise<void>;
onMuteParticipant?: (userId: string) => Promise<void>;
onPinParticipant?: (userId: string) => void;
onRenderAvatar?: OnRenderAvatarCallback;
onRenderLocalVideoTile?: (localParticipant: VideoGalleryLocalParticipant) => JSX.Element;
onRenderRemoteVideoTile?: (remoteParticipant: VideoGalleryRemoteParticipant) => JSX.Element;
// (undocumented)
onSetTogetherModeSceneSize?: (width: number, height: number) => void;
onStartLocalSpotlight?: () => Promise<void>;
onStartRemoteSpotlight?: (userIds: string[]) => Promise<void>;
onStartTogetherMode?: () => Promise<void>;
onStopLocalSpotlight?: () => Promise<void>;
onStopRemoteSpotlight?: (userIds: string[]) => Promise<void>;
onUnpinParticipant?: (userId: string) => void;
Expand All @@ -5502,8 +5513,14 @@ export interface VideoGalleryProps {
showCameraSwitcherInLocalPreview?: boolean;
showMuteIndicator?: boolean;
spotlightedParticipants?: string[];
// (undocumented)
startTogetherModeEnabled?: boolean;
strings?: Partial<VideoGalleryStrings>;
styles?: VideoGalleryStyles;
// (undocumented)
togetherModeSeatingCoordinates?: VideoGalleryTogetherModeParticipantPosition;
// (undocumented)
togetherModeStreams?: VideoGalleryTogetherModeStreams;
videoTilesOptions?: VideoTilesOptions;
}

Expand All @@ -5527,6 +5544,10 @@ export type VideoGallerySelector = (state: CallClientState, props: CallingBaseSe
optimalVideoCount?: number;
spotlightedParticipants?: string[];
maxParticipantsToSpotlight?: number;
isTogetherModeActive?: boolean;
startTogetherModeEnabled?: boolean;
togetherModeStreams?: VideoGalleryTogetherModeStreams;
togetherModeSeatingCoordinates?: VideoGalleryTogetherModeParticipantPosition;
};

// @public
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4180,7 +4180,7 @@ export type SpotlightChangedListener = (args: {

// @public
export interface SpotlightPromptStrings {
closeSpotlightPromptButtonLabel: string;
closeSpotlightPromptButtonLabel?: string;
startSpotlightCancelButtonLabel: string;
startSpotlightConfirmButtonLabel: string;
startSpotlightHeading: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ import {
VideoGalleryLocalParticipant,
VideoGalleryRemoteParticipant
} from '../types';
/* @conditional-compile-remove(together-mode) */
import { VideoGalleryTogetherModeParticipantPosition } from '../types';
import React, { useLayoutEffect, useRef, useState } from 'react';
import { ParticipantVideoTileOverlay } from './VideoGallery/ParticipantVideoTileOverlay';
import { RemoteContentShareReactionOverlay } from './VideoGallery/RemoteContentShareReactionOverlay';
/* @conditional-compile-remove(together-mode) */
import { TogetherModeOverlay } from './TogetherModeOverlay';

/**
* Reaction overlay component props
Expand Down Expand Up @@ -40,6 +44,9 @@ export interface MeetingReactionOverlayProps {
* Remote participant's reaction event.
*/
remoteParticipants?: VideoGalleryRemoteParticipant[];

/* @conditional-compile-remove(together-mode) */
seatingCoordinates?: VideoGalleryTogetherModeParticipantPosition;
}

/**
Expand Down Expand Up @@ -68,7 +75,7 @@ const REACTION_EMOJI_RESIZE_SCALE_CONSTANT = 3;
* @internal
*/
export const MeetingReactionOverlay = (props: MeetingReactionOverlayProps): JSX.Element => {
const { overlayMode, reaction, reactionResources, localParticipant, remoteParticipants } = props;
const { overlayMode, reaction, reactionResources, localParticipant, remoteParticipants, seatingCoordinates } = props;
const [emojiSizePx, setEmojiSizePx] = useState(0);
const [divHeight, setDivHeight] = useState(0);
const [divWidth, setDivWidth] = useState(0);
Expand Down Expand Up @@ -125,6 +132,29 @@ export const MeetingReactionOverlay = (props: MeetingReactionOverlayProps): JSX.
/>
</div>
);
} else if (props.overlayMode === 'together-mode') {
/* @conditional-compile-remove(together-mode) */
return (
<div
ref={videoTileRef}
style={{
width: '100%',
height: '100%',
position: 'absolute',
top: '0',
left: '0'
}}
>
<TogetherModeOverlay
emojiSize={emojiSizePx}
reactionResources={reactionResources}
localParticipant={localParticipant ?? ({} as VideoGalleryLocalParticipant)}
remoteParticipants={remoteParticipants ?? ([] as VideoGalleryRemoteParticipant[])}
participantsSeatingArrangement={seatingCoordinates ?? {}}
/>
</div>
);
return <></>;
} else {
return <></>;
}
Expand Down
Loading
Loading