in packages/calling-stateful-client/src/StreamUtils.ts [334:448]
function disposeViewVideo(
context: CallContext,
internalContext: InternalCallContext,
callId: string,
stream: RemoteVideoStreamState | LocalVideoStreamState,
participantId?: CommunicationIdentifierKind | string
): void {
// we can only have 3 types of createView
let streamEventType: 'disposeViewLocal' | 'disposeViewRemote' | 'disposeViewUnparented';
// we will reuse these for local as well but we need to make sure the remote stream is passed in like before.
if (participantId) {
streamEventType = 'disposeViewRemote';
} else if (callId) {
streamEventType = 'disposeViewLocal';
} else {
// TODO update for when unparented view.
streamEventType = 'disposeViewUnparented';
}
const streamType = stream.mediaStreamType;
const localStreamKey = (stream as LocalVideoStream).mediaStreamType;
const remoteStreamId = (stream as RemoteVideoStream).id;
// we want to check to see if there is a participantId this will tell us whether its a local stream or a remote one.
const participantKey =
streamEventType === 'disposeViewRemote' && participantId
? typeof participantId === 'string'
? participantId
: toFlatCommunicationIdentifier(participantId)
: undefined;
const streamLogInfo = { callId, participantKey, streamId: remoteStreamId ?? localStreamKey, streamType };
_logStreamEvent(EventNames.START_DISPOSE_STREAM, streamLogInfo);
if (streamEventType === 'disposeViewRemote' && participantKey) {
context.setRemoteVideoStreamRendererView(callId, participantKey, remoteStreamId, undefined);
}
const renderInfo =
streamEventType === 'disposeViewRemote' && participantKey
? internalContext.getRemoteRenderInfoForParticipant(callId, participantKey, remoteStreamId)
: internalContext.getLocalRenderInfo(callId, localStreamKey);
if (!renderInfo) {
_logStreamEvent(EventNames.DISPOSE_INFO_NOT_FOUND, streamLogInfo);
return;
}
// Nothing to dispose of or clean up -- we can safely exit early here.
if (renderInfo.status === 'NotRendered') {
_logStreamEvent(EventNames.STREAM_ALREADY_DISPOSED, streamLogInfo);
return;
}
// Status is already marked as "stopping" so we can exit early here. This is because stopping only occurs
// when the stream is being created in createView but hasn't been completed being created yet. The createView
// method will see the "stopping" status and perform the cleanup
if (renderInfo.status === 'Stopping') {
_logStreamEvent(EventNames.STREAM_STOPPING, streamLogInfo);
return;
}
// If the stream is in the middle of being rendered (i.e. has state "Rendering"), we need the status as
// "stopping" without performing any cleanup. This will tell the `createView` method that it should stop
// rendering and clean up the state once the view has finished being created.
if (renderInfo.status === 'Rendering') {
_logStreamEvent(EventNames.STREAM_STOPPING, streamLogInfo);
streamEventType === 'disposeViewRemote' && participantKey
? internalContext.setRemoteRenderInfo(
callId,
participantKey,
remoteStreamId,
renderInfo.stream as RemoteVideoStream,
'Stopping',
undefined
)
: internalContext.setLocalRenderInfo(
callId,
localStreamKey,
renderInfo.stream as LocalVideoStream,
'Stopping',
renderInfo.renderer
);
return;
}
if (renderInfo.renderer) {
_logStreamEvent(EventNames.DISPOSING_RENDERER, streamLogInfo);
renderInfo.renderer.dispose();
// Else the state must be in the "Rendered" state, so we can dispose the renderer and clean up the state.
if (streamEventType === 'disposeViewRemote' && participantKey) {
internalContext.setRemoteRenderInfo(
callId,
participantKey,
remoteStreamId,
renderInfo.stream as RemoteVideoStream,
'NotRendered',
undefined
);
} else if (streamEventType === 'disposeViewLocal') {
internalContext.setLocalRenderInfo(
callId,
localStreamKey,
renderInfo.stream as LocalVideoStream,
'NotRendered',
undefined
);
context.setLocalVideoStreamRendererView(callId, localStreamKey, undefined);
}
} else {
_logStreamEvent(EventNames.RENDERER_NOT_FOUND, streamLogInfo);
}
}