From 3c04634609abeff61a7d1bc44688fdcdceebbf95 Mon Sep 17 00:00:00 2001 From: Lyubomir Marinov Date: Fri, 20 Jan 2017 12:11:11 -0600 Subject: [PATCH] Simplify Simplify the source code (with the idea that source code which does not exist does not have to be maintained). Additionally, apply modifications to have the source code comply with the coding style. Overall, prepare saghul:audio-mode for merge into jitsi:master. --- ios/app/AudioMode.h | 14 -- ios/app/AudioMode.m | 128 +++++++++--------- ios/app/POSIX.h | 4 - ios/app/POSIX.m | 5 +- .../project.pbxproj | 6 +- react/features/audio-mode/middleware.js | 67 ++++----- react/features/base/conference/actionTypes.js | 22 +-- react/features/base/conference/actions.js | 48 ++++--- react/features/base/react-native/AudioMode.js | 20 --- react/features/base/react-native/index.js | 1 - 10 files changed, 139 insertions(+), 176 deletions(-) delete mode 100644 ios/app/AudioMode.h delete mode 100644 ios/app/POSIX.h delete mode 100644 react/features/base/react-native/AudioMode.js diff --git a/ios/app/AudioMode.h b/ios/app/AudioMode.h deleted file mode 100644 index 30ad863a2..000000000 --- a/ios/app/AudioMode.h +++ /dev/null @@ -1,14 +0,0 @@ -#import -#import - -#import "RCTBridgeModule.h" - - -@interface AudioMode : NSObject - -@property (nonatomic, readonly) AVAudioSession *session; -@property (nonatomic, readonly) NSString *category; -@property (nonatomic, readonly) NSString *mode; -@property (nonatomic, readonly) BOOL initialized; - -@end diff --git a/ios/app/AudioMode.m b/ios/app/AudioMode.m index 1ad5e482d..4acec567a 100644 --- a/ios/app/AudioMode.m +++ b/ios/app/AudioMode.m @@ -1,8 +1,15 @@ -#import "AudioMode.h" +#import "RCTBridgeModule.h" #import "RCTLog.h" +#import -@implementation AudioMode +@interface AudioMode : NSObject +@end + +@implementation AudioMode { + NSString *_category; + NSString *_mode; +} RCT_EXPORT_MODULE(); @@ -12,20 +19,24 @@ typedef enum { kAudioModeVideoCall } JitsiMeetAudioMode; -- (instancetype)init -{ +- (NSDictionary *)constantsToExport { + return @{ + @"AUDIO_CALL" : [NSNumber numberWithInt: kAudioModeAudioCall], + @"DEFAULT" : [NSNumber numberWithInt: kAudioModeDefault], + @"VIDEO_CALL" : [NSNumber numberWithInt: kAudioModeVideoCall] + }; +}; + +- (instancetype)init { self = [super init]; if (self) { - _initialized = NO; _category = nil; _mode = nil; - _session = [AVAudioSession sharedInstance]; } return self; } -- (dispatch_queue_t)methodQueue -{ +- (dispatch_queue_t)methodQueue { // Make sure all our methods run in the main thread. The route change // notification runs there so this will make sure it will only be fired // after our changes have been applied (when we cause them, that is). @@ -33,97 +44,90 @@ typedef enum { } - (void)routeChanged:(NSNotification*)notification { - NSDictionary *dict = notification.userInfo; - NSInteger reason = [[dict valueForKey:AVAudioSessionRouteChangeReasonKey] - integerValue]; + NSInteger reason + = [[notification.userInfo + valueForKey:AVAudioSessionRouteChangeReasonKey] + integerValue]; + switch (reason) { - case AVAudioSessionRouteChangeReasonCategoryChange: { - // The category has changed, check if it's the one we want and adjust - // as needed. - BOOL success; - NSError *error; + case AVAudioSessionRouteChangeReasonCategoryChange: + // The category has changed. Check if it's the one we want and adjust as + // needed. + [self setCategory:_category mode:_mode error:nil]; + break; - if (_session.category != _category) { - success = [_session setCategory: _category error: &error]; - if (!success || error) { - RCTLogInfo(@"Error overriding the desired session category"); - } - } - - if (_session.mode != _mode) { - success = [_session setMode: _mode error: &error]; - if (!success || error) { - RCTLogInfo(@"Error overriding the desired session mode"); - } - } - } default: - // Do nothing + // Do nothing. break; } } -- (NSDictionary *)constantsToExport -{ - return @{ @"AUDIO_CALL" : [NSNumber numberWithInt: kAudioModeAudioCall], - @"VIDEO_CALL" : [NSNumber numberWithInt: kAudioModeVideoCall], - @"DEFAULT" : [NSNumber numberWithInt: kAudioModeDefault] - }; -}; +- (BOOL)setCategory:(NSString *)category + mode:(NSString *)mode + error:(NSError * _Nullable *)outError { + AVAudioSession *session = [AVAudioSession sharedInstance]; + + if (session.category != category + && ![session setCategory:category error:outError]) { + RCTLogError(@"Failed to (re)apply specified AVAudioSession category!"); + return NO; + } + + if (session.mode != mode && ![session setMode:mode error:outError]) { + RCTLogError(@"Failed to (re)apply specified AVAudioSession mode!"); + return NO; + } + + return YES; +} RCT_EXPORT_METHOD(setMode:(int)mode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - NSError *error; - BOOL success; NSString *avCategory; NSString *avMode; + NSError *error; switch (mode) { case kAudioModeAudioCall: avCategory = AVAudioSessionCategoryPlayAndRecord; avMode = AVAudioSessionModeVoiceChat; break; - case kAudioModeVideoCall: - avCategory = AVAudioSessionCategoryPlayAndRecord; - avMode = AVAudioSessionModeVideoChat; - break; case kAudioModeDefault: avCategory = AVAudioSessionCategorySoloAmbient; avMode = AVAudioSessionModeDefault; break; + case kAudioModeVideoCall: + avCategory = AVAudioSessionCategoryPlayAndRecord; + avMode = AVAudioSessionModeVideoChat; + break; default: reject(@"setMode", @"Invalid mode", nil); return; } - // Configure AVAudioSession category - success = [_session setCategory: avCategory error: &error]; - if (!success || error) { + if (![self setCategory:avCategory mode:avMode error:&error] || error) { reject(@"setMode", error.localizedDescription, error); return; } - // Configure AVAudioSession mode - success = [_session setMode: avMode error: &error]; - if (!success || error) { - reject(@"setMode", error.localizedDescription, error); - return; + // Even though the specified category and mode were successfully set, the + // AVAudioSession is a singleton and other parts of the application such as + // WebRTC may undo the settings. Make sure that the settings are reapplied + // upon undoes. + if (!_category || !_mode) { + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(routeChanged:) + name:AVAudioSessionRouteChangeNotification + object:nil]; } - // Save the desired mode and category + // Save the desired/specified category and mode so that they may be + // reapplied (upon undoes as described above). _category = avCategory; _mode = avMode; - // Initialize audio route changes observer if needed - if (!_initialized) { - [[NSNotificationCenter defaultCenter] addObserver: self - selector: @selector(routeChanged:) - name: AVAudioSessionRouteChangeNotification - object: nil]; - _initialized = YES; - } - resolve(nil); } diff --git a/ios/app/POSIX.h b/ios/app/POSIX.h deleted file mode 100644 index 1f589fb55..000000000 --- a/ios/app/POSIX.h +++ /dev/null @@ -1,4 +0,0 @@ -#import "RCTBridgeModule.h" - -@interface POSIX : NSObject -@end diff --git a/ios/app/POSIX.m b/ios/app/POSIX.m index 8f6af0ff7..19a5a3713 100644 --- a/ios/app/POSIX.m +++ b/ios/app/POSIX.m @@ -1,10 +1,13 @@ -#import "POSIX.h" +#import "RCTBridgeModule.h" #include #include #include #include +@interface POSIX : NSObject +@end + @implementation POSIX RCT_EXPORT_MODULE(); diff --git a/ios/jitsi-meet-react.xcodeproj/project.pbxproj b/ios/jitsi-meet-react.xcodeproj/project.pbxproj index 937237c99..ee33635ac 100644 --- a/ios/jitsi-meet-react.xcodeproj/project.pbxproj +++ b/ios/jitsi-meet-react.xcodeproj/project.pbxproj @@ -206,7 +206,6 @@ 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; }; 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; }; 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; }; - 0B42DFAC1E2FD90700111B12 /* AudioMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioMode.h; path = app/AudioMode.h; sourceTree = ""; }; 0B42DFAD1E2FD90700111B12 /* AudioMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AudioMode.m; path = app/AudioMode.m; sourceTree = ""; }; 0EA8C046B2BF46279796F07D /* libKCKeepAwake.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libKCKeepAwake.a; sourceTree = ""; }; 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; @@ -226,7 +225,6 @@ 821D8ABD506944B4BDBB069B /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = ""; }; 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; B30EF2301DC0ED7C00690F45 /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = "../node_modules/react-native-webrtc/ios/WebRTC.framework"; sourceTree = ""; }; - B3A9D0231E0481E10009343D /* POSIX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = POSIX.h; path = app/POSIX.h; sourceTree = ""; }; B3A9D0241E0481E10009343D /* POSIX.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = POSIX.m; path = app/POSIX.m; sourceTree = ""; }; B3B083EB1D4955FF0069CEE7 /* jitsi-meet-react.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "jitsi-meet-react.entitlements"; sourceTree = ""; }; B96AF9B6FBC0453798399985 /* FontAwesome.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf"; sourceTree = ""; }; @@ -351,14 +349,12 @@ children = ( 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 13B07FB01A68108700A75B9A /* AppDelegate.m */, - 0B42DFAC1E2FD90700111B12 /* AudioMode.h */, 0B42DFAD1E2FD90700111B12 /* AudioMode.m */, 13B07FB51A68108700A75B9A /* Images.xcassets */, 13B07FB61A68108700A75B9A /* Info.plist */, 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, 008F07F21AC5B25A0029DE68 /* main.jsbundle */, 13B07FB71A68108700A75B9A /* main.m */, - B3A9D0231E0481E10009343D /* POSIX.h */, B3A9D0241E0481E10009343D /* POSIX.m */, ); name = app; @@ -402,6 +398,7 @@ 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( + 5B09C20C78C74A548AAAC1FA /* KCKeepAwake.xcodeproj */, BF96438F1C34FBEB00B0BBDF /* libc.tbd */, BF9643911C34FBF100B0BBDF /* libsqlite3.tbd */, BF9643931C34FBF900B0BBDF /* libstdc++.tbd */, @@ -417,7 +414,6 @@ 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, 146833FF1AC3E56700842450 /* React.xcodeproj */, 22418656B14845609F953A42 /* RNVectorIcons.xcodeproj */, - 5B09C20C78C74A548AAAC1FA /* KCKeepAwake.xcodeproj */, ); name = Libraries; sourceTree = ""; diff --git a/react/features/audio-mode/middleware.js b/react/features/audio-mode/middleware.js index 5d3b9df50..716185623 100644 --- a/react/features/audio-mode/middleware.js +++ b/react/features/audio-mode/middleware.js @@ -1,4 +1,4 @@ -import { AudioMode } from '../base/react-native'; +import { NativeModules } from 'react-native'; import { APP_WILL_MOUNT } from '../app'; import { @@ -6,50 +6,51 @@ import { CONFERENCE_LEFT, CONFERENCE_WILL_JOIN } from '../base/conference'; - import { MiddlewareRegistry } from '../base/redux'; /** - * Middleware that captures conference actions and sets the correct audio - * mode based on the type of conference. Audio-only conferences don't - * use the speaker by default, and video conferences do. + * Middleware that captures conference actions and sets the correct audio mode + * based on the type of conference. Audio-only conferences don't use the speaker + * by default, and video conferences do. * * @param {Store} store - Redux store. * @returns {Function} */ MiddlewareRegistry.register(store => next => action => { - switch (action.type) { - case APP_WILL_MOUNT: { - AudioMode.setMode(AudioMode.DEFAULT) - .catch(err => { - console.warn(`Error setting audio mode: ${err}`); - }); - break; - } - case CONFERENCE_WILL_JOIN: { - let mode; - const state = store.getState()['features/base/conference']; + const AudioMode = NativeModules.AudioMode; - if (state.audioOnly) { - // TODO(saghul): Implement audio-only mode - mode = AudioMode.AUDIO_CALL; - } else { - mode = AudioMode.VIDEO_CALL; + // The react-native module AudioMode is implemented on iOS at the time of + // this writing. + if (AudioMode) { + let audioMode; + + switch (action.type) { + case APP_WILL_MOUNT: + case CONFERENCE_FAILED: + case CONFERENCE_LEFT: + audioMode = AudioMode.DEFAULT; + break; + + case CONFERENCE_WILL_JOIN: { + const conference = store.getState()['features/base/conference']; + + audioMode + = conference.audioOnly + ? AudioMode.AUDIO_CALL + : AudioMode.VIDEO_CALL; + break; } - AudioMode.setMode(mode) - .catch(err => { - console.warn(`Error setting audio mode: ${err}`); + default: + audioMode = null; + break; + } + + if (audioMode !== null) { + AudioMode.setMode(audioMode).catch(err => { + console.error(`Failed to set audio mode ${audioMode}: ${err}`); }); - break; - } - case CONFERENCE_FAILED: - case CONFERENCE_LEFT: - AudioMode.setMode(AudioMode.DEFAULT) - .catch(err => { - console.warn(`Error setting audio mode: ${err}`); - }); - break; + } } return next(action); diff --git a/react/features/base/conference/actionTypes.js b/react/features/base/conference/actionTypes.js index 2624c341e..69c622977 100644 --- a/react/features/base/conference/actionTypes.js +++ b/react/features/base/conference/actionTypes.js @@ -23,17 +23,6 @@ export const CONFERENCE_FAILED = Symbol('CONFERENCE_FAILED'); */ export const CONFERENCE_JOINED = Symbol('CONFERENCE_JOINED'); -/** - * The type of the Redux action which signals that a specific conference will be - * joined. - * - * { - * type: CONFERENCE_WILL_JOIN, - * room: string - * } - */ -export const CONFERENCE_WILL_JOIN = Symbol('CONFERENCE_WILL_JOIN'); - /** * The type of the Redux action which signals that a specific conference has * been left. @@ -45,6 +34,17 @@ export const CONFERENCE_WILL_JOIN = Symbol('CONFERENCE_WILL_JOIN'); */ export const CONFERENCE_LEFT = Symbol('CONFERENCE_LEFT'); +/** + * The type of the Redux action which signals that a specific conference will be + * joined. + * + * { + * type: CONFERENCE_WILL_JOIN, + * room: string + * } + */ +export const CONFERENCE_WILL_JOIN = Symbol('CONFERENCE_WILL_JOIN'); + /** * The type of the Redux action which signals that a specific conference will be * left. diff --git a/react/features/base/conference/actions.js b/react/features/base/conference/actions.js index 39547ee46..bb2102267 100644 --- a/react/features/base/conference/actions.js +++ b/react/features/base/conference/actions.js @@ -124,26 +124,6 @@ function _conferenceJoined(conference) { }; } -/** - * Signals the intention of the application to have the local participant leave - * a specific conference. Similar in fashion to CONFERENCE_LEFT. Contrary to it - * though, it's not guaranteed because CONFERENCE_LEFT may be triggered by - * lib-jitsi-meet and not the application. - * - * @param {string} room - The JitsiConference instance which will - * be left by the local participant. - * @returns {{ - * type: CONFERENCE_WILL_JOIN, - * room: string - * }} - */ -function _conferenceWillJoin(room) { - return { - type: CONFERENCE_WILL_JOIN, - room - }; -} - /** * Signals that a specific conference has been left. * @@ -161,6 +141,25 @@ function _conferenceLeft(conference) { }; } +/** + * Signals the intention of the application to have the local participant join a + * conference with a specific room (name). Similar in fashion + * to CONFERENCE_JOINED. + * + * @param {string} room - The room (name) which identifies the conference the + * local participant will (try to) join. + * @returns {{ + * type: CONFERENCE_WILL_JOIN, + * room: string + * }} + */ +function _conferenceWillJoin(room) { + return { + type: CONFERENCE_WILL_JOIN, + room + }; +} + /** * Signals the intention of the application to have the local participant leave * a specific conference. Similar in fashion to CONFERENCE_LEFT. Contrary to it @@ -201,15 +200,14 @@ export function createConference() { throw new Error('Cannot join conference without room name'); } - // XXX Lib-jitsi-meet does not accept uppercase letters. - const _room = room.toLowerCase(); - - dispatch(_conferenceWillJoin(_room)); + dispatch(_conferenceWillJoin(room)); // TODO Take options from config. const conference = connection.initJitsiConference( - _room, + + // XXX Lib-jitsi-meet does not accept uppercase letters. + room.toLowerCase(), { openSctp: true }); _addConferenceListeners(conference, dispatch); diff --git a/react/features/base/react-native/AudioMode.js b/react/features/base/react-native/AudioMode.js deleted file mode 100644 index 3a4bb6c48..000000000 --- a/react/features/base/react-native/AudioMode.js +++ /dev/null @@ -1,20 +0,0 @@ -import { NativeModules } from 'react-native'; -import { Platform } from '../react'; - -let AudioMode; - -if (Platform.OS === 'ios') { - AudioMode = NativeModules.AudioMode; -} else { - // TODO(saghul): Implement for Android - AudioMode = { - DEFAULT: 0, - AUDIO_CALL: 1, - VIDEO_CALL: 2, - setMode() { - return Promise.resolve(null); - } - }; -} - -export default AudioMode; diff --git a/react/features/base/react-native/index.js b/react/features/base/react-native/index.js index 0e27480f9..0690ec17f 100644 --- a/react/features/base/react-native/index.js +++ b/react/features/base/react-native/index.js @@ -1,2 +1 @@ -export { default as AudioMode } from './AudioMode'; export { default as POSIX } from './POSIX';