소스 검색

feat(rn) implement startSilent

Technically, on Android, the audio mode is configured but no audio is
played. Since the configured audio mode matches what we expect from a
calling app (what we support to coexist with) this is enough to not
create audio disruptions.
factor2
Saúl Ibarra Corretgé 8 달 전
부모
커밋
b3ee8fe127

+ 38
- 1
android/sdk/src/main/java/org/jitsi/meet/sdk/AudioModeModule.java 파일 보기

@@ -136,6 +136,11 @@ class AudioModeModule extends ReactContextBaseJavaModule {
136 136
      */
137 137
     private String userSelectedDevice;
138 138
 
139
+    /**
140
+     * Whether or not audio is disabled.
141
+     */
142
+    private boolean audioDisabled;
143
+
139 144
     /**
140 145
      * Initializes a new module instance. There shall be a single instance of
141 146
      * this module throughout the lifetime of the application.
@@ -236,6 +241,12 @@ class AudioModeModule extends ReactContextBaseJavaModule {
236 241
             audioDeviceHandler.stop();
237 242
         }
238 243
 
244
+        audioDeviceHandler = null;
245
+
246
+        if (audioDisabled) {
247
+            return;
248
+        }
249
+
239 250
         if (useConnectionService()) {
240 251
             audioDeviceHandler = new AudioDeviceHandlerConnectionService(audioManager);
241 252
         } else {
@@ -278,6 +289,27 @@ class AudioModeModule extends ReactContextBaseJavaModule {
278 289
         });
279 290
     }
280 291
 
292
+    @ReactMethod
293
+    public void setDisabled(final boolean disabled, final Promise promise) {
294
+        if (audioDisabled == disabled) {
295
+            promise.resolve(null);
296
+            return;
297
+        }
298
+
299
+        JitsiMeetLogger.i(TAG + "  audio disabled: " + disabled);
300
+
301
+        audioDisabled = disabled;
302
+        setAudioDeviceHandler();
303
+
304
+        if (disabled) {
305
+            mode = -1;
306
+            availableDevices.clear();
307
+            resetSelectedDevice();
308
+        }
309
+
310
+        promise.resolve(null);
311
+    }
312
+
281 313
     /**
282 314
      * Public method to set the current audio mode.
283 315
      *
@@ -287,7 +319,12 @@ class AudioModeModule extends ReactContextBaseJavaModule {
287 319
      */
288 320
     @ReactMethod
289 321
     public void setMode(final int mode, final Promise promise) {
290
-        if (mode != DEFAULT && mode != AUDIO_CALL && mode != VIDEO_CALL) {
322
+        if (audioDisabled) {
323
+            promise.resolve(null);
324
+            return;
325
+        }
326
+
327
+        if (mode < DEFAULT || mode > VIDEO_CALL) {
291 328
             promise.reject("setMode", "Invalid audio mode " + mode);
292 329
             return;
293 330
         }

+ 38
- 0
ios/sdk/src/AudioMode.m 파일 보기

@@ -21,6 +21,7 @@
21 21
 #import <WebRTC/WebRTC.h>
22 22
 
23 23
 #import "JitsiAudioSession+Private.h"
24
+#import "callkit/JMCallKitProxy.h"
24 25
 
25 26
 
26 27
 // Audio mode
@@ -54,6 +55,7 @@ static NSString * const kDeviceTypeUnknown    = @"UNKNOWN";
54 55
     RTCAudioSessionConfiguration *audioCallConfig;
55 56
     RTCAudioSessionConfiguration *videoCallConfig;
56 57
     RTCAudioSessionConfiguration *earpieceConfig;
58
+    BOOL audioDisabled;
57 59
     BOOL forceSpeaker;
58 60
     BOOL forceEarpiece;
59 61
     BOOL isSpeakerOn;
@@ -146,9 +148,36 @@ RCT_EXPORT_MODULE();
146 148
 
147 149
 #pragma mark - Exported methods
148 150
 
151
+RCT_EXPORT_METHOD(setDisabled:(BOOL)disabled
152
+                  resolve:(RCTPromiseResolveBlock)resolve
153
+                   reject:(RCTPromiseRejectBlock)reject) {
154
+    if (audioDisabled == disabled) {
155
+        resolve(nil);
156
+        return;
157
+    }
158
+
159
+    RCTLogInfo(@"[AudioMode] audio disabled: %d", disabled);
160
+
161
+    audioDisabled = disabled;
162
+    JMCallKitProxy.enabled = !disabled;
163
+
164
+    RTCAudioSession *session = JitsiAudioSession.rtcAudioSession;
165
+    if (disabled) {
166
+        [session removeDelegate:self];
167
+    } else {
168
+        [session addDelegate:self];
169
+    }
170
+    session.useManualAudio = disabled;
171
+}
172
+
149 173
 RCT_EXPORT_METHOD(setMode:(int)mode
150 174
                   resolve:(RCTPromiseResolveBlock)resolve
151 175
                    reject:(RCTPromiseRejectBlock)reject) {
176
+    if (audioDisabled) {
177
+        resolve(nil);
178
+        return;
179
+    }
180
+
152 181
     RTCAudioSessionConfiguration *config = [self configForMode:mode];
153 182
     NSError *error;
154 183
 
@@ -177,6 +206,11 @@ RCT_EXPORT_METHOD(setMode:(int)mode
177 206
 RCT_EXPORT_METHOD(setAudioDevice:(NSString *)device
178 207
                   resolve:(RCTPromiseResolveBlock)resolve
179 208
                   reject:(RCTPromiseRejectBlock)reject) {
209
+    if (audioDisabled) {
210
+        resolve(nil);
211
+        return;
212
+    }
213
+
180 214
     RCTLogInfo(@"[AudioMode] Selected device: %@", device);
181 215
     
182 216
     RTCAudioSession *session = JitsiAudioSession.rtcAudioSession;
@@ -239,6 +273,10 @@ RCT_EXPORT_METHOD(setAudioDevice:(NSString *)device
239 273
 }
240 274
 
241 275
 RCT_EXPORT_METHOD(updateDeviceList) {
276
+    if (audioDisabled) {
277
+        return;
278
+    }
279
+
242 280
     [self notifyDevicesChanged];
243 281
 }
244 282
 

+ 6
- 2
ios/sdk/src/JitsiAudioSession.m 파일 보기

@@ -24,11 +24,15 @@
24 24
 }
25 25
 
26 26
 + (void)activateWithAudioSession:(AVAudioSession *)session {
27
-    [self.rtcAudioSession audioSessionDidActivate:session];
27
+    if (!self.rtcAudioSession.useManualAudio) {
28
+        [self.rtcAudioSession audioSessionDidActivate:session];
29
+    }
28 30
 }
29 31
 
30 32
 + (void)deactivateWithAudioSession:(AVAudioSession *)session {
31
-    [self.rtcAudioSession audioSessionDidDeactivate:session];
33
+    if (!self.rtcAudioSession.useManualAudio) {
34
+        [self.rtcAudioSession audioSessionDidDeactivate:session];
35
+    }
32 36
 }
33 37
 
34 38
 @end

+ 8
- 4
react/features/base/tracks/actions.any.ts 파일 보기

@@ -86,12 +86,16 @@ export function createDesiredLocalTracks(...desiredTypes: any) {
86 86
         dispatch(destroyLocalDesktopTrackIfExists());
87 87
 
88 88
         if (desiredTypes.length === 0) {
89
+            const { startSilent } = state['features/base/config'];
89 90
             const { video } = state['features/base/media'];
90 91
 
91
-            // XXX: Always create the audio track early, even if it will be muted.
92
-            // This fixes a timing issue when adding the track to the conference which
93
-            // manifests primarily on iOS 15.
94
-            desiredTypes.push(MEDIA_TYPE.AUDIO);
92
+            if (!startSilent) {
93
+                // Always create the audio track early, even if it will be muted.
94
+                // This fixes a timing issue when adding the track to the conference which
95
+                // manifests primarily on iOS 15.
96
+                // Unless we are silent, of course.
97
+                desiredTypes.push(MEDIA_TYPE.AUDIO);
98
+            }
95 99
 
96 100
             // XXX When the app is coming into the foreground from the
97 101
             // background in order to handle a URL, it may realize the new

+ 20
- 1
react/features/mobile/audio-mode/middleware.ts 파일 보기

@@ -10,9 +10,11 @@ import {
10 10
     CONFERENCE_LEFT
11 11
 } from '../../base/conference/actionTypes';
12 12
 import { getCurrentConference } from '../../base/conference/functions';
13
+import { SET_CONFIG } from '../../base/config/actionTypes';
13 14
 import { AUDIO_FOCUS_DISABLED } from '../../base/flags/constants';
14 15
 import { getFeatureFlag } from '../../base/flags/functions';
15 16
 import MiddlewareRegistry from '../../base/redux/MiddlewareRegistry';
17
+import { parseURIString } from '../../base/util/uri';
16 18
 
17 19
 import { _SET_AUDIOMODE_DEVICES, _SET_AUDIOMODE_SUBSCRIPTIONS } from './actionTypes';
18 20
 import logger from './logger';
@@ -44,7 +46,7 @@ MiddlewareRegistry.register(store => next => action => {
44 46
     }
45 47
     case APP_WILL_MOUNT:
46 48
         _appWillMount(store);
47
-    case CONFERENCE_FAILED: // eslint-disable-line no-fallthrough
49
+    case CONFERENCE_FAILED:
48 50
     case CONFERENCE_LEFT:
49 51
 
50 52
     /*
@@ -60,6 +62,23 @@ MiddlewareRegistry.register(store => next => action => {
60 62
     case SET_AUDIO_ONLY:
61 63
         return _updateAudioMode(store, next, action);
62 64
 
65
+    case SET_CONFIG: {
66
+        const { locationURL } = store.getState()['features/base/connection'];
67
+        const location = parseURIString(locationURL?.href ?? '');
68
+
69
+        /**
70
+         * Don't touch the current value if there is no room in the URL. This
71
+         * avoids audio cutting off for a moment right after the user leaves
72
+         * a meeting. The next meeting join will set it to the right value.
73
+         */
74
+        if (location.room) {
75
+            const { startSilent } = action.config;
76
+
77
+            AudioMode.setDisabled?.(Boolean(startSilent));
78
+        }
79
+
80
+        break;
81
+    }
63 82
     }
64 83
 
65 84
     /* eslint-enable no-fallthrough */

Loading…
취소
저장