Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Introduce new handler for disposing screen share for remote particapants, stops flash when navigating overflow galleries",
"packageName": "@azure/communication-react",
"email": "94866715+dmceachernmsft@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "add new handler to dispose screenshare",
"packageName": "@azure/communication-react",
"email": "94866715+dmceachernmsft@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Introduce new handler for disposing screen share for remote particapants, stops flash when navigating overflow galleries",
"packageName": "@azure/communication-react",
"email": "94866715+dmceachernmsft@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "add new handler to dispose screenshare",
"packageName": "@azure/communication-react",
"email": "94866715+dmceachernmsft@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ export interface CommonCallingHandlers {
// (undocumented)
onDisposeLocalStreamView: () => Promise<void>;
// (undocumented)
onDisposeRemoteScreenShareStreamView: (userId: string) => Promise<void>;
// (undocumented)
onDisposeRemoteStreamView: (userId: string) => Promise<void>;
// (undocumented)
onHangUp: (forEveryone?: boolean) => Promise<void>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ export interface CommonCallingHandlers {
// (undocumented)
onDisposeLocalStreamView: () => Promise<void>;
// (undocumented)
onDisposeRemoteScreenShareStreamView: (userId: string) => Promise<void>;
// (undocumented)
onDisposeRemoteStreamView: (userId: string) => Promise<void>;
// (undocumented)
onHangUp: (forEveryone?: boolean) => Promise<void>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export interface CommonCallingHandlers {
) => Promise<void | CreateVideoStreamViewResult>;
onDisposeRemoteStreamView: (userId: string) => Promise<void>;
onDisposeLocalStreamView: () => Promise<void>;
onDisposeRemoteScreenShareStreamView: (userId: string) => Promise<void>;
/* @conditional-compile-remove(dialpad) */ /* @conditional-compile-remove(PSTN-calls) */
onSendDtmfTone: (dtmfTone: DtmfTone) => Promise<void>;
onRemoveParticipant(userId: string): Promise<void>;
Expand Down Expand Up @@ -354,13 +355,30 @@ export const createDefaultCommonCallingHandlers = memoizeOne(
}

const remoteVideoStream = Object.values(participant.videoStreams).find((i) => i.mediaStreamType === 'Video');
const screenShareStream = Object.values(participant.videoStreams).find(
(i) => i.mediaStreamType === 'ScreenSharing'
);

if (remoteVideoStream && remoteVideoStream.view) {
callClient.disposeView(call.id, participant.identifier, remoteVideoStream);
}
};

