Populate localVideoStreamState state with video effects status#2728
Populate localVideoStreamState state with video effects status#2728JamesBurnside merged 24 commits intomainfrom
Conversation
…context when subscription events fire. Ensure this is created when unparented views are created or when the calls localvideostreams are updated
…fects-state-definitions
…-definitions' into jaburnsi/populate-video-effects-state
Chat bundle size is not changed.
|
CallWithChat bundle size is increased❗.
|
Calling bundle size is increased❗.
|
| private _recordingSubscriber: RecordingSubscriber; | ||
| private _transcriptionSubscriber: TranscriptionSubscriber; | ||
| /* @conditional-compile-remove(video-background-effects) */ | ||
| private _localVideoStreamVideoEffectsSubscribers: Map<string, LocalVideoStreamVideoEffectsSubscriber>; |
There was a problem hiding this comment.
Do we have any other events to be subscribed from stream in near future? If yes then it would be nice to name it LocalStreamSubScriber and put it all there
There was a problem hiding this comment.
Oh good point, I'll look at making this more generic so new localVideoStream subscriptions could be easily added
There was a problem hiding this comment.
Going to leave this as is. If someone were to create a local video stream subcriber for different events (or a declarativelocalvideostream) they would use this subscriber themselves.
Which from playing around with how this feature should be implemented, could look something like this!~
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
/* @conditional-compile-remove(video-background-effects) */
import { Features, LocalVideoStream } from '@azure/communication-calling';
/* @conditional-compile-remove(video-background-effects) */
import { CallContext } from './CallContext';
/* @conditional-compile-remove(video-background-effects) */
import { CallIdRef } from './CallIdRef';
/* @conditional-compile-remove(video-background-effects) */
import { convertSdkLocalStreamToDeclarativeLocalStream } from './Converter';
/* @conditional-compile-remove(video-background-effects) */
import { LocalVideoStreamVideoEffectsSubscriber } from './LocalVideoStreamVideoEffectsSubscriber';
/* @conditional-compile-remove(video-background-effects) */
/**
* @private
*/
export class ProxyLocalVideoStream implements ProxyHandler<LocalVideoStream> {
private _context: CallContext;
private _callIdRef: CallIdRef | 'unparented';
private _localVideoStreamVideoEffectsSubscriber?: LocalVideoStreamVideoEffectsSubscriber;
constructor(context: CallContext, callId: CallIdRef | 'unparented') {
this._context = context;
this._callIdRef = callId;
}
public construct(target: LocalVideoStream): LocalVideoStream {
const statefulLocalVideoStream = convertSdkLocalStreamToDeclarativeLocalStream(target);
const effectsApi = target.feature(Features.VideoEffects);
this._localVideoStreamVideoEffectsSubscriber = new LocalVideoStreamVideoEffectsSubscriber({
parent: this._callIdRef,
context: this._context,
localVideoStream: statefulLocalVideoStream,
localVideoStreamEffectsAPI: effectsApi
});
return new Proxy(target, this);
}
public unsubscribe(): void {
if (this._localVideoStreamVideoEffectsSubscriber) {
this._localVideoStreamVideoEffectsSubscriber.unsubscribe();
}
}
public get<P extends keyof LocalVideoStream>(target: LocalVideoStream, prop: P): any {
switch (prop) {
case 'feature': {
return async (...args: Parameters<LocalVideoStream['feature']>) => {
if (args[0] === Features.VideoEffects) {
const feature = target.feature(Features.VideoEffects);
return {
...feature,
dispose: (...args: Parameters<typeof feature.dispose>) => {
this.unsubscribe();
return feature.dispose(...args);
}
};
} else {
return target.feature(...args);
}
};
}
default:
return Reflect.get(target, prop);
}
}
}
/* @conditional-compile-remove(video-background-effects) */
/**
* Creates a declarative LocalVideoStream that is backed by a LocalVideoStream from the SDK.
* Calling methods on this declarative object triggers state updates in the stateful client.
*/
export const localVideoStreamDeclaratify = (
view: LocalVideoStream,
context: CallContext,
callId: CallIdRef | 'unparented'
): LocalVideoStream => {
const proxyLocalVideoStream = new ProxyLocalVideoStream(context, callId);
return new Proxy(view, proxyLocalVideoStream) as LocalVideoStream;
};
export {};| /* @conditional-compile-remove(video-background-effects) */ | ||
| { | ||
| this._unparentedViewVideoEffectsSubscriber?.unsubscribe(); | ||
| this._unparentedViewVideoEffectsSubscriber = new LocalVideoStreamVideoEffectsSubscriber({ |
There was a problem hiding this comment.
I can see why we put a subscriber here - cause we only create localStream in StreamUtil function then it's hard to get the stream and subscribe to it in other functions
But this adds complexity to the overall dependency graph, previously call context is only responsible for getting and setting data and all the other logics are in subscriber/client
But now it's like subscriber->context->subscriber->context, so it could be easily a circular ref when someone doesn't understand this well
I guess either finding a way to create stream outside of context or getting stream from internal context after the creation or even creating subscriber in internal context would be nice
Lets keep CallContext only the final stop for data and logic to flow in ;D
There was a problem hiding this comment.
great point, will look into where else it could go...
There was a problem hiding this comment.
Moved the subscription logic into internalContext, not super ideal as then the internalcontext kinda has a handle to the regular context but changes
subscriber->context->subscriber->context
to
subscriber->internalcontext->subscriber->context
which is a little nicer!
|
Failed to pass the Static HTML UI Test. If this PR is for UI change and the error is snapshot mismatch, please add "update_snapshots" label to the PR for updating the snapshot. |
What
When a new local video stream is created we subscribe to changes (effectsStarted, effectsStopped and effectsError), subscriptions happen in two places:
addedremovedWhat's not in this PR
Why
Getting video effects status of the local video stream into state
How Tested
Manually trigger local video streams and verified subscriptions where fired when in config screen and in a cal, and verified localVideoStreamState correctly had the new state properties