18
18
*/
19
19
20
20
import { QualifiedId } from '@wireapp/api-client/lib/user' ;
21
- import ko from 'knockout' ;
21
+ import ko , { observable , pureComputed } from 'knockout' ;
22
22
23
23
import { VIDEO_STATE } from '@wireapp/avs' ;
24
24
25
25
import { matchQualifiedIds } from 'Util/QualifiedId' ;
26
26
27
27
import { User } from '../entity/User' ;
28
+ import { applyBlur } from '../media/VideoBackgroundBlur' ;
28
29
29
30
export type UserId = string ;
30
31
export type ClientId = string ;
31
32
32
33
export class Participant {
33
34
// Video
34
- public videoState : ko . Observable < VIDEO_STATE > ;
35
- public videoStream : ko . Observable < MediaStream | undefined > ;
36
- public blurredVideoStream = ko . observable < { stream : MediaStream ; release : ( ) => void } | undefined > ( undefined ) ;
37
- public hasActiveVideo : ko . PureComputed < boolean > ;
38
- public hasPausedVideo : ko . PureComputed < boolean > ;
39
- public sharesScreen : ko . PureComputed < boolean > ;
40
- public sharesCamera : ko . PureComputed < boolean > ;
41
- public startedScreenSharingAt : ko . Observable < number > ;
42
- public isActivelySpeaking : ko . Observable < boolean > ;
43
- public isSendingVideo : ko . PureComputed < boolean > ;
44
- public isAudioEstablished : ko . Observable < boolean > ;
35
+ public readonly videoState = observable ( VIDEO_STATE . STOPPED ) ;
36
+ public readonly videoStream = observable < MediaStream | undefined > ( ) ;
37
+ public readonly blurredVideoStream = observable < { stream : MediaStream ; release : ( ) => void } | undefined > ( ) ;
38
+ public readonly hasActiveVideo : ko . PureComputed < boolean > ;
39
+ public readonly hasPausedVideo : ko . PureComputed < boolean > ;
40
+ public readonly sharesScreen : ko . PureComputed < boolean > ;
41
+ public readonly sharesCamera : ko . PureComputed < boolean > ;
42
+ public readonly startedScreenSharingAt = observable < number > ( 0 ) ;
43
+ public readonly isActivelySpeaking = observable ( false ) ;
44
+ public readonly isSendingVideo : ko . PureComputed < boolean > ;
45
+ public readonly isAudioEstablished = observable ( false ) ;
45
46
46
47
// Audio
47
- public audioStream : ko . Observable < MediaStream | undefined > ;
48
- public isMuted : ko . Observable < boolean > ;
48
+ public readonly audioStream = observable < MediaStream | undefined > ( ) ;
49
+ public readonly isMuted = observable ( false ) ;
49
50
50
51
constructor (
51
- public user : User ,
52
- public clientId : ClientId ,
52
+ public readonly user : User ,
53
+ public readonly clientId : ClientId ,
53
54
) {
54
- this . videoState = ko . observable ( VIDEO_STATE . STOPPED ) ;
55
- this . hasActiveVideo = ko . pureComputed ( ( ) => {
55
+ this . hasActiveVideo = pureComputed ( ( ) => {
56
56
return ( this . sharesCamera ( ) || this . sharesScreen ( ) ) && ! ! this . videoStream ( ) ;
57
57
} ) ;
58
- this . sharesScreen = ko . pureComputed ( ( ) => {
58
+ this . sharesScreen = pureComputed ( ( ) => {
59
59
return this . videoState ( ) === VIDEO_STATE . SCREENSHARE ;
60
60
} ) ;
61
- this . sharesCamera = ko . pureComputed ( ( ) => {
61
+ this . sharesCamera = pureComputed ( ( ) => {
62
62
return [ VIDEO_STATE . STARTED , VIDEO_STATE . PAUSED ] . includes ( this . videoState ( ) ) ;
63
63
} ) ;
64
- this . hasPausedVideo = ko . pureComputed ( ( ) => {
64
+ this . hasPausedVideo = pureComputed ( ( ) => {
65
65
return this . videoState ( ) === VIDEO_STATE . PAUSED ;
66
66
} ) ;
67
- this . videoStream = ko . observable ( ) ;
68
- this . audioStream = ko . observable ( ) ;
69
- this . isActivelySpeaking = ko . observable ( false ) ;
70
- this . startedScreenSharingAt = ko . observable ( ) ;
71
- this . isMuted = ko . observable ( false ) ;
72
- this . isSendingVideo = ko . pureComputed ( ( ) => {
67
+ this . isSendingVideo = pureComputed ( ( ) => {
73
68
return this . videoState ( ) !== VIDEO_STATE . STOPPED ;
74
69
} ) ;
75
- this . isAudioEstablished = ko . observable ( false ) ;
76
70
}
77
71
78
72
public releaseBlurredVideoStream ( ) : void {
79
73
this . blurredVideoStream ( ) ?. release ( ) ;
80
74
this . blurredVideoStream ( undefined ) ;
81
75
}
82
76
77
+ public async setBlurredBackground ( isBlurred : boolean ) {
78
+ const originalVideoStream = this . videoStream ( ) ;
79
+ if ( isBlurred && originalVideoStream ) {
80
+ this . blurredVideoStream ( await applyBlur ( originalVideoStream ) ) ;
81
+ } else {
82
+ this . releaseBlurredVideoStream ( ) ;
83
+ }
84
+ return this . blurredVideoStream ( ) ?. stream ;
85
+ }
86
+
83
87
readonly doesMatchIds = ( userId : QualifiedId , clientId : ClientId ) : boolean =>
84
88
matchQualifiedIds ( userId , this . user . qualifiedId ) && clientId === this . clientId ;
85
89
@@ -89,6 +93,7 @@ export class Participant {
89
93
}
90
94
91
95
setVideoStream ( videoStream : MediaStream , stopTracks : boolean ) : void {
96
+ this . releaseBlurredVideoStream ( ) ;
92
97
this . releaseStream ( this . videoStream ( ) , stopTracks ) ;
93
98
this . videoStream ( videoStream ) ;
94
99
}
@@ -104,8 +109,9 @@ export class Participant {
104
109
}
105
110
106
111
getMediaStream ( ) : MediaStream {
107
- const audioTracks : MediaStreamTrack [ ] = this . audioStream ( ) ? this . audioStream ( ) . getTracks ( ) : [ ] ;
108
- const videoTracks : MediaStreamTrack [ ] = this . videoStream ( ) ? this . videoStream ( ) . getTracks ( ) : [ ] ;
112
+ const audioTracks : MediaStreamTrack [ ] = this . audioStream ( ) ?. getTracks ( ) ?? [ ] ;
113
+ const videoTracks : MediaStreamTrack [ ] =
114
+ this . blurredVideoStream ( ) ?. stream . getTracks ( ) ?? this . videoStream ( ) ?. getTracks ( ) ?? [ ] ;
109
115
return new MediaStream ( audioTracks . concat ( videoTracks ) ) ;
110
116
}
111
117
0 commit comments