|
@@ -2,10 +2,7 @@
|
2
|
2
|
|
3
|
3
|
import { _handleParticipantError } from '../base/conference';
|
4
|
4
|
import { MEDIA_TYPE, VIDEO_TYPE } from '../base/media';
|
5
|
|
-import {
|
6
|
|
- getLocalVideoTrack,
|
7
|
|
- getTrackByMediaTypeAndParticipant
|
8
|
|
-} from '../base/tracks';
|
|
5
|
+import { getTrackByMediaTypeAndParticipant } from '../base/tracks';
|
9
|
6
|
|
10
|
7
|
import {
|
11
|
8
|
SELECT_LARGE_VIDEO_PARTICIPANT,
|
|
@@ -86,14 +83,13 @@ export function updateKnownLargeVideoResolution(resolution: number) {
|
86
|
83
|
}
|
87
|
84
|
|
88
|
85
|
/**
|
89
|
|
- * Returns the most recent existing video track. It can be local or remote
|
90
|
|
- * video.
|
|
86
|
+ * Returns the most recent existing remote video track.
|
91
|
87
|
*
|
92
|
88
|
* @param {Track[]} tracks - All current tracks.
|
93
|
89
|
* @private
|
94
|
90
|
* @returns {(Track|undefined)}
|
95
|
91
|
*/
|
96
|
|
-function _electLastVisibleVideo(tracks) {
|
|
92
|
+function _electLastVisibleRemoteVideo(tracks) {
|
97
|
93
|
// First we try to get most recent remote video track.
|
98
|
94
|
for (let i = tracks.length - 1; i >= 0; --i) {
|
99
|
95
|
const track = tracks[i];
|
|
@@ -102,9 +98,6 @@ function _electLastVisibleVideo(tracks) {
|
102
|
98
|
return track;
|
103
|
99
|
}
|
104
|
100
|
}
|
105
|
|
-
|
106
|
|
- // And if no remote video tracks are available, we select the local one.
|
107
|
|
- return getLocalVideoTrack(tracks);
|
108
|
101
|
}
|
109
|
102
|
|
110
|
103
|
/**
|
|
@@ -117,29 +110,36 @@ function _electLastVisibleVideo(tracks) {
|
117
|
110
|
* @returns {(string|undefined)}
|
118
|
111
|
*/
|
119
|
112
|
function _electParticipantInLargeVideo(state) {
|
120
|
|
- // First get the pinned participant. If the local participant is pinned,
|
121
|
|
- // he/she will be shown in LargeVideo.
|
|
113
|
+ // First get the pinned participant. If a participant is pinned, they will
|
|
114
|
+ // be shown in the LargeVideo.
|
122
|
115
|
const participants = state['features/base/participants'];
|
123
|
116
|
let participant = participants.find(p => p.pinned);
|
124
|
|
- let id = participant ? participant.id : undefined;
|
|
117
|
+ let id = participant && participant.id;
|
125
|
118
|
|
126
|
119
|
if (!id) {
|
127
|
120
|
// No participant is pinned so get the dominant speaker. But the local
|
128
|
121
|
// participant won't be displayed in LargeVideo even if he/she is the
|
129
|
122
|
// dominant speaker.
|
130
|
123
|
participant = participants.find(p => p.dominantSpeaker && !p.local);
|
131
|
|
- if (participant) {
|
132
|
|
- id = participant.id;
|
133
|
|
- }
|
|
124
|
+ id = participant && participant.id;
|
134
|
125
|
|
135
|
126
|
if (!id) {
|
136
|
|
- // There is no dominant speaker so get the participant with the last
|
137
|
|
- // visible video track. This may turn out to be the local
|
138
|
|
- // participant.
|
|
127
|
+ // There is no dominant speaker so select the participant which last
|
|
128
|
+ // had visible video (excluding ourselves).
|
139
|
129
|
const tracks = state['features/base/tracks'];
|
140
|
|
- const videoTrack = _electLastVisibleVideo(tracks);
|
|
130
|
+ const videoTrack = _electLastVisibleRemoteVideo(tracks);
|
141
|
131
|
|
142
|
132
|
id = videoTrack && videoTrack.participantId;
|
|
133
|
+
|
|
134
|
+ if (!id) {
|
|
135
|
+ // It's possible there is no participant with visible video,
|
|
136
|
+ // this can happen for a number or reasons:
|
|
137
|
+ // - there is only one participant (the local user)
|
|
138
|
+ // - other participants joined with video muted
|
|
139
|
+ // As a last resort, pick the last participant.
|
|
140
|
+ participant = participants[participants.length - 1];
|
|
141
|
+ id = participant && participant.id;
|
|
142
|
+ }
|
143
|
143
|
}
|
144
|
144
|
}
|
145
|
145
|
|