2017-01-20 18:11:11 +00:00
|
|
|
#import "RCTBridgeModule.h"
|
2017-01-18 19:30:11 +00:00
|
|
|
#import "RCTLog.h"
|
|
|
|
|
2017-01-20 18:11:11 +00:00
|
|
|
#import <AVFoundation/AVFoundation.h>
|
2017-01-18 19:30:11 +00:00
|
|
|
|
2017-01-20 18:11:11 +00:00
|
|
|
@interface AudioMode : NSObject<RCTBridgeModule>
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation AudioMode {
|
|
|
|
NSString *_category;
|
|
|
|
NSString *_mode;
|
|
|
|
}
|
2017-01-18 19:30:11 +00:00
|
|
|
|
|
|
|
RCT_EXPORT_MODULE();
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
kAudioModeDefault,
|
|
|
|
kAudioModeAudioCall,
|
|
|
|
kAudioModeVideoCall
|
|
|
|
} JitsiMeetAudioMode;
|
|
|
|
|
2017-01-20 18:11:11 +00:00
|
|
|
- (NSDictionary *)constantsToExport {
|
|
|
|
return @{
|
|
|
|
@"AUDIO_CALL" : [NSNumber numberWithInt: kAudioModeAudioCall],
|
|
|
|
@"DEFAULT" : [NSNumber numberWithInt: kAudioModeDefault],
|
|
|
|
@"VIDEO_CALL" : [NSNumber numberWithInt: kAudioModeVideoCall]
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
- (instancetype)init {
|
2017-01-18 19:30:11 +00:00
|
|
|
self = [super init];
|
|
|
|
if (self) {
|
|
|
|
_category = nil;
|
|
|
|
_mode = nil;
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2017-01-20 18:11:11 +00:00
|
|
|
- (dispatch_queue_t)methodQueue {
|
2017-01-18 19:30:11 +00:00
|
|
|
// 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).
|
|
|
|
return dispatch_get_main_queue();
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)routeChanged:(NSNotification*)notification {
|
2017-01-20 18:11:11 +00:00
|
|
|
NSInteger reason
|
|
|
|
= [[notification.userInfo
|
|
|
|
valueForKey:AVAudioSessionRouteChangeReasonKey]
|
|
|
|
integerValue];
|
|
|
|
|
2017-01-18 19:30:11 +00:00
|
|
|
switch (reason) {
|
2017-01-20 18:11:11 +00:00
|
|
|
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;
|
|
|
|
|
2017-01-18 19:30:11 +00:00
|
|
|
default:
|
2017-01-20 18:11:11 +00:00
|
|
|
// Do nothing.
|
2017-01-18 19:30:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-20 18:11:11 +00:00
|
|
|
- (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;
|
|
|
|
}
|
2017-01-18 19:30:11 +00:00
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(setMode:(int)mode
|
|
|
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
|
|
reject:(RCTPromiseRejectBlock)reject) {
|
|
|
|
NSString *avCategory;
|
|
|
|
NSString *avMode;
|
2017-01-20 18:11:11 +00:00
|
|
|
NSError *error;
|
2017-01-18 19:30:11 +00:00
|
|
|
|
|
|
|
switch (mode) {
|
|
|
|
case kAudioModeAudioCall:
|
|
|
|
avCategory = AVAudioSessionCategoryPlayAndRecord;
|
|
|
|
avMode = AVAudioSessionModeVoiceChat;
|
|
|
|
break;
|
|
|
|
case kAudioModeDefault:
|
|
|
|
avCategory = AVAudioSessionCategorySoloAmbient;
|
|
|
|
avMode = AVAudioSessionModeDefault;
|
|
|
|
break;
|
2017-01-20 18:11:11 +00:00
|
|
|
case kAudioModeVideoCall:
|
|
|
|
avCategory = AVAudioSessionCategoryPlayAndRecord;
|
|
|
|
avMode = AVAudioSessionModeVideoChat;
|
|
|
|
break;
|
2017-01-18 19:30:11 +00:00
|
|
|
default:
|
|
|
|
reject(@"setMode", @"Invalid mode", nil);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-20 18:11:11 +00:00
|
|
|
if (![self setCategory:avCategory mode:avMode error:&error] || error) {
|
2017-01-18 19:30:11 +00:00
|
|
|
reject(@"setMode", error.localizedDescription, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-20 18:11:11 +00:00
|
|
|
// 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];
|
2017-01-18 19:30:11 +00:00
|
|
|
}
|
|
|
|
|
2017-01-20 18:11:11 +00:00
|
|
|
// Save the desired/specified category and mode so that they may be
|
|
|
|
// reapplied (upon undoes as described above).
|
2017-01-18 19:30:11 +00:00
|
|
|
_category = avCategory;
|
|
|
|
_mode = avMode;
|
|
|
|
|
|
|
|
resolve(nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|