|
|
@@ -1,4 +1,4 @@
|
|
1
|
|
-/* @flow */
|
|
|
1
|
+// @flow
|
|
2
|
2
|
|
|
3
|
3
|
import {
|
|
4
|
4
|
createStartAudioOnlyEvent,
|
|
|
@@ -6,7 +6,7 @@ import {
|
|
6
|
6
|
createSyncTrackStateEvent,
|
|
7
|
7
|
sendAnalytics
|
|
8
|
8
|
} from '../../analytics';
|
|
9
|
|
-import { SET_ROOM, setAudioOnly } from '../conference';
|
|
|
9
|
+import { isRoomValid, SET_ROOM, setAudioOnly } from '../conference';
|
|
10
|
10
|
import JitsiMeetJS from '../lib-jitsi-meet';
|
|
11
|
11
|
import { getPropertyValue } from '../profile';
|
|
12
|
12
|
import { MiddlewareRegistry } from '../redux';
|
|
|
@@ -14,6 +14,10 @@ import { setTrackMuted, TRACK_ADDED } from '../tracks';
|
|
14
|
14
|
|
|
15
|
15
|
import { setAudioMuted, setCameraFacingMode, setVideoMuted } from './actions';
|
|
16
|
16
|
import { CAMERA_FACING_MODE } from './constants';
|
|
|
17
|
+import {
|
|
|
18
|
+ _AUDIO_INITIAL_MEDIA_STATE,
|
|
|
19
|
+ _VIDEO_INITIAL_MEDIA_STATE
|
|
|
20
|
+} from './reducer';
|
|
17
|
21
|
|
|
18
|
22
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
|
19
|
23
|
|
|
|
@@ -30,8 +34,9 @@ MiddlewareRegistry.register(store => next => action => {
|
|
30
|
34
|
|
|
31
|
35
|
case TRACK_ADDED: {
|
|
32
|
36
|
const result = next(action);
|
|
|
37
|
+ const { track } = action;
|
|
33
|
38
|
|
|
34
|
|
- action.track.local && _syncTrackMutedState(store, action.track);
|
|
|
39
|
+ track.local && _syncTrackMutedState(store, track);
|
|
35
|
40
|
|
|
36
|
41
|
return result;
|
|
37
|
42
|
}
|
|
|
@@ -55,25 +60,51 @@ MiddlewareRegistry.register(store => next => action => {
|
|
55
|
60
|
* specified {@code action}.
|
|
56
|
61
|
*/
|
|
57
|
62
|
function _setRoom({ dispatch, getState }, next, action) {
|
|
58
|
|
- const { room } = action;
|
|
59
|
|
-
|
|
60
|
|
- // Read the config.
|
|
|
63
|
+ // Figure out the desires/intents i.e. the state of base/media. There are
|
|
|
64
|
+ // multiple desires/intents ordered by precedence such as server-side
|
|
|
65
|
+ // config, config overrides in the user-supplied URL, user's own app
|
|
|
66
|
+ // settings, etc.
|
|
61
|
67
|
|
|
62
|
68
|
const state = getState();
|
|
63
|
|
- const hasRoom = Boolean(room);
|
|
64
|
|
-
|
|
65
|
|
- const audioMuted = Boolean(getPropertyValue(state, 'startWithAudioMuted', {
|
|
66
|
|
- urlParams: hasRoom
|
|
67
|
|
- }));
|
|
68
|
|
- const videoMuted = Boolean(getPropertyValue(state, 'startWithVideoMuted', {
|
|
69
|
|
- urlParams: hasRoom
|
|
70
|
|
- }));
|
|
71
|
|
-
|
|
72
|
|
- sendAnalytics(createStartMutedConfigurationEvent(
|
|
73
|
|
- 'local', audioMuted, videoMuted));
|
|
74
|
|
-
|
|
75
|
|
- logger.log(`Start muted: ${audioMuted ? 'audio, ' : ''}${
|
|
76
|
|
- videoMuted ? 'video' : ''}`);
|
|
|
69
|
+ const { room } = action;
|
|
|
70
|
+ const roomIsValid = isRoomValid(room);
|
|
|
71
|
+
|
|
|
72
|
+ // XXX The configurations/preferences/settings startWithAudioMuted,
|
|
|
73
|
+ // startWithVideoMuted, and startAudioOnly were introduced for
|
|
|
74
|
+ // conferences/meetings. So it makes sense for these to not be considered
|
|
|
75
|
+ // outside of conferences/meetings (e.g. WelcomePage). Later on, though, we
|
|
|
76
|
+ // introduced a "Video <-> Voice" toggle on the WelcomePage which utilizes
|
|
|
77
|
+ // startAudioOnly outside of conferences/meetings so that particular
|
|
|
78
|
+ // configuration/preference/setting employs slightly exclusive logic.
|
|
|
79
|
+ const mutedSources = {
|
|
|
80
|
+ // We have startWithAudioMuted and startWithVideoMuted here:
|
|
|
81
|
+ config: true,
|
|
|
82
|
+ profile: true,
|
|
|
83
|
+
|
|
|
84
|
+ // XXX We've already overwritten base/config with urlParams. However,
|
|
|
85
|
+ // profile is more important than the server-side config. Consequently,
|
|
|
86
|
+ // we need to read from urlParams anyway:
|
|
|
87
|
+ urlParams: true,
|
|
|
88
|
+
|
|
|
89
|
+ // We don't have startWithAudioMuted and startWithVideoMuted here:
|
|
|
90
|
+ jwt: false
|
|
|
91
|
+ };
|
|
|
92
|
+ const audioMuted
|
|
|
93
|
+ = roomIsValid
|
|
|
94
|
+ ? Boolean(
|
|
|
95
|
+ getPropertyValue(state, 'startWithAudioMuted', mutedSources))
|
|
|
96
|
+ : _AUDIO_INITIAL_MEDIA_STATE.muted;
|
|
|
97
|
+ const videoMuted
|
|
|
98
|
+ = roomIsValid
|
|
|
99
|
+ ? Boolean(
|
|
|
100
|
+ getPropertyValue(state, 'startWithVideoMuted', mutedSources))
|
|
|
101
|
+ : _VIDEO_INITIAL_MEDIA_STATE.muted;
|
|
|
102
|
+
|
|
|
103
|
+ sendAnalytics(
|
|
|
104
|
+ createStartMutedConfigurationEvent('local', audioMuted, videoMuted));
|
|
|
105
|
+ logger.log(
|
|
|
106
|
+ `Start muted: ${audioMuted ? 'audio, ' : ''}${
|
|
|
107
|
+ videoMuted ? 'video' : ''}`);
|
|
77
|
108
|
|
|
78
|
109
|
// Unconditionally express the desires/expectations/intents of the app and
|
|
79
|
110
|
// the user i.e. the state of base/media. Eventually, practice/reality i.e.
|
|
|
@@ -82,29 +113,57 @@ function _setRoom({ dispatch, getState }, next, action) {
|
|
82
|
113
|
dispatch(setCameraFacingMode(CAMERA_FACING_MODE.USER));
|
|
83
|
114
|
dispatch(setVideoMuted(videoMuted));
|
|
84
|
115
|
|
|
85
|
|
- // config.startAudioOnly
|
|
|
116
|
+ // startAudioOnly
|
|
86
|
117
|
//
|
|
87
|
118
|
// FIXME Technically, the audio-only feature is owned by base/conference,
|
|
88
|
119
|
// not base/media so the following should be in base/conference.
|
|
89
|
120
|
// Practically, I presume it was easier to write the source code here
|
|
90
|
|
- // because it looks like config.startWithAudioMuted and
|
|
91
|
|
- // config.startWithVideoMuted.
|
|
92
|
|
- if (room) {
|
|
93
|
|
- let audioOnly;
|
|
94
|
|
-
|
|
95
|
|
- if (JitsiMeetJS.mediaDevices.supportsVideo()) {
|
|
96
|
|
- audioOnly = Boolean(getPropertyValue(state, 'startAudioOnly'));
|
|
97
|
|
- } else {
|
|
98
|
|
- // Always default to being audio only if the current environment
|
|
99
|
|
- // does not support sending or receiving video.
|
|
100
|
|
- audioOnly = true;
|
|
101
|
|
- }
|
|
102
|
|
-
|
|
103
|
|
- sendAnalytics(createStartAudioOnlyEvent(audioOnly));
|
|
104
|
|
- logger.log(`Start audio only set to ${audioOnly.toString()}`);
|
|
105
|
|
- dispatch(setAudioOnly(audioOnly));
|
|
|
121
|
+ // because it looks like startWithAudioMuted and startWithVideoMuted.
|
|
|
122
|
+ //
|
|
|
123
|
+ // XXX After the introduction of the "Video <-> Voice" toggle on the
|
|
|
124
|
+ // WelcomePage, startAudioOnly is utilized even outside of
|
|
|
125
|
+ // conferences/meetings.
|
|
|
126
|
+ let audioOnly;
|
|
|
127
|
+
|
|
|
128
|
+ if (JitsiMeetJS.mediaDevices.supportsVideo()) {
|
|
|
129
|
+ audioOnly
|
|
|
130
|
+ = Boolean(
|
|
|
131
|
+ getPropertyValue(
|
|
|
132
|
+ state,
|
|
|
133
|
+ 'startAudioOnly',
|
|
|
134
|
+ /* sources */ {
|
|
|
135
|
+ // FIXME Practically, base/config is (really) correct
|
|
|
136
|
+ // only if roomIsValid. At the time of this writing,
|
|
|
137
|
+ // base/config is overwritten by URL params which leaves
|
|
|
138
|
+ // base/config incorrect on the WelcomePage after
|
|
|
139
|
+ // leaving a conference which explicitly overwrites
|
|
|
140
|
+ // base/config with URL params.
|
|
|
141
|
+ config: roomIsValid,
|
|
|
142
|
+
|
|
|
143
|
+ // XXX We've already overwritten base/config with
|
|
|
144
|
+ // urlParams if roomIsValid. However, profile is more
|
|
|
145
|
+ // important than the server-side config. Consequently,
|
|
|
146
|
+ // we need to read from urlParams anyway. We also
|
|
|
147
|
+ // probably want to read from urlParams when
|
|
|
148
|
+ // !roomIsValid.
|
|
|
149
|
+ urlParams: true,
|
|
|
150
|
+
|
|
|
151
|
+ // The following don't have complications around whether
|
|
|
152
|
+ // they are defined or not:
|
|
|
153
|
+ jwt: false,
|
|
|
154
|
+ profile: true
|
|
|
155
|
+ }));
|
|
|
156
|
+ } else {
|
|
|
157
|
+ // Default to audio-only if the (execution) environment does not
|
|
|
158
|
+ // support (sending and/or receiving) video.
|
|
|
159
|
+ audioOnly = true;
|
|
106
|
160
|
}
|
|
107
|
161
|
|
|
|
162
|
+ sendAnalytics(createStartAudioOnlyEvent(audioOnly));
|
|
|
163
|
+ logger.log(`Start audio only set to ${audioOnly.toString()}`);
|
|
|
164
|
+
|
|
|
165
|
+ dispatch(setAudioOnly(audioOnly));
|
|
|
166
|
+
|
|
108
|
167
|
return next(action);
|
|
109
|
168
|
}
|
|
110
|
169
|
|
|
|
@@ -127,8 +186,10 @@ function _syncTrackMutedState({ getState }, track) {
|
|
127
|
186
|
// fired before track gets to state.
|
|
128
|
187
|
if (track.muted !== muted) {
|
|
129
|
188
|
sendAnalytics(createSyncTrackStateEvent(track.mediaType, muted));
|
|
130
|
|
- logger.log(`Sync ${track.mediaType} track muted state to ${
|
|
131
|
|
- muted ? 'muted' : 'unmuted'}`);
|
|
|
189
|
+ logger.log(
|
|
|
190
|
+ `Sync ${track.mediaType} track muted state to ${
|
|
|
191
|
+ muted ? 'muted' : 'unmuted'}`);
|
|
|
192
|
+
|
|
132
|
193
|
track.muted = muted;
|
|
133
|
194
|
setTrackMuted(track.jitsiTrack, muted);
|
|
134
|
195
|
}
|