const onDisposeRemoteScreenShareStreamView = async (userId: string): Promise<void> => {
if (!call) {
return;
}
const callState = callClient.getState().calls[call.id];
if (!callState) {
throw new Error(`Call Not Found: ${call.id}`);
}
const participant = Object.values(callState.remoteParticipants).find(
(participant) => toFlatCommunicationIdentifier(participant.identifier) === userId
);

if (!participant || !participant.videoStreams) {
return;
}
const screenShareStream = Object.values(participant.videoStreams).find(
(i) => i.mediaStreamType === 'ScreenSharing'
);

if (screenShareStream && screenShareStream.view) {
callClient.disposeView(call.id, participant.identifier, screenShareStream);
Expand Down Expand Up @@ -462,6 +480,7 @@ export const createDefaultCommonCallingHandlers = memoizeOne(
onStartLocalVideo,
onDisposeRemoteStreamView,
onDisposeLocalStreamView,
onDisposeRemoteScreenShareStreamView,
/* @conditional-compile-remove(PSTN-calls) */
onAddParticipant: notImplemented,
onRemoveParticipant: notImplemented,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ export interface CallAdapterCallManagement extends CallAdapterCallOperations {
// @public
export interface CallAdapterCallOperations {
createStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void | CreateVideoStreamViewResult>;
disposeScreenShareStreamView(remoteUserId: string): Promise<void>;
disposeStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void>;
leaveCall(forEveryone?: boolean): Promise<void>;
mute(): Promise<void>;
Expand Down Expand Up @@ -562,6 +563,7 @@ export interface CallWithChatAdapterManagement {
askDevicePermission(constrain: PermissionConstraints): Promise<void>;
createStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void | CreateVideoStreamViewResult>;
deleteMessage(messageId: string): Promise<void>;
disposeScreenShareStreamView(remoteUserId: string): Promise<void>;
disposeStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void>;
fetchInitialData(): Promise<void>;
joinCall(microphoneOn?: boolean): Call | undefined;
Expand Down Expand Up @@ -1114,6 +1116,8 @@ export interface CommonCallingHandlers {
// (undocumented)
onDisposeLocalStreamView: () => Promise<void>;
// (undocumented)
onDisposeRemoteScreenShareStreamView: (userId: string) => Promise<void>;
// (undocumented)
onDisposeRemoteStreamView: (userId: string) => Promise<void>;
// (undocumented)
onHangUp: (forEveryone?: boolean) => Promise<void>;
Expand Down Expand Up @@ -2557,6 +2561,7 @@ export interface VideoGalleryProps {
onCreateLocalStreamView?: (options?: VideoStreamOptions) => Promise<void | CreateVideoStreamViewResult>;
onCreateRemoteStreamView?: (userId: string, options?: VideoStreamOptions) => Promise<void | CreateVideoStreamViewResult>;
onDisposeLocalStreamView?: () => void;
onDisposeRemoteScreenShareStreamView?: (userId: string) => Promise<void>;
onDisposeRemoteStreamView?: (userId: string) => Promise<void>;
onRenderAvatar?: OnRenderAvatarCallback;
onRenderLocalVideoTile?: (localParticipant: VideoGalleryLocalParticipant) => JSX.Element;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2115,6 +2115,7 @@ export interface VideoGalleryProps {
onCreateLocalStreamView?: (options?: VideoStreamOptions) => Promise<void | CreateVideoStreamViewResult>;
onCreateRemoteStreamView?: (userId: string, options?: VideoStreamOptions) => Promise<void | CreateVideoStreamViewResult>;
onDisposeLocalStreamView?: () => void;
onDisposeRemoteScreenShareStreamView?: (userId: string) => Promise<void>;
onDisposeRemoteStreamView?: (userId: string) => Promise<void>;
onPinParticipant?: (userId: string) => void;
onRenderAvatar?: OnRenderAvatarCallback;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1553,6 +1553,7 @@ export interface VideoGalleryProps {
onCreateLocalStreamView?: (options?: VideoStreamOptions) => Promise<void | CreateVideoStreamViewResult>;
onCreateRemoteStreamView?: (userId: string, options?: VideoStreamOptions) => Promise<void | CreateVideoStreamViewResult>;
onDisposeLocalStreamView?: () => void;
onDisposeRemoteScreenShareStreamView?: (userId: string) => Promise<void>;
onDisposeRemoteStreamView?: (userId: string) => Promise<void>;
onRenderAvatar?: OnRenderAvatarCallback;
onRenderLocalVideoTile?: (localParticipant: VideoGalleryLocalParticipant) => JSX.Element;
Expand Down
5 changes: 4 additions & 1 deletion packages/react-components/src/components/VideoGallery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ export interface VideoGalleryProps {
onRenderRemoteVideoTile?: (remoteParticipant: VideoGalleryRemoteParticipant) => JSX.Element;
/** Callback to dispose a remote video stream view */
onDisposeRemoteStreamView?: (userId: string) => Promise<void>;
/** Callback to dispose a remote screen share stream view */
onDisposeRemoteScreenShareStreamView?: (userId: string) => Promise<void>;
/** Callback to render a particpant avatar */
onRenderAvatar?: OnRenderAvatarCallback;
/**
Expand Down Expand Up @@ -311,6 +313,7 @@ export const VideoGallery = (props: VideoGalleryProps): JSX.Element => {
onDisposeLocalStreamView,
onCreateRemoteStreamView,
onDisposeRemoteStreamView,
onDisposeRemoteScreenShareStreamView,
styles,
layout,
onRenderAvatar,
Expand Down Expand Up @@ -552,7 +555,7 @@ export const VideoGallery = (props: VideoGalleryProps): JSX.Element => {
{...screenShareParticipant}
renderElement={screenShareParticipant.screenShareStream?.renderElement}
onCreateRemoteStreamView={onCreateRemoteStreamView}
onDisposeRemoteStreamView={onDisposeRemoteStreamView}
onDisposeRemoteStreamView={onDisposeRemoteScreenShareStreamView}
isReceiving={screenShareParticipant.screenShareStream?.isReceiving}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ export interface CallAdapterCallOperations {
addParticipant(participant: CommunicationUserIdentifier): Promise<void>;
allowUnsupportedBrowserVersion(): void;
createStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void | CreateVideoStreamViewResult>;
disposeScreenShareStreamView(remoteUserId: string): Promise<void>;
disposeStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void>;
// @beta
holdCall(): Promise<void>;
Expand Down Expand Up @@ -545,6 +546,7 @@ export interface CallWithChatAdapterManagement {
clearFileUploads: () => void;
createStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void | CreateVideoStreamViewResult>;
deleteMessage(messageId: string): Promise<void>;
disposeScreenShareStreamView(remoteUserId: string): Promise<void>;
disposeStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void>;
// (undocumented)
downloadAttachments: (options: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export interface CallAdapterCallManagement extends CallAdapterCallOperations {
// @public
export interface CallAdapterCallOperations {
createStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void | CreateVideoStreamViewResult>;
disposeScreenShareStreamView(remoteUserId: string): Promise<void>;
disposeStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void>;
leaveCall(forEveryone?: boolean): Promise<void>;
mute(): Promise<void>;
Expand Down Expand Up @@ -377,6 +378,7 @@ export interface CallWithChatAdapterManagement {
askDevicePermission(constrain: PermissionConstraints): Promise<void>;
createStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void | CreateVideoStreamViewResult>;
deleteMessage(messageId: string): Promise<void>;
disposeScreenShareStreamView(remoteUserId: string): Promise<void>;
disposeStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void>;
fetchInitialData(): Promise<void>;
joinCall(microphoneOn?: boolean): Call | undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ export class MockCallAdapter implements CallAdapter {
disposeStreamView(): Promise<void> {
return Promise.resolve();
}
disposeScreenShareStreamView(): Promise<void> {
return Promise.resolve();
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
askDevicePermission(constrain: PermissionConstraints): Promise<void> {
throw Error('askDevicePermission not implemented');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ export class AzureCommunicationCallAdapter<AgentType extends CallAgent | BetaTea
this.removeParticipant.bind(this);
this.createStreamView.bind(this);
this.disposeStreamView.bind(this);
this.disposeScreenShareStreamView.bind(this);
this.on.bind(this);
this.off.bind(this);
this.processNewCall.bind(this);
Expand Down Expand Up @@ -602,6 +603,10 @@ export class AzureCommunicationCallAdapter<AgentType extends CallAgent | BetaTea
}
}

public async disposeScreenShareStreamView(remoteUserId: string): Promise<void> {
await this.handlers.onDisposeRemoteScreenShareStreamView(remoteUserId);
}

public async leaveCall(forEveryone?: boolean): Promise<void> {
await this.handlers.onHangUp(forEveryone);
this.unsubscribeCallEvents();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,17 @@ export interface CallAdapterCallOperations {
* @public
*/
disposeStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void>;
/**
* Dispose the html view for a screen share stream
*
* @remarks
* this method is implemented for composite
*
* @param remoteUserId - Id of the participant to dispose the screen share stream view for.
*
* @public
*/
disposeScreenShareStreamView(remoteUserId: string): Promise<void>;
/* @conditional-compile-remove(PSTN-calls) */
/**
* Holds the call.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ const createCompositeHandlers = memoizeOne(
onDisposeRemoteStreamView: async (userId) => {
return adapter.disposeStreamView(userId);
},
onDisposeRemoteScreenShareStreamView: async (userId) => {
return adapter.disposeScreenShareStreamView(userId);
},
/* @conditional-compile-remove(call-readiness) */
askDevicePermission: async (constrain) => {
return adapter.askDevicePermission(constrain);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ export class AzureCommunicationCallWithChatAdapter implements CallWithChatAdapte
this.removeParticipant.bind(this);
this.createStreamView.bind(this);
this.disposeStreamView.bind(this);
this.disposeScreenShareStreamView.bind(this);
this.fetchInitialData.bind(this);
this.sendMessage.bind(this);
this.sendReadReceipt.bind(this);
Expand Down Expand Up @@ -350,6 +351,10 @@ export class AzureCommunicationCallWithChatAdapter implements CallWithChatAdapte
public async disposeStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void> {
await this.callAdapter.disposeStreamView(remoteUserId, options);
}
/** Dispose of a remote screen share */
public async disposeScreenShareStreamView(remoteUserId: string): Promise<void> {
await this.callAdapter.disposeScreenShareStreamView(remoteUserId);
}
/** Fetch initial Call and Chat data such as chat messages. */
public async fetchInitialData(): Promise<void> {
await this.chatAdapter.fetchInitialData();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,17 @@ export interface CallWithChatAdapterManagement {
* @public
*/
disposeStreamView(remoteUserId?: string, options?: VideoStreamOptions): Promise<void>;
/**
* Dispose the html view for a screen share stream
*
* @remarks
* this method is implemented for composite
*
* @param remoteUserId - Id of the participant to dispose the screen share stream view for.
*
* @public
*/
disposeScreenShareStreamView(remoteUserId: string): Promise<void>;
/**
* Ask for permissions of devices.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ export class CallWithChatBackedCallAdapter implements CallAdapter {
await this.callWithChatAdapter.createStreamView(remoteUserId, options);
public disposeStreamView = async (remoteUserId?: string, options?: VideoStreamOptions): Promise<void> =>
await this.callWithChatAdapter.disposeStreamView(remoteUserId, options);
public disposeScreenShareStreamView(remoteUserId: string): Promise<void> {
return this.callWithChatAdapter.disposeScreenShareStreamView(remoteUserId);
}
/* @conditional-compile-remove(PSTN-calls) */
public holdCall = async (): Promise<void> => {
await this.callWithChatAdapter.holdCall();
Expand Down