@cloudflare/realtimekit-react-native 0.0.0 → 0.0.1-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +13 -0
- package/README.md +83 -0
- package/RealtimeKitCore.podspec +19 -0
- package/android/build.gradle +58 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/android/gradlew +185 -0
- package/android/gradlew.bat +89 -0
- package/android/src/main/AndroidManifest.xml +23 -0
- package/android/src/main/java/com/reactnativecore/BackgroundTimer/RNBackgroundTimer.java +97 -0
- package/android/src/main/java/com/reactnativecore/Constants.java +14 -0
- package/android/src/main/java/com/reactnativecore/CoreModule.java +49 -0
- package/android/src/main/java/com/reactnativecore/CorePackage.java +34 -0
- package/android/src/main/java/com/reactnativecore/DyteHelperModule.java +268 -0
- package/android/src/main/java/com/reactnativecore/DyteHolder.java +7 -0
- package/android/src/main/java/com/reactnativecore/ForegroundService.java +48 -0
- package/android/src/main/java/com/reactnativecore/NotificationHelper.java +127 -0
- package/android/src/main/java/com/reactnativecore/RNPermissionsModule.java +226 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/AppRTCBluetoothManager.java +637 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/AppRTCProximitySensor.java +133 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/AppRTCUtils.java +41 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/InCallManagerModule.java +1881 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/InCallProximityManager.java +162 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/InCallWakeLockUtils.java +116 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/ThreadUtils.java +39 -0
- package/app.plugin.js +1 -0
- package/ios/BroadcastEventEmitter.h +11 -0
- package/ios/BroadcastEventEmitter.m +72 -0
- package/ios/Core.h +5 -0
- package/ios/Core.m +28 -0
- package/ios/Core.xcodeproj/project.pbxproj +287 -0
- package/ios/DyteRNBackgroundTimer.h +22 -0
- package/ios/DyteRNBackgroundTimer.m +90 -0
- package/ios/DyteRNPermissionHandlerNotifications.h +17 -0
- package/ios/DyteRNPermissionHandlerNotifications.m +127 -0
- package/ios/DyteRNPermissions.h +50 -0
- package/ios/DyteRNPermissions.m +275 -0
- package/ios/DyteScreensharePickerView.h +8 -0
- package/ios/DyteScreensharePickerView.m +27 -0
- package/ios/PrivacyInfo.xcprivacy +60 -0
- package/ios/RNInCallManager.h +16 -0
- package/ios/RNInCallManager.m +1354 -0
- package/ios/permissions/DyteRNPermissionHandlerBluetoothPeripheral.h +4 -0
- package/ios/permissions/DyteRNPermissionHandlerBluetoothPeripheral.m +87 -0
- package/ios/permissions/DyteRNPermissionHandlerCamera.h +5 -0
- package/ios/permissions/DyteRNPermissionHandlerCamera.m +38 -0
- package/ios/permissions/DyteRNPermissionHandlerMicrophone.h +5 -0
- package/ios/permissions/DyteRNPermissionHandlerMicrophone.m +34 -0
- package/ios/permissions/DyteRNPermissionHandlerPhotoLibrary.h +8 -0
- package/ios/permissions/DyteRNPermissionHandlerPhotoLibrary.m +70 -0
- package/ios/screenshare/DyteDarwinNotificationCenter.swift +21 -0
- package/ios/screenshare/DyteScreenshareAtomic.swift +29 -0
- package/ios/screenshare/DyteScreenshareHandler.swift +103 -0
- package/ios/screenshare/DyteScreenshareUploader.swift +139 -0
- package/ios/screenshare/DyteSocketConnection.swift +190 -0
- package/lib/BackgroundHandler.d.ts +20 -0
- package/lib/BackgroundHandler.js +87 -0
- package/lib/LocalMediaError.d.ts +4 -0
- package/lib/LocalMediaError.js +6 -0
- package/lib/LocalMediaHandler.d.ts +118 -0
- package/lib/LocalMediaHandler.js +853 -0
- package/lib/LocalMediaInterfaces.d.ts +76 -0
- package/lib/LocalMediaInterfaces.js +1 -0
- package/lib/LocalMediaUtils.d.ts +93 -0
- package/lib/LocalMediaUtils.js +276 -0
- package/lib/NativeAudioManager.d.ts +16 -0
- package/lib/NativeAudioManager.js +93 -0
- package/lib/PermissionHandler.d.ts +34 -0
- package/lib/PermissionHandler.js +179 -0
- package/lib/ReactContext.d.ts +42 -0
- package/lib/ReactContext.js +96 -0
- package/lib/ReactHooks.d.ts +11 -0
- package/lib/ReactHooks.js +73 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.js +40 -0
- package/lib/utils/crypto.d.ts +17 -0
- package/lib/utils/crypto.js +82 -0
- package/package.json +51 -4
- package/plugin/build/withDyte.d.ts +25 -0
- package/plugin/build/withDyte.js +100 -0
- package/plugin/src/withDyte.ts +150 -0
- package/plugin/tsconfig.json +10 -0
- package/plugin/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,1354 @@
|
|
|
1
|
+
#import "RNInCallManager.h"
|
|
2
|
+
#import <React/RCTBridge.h>
|
|
3
|
+
#import <React/RCTConvert.h>
|
|
4
|
+
#import <React/RCTEventDispatcher.h>
|
|
5
|
+
#import <React/RCTUtils.h>
|
|
6
|
+
|
|
7
|
+
//static BOOL const automatic = YES;
|
|
8
|
+
|
|
9
|
+
@implementation RNInCallManager
|
|
10
|
+
|
|
11
|
+
{
|
|
12
|
+
|
|
13
|
+
UIDevice *_currentDevice;
|
|
14
|
+
|
|
15
|
+
AVAudioSession *_audioSession;
|
|
16
|
+
AVAudioPlayer *_ringtone;
|
|
17
|
+
AVAudioPlayer *_ringback;
|
|
18
|
+
AVAudioPlayer *_busytone;
|
|
19
|
+
|
|
20
|
+
NSURL *_defaultRingtoneUri;
|
|
21
|
+
NSURL *_defaultRingbackUri;
|
|
22
|
+
NSURL *_defaultBusytoneUri;
|
|
23
|
+
NSURL *_bundleRingtoneUri;
|
|
24
|
+
NSURL *_bundleRingbackUri;
|
|
25
|
+
NSURL *_bundleBusytoneUri;
|
|
26
|
+
|
|
27
|
+
//BOOL isProximitySupported;
|
|
28
|
+
BOOL _proximityIsNear;
|
|
29
|
+
|
|
30
|
+
// --- tags to indicating which observer has added
|
|
31
|
+
BOOL _isProximityRegistered;
|
|
32
|
+
BOOL _isAudioSessionInterruptionRegistered;
|
|
33
|
+
BOOL _isAudioSessionRouteChangeRegistered;
|
|
34
|
+
BOOL _isAudioSessionMediaServicesWereLostRegistered;
|
|
35
|
+
BOOL _isAudioSessionMediaServicesWereResetRegistered;
|
|
36
|
+
BOOL _isAudioSessionSilenceSecondaryAudioHintRegistered;
|
|
37
|
+
|
|
38
|
+
// -- notification observers
|
|
39
|
+
id _proximityObserver;
|
|
40
|
+
id _audioSessionInterruptionObserver;
|
|
41
|
+
id _audioSessionRouteChangeObserver;
|
|
42
|
+
id _audioSessionMediaServicesWereLostObserver;
|
|
43
|
+
id _audioSessionMediaServicesWereResetObserver;
|
|
44
|
+
id _audioSessionSilenceSecondaryAudioHintObserver;
|
|
45
|
+
|
|
46
|
+
NSString *_incallAudioMode;
|
|
47
|
+
NSString *_incallAudioCategory;
|
|
48
|
+
NSString *_origAudioCategory;
|
|
49
|
+
NSString *_origAudioMode;
|
|
50
|
+
NSString *_userSelectedAudioRoute;
|
|
51
|
+
NSString *_currentAudioRoute;
|
|
52
|
+
BOOL _audioSessionInitialized;
|
|
53
|
+
int _forceSpeakerOn;
|
|
54
|
+
int _turnBluetoothOn;
|
|
55
|
+
NSString *_media;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
+ (BOOL)requiresMainQueueSetup
|
|
59
|
+
{
|
|
60
|
+
return NO;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
RCT_EXPORT_MODULE(InCallManager)
|
|
64
|
+
|
|
65
|
+
- (instancetype)init
|
|
66
|
+
{
|
|
67
|
+
if (self = [super init]) {
|
|
68
|
+
_currentDevice = [UIDevice currentDevice];
|
|
69
|
+
_audioSession = [AVAudioSession sharedInstance];
|
|
70
|
+
_ringtone = nil;
|
|
71
|
+
_ringback = nil;
|
|
72
|
+
_busytone = nil;
|
|
73
|
+
|
|
74
|
+
_defaultRingtoneUri = nil;
|
|
75
|
+
_defaultRingbackUri = nil;
|
|
76
|
+
_defaultBusytoneUri = nil;
|
|
77
|
+
_bundleRingtoneUri = nil;
|
|
78
|
+
_bundleRingbackUri = nil;
|
|
79
|
+
_bundleBusytoneUri = nil;
|
|
80
|
+
|
|
81
|
+
_proximityIsNear = NO;
|
|
82
|
+
|
|
83
|
+
_isProximityRegistered = NO;
|
|
84
|
+
_isAudioSessionInterruptionRegistered = NO;
|
|
85
|
+
_isAudioSessionRouteChangeRegistered = NO;
|
|
86
|
+
_isAudioSessionMediaServicesWereLostRegistered = NO;
|
|
87
|
+
_isAudioSessionMediaServicesWereResetRegistered = NO;
|
|
88
|
+
_isAudioSessionSilenceSecondaryAudioHintRegistered = NO;
|
|
89
|
+
|
|
90
|
+
_proximityObserver = nil;
|
|
91
|
+
_audioSessionInterruptionObserver = nil;
|
|
92
|
+
_audioSessionRouteChangeObserver = nil;
|
|
93
|
+
_audioSessionMediaServicesWereLostObserver = nil;
|
|
94
|
+
_audioSessionMediaServicesWereResetObserver = nil;
|
|
95
|
+
_audioSessionSilenceSecondaryAudioHintObserver = nil;
|
|
96
|
+
|
|
97
|
+
_incallAudioMode = AVAudioSessionModeVoiceChat;
|
|
98
|
+
_incallAudioCategory = AVAudioSessionCategoryPlayAndRecord;
|
|
99
|
+
_origAudioCategory = nil;
|
|
100
|
+
_origAudioMode = nil;
|
|
101
|
+
_audioSessionInitialized = NO;
|
|
102
|
+
_forceSpeakerOn = 0;
|
|
103
|
+
_media = @"audio";
|
|
104
|
+
|
|
105
|
+
// NSLog(@"RNInCallManager.init(): initialized");
|
|
106
|
+
}
|
|
107
|
+
return self;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
- (void)dealloc
|
|
111
|
+
{
|
|
112
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
113
|
+
[self stop:@""];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
//Supported events
|
|
117
|
+
- (NSArray<NSString *> *)supportedEvents
|
|
118
|
+
{
|
|
119
|
+
return @[@"Proximity",
|
|
120
|
+
@"WiredHeadset",
|
|
121
|
+
@"onAudioDeviceChanged",
|
|
122
|
+
@"Bluetooth"];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
RCT_EXPORT_METHOD(start:(NSString *)mediaType
|
|
126
|
+
auto:(BOOL)_auto
|
|
127
|
+
ringbackUriType:(NSString *)ringbackUriType)
|
|
128
|
+
{
|
|
129
|
+
// NSLog(@"🤟 Starting InCall manager 🤟 ");
|
|
130
|
+
if (_audioSessionInitialized) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
_media = mediaType;
|
|
134
|
+
|
|
135
|
+
// --- auto is always true on ios
|
|
136
|
+
// if ([_media isEqualToString:@"video"]) {
|
|
137
|
+
// _incallAudioMode = AVAudioSessionModeVideoChat;
|
|
138
|
+
// } else {
|
|
139
|
+
// _incallAudioMode = AVAudioSessionModeVoiceChat;
|
|
140
|
+
// }
|
|
141
|
+
_incallAudioMode = AVAudioSessionModeVoiceChat;
|
|
142
|
+
// NSLog(@"🧑💻 RNInCallManager.start() start InCallManager. media=%@, type=%@, mode=%@", _media, _media, _incallAudioMode);
|
|
143
|
+
[self storeOriginalAudioSetup];
|
|
144
|
+
_forceSpeakerOn = 0;
|
|
145
|
+
[self startAudioSessionNotification];
|
|
146
|
+
[self audioSessionSetCategory:_incallAudioCategory
|
|
147
|
+
options:0
|
|
148
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
149
|
+
[self audioSessionSetMode:_incallAudioMode
|
|
150
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
151
|
+
[self audioSessionSetActive:YES
|
|
152
|
+
options:0
|
|
153
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
154
|
+
|
|
155
|
+
if (ringbackUriType.length > 0) {
|
|
156
|
+
// NSLog(@"RNInCallManager.start() play ringback first. type=%@", ringbackUriType);
|
|
157
|
+
[self startRingback:ringbackUriType];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// if ([_media isEqualToString:@"audio"]) {
|
|
161
|
+
// [self startProximitySensor];
|
|
162
|
+
// }
|
|
163
|
+
[self setKeepScreenOn:YES];
|
|
164
|
+
_audioSessionInitialized = YES;
|
|
165
|
+
//self.debugAudioSession()
|
|
166
|
+
// NSLog(@"🤟 Audio Session Initalized 🤟 ");
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
RCT_EXPORT_METHOD(chooseAudioRoute: (NSString *)audioRoute Promise:(RCTPromiseResolveBlock)resolve
|
|
170
|
+
reject:(RCTPromiseRejectBlock)reject) {
|
|
171
|
+
// NSLog(@"💂♂️💂♂️ choseAudio Route Called");
|
|
172
|
+
// NSLog(@"👨💻 Selected Audio Route: %@", audioRoute);
|
|
173
|
+
BOOL success;
|
|
174
|
+
// SPEAKER_PHONE,
|
|
175
|
+
// WIRED_HEADSET,
|
|
176
|
+
// EARPIECE,
|
|
177
|
+
// BLUETOOTH,
|
|
178
|
+
// NONE
|
|
179
|
+
// TODO: Create enums for AudioRoute
|
|
180
|
+
_userSelectedAudioRoute = audioRoute;
|
|
181
|
+
if (![_userSelectedAudioRoute isEqualToString:_currentAudioRoute]) {
|
|
182
|
+
if ([audioRoute isEqual: @"SPEAKER_PHONE"] || [audioRoute isEqualToString:@"speaker"]) {
|
|
183
|
+
_forceSpeakerOn = 1;
|
|
184
|
+
[self updateAudioRoute];
|
|
185
|
+
success = true;
|
|
186
|
+
} else if ([audioRoute isEqualToString:@"WIRED_HEADSET"] || [audioRoute isEqualToString:@"wired"]) {
|
|
187
|
+
_forceSpeakerOn = 0;
|
|
188
|
+
success = [self routeAudioFromEarpiece];
|
|
189
|
+
} else if ([audioRoute isEqual: @"EARPIECE"] || [audioRoute isEqualToString:@"earpiece"]) {
|
|
190
|
+
_forceSpeakerOn = 0;
|
|
191
|
+
success = [self routeAudioFromEarpiece];
|
|
192
|
+
} else if ([audioRoute isEqualToString:@"BLUETOOTH"] || [audioRoute isEqualToString:@"bluetooth"]) {
|
|
193
|
+
_forceSpeakerOn = 0;
|
|
194
|
+
success = [self routeAudioFromBluetooth];
|
|
195
|
+
}
|
|
196
|
+
//TODO: Better Error Handling
|
|
197
|
+
if (success) {
|
|
198
|
+
resolve(@"🎉 Audio Route sucessfully changed");
|
|
199
|
+
} else {
|
|
200
|
+
reject(@"😭 error_code", @"getAudioUriJS() failed in chooseAudioRoute", RCTErrorWithMessage(@"Failed to change audio route"));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
- (void)updateAudioDeviceState:(NSString *)audioDevice {
|
|
206
|
+
// check if route exist and value isn't null
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
RCT_EXPORT_METHOD(stop:(NSString *)busytoneUriType)
|
|
211
|
+
{
|
|
212
|
+
if (!_audioSessionInitialized) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
[self stopRingback];
|
|
217
|
+
|
|
218
|
+
if (busytoneUriType.length > 0 && [self startBusytone:busytoneUriType]) {
|
|
219
|
+
// play busytone first, and call this func again when finish
|
|
220
|
+
// NSLog(@"RNInCallManager.stop(): play busytone before stop");
|
|
221
|
+
return;
|
|
222
|
+
} else {
|
|
223
|
+
// NSLog(@"RNInCallManager.stop(): stop InCallManager");
|
|
224
|
+
[self restoreOriginalAudioSetup];
|
|
225
|
+
[self stopBusytone];
|
|
226
|
+
[self stopProximitySensor];
|
|
227
|
+
[self audioSessionSetActive:NO
|
|
228
|
+
options:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
|
|
229
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
230
|
+
[self setKeepScreenOn:NO];
|
|
231
|
+
[self stopAudioSessionNotification];
|
|
232
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
233
|
+
_forceSpeakerOn = 0;
|
|
234
|
+
_audioSessionInitialized = NO;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
RCT_EXPORT_METHOD(turnScreenOn)
|
|
239
|
+
{
|
|
240
|
+
// NSLog(@"RNInCallManager.turnScreenOn(): ios doesn't support turnScreenOn()");
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
RCT_EXPORT_METHOD(turnScreenOff)
|
|
244
|
+
{
|
|
245
|
+
// NSLog(@"RNInCallManager.turnScreenOff(): ios doesn't support turnScreenOff()");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
RCT_EXPORT_METHOD(setFlashOn:(BOOL)enable
|
|
249
|
+
brightness:(nonnull NSNumber *)brightness)
|
|
250
|
+
{
|
|
251
|
+
if ([AVCaptureDevice class]) {
|
|
252
|
+
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
|
|
253
|
+
if (device.hasTorch && device.position == AVCaptureDevicePositionBack) {
|
|
254
|
+
@try {
|
|
255
|
+
[device lockForConfiguration:nil];
|
|
256
|
+
|
|
257
|
+
if (enable) {
|
|
258
|
+
[device setTorchMode:AVCaptureTorchModeOn];
|
|
259
|
+
} else {
|
|
260
|
+
[device setTorchMode:AVCaptureTorchModeOff];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
[device unlockForConfiguration];
|
|
264
|
+
} @catch (NSException *e) {}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
RCT_EXPORT_METHOD(setKeepScreenOn:(BOOL)enable)
|
|
270
|
+
{
|
|
271
|
+
// NSLog(@"RNInCallManager.setKeepScreenOn(): enable: %@", enable ? @"YES" : @"NO");
|
|
272
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
273
|
+
[[UIApplication sharedApplication] setIdleTimerDisabled:enable];
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
RCT_EXPORT_METHOD(setSpeakerphoneOn:(BOOL)enable)
|
|
280
|
+
{
|
|
281
|
+
if(!enable){
|
|
282
|
+
[self routeAudioFromEarpiece];
|
|
283
|
+
} else {
|
|
284
|
+
[self routeAudioFromSpeakerphone];
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
- (BOOL)routeAudioFromBluetooth {
|
|
289
|
+
NSError *error = nil;
|
|
290
|
+
_audioSession = [AVAudioSession sharedInstance];
|
|
291
|
+
for (AVAudioSessionPortDescription* input in [_audioSession availableInputs]) {
|
|
292
|
+
if ([[input portType] isEqualToString:AVAudioSessionPortBluetoothHFP] ||
|
|
293
|
+
[[input portType] isEqualToString:AVAudioSessionPortBluetoothA2DP] ||
|
|
294
|
+
[[input portType] isEqualToString:AVAudioSessionPortBluetoothLE]) {
|
|
295
|
+
// Turn off current input
|
|
296
|
+
@try {
|
|
297
|
+
[_audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:&error];
|
|
298
|
+
} @catch (NSException *e) {
|
|
299
|
+
// NSLog(@"😭 Unable to override audio port none in bluetooth %@", e.reason);
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
// set current input to bluetooth
|
|
303
|
+
@try {
|
|
304
|
+
[_audioSession setPreferredInput:input error:&error];
|
|
305
|
+
} @catch (NSException *e) {
|
|
306
|
+
// NSLog(@"😭 Unable to set audio input port to bluetooth%@", e.reason);
|
|
307
|
+
// Set Prefeered route to speaker
|
|
308
|
+
[self routeAudioFromSpeakerphone];
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
- (BOOL)routeAudioFromEarpiece {
|
|
319
|
+
BOOL success;
|
|
320
|
+
NSError *error = nil;
|
|
321
|
+
// NSLog(@"Routing audio via Earpiece");
|
|
322
|
+
@try {
|
|
323
|
+
|
|
324
|
+
success = [_audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
|
|
325
|
+
if (!success) NSLog(@"Cannot set category due to error: %@", error);
|
|
326
|
+
success = [_audioSession setMode:AVAudioSessionModeVoiceChat error:&error];
|
|
327
|
+
if (!success) NSLog(@"Cannot set mode due to error: %@", error);
|
|
328
|
+
[_audioSession setPreferredOutputNumberOfChannels:0 error:nil];
|
|
329
|
+
if (!success) NSLog(@"Port override failed due to: %@", error);
|
|
330
|
+
[_audioSession overrideOutputAudioPort:[AVAudioSessionPortBuiltInReceiver intValue] error:&error];
|
|
331
|
+
success = [_audioSession setActive:YES error:&error];
|
|
332
|
+
if (!success) {
|
|
333
|
+
NSLog(@"Audio session override failed: %@", error);
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
// NSLog(@"AudioSession override is successful ");
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
} @catch (NSException *e) {
|
|
341
|
+
NSLog(@"Error occurred while routing audio via Earpiece: %@", e.reason);
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
- (BOOL)routeAudioFromSpeakerphone
|
|
347
|
+
{
|
|
348
|
+
// NSLog(@"📘 Routing audio via Loudspeaker");
|
|
349
|
+
BOOL success;
|
|
350
|
+
NSError *error = nil;
|
|
351
|
+
@try {
|
|
352
|
+
success = [_audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
|
|
353
|
+
withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker
|
|
354
|
+
error:nil];
|
|
355
|
+
if (!success) {
|
|
356
|
+
NSLog(@"📕 Cannot set category due to error: %@", error);
|
|
357
|
+
}
|
|
358
|
+
success = [_audioSession setMode:AVAudioSessionModeVoiceChat error: &error];
|
|
359
|
+
if (!success) {
|
|
360
|
+
NSLog(@"📕 Cannot set mode due to error: %@", error);
|
|
361
|
+
}
|
|
362
|
+
[_audioSession overrideOutputAudioPort:[AVAudioSessionPortBuiltInSpeaker intValue] error: &error];
|
|
363
|
+
if (!success) {
|
|
364
|
+
NSLog(@"📕 Port override failed due to: %@", error);
|
|
365
|
+
}
|
|
366
|
+
success = [_audioSession setActive:YES error:&error];
|
|
367
|
+
if (!success) {
|
|
368
|
+
NSLog(@"📕 Audio session override failed: %@", error);
|
|
369
|
+
return false;
|
|
370
|
+
} else {
|
|
371
|
+
// NSLog(@"📗 Sucessfully routed audio from Loudspeaker");
|
|
372
|
+
return true;
|
|
373
|
+
}
|
|
374
|
+
} @catch (NSException *e) {
|
|
375
|
+
NSLog(@"📕 Error occurred while routing audio via Loudspeaker: %@", e.reason);
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
RCT_EXPORT_METHOD(setForceSpeakerphoneOn:(int)flag)
|
|
381
|
+
{
|
|
382
|
+
_forceSpeakerOn = flag;
|
|
383
|
+
// NSLog(@"RNInCallManager.setForceSpeakerphoneOn(): flag: %d", flag);
|
|
384
|
+
[self updateAudioRoute];
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
RCT_EXPORT_METHOD(setMicrophoneMute:(BOOL)enable)
|
|
388
|
+
{
|
|
389
|
+
// NSLog(@"RNInCallManager.setMicrophoneMute(): ios doesn't support setMicrophoneMute()");
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
RCT_EXPORT_METHOD(startRingback:(NSString *)_ringbackUriType)
|
|
393
|
+
{
|
|
394
|
+
// you may rejected by apple when publish app if you use system sound instead of bundled sound.
|
|
395
|
+
// NSLog(@"RNInCallManager.startRingback(): type=%@", _ringbackUriType);
|
|
396
|
+
|
|
397
|
+
@try {
|
|
398
|
+
if (_ringback != nil) {
|
|
399
|
+
if ([_ringback isPlaying]) {
|
|
400
|
+
// NSLog(@"RNInCallManager.startRingback(): is already playing");
|
|
401
|
+
return;
|
|
402
|
+
} else {
|
|
403
|
+
[self stopRingback];
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
// ios don't have embedded DTMF tone generator. use system dtmf sound files.
|
|
407
|
+
NSString *ringbackUriType = [_ringbackUriType isEqualToString:@"_DTMF_"]
|
|
408
|
+
? @"_DEFAULT_"
|
|
409
|
+
: _ringbackUriType;
|
|
410
|
+
NSURL *ringbackUri = [self getRingbackUri:ringbackUriType];
|
|
411
|
+
if (ringbackUri == nil) {
|
|
412
|
+
// NSLog(@"RNInCallManager.startRingback(): no available media");
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
//self.storeOriginalAudioSetup()
|
|
416
|
+
_ringback = [[AVAudioPlayer alloc] initWithContentsOfURL:ringbackUri error:nil];
|
|
417
|
+
_ringback.delegate = self;
|
|
418
|
+
_ringback.numberOfLoops = -1; // you need to stop it explicitly
|
|
419
|
+
[_ringback prepareToPlay];
|
|
420
|
+
|
|
421
|
+
//self.audioSessionSetCategory(self.incallAudioCategory, [.DefaultToSpeaker, .AllowBluetooth], #function)
|
|
422
|
+
[self audioSessionSetCategory:_incallAudioCategory
|
|
423
|
+
options:0
|
|
424
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
425
|
+
[self audioSessionSetMode:_incallAudioMode
|
|
426
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
427
|
+
[_ringback play];
|
|
428
|
+
} @catch (NSException *e) {
|
|
429
|
+
NSLog(@"RNInCallManager.startRingback(): caught error=%@", e.reason);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
RCT_EXPORT_METHOD(stopRingback)
|
|
434
|
+
{
|
|
435
|
+
if (_ringback != nil) {
|
|
436
|
+
// NSLog(@"RNInCallManager.stopRingback()");
|
|
437
|
+
[_ringback stop];
|
|
438
|
+
_ringback = nil;
|
|
439
|
+
// --- need to reset route based on config because WebRTC seems will switch audio mode automatically when call established.
|
|
440
|
+
//[self updateAudioRoute];
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
RCT_EXPORT_METHOD(startRingtone:(NSString *)ringtoneUriType
|
|
445
|
+
ringtoneCategory:(NSString *)ringtoneCategory)
|
|
446
|
+
{
|
|
447
|
+
// you may rejected by apple when publish app if you use system sound instead of bundled sound.
|
|
448
|
+
// NSLog(@"RNInCallManager.startRingtone(): type: %@", ringtoneUriType);
|
|
449
|
+
@try {
|
|
450
|
+
if (_ringtone != nil) {
|
|
451
|
+
if ([_ringtone isPlaying]) {
|
|
452
|
+
// NSLog(@"RNInCallManager.startRingtone(): is already playing.");
|
|
453
|
+
return;
|
|
454
|
+
} else {
|
|
455
|
+
[self stopRingtone];
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
NSURL *ringtoneUri = [self getRingtoneUri:ringtoneUriType];
|
|
459
|
+
if (ringtoneUri == nil) {
|
|
460
|
+
// NSLog(@"RNInCallManager.startRingtone(): no available media");
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// --- ios has Ringer/Silent switch, so just play without check ringer volume.
|
|
465
|
+
[self storeOriginalAudioSetup];
|
|
466
|
+
_ringtone = [[AVAudioPlayer alloc] initWithContentsOfURL:ringtoneUri error:nil];
|
|
467
|
+
_ringtone.delegate = self;
|
|
468
|
+
_ringtone.numberOfLoops = -1; // you need to stop it explicitly
|
|
469
|
+
[_ringtone prepareToPlay];
|
|
470
|
+
|
|
471
|
+
// --- 1. if we use Playback, it can supports background playing (starting from foreground), but it would not obey Ring/Silent switch.
|
|
472
|
+
// --- make sure you have enabled 'audio' tag ( or 'voip' tag ) at XCode -> Capabilities -> BackgroundMode
|
|
473
|
+
// --- 2. if we use SoloAmbient, it would obey Ring/Silent switch in the foreground, but does not support background playing,
|
|
474
|
+
// --- thus, then you should play ringtone again via local notification after back to home during a ring session.
|
|
475
|
+
|
|
476
|
+
// we prefer 2. by default, since most of users doesn't want to interrupted by a ringtone if Silent mode is on.
|
|
477
|
+
|
|
478
|
+
//self.audioSessionSetCategory(AVAudioSessionCategoryPlayback, [.DuckOthers], #function)
|
|
479
|
+
if ([ringtoneCategory isEqualToString:@"playback"]) {
|
|
480
|
+
[self audioSessionSetCategory:AVAudioSessionCategoryPlayback
|
|
481
|
+
options:0
|
|
482
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
483
|
+
} else {
|
|
484
|
+
[self audioSessionSetCategory:AVAudioSessionCategorySoloAmbient
|
|
485
|
+
options:0
|
|
486
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
487
|
+
}
|
|
488
|
+
[self audioSessionSetMode:AVAudioSessionModeDefault
|
|
489
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
490
|
+
//[self audioSessionSetActive:YES
|
|
491
|
+
// options:nil
|
|
492
|
+
// callerMemo:NSStringFromSelector(_cmd)];
|
|
493
|
+
[_ringtone play];
|
|
494
|
+
} @catch (NSException *e) {
|
|
495
|
+
NSLog(@"RNInCallManager.startRingtone(): caught error = %@", e.reason);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
RCT_EXPORT_METHOD(stopRingtone)
|
|
500
|
+
{
|
|
501
|
+
if (_ringtone != nil) {
|
|
502
|
+
// NSLog(@"RNInCallManager.stopRingtone()");
|
|
503
|
+
[_ringtone stop];
|
|
504
|
+
_ringtone = nil;
|
|
505
|
+
[self restoreOriginalAudioSetup];
|
|
506
|
+
[self audioSessionSetActive:NO
|
|
507
|
+
options:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
|
|
508
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
RCT_EXPORT_METHOD(getAudioUriJS:(NSString *)audioType
|
|
518
|
+
fileType:(NSString *)fileType
|
|
519
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
520
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
521
|
+
{
|
|
522
|
+
NSURL *result = nil;
|
|
523
|
+
if ([audioType isEqualToString:@"ringback"]) {
|
|
524
|
+
result = [self getRingbackUri:fileType];
|
|
525
|
+
} else if ([audioType isEqualToString:@"busytone"]) {
|
|
526
|
+
result = [self getBusytoneUri:fileType];
|
|
527
|
+
} else if ([audioType isEqualToString:@"ringtone"]) {
|
|
528
|
+
result = [self getRingtoneUri:fileType];
|
|
529
|
+
}
|
|
530
|
+
if (result != nil) {
|
|
531
|
+
if (result.absoluteString.length > 0) {
|
|
532
|
+
resolve(result.absoluteString);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
reject(@"error_code", @"getAudioUriJS() failed in main fn", RCTErrorWithMessage(@"getAudioUriJS() failed"));
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
RCT_EXPORT_METHOD(getIsWiredHeadsetPluggedIn:(RCTPromiseResolveBlock)resolve
|
|
540
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
541
|
+
{
|
|
542
|
+
BOOL wiredHeadsetPluggedIn = [self isWiredHeadsetPluggedIn];
|
|
543
|
+
resolve(wiredHeadsetPluggedIn ? @YES : @NO);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
RCT_EXPORT_METHOD(isBluetoothHeadsetConnected: (RCTPromiseResolveBlock) resolve
|
|
548
|
+
reject:(RCTPromiseRejectBlock) reject)
|
|
549
|
+
{
|
|
550
|
+
// NSLog(@"👉 Checking if Bluetooth device is connected");
|
|
551
|
+
NSMutableArray *devices = [NSMutableArray array];
|
|
552
|
+
AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute];
|
|
553
|
+
for (AVAudioSessionPortDescription* desc in [route outputs]) {
|
|
554
|
+
// NSLog(@"🧑💻 Bluetooth Desc: %@", desc);
|
|
555
|
+
if ([[desc portType] isEqualToString:AVAudioSessionPortBluetoothHFP] ||
|
|
556
|
+
[[desc portType] isEqualToString:AVAudioSessionPortBluetoothA2DP] ||
|
|
557
|
+
[[desc portType] isEqualToString:AVAudioSessionPortBluetoothLE]) {
|
|
558
|
+
[devices addObject:[desc portName]];
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
// NSLog(@"🧑💻 Bluetooth Devices %@", devices);
|
|
562
|
+
if (!devices || !devices.count){
|
|
563
|
+
resolve(@NO);
|
|
564
|
+
} else {
|
|
565
|
+
resolve(@YES);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
//TODO: Rewrite this function so that we manage bluetooth, wiredHeadset and all the updates from here
|
|
570
|
+
- (BOOL)updateAudioRoute
|
|
571
|
+
{
|
|
572
|
+
// NSLog(@" 👉 RNInCallManager.updateAudioRoute(): [Enter] forceSpeakerOn flag=%d media=%@ category=%@ mode=%@", _forceSpeakerOn, _media, _audioSession.category, _audioSession.mode);
|
|
573
|
+
//self.debugAudioSession()
|
|
574
|
+
|
|
575
|
+
//AVAudioSessionPortOverride overrideAudioPort;
|
|
576
|
+
int overrideAudioPort;
|
|
577
|
+
NSString *overrideAudioPortString = @"";
|
|
578
|
+
NSString *audioMode = @"";
|
|
579
|
+
|
|
580
|
+
// --- WebRTC native code will change audio mode automatically when established.
|
|
581
|
+
// --- It would have some race condition if we change audio mode with webrtc at the same time.
|
|
582
|
+
// --- So we should not change audio mode as possible as we can. Only when default video call which wants to force speaker off.
|
|
583
|
+
// --- audio: only override speaker on/off; video: should change category if needed and handle proximity sensor. ( because default proximity is off when video call )
|
|
584
|
+
if (_forceSpeakerOn == 1) {
|
|
585
|
+
// NSLog(@"👨💻 Force Speaker on");
|
|
586
|
+
// --- force ON, override speaker only, keep audio mode remain.
|
|
587
|
+
overrideAudioPort = AVAudioSessionPortOverrideSpeaker;
|
|
588
|
+
overrideAudioPortString = @".Speaker";
|
|
589
|
+
// if ([_media isEqualToString:@"video"]) {
|
|
590
|
+
// audioMode = AVAudioSessionModeVideoChat;
|
|
591
|
+
// [self stopProximitySensor];
|
|
592
|
+
// }
|
|
593
|
+
//Bluetooth device
|
|
594
|
+
} else { // use default behavior
|
|
595
|
+
// NSLog(@"👨💻 Else Audio Route");
|
|
596
|
+
overrideAudioPort = AVAudioSessionPortOverrideNone;
|
|
597
|
+
overrideAudioPortString = @".None";
|
|
598
|
+
// if ([_media isEqualToString:@"video"]) {
|
|
599
|
+
// audioMode = AVAudioSessionModeVideoChat;
|
|
600
|
+
// [self stopProximitySensor];
|
|
601
|
+
// }
|
|
602
|
+
}
|
|
603
|
+
//NOTE: Check Current route to speaker
|
|
604
|
+
BOOL isCurrentRouteToSpeaker;
|
|
605
|
+
isCurrentRouteToSpeaker = [self checkAudioRoute:@[AVAudioSessionPortBuiltInSpeaker]
|
|
606
|
+
routeType:@"output"];
|
|
607
|
+
if ((overrideAudioPort == AVAudioSessionPortOverrideSpeaker && !isCurrentRouteToSpeaker)
|
|
608
|
+
|| (overrideAudioPort == AVAudioSessionPortOverrideNone && isCurrentRouteToSpeaker)) {
|
|
609
|
+
@try {
|
|
610
|
+
[_audioSession overrideOutputAudioPort:overrideAudioPort error:nil];
|
|
611
|
+
// NSLog(@"💯 RNInCallManager.updateAudioRoute(): audioSession.overrideOutputAudioPort(%@) success", overrideAudioPortString);
|
|
612
|
+
} @catch (NSException *e) {
|
|
613
|
+
NSLog(@"😭 RNInCallManager.updateAudioRoute(): audioSession.overrideOutputAudioPort(%@) fail: %@", overrideAudioPortString, e.reason);
|
|
614
|
+
}
|
|
615
|
+
} else {
|
|
616
|
+
// NSLog(@"👨💻 RNInCallManager.updateAudioRoute(): did NOT overrideOutputAudioPort()");
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (audioMode.length > 0 && ![_audioSession.mode isEqualToString:audioMode]) {
|
|
620
|
+
[self audioSessionSetMode:audioMode
|
|
621
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
622
|
+
|
|
623
|
+
[self sendEventWithName:@"onAudioDeviceChanged" body:@{@"devices": audioMode}];
|
|
624
|
+
// NSLog(@"👨💻 RNInCallManager.updateAudioRoute() audio mode has changed to %@", audioMode);
|
|
625
|
+
return true;
|
|
626
|
+
} else {
|
|
627
|
+
// NSLog(@"👨💻 RNInCallManager.updateAudioRoute() did NOT change audio mode");
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
//self.debugAudioSession()
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
- (BOOL)checkAudioRoute:(NSArray<NSString *> *)targetPortTypeArray
|
|
634
|
+
routeType:(NSString *)routeType
|
|
635
|
+
{
|
|
636
|
+
//TODO: Checking bluetooth route should be called from here
|
|
637
|
+
AVAudioSessionRouteDescription *currentRoute = _audioSession.currentRoute;
|
|
638
|
+
// NSLog(@"👉 Check Audio Route called ");
|
|
639
|
+
// NSLog(@"👨💻 Route Type: %@", routeType);
|
|
640
|
+
// NSLog(@"👨💻 Current Audio Route: %@", currentRoute);
|
|
641
|
+
// NSLog(@"👨💻 targetPortTypeArray: %@", targetPortTypeArray);
|
|
642
|
+
if (currentRoute != nil) {
|
|
643
|
+
NSArray<AVAudioSessionPortDescription *> *routes = [routeType isEqualToString:@"input"]
|
|
644
|
+
? currentRoute.inputs
|
|
645
|
+
: currentRoute.outputs;
|
|
646
|
+
for (AVAudioSessionPortDescription *portDescription in routes) {
|
|
647
|
+
if ([targetPortTypeArray containsObject:portDescription.portType]) {
|
|
648
|
+
// NSLog(@"🌏 Audio Route for %@ does exist", targetPortTypeArray);
|
|
649
|
+
return YES;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
// NSLog(@"🌏 Audio Route for %@ does not exist", targetPortTypeArray);
|
|
654
|
+
return NO;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
- (BOOL)startBusytone:(NSString *)_busytoneUriType
|
|
658
|
+
{
|
|
659
|
+
// you may rejected by apple when publish app if you use system sound instead of bundled sound.
|
|
660
|
+
NSLog(@"RNInCallManager.startBusytone(): type: %@", _busytoneUriType);
|
|
661
|
+
@try {
|
|
662
|
+
if (_busytone != nil) {
|
|
663
|
+
if ([_busytone isPlaying]) {
|
|
664
|
+
// NSLog(@"RNInCallManager.startBusytone(): is already playing");
|
|
665
|
+
return NO;
|
|
666
|
+
} else {
|
|
667
|
+
[self stopBusytone];
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// ios don't have embedded DTMF tone generator. use system dtmf sound files.
|
|
672
|
+
NSString *busytoneUriType = [_busytoneUriType isEqualToString:@"_DTMF_"]
|
|
673
|
+
? @"_DEFAULT_"
|
|
674
|
+
: _busytoneUriType;
|
|
675
|
+
NSURL *busytoneUri = [self getBusytoneUri:busytoneUriType];
|
|
676
|
+
if (busytoneUri == nil) {
|
|
677
|
+
// NSLog(@"RNInCallManager.startBusytone(): no available media");
|
|
678
|
+
return NO;
|
|
679
|
+
}
|
|
680
|
+
//[self storeOriginalAudioSetup];
|
|
681
|
+
_busytone = [[AVAudioPlayer alloc] initWithContentsOfURL:busytoneUri error:nil];
|
|
682
|
+
_busytone.delegate = self;
|
|
683
|
+
_busytone.numberOfLoops = 0; // it's part of start(), will stop at stop()
|
|
684
|
+
[_busytone prepareToPlay];
|
|
685
|
+
|
|
686
|
+
//self.audioSessionSetCategory(self.incallAudioCategory, [.DefaultToSpeaker, .AllowBluetooth], #function)
|
|
687
|
+
[self audioSessionSetCategory:_incallAudioCategory
|
|
688
|
+
options:0
|
|
689
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
690
|
+
[self audioSessionSetMode:_incallAudioMode
|
|
691
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
692
|
+
[_busytone play];
|
|
693
|
+
} @catch (NSException *e) {
|
|
694
|
+
// NSLog(@"RNInCallManager.startBusytone(): caught error = %@", e.reason);
|
|
695
|
+
return NO;
|
|
696
|
+
}
|
|
697
|
+
return YES;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
- (void)stopBusytone
|
|
701
|
+
{
|
|
702
|
+
if (_busytone != nil) {
|
|
703
|
+
// NSLog(@"RNInCallManager.stopBusytone()");
|
|
704
|
+
[_busytone stop];
|
|
705
|
+
_busytone = nil;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
- (BOOL)isWiredHeadsetPluggedIn
|
|
710
|
+
{
|
|
711
|
+
// NSLog(@"👉 checking if isWiredHeadset is plusgged in or not");
|
|
712
|
+
// --- only check for a audio device plugged into headset port instead bluetooth/usb/hdmi
|
|
713
|
+
return [self checkAudioRoute:@[AVAudioSessionPortHeadphones]
|
|
714
|
+
routeType:@"output"]
|
|
715
|
+
|| [self checkAudioRoute:@[AVAudioSessionPortHeadsetMic]
|
|
716
|
+
routeType:@"input"];
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
- (void)audioSessionSetCategory:(NSString *)audioCategory
|
|
720
|
+
options:(AVAudioSessionCategoryOptions)options
|
|
721
|
+
callerMemo:(NSString *)callerMemo
|
|
722
|
+
{
|
|
723
|
+
@try {
|
|
724
|
+
if (options != 0) {
|
|
725
|
+
[_audioSession setCategory:audioCategory
|
|
726
|
+
withOptions:options
|
|
727
|
+
error:nil];
|
|
728
|
+
} else {
|
|
729
|
+
[_audioSession setCategory:audioCategory
|
|
730
|
+
error:nil];
|
|
731
|
+
}
|
|
732
|
+
// NSLog(@"RNInCallManager.%@: audioSession.setCategory: %@, withOptions: %lu success", callerMemo, audioCategory, (unsigned long)options);
|
|
733
|
+
} @catch (NSException *e) {
|
|
734
|
+
// NSLog(@"RNInCallManager.%@: audioSession.setCategory: %@, withOptions: %lu fail: %@", callerMemo, audioCategory, (unsigned long)options, e.reason);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
- (void)audioSessionSetMode:(NSString *)audioMode
|
|
739
|
+
callerMemo:(NSString *)callerMemo
|
|
740
|
+
{
|
|
741
|
+
@try {
|
|
742
|
+
[_audioSession setMode:audioMode error:nil];
|
|
743
|
+
// NSLog(@"RNInCallManager.%@: audioSession.setMode(%@) success", callerMemo, audioMode);
|
|
744
|
+
} @catch (NSException *e) {
|
|
745
|
+
// NSLog(@"RNInCallManager.%@: audioSession.setMode(%@) fail: %@", callerMemo, audioMode, e.reason);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
- (void)audioSessionSetActive:(BOOL)audioActive
|
|
750
|
+
options:(AVAudioSessionSetActiveOptions)options
|
|
751
|
+
callerMemo:(NSString *)callerMemo
|
|
752
|
+
{
|
|
753
|
+
@try {
|
|
754
|
+
if (options != 0) {
|
|
755
|
+
[_audioSession setActive:audioActive
|
|
756
|
+
withOptions:options
|
|
757
|
+
error:nil];
|
|
758
|
+
} else {
|
|
759
|
+
[_audioSession setActive:audioActive
|
|
760
|
+
error:nil];
|
|
761
|
+
}
|
|
762
|
+
// NSLog(@"RNInCallManager.%@: audioSession.setActive(%@), withOptions: %lu success", callerMemo, audioActive ? @"YES" : @"NO", (unsigned long)options);
|
|
763
|
+
} @catch (NSException *e) {
|
|
764
|
+
// NSLog(@"RNInCallManager.%@: audioSession.setActive(%@), withOptions: %lu fail: %@", callerMemo, audioActive ? @"YES" : @"NO", (unsigned long)options, e.reason);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
- (void)storeOriginalAudioSetup
|
|
769
|
+
{
|
|
770
|
+
// NSLog(@"👨💻 RNInCallManager.storeOriginalAudioSetup(): origAudioCategory=%@, origAudioMode=%@", _audioSession.category, _audioSession.mode);
|
|
771
|
+
_origAudioCategory = _audioSession.category;
|
|
772
|
+
_origAudioMode = _audioSession.mode;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
- (void)restoreOriginalAudioSetup
|
|
776
|
+
{
|
|
777
|
+
// NSLog(@"RNInCallManager.restoreOriginalAudioSetup(): origAudioCategory=%@, origAudioMode=%@", _audioSession.category, _audioSession.mode);
|
|
778
|
+
[self audioSessionSetCategory:_origAudioCategory
|
|
779
|
+
options:0
|
|
780
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
781
|
+
[self audioSessionSetMode:_origAudioMode
|
|
782
|
+
callerMemo:NSStringFromSelector(_cmd)];
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
- (void)startProximitySensor
|
|
786
|
+
{
|
|
787
|
+
if (_isProximityRegistered) {
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// NSLog(@"RNInCallManager.startProximitySensor()");
|
|
792
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
793
|
+
self->_currentDevice.proximityMonitoringEnabled = YES;
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
// --- in case it didn't deallocate when ViewDidUnload
|
|
797
|
+
[self stopObserve:_proximityObserver
|
|
798
|
+
name:UIDeviceProximityStateDidChangeNotification
|
|
799
|
+
object:nil];
|
|
800
|
+
|
|
801
|
+
_proximityObserver = [self startObserve:UIDeviceProximityStateDidChangeNotification
|
|
802
|
+
object:_currentDevice
|
|
803
|
+
queue: nil
|
|
804
|
+
block:^(NSNotification *notification) {
|
|
805
|
+
BOOL state = self->_currentDevice.proximityState;
|
|
806
|
+
if (state != self->_proximityIsNear) {
|
|
807
|
+
// NSLog(@"RNInCallManager.UIDeviceProximityStateDidChangeNotification(): isNear: %@", state ? @"YES" : @"NO");
|
|
808
|
+
self->_proximityIsNear = state;
|
|
809
|
+
[self sendEventWithName:@"Proximity" body:@{@"isNear": state ? @YES : @NO}];
|
|
810
|
+
}
|
|
811
|
+
}];
|
|
812
|
+
|
|
813
|
+
_isProximityRegistered = YES;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
- (void)stopProximitySensor
|
|
817
|
+
{
|
|
818
|
+
if (!_isProximityRegistered) {
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// NSLog(@"RNInCallManager.stopProximitySensor()");
|
|
823
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
824
|
+
self->_currentDevice.proximityMonitoringEnabled = NO;
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
// --- remove all no matter what object
|
|
828
|
+
[self stopObserve:_proximityObserver
|
|
829
|
+
name:UIDeviceProximityStateDidChangeNotification
|
|
830
|
+
object:nil];
|
|
831
|
+
|
|
832
|
+
_isProximityRegistered = NO;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
- (void)startAudioSessionNotification
|
|
836
|
+
{
|
|
837
|
+
// NSLog(@"👉 RNInCallManager.startAudioSessionNotification() starting...");
|
|
838
|
+
[self startAudioSessionInterruptionNotification];
|
|
839
|
+
[self startAudioSessionRouteChangeNotification];
|
|
840
|
+
[self startAudioSessionMediaServicesWereLostNotification];
|
|
841
|
+
[self startAudioSessionMediaServicesWereResetNotification];
|
|
842
|
+
[self startAudioSessionSilenceSecondaryAudioHintNotification];
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
- (void)stopAudioSessionNotification
|
|
846
|
+
{
|
|
847
|
+
// NSLog(@"👉 RNInCallManager.startAudioSessionNotification() stopping...");
|
|
848
|
+
[self stopAudioSessionInterruptionNotification];
|
|
849
|
+
[self stopAudioSessionRouteChangeNotification];
|
|
850
|
+
[self stopAudioSessionMediaServicesWereLostNotification];
|
|
851
|
+
[self stopAudioSessionMediaServicesWereResetNotification];
|
|
852
|
+
[self stopAudioSessionSilenceSecondaryAudioHintNotification];
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
- (void)startAudioSessionInterruptionNotification
|
|
856
|
+
{
|
|
857
|
+
if (_isAudioSessionInterruptionRegistered) {
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
// NSLog(@"👉 RNInCallManager.startAudioSessionInterruptionNotification()");
|
|
861
|
+
|
|
862
|
+
// --- in case it didn't deallocate when ViewDidUnload
|
|
863
|
+
[self stopObserve:_audioSessionInterruptionObserver
|
|
864
|
+
name:AVAudioSessionInterruptionNotification
|
|
865
|
+
object:nil];
|
|
866
|
+
|
|
867
|
+
_audioSessionInterruptionObserver = [self startObserve:AVAudioSessionInterruptionNotification
|
|
868
|
+
object:nil
|
|
869
|
+
queue:nil
|
|
870
|
+
block:^(NSNotification *notification) {
|
|
871
|
+
if (notification.userInfo == nil
|
|
872
|
+
|| ![notification.name isEqualToString:AVAudioSessionInterruptionNotification]) {
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
//NSUInteger rawValue = notification.userInfo[AVAudioSessionInterruptionTypeKey].unsignedIntegerValue;
|
|
877
|
+
NSNumber *interruptType = [notification.userInfo objectForKey:@"AVAudioSessionInterruptionTypeKey"];
|
|
878
|
+
if ([interruptType unsignedIntegerValue] == AVAudioSessionInterruptionTypeBegan) {
|
|
879
|
+
// NSLog(@"RNInCallManager.AudioSessionInterruptionNotification: Began");
|
|
880
|
+
} else if ([interruptType unsignedIntegerValue] == AVAudioSessionInterruptionTypeEnded) {
|
|
881
|
+
// NSLog(@"🧑💻 RNInCallManager.AudioSessionInterruptionNotification: Ended");
|
|
882
|
+
} else {
|
|
883
|
+
// NSLog(@"🧑💻 RNInCallManager.AudioSessionInterruptionNotification: Unknow Value");
|
|
884
|
+
}
|
|
885
|
+
//NSLog(@"RNInCallManager.AudioSessionInterruptionNotification: could not resolve notification");
|
|
886
|
+
}];
|
|
887
|
+
|
|
888
|
+
_isAudioSessionInterruptionRegistered = YES;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
- (void)stopAudioSessionInterruptionNotification
|
|
892
|
+
{
|
|
893
|
+
if (!_isAudioSessionInterruptionRegistered) {
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
896
|
+
// NSLog(@"RNInCallManager.stopAudioSessionInterruptionNotification()");
|
|
897
|
+
// --- remove all no matter what object
|
|
898
|
+
[self stopObserve:_audioSessionInterruptionObserver
|
|
899
|
+
name:AVAudioSessionInterruptionNotification
|
|
900
|
+
object: nil];
|
|
901
|
+
_isAudioSessionInterruptionRegistered = NO;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
- (void)startAudioSessionRouteChangeNotification
|
|
905
|
+
{
|
|
906
|
+
if (_isAudioSessionRouteChangeRegistered) {
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
// NSLog(@"RNInCallManager.startAudioSessionRouteChangeNotification()");
|
|
911
|
+
|
|
912
|
+
// --- in case it didn't deallocate when ViewDidUnload
|
|
913
|
+
[self stopObserve:_audioSessionRouteChangeObserver
|
|
914
|
+
name: AVAudioSessionRouteChangeNotification
|
|
915
|
+
object: nil];
|
|
916
|
+
//NOTE: On Audio Change this function is called
|
|
917
|
+
_audioSessionRouteChangeObserver = [self startObserve:AVAudioSessionRouteChangeNotification
|
|
918
|
+
object: nil
|
|
919
|
+
queue: nil
|
|
920
|
+
block:^(NSNotification *notification) {
|
|
921
|
+
// NSLog(@"🧑💻 Audio Session changed, user route %@ and %@ current route", _userSelectedAudioRoute, self->_audioSession.currentRoute);
|
|
922
|
+
if (notification.userInfo == nil
|
|
923
|
+
|| ![notification.name isEqualToString:AVAudioSessionRouteChangeNotification]) {
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
NSNumber *routeChangeType = [notification.userInfo objectForKey:@"AVAudioSessionRouteChangeReasonKey"];
|
|
928
|
+
NSUInteger routeChangeTypeValue = [routeChangeType unsignedIntegerValue];
|
|
929
|
+
|
|
930
|
+
switch (routeChangeTypeValue) {
|
|
931
|
+
case AVAudioSessionRouteChangeReasonUnknown:
|
|
932
|
+
// NSLog(@"🧑💻 RNInCallManager.AudioRouteChange.Reason: Unknown");
|
|
933
|
+
break;
|
|
934
|
+
case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
|
|
935
|
+
// NSLog(@"🧑💻 RNInCallManager.AudioRouteChange.Reason: NewDeviceAvailable");
|
|
936
|
+
if ([self checkAudioRoute:@[AVAudioSessionPortHeadsetMic]
|
|
937
|
+
routeType:@"input"]) {
|
|
938
|
+
_forceSpeakerOn = 0;
|
|
939
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
940
|
+
body:@{
|
|
941
|
+
@"availableAudioDeviceList": @"[speaker, earpiece, wired]",
|
|
942
|
+
@"selectedAudioDevice": AVAudioSessionPortHeadsetMic,
|
|
943
|
+
}];
|
|
944
|
+
} else if ([self checkAudioRoute:@[AVAudioSessionPortHeadphones]
|
|
945
|
+
routeType:@"output"]) {
|
|
946
|
+
_forceSpeakerOn = 0;
|
|
947
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
948
|
+
body:@{
|
|
949
|
+
@"availableAudioDeviceList": @"[speaker, earpiece, wired]",
|
|
950
|
+
@"selectedAudioDevice": AVAudioSessionPortHeadphones,
|
|
951
|
+
}];
|
|
952
|
+
} else if ([self checkAudioRoute:@[AVAudioSessionPortBluetoothHFP]
|
|
953
|
+
routeType:@"input"]) {
|
|
954
|
+
_forceSpeakerOn = 0;
|
|
955
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
956
|
+
body:@{
|
|
957
|
+
@"availableAudioDeviceList": @"[speaker, earpiece, bluetooth]",
|
|
958
|
+
@"selectedAudioDevice": AVAudioSessionPortBluetoothHFP,
|
|
959
|
+
}];
|
|
960
|
+
} else if ([self checkAudioRoute:@[AVAudioSessionPortBluetoothA2DP]
|
|
961
|
+
routeType:@"input"]) {
|
|
962
|
+
_forceSpeakerOn = 0;
|
|
963
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
964
|
+
body:@{
|
|
965
|
+
@"availableAudioDeviceList": @"[speaker, earpiece, bluetooth]",
|
|
966
|
+
@"selectedAudioDevice": AVAudioSessionPortBluetoothA2DP,
|
|
967
|
+
}];
|
|
968
|
+
} else if ([self checkAudioRoute:@[AVAudioSessionPortBluetoothLE]
|
|
969
|
+
routeType:@"input"]) {
|
|
970
|
+
_forceSpeakerOn = 0;
|
|
971
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
972
|
+
body:@{
|
|
973
|
+
@"availableAudioDeviceList": @"[speaker, earpiece, bluetooth]",
|
|
974
|
+
@"selectedAudioDevice": AVAudioSessionPortBluetoothLE,
|
|
975
|
+
}];
|
|
976
|
+
}
|
|
977
|
+
break;
|
|
978
|
+
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
|
|
979
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
980
|
+
body:@{
|
|
981
|
+
@"availableAudioDeviceList": @"[speaker, earpiece]",
|
|
982
|
+
@"selectedAudioDevice": @"speaker",
|
|
983
|
+
}];
|
|
984
|
+
break;
|
|
985
|
+
case AVAudioSessionRouteChangeReasonCategoryChange:
|
|
986
|
+
// NSLog(@"🧑💻 RNInCallManager.AudioRouteChange.Reason: CategoryChange. category=%@ mode=%@", self->_audioSession.category, self->_audioSession.mode);
|
|
987
|
+
break;
|
|
988
|
+
case AVAudioSessionRouteChangeReasonOverride:
|
|
989
|
+
// NSLog(@"🧑💻 RNInCallManager.AudioRouteChange.Reason: Override");
|
|
990
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
991
|
+
body:@{
|
|
992
|
+
@"availableAudioDeviceList": @"[speaker, earpiece]",
|
|
993
|
+
@"selectedAudioDevice": @"speaker",
|
|
994
|
+
}];
|
|
995
|
+
break;
|
|
996
|
+
case AVAudioSessionRouteChangeReasonWakeFromSleep:
|
|
997
|
+
// NSLog(@"RNInCallManager.AudioRouteChange.Reason: WakeFromSleep");
|
|
998
|
+
break;
|
|
999
|
+
case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
|
|
1000
|
+
// NSLog(@"🧑💻 RNInCallManager.AudioRouteChange.Reason: NoSuitableRouteForCategory");
|
|
1001
|
+
break;
|
|
1002
|
+
case AVAudioSessionRouteChangeReasonRouteConfigurationChange:
|
|
1003
|
+
// NSLog(@"🧑💻 RNInCallManager.AudioRouteChange.Reason: RouteConfigurationChange. category=%@ mode=%@", self->_audioSession.category, self->_audioSession.mode);
|
|
1004
|
+
break;
|
|
1005
|
+
default:
|
|
1006
|
+
// NSLog(@"🧑💻 RNInCallManager.AudioRouteChange.Reason: Unknow Value");
|
|
1007
|
+
break;
|
|
1008
|
+
}
|
|
1009
|
+
[self updateAudioRoute];
|
|
1010
|
+
|
|
1011
|
+
NSNumber *silenceSecondaryAudioHintType = [notification.userInfo objectForKey:@"AVAudioSessionSilenceSecondaryAudioHintTypeKey"];
|
|
1012
|
+
NSUInteger silenceSecondaryAudioHintTypeValue = [silenceSecondaryAudioHintType unsignedIntegerValue];
|
|
1013
|
+
// switch (silenceSecondaryAudioHintTypeValue) {
|
|
1014
|
+
// case AVAudioSessionSilenceSecondaryAudioHintTypeBegin:
|
|
1015
|
+
// // NSLog(@"RNInCallManager.AudioRouteChange.SilenceSecondaryAudioHint: Begin");
|
|
1016
|
+
// case AVAudioSessionSilenceSecondaryAudioHintTypeEnd:
|
|
1017
|
+
// // NSLog(@"RNInCallManager.AudioRouteChange.SilenceSecondaryAudioHint: End");
|
|
1018
|
+
// default:
|
|
1019
|
+
// // NSLog(@"RNInCallManager.AudioRouteChange.SilenceSecondaryAudioHint: Unknow Value");
|
|
1020
|
+
// }
|
|
1021
|
+
}];
|
|
1022
|
+
|
|
1023
|
+
_isAudioSessionRouteChangeRegistered = YES;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
- (void)stopAudioSessionRouteChangeNotification
|
|
1027
|
+
{
|
|
1028
|
+
if (!_isAudioSessionRouteChangeRegistered) {
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
// NSLog(@"RNInCallManager.stopAudioSessionRouteChangeNotification()");
|
|
1033
|
+
// --- remove all no matter what object
|
|
1034
|
+
[self stopObserve:_audioSessionRouteChangeObserver
|
|
1035
|
+
name:AVAudioSessionRouteChangeNotification
|
|
1036
|
+
object:nil];
|
|
1037
|
+
_isAudioSessionRouteChangeRegistered = NO;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
- (void)startAudioSessionMediaServicesWereLostNotification
|
|
1041
|
+
{
|
|
1042
|
+
if (_isAudioSessionMediaServicesWereLostRegistered) {
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
// NSLog(@"RNInCallManager.startAudioSessionMediaServicesWereLostNotification()");
|
|
1047
|
+
|
|
1048
|
+
// --- in case it didn't deallocate when ViewDidUnload
|
|
1049
|
+
[self stopObserve:_audioSessionMediaServicesWereLostObserver
|
|
1050
|
+
name:AVAudioSessionMediaServicesWereLostNotification
|
|
1051
|
+
object:nil];
|
|
1052
|
+
|
|
1053
|
+
_audioSessionMediaServicesWereLostObserver = [self startObserve:AVAudioSessionMediaServicesWereLostNotification
|
|
1054
|
+
object:nil
|
|
1055
|
+
queue:nil
|
|
1056
|
+
block:^(NSNotification *notification) {
|
|
1057
|
+
// --- This notification has no userInfo dictionary.
|
|
1058
|
+
// NSLog(@"RNInCallManager.AudioSessionMediaServicesWereLostNotification: Media Services Were Lost");
|
|
1059
|
+
}];
|
|
1060
|
+
|
|
1061
|
+
_isAudioSessionMediaServicesWereLostRegistered = YES;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
- (void)stopAudioSessionMediaServicesWereLostNotification
|
|
1065
|
+
{
|
|
1066
|
+
if (!_isAudioSessionMediaServicesWereLostRegistered) {
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// NSLog(@"RNInCallManager.stopAudioSessionMediaServicesWereLostNotification()");
|
|
1071
|
+
|
|
1072
|
+
// --- remove all no matter what object
|
|
1073
|
+
[self stopObserve:_audioSessionMediaServicesWereLostObserver
|
|
1074
|
+
name:AVAudioSessionMediaServicesWereLostNotification
|
|
1075
|
+
object:nil];
|
|
1076
|
+
|
|
1077
|
+
_isAudioSessionMediaServicesWereLostRegistered = NO;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
- (void)startAudioSessionMediaServicesWereResetNotification
|
|
1081
|
+
{
|
|
1082
|
+
if (_isAudioSessionMediaServicesWereResetRegistered) {
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// NSLog(@"RNInCallManager.startAudioSessionMediaServicesWereResetNotification()");
|
|
1087
|
+
|
|
1088
|
+
// --- in case it didn't deallocate when ViewDidUnload
|
|
1089
|
+
[self stopObserve:_audioSessionMediaServicesWereResetObserver
|
|
1090
|
+
name:AVAudioSessionMediaServicesWereResetNotification
|
|
1091
|
+
object:nil];
|
|
1092
|
+
|
|
1093
|
+
_audioSessionMediaServicesWereResetObserver = [self startObserve:AVAudioSessionMediaServicesWereResetNotification
|
|
1094
|
+
object:nil
|
|
1095
|
+
queue:nil
|
|
1096
|
+
block:^(NSNotification *notification) {
|
|
1097
|
+
// --- This notification has no userInfo dictionary.
|
|
1098
|
+
// NSLog(@"RNInCallManager.AudioSessionMediaServicesWereResetNotification: Media Services Were Reset");
|
|
1099
|
+
}];
|
|
1100
|
+
|
|
1101
|
+
_isAudioSessionMediaServicesWereResetRegistered = YES;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
- (void)stopAudioSessionMediaServicesWereResetNotification
|
|
1105
|
+
{
|
|
1106
|
+
if (!_isAudioSessionMediaServicesWereResetRegistered) {
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// NSLog(@"RNInCallManager.stopAudioSessionMediaServicesWereResetNotification()");
|
|
1111
|
+
|
|
1112
|
+
// --- remove all no matter what object
|
|
1113
|
+
[self stopObserve:_audioSessionMediaServicesWereResetObserver
|
|
1114
|
+
name:AVAudioSessionMediaServicesWereResetNotification
|
|
1115
|
+
object:nil];
|
|
1116
|
+
|
|
1117
|
+
_isAudioSessionMediaServicesWereResetRegistered = NO;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
- (void)startAudioSessionSilenceSecondaryAudioHintNotification
|
|
1121
|
+
{
|
|
1122
|
+
if (_isAudioSessionSilenceSecondaryAudioHintRegistered) {
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// NSLog(@"RNInCallManager.startAudioSessionSilenceSecondaryAudioHintNotification()");
|
|
1127
|
+
|
|
1128
|
+
// --- in case it didn't deallocate when ViewDidUnload
|
|
1129
|
+
[self stopObserve:_audioSessionSilenceSecondaryAudioHintObserver
|
|
1130
|
+
name:AVAudioSessionSilenceSecondaryAudioHintNotification
|
|
1131
|
+
object:nil];
|
|
1132
|
+
|
|
1133
|
+
_audioSessionSilenceSecondaryAudioHintObserver = [self startObserve:AVAudioSessionSilenceSecondaryAudioHintNotification
|
|
1134
|
+
object:nil
|
|
1135
|
+
queue:nil
|
|
1136
|
+
block:^(NSNotification *notification) {
|
|
1137
|
+
if (notification.userInfo == nil
|
|
1138
|
+
|| ![notification.name isEqualToString:AVAudioSessionSilenceSecondaryAudioHintNotification]) {
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
NSNumber *silenceSecondaryAudioHintType = [notification.userInfo objectForKey:@"AVAudioSessionSilenceSecondaryAudioHintTypeKey"];
|
|
1143
|
+
NSUInteger silenceSecondaryAudioHintTypeValue = [silenceSecondaryAudioHintType unsignedIntegerValue];
|
|
1144
|
+
switch (silenceSecondaryAudioHintTypeValue) {
|
|
1145
|
+
case AVAudioSessionSilenceSecondaryAudioHintTypeBegin:
|
|
1146
|
+
// NSLog(@"RNInCallManager.AVAudioSessionSilenceSecondaryAudioHintNotification: Begin");
|
|
1147
|
+
break;
|
|
1148
|
+
case AVAudioSessionSilenceSecondaryAudioHintTypeEnd:
|
|
1149
|
+
// NSLog(@"RNInCallManager.AVAudioSessionSilenceSecondaryAudioHintNotification: End");
|
|
1150
|
+
break;
|
|
1151
|
+
default:
|
|
1152
|
+
// NSLog(@"RNInCallManager.AVAudioSessionSilenceSecondaryAudioHintNotification: Unknow Value");
|
|
1153
|
+
break;
|
|
1154
|
+
}
|
|
1155
|
+
}];
|
|
1156
|
+
_isAudioSessionSilenceSecondaryAudioHintRegistered = YES;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
- (void)stopAudioSessionSilenceSecondaryAudioHintNotification
|
|
1160
|
+
{
|
|
1161
|
+
if (!_isAudioSessionSilenceSecondaryAudioHintRegistered) {
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// NSLog(@"RNInCallManager.stopAudioSessionSilenceSecondaryAudioHintNotification()");
|
|
1166
|
+
// --- remove all no matter what object
|
|
1167
|
+
[self stopObserve:_audioSessionSilenceSecondaryAudioHintObserver
|
|
1168
|
+
name:AVAudioSessionSilenceSecondaryAudioHintNotification
|
|
1169
|
+
object:nil];
|
|
1170
|
+
|
|
1171
|
+
_isAudioSessionSilenceSecondaryAudioHintRegistered = NO;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
- (id)startObserve:(NSString *)name
|
|
1175
|
+
object:(id)object
|
|
1176
|
+
queue:(NSOperationQueue *)queue
|
|
1177
|
+
block:(void (^)(NSNotification *))block
|
|
1178
|
+
{
|
|
1179
|
+
return [[NSNotificationCenter defaultCenter] addObserverForName:name
|
|
1180
|
+
object:object
|
|
1181
|
+
queue:queue
|
|
1182
|
+
usingBlock:block];
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
- (void)stopObserve:(id)observer
|
|
1186
|
+
name:(NSString *)name
|
|
1187
|
+
object:(id)object
|
|
1188
|
+
{
|
|
1189
|
+
if (observer == nil) return;
|
|
1190
|
+
[[NSNotificationCenter defaultCenter] removeObserver:observer
|
|
1191
|
+
name:name
|
|
1192
|
+
object:object];
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
- (NSURL *)getRingbackUri:(NSString *)_type
|
|
1196
|
+
{
|
|
1197
|
+
NSString *fileBundle = @"incallmanager_ringback";
|
|
1198
|
+
NSString *fileBundleExt = @"mp3";
|
|
1199
|
+
//NSString *fileSysWithExt = @"vc~ringing.caf"; // --- ringtone of facetime, but can't play it.
|
|
1200
|
+
//NSString *fileSysPath = @"/System/Library/Audio/UISounds";
|
|
1201
|
+
NSString *fileSysWithExt = @"Marimba.m4r";
|
|
1202
|
+
NSString *fileSysPath = @"/Library/Ringtones";
|
|
1203
|
+
|
|
1204
|
+
// --- you can't get default user perfrence sound in ios
|
|
1205
|
+
NSString *type = [_type isEqualToString:@""] || [_type isEqualToString:@"_DEFAULT_"]
|
|
1206
|
+
? fileSysWithExt
|
|
1207
|
+
: _type;
|
|
1208
|
+
|
|
1209
|
+
NSURL *bundleUri = _bundleRingbackUri;
|
|
1210
|
+
NSURL *defaultUri = _defaultRingbackUri;
|
|
1211
|
+
|
|
1212
|
+
NSURL *uri = [self getAudioUri:type
|
|
1213
|
+
fileBundle:fileBundle
|
|
1214
|
+
fileBundleExt:fileBundleExt
|
|
1215
|
+
fileSysWithExt:fileSysWithExt
|
|
1216
|
+
fileSysPath:fileSysPath
|
|
1217
|
+
uriBundle:&bundleUri
|
|
1218
|
+
uriDefault:&defaultUri];
|
|
1219
|
+
|
|
1220
|
+
_bundleRingbackUri = bundleUri;
|
|
1221
|
+
_defaultRingbackUri = defaultUri;
|
|
1222
|
+
|
|
1223
|
+
return uri;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
- (NSURL *)getBusytoneUri:(NSString *)_type
|
|
1227
|
+
{
|
|
1228
|
+
NSString *fileBundle = @"incallmanager_busytone";
|
|
1229
|
+
NSString *fileBundleExt = @"mp3";
|
|
1230
|
+
NSString *fileSysWithExt = @"ct-busy.caf"; //ct-congestion.caf
|
|
1231
|
+
NSString *fileSysPath = @"/System/Library/Audio/UISounds";
|
|
1232
|
+
// --- you can't get default user perfrence sound in ios
|
|
1233
|
+
NSString *type = [_type isEqualToString:@""] || [_type isEqualToString:@"_DEFAULT_"]
|
|
1234
|
+
? fileSysWithExt
|
|
1235
|
+
: _type;
|
|
1236
|
+
|
|
1237
|
+
NSURL *bundleUri = _bundleBusytoneUri;
|
|
1238
|
+
NSURL *defaultUri = _defaultBusytoneUri;
|
|
1239
|
+
|
|
1240
|
+
NSURL *uri = [self getAudioUri:type
|
|
1241
|
+
fileBundle:fileBundle
|
|
1242
|
+
fileBundleExt:fileBundleExt
|
|
1243
|
+
fileSysWithExt:fileSysWithExt
|
|
1244
|
+
fileSysPath:fileSysPath
|
|
1245
|
+
uriBundle:&bundleUri
|
|
1246
|
+
uriDefault:&defaultUri];
|
|
1247
|
+
|
|
1248
|
+
_bundleBusytoneUri = bundleUri;
|
|
1249
|
+
_defaultBusytoneUri = defaultUri;
|
|
1250
|
+
|
|
1251
|
+
return uri;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
- (NSURL *)getRingtoneUri:(NSString *)_type
|
|
1255
|
+
{
|
|
1256
|
+
NSString *fileBundle = @"incallmanager_ringtone";
|
|
1257
|
+
NSString *fileBundleExt = @"mp3";
|
|
1258
|
+
NSString *fileSysWithExt = @"Opening.m4r"; //Marimba.m4r
|
|
1259
|
+
NSString *fileSysPath = @"/Library/Ringtones";
|
|
1260
|
+
// --- you can't get default user perfrence sound in ios
|
|
1261
|
+
NSString *type = [_type isEqualToString:@""] || [_type isEqualToString:@"_DEFAULT_"]
|
|
1262
|
+
? fileSysWithExt
|
|
1263
|
+
: _type;
|
|
1264
|
+
|
|
1265
|
+
NSURL *bundleUri = _bundleRingtoneUri;
|
|
1266
|
+
NSURL *defaultUri = _defaultRingtoneUri;
|
|
1267
|
+
|
|
1268
|
+
NSURL *uri = [self getAudioUri:type
|
|
1269
|
+
fileBundle:fileBundle
|
|
1270
|
+
fileBundleExt:fileBundleExt
|
|
1271
|
+
fileSysWithExt:fileSysWithExt
|
|
1272
|
+
fileSysPath:fileSysPath
|
|
1273
|
+
uriBundle:&bundleUri
|
|
1274
|
+
uriDefault:&defaultUri];
|
|
1275
|
+
|
|
1276
|
+
_bundleRingtoneUri = bundleUri;
|
|
1277
|
+
_defaultRingtoneUri = defaultUri;
|
|
1278
|
+
|
|
1279
|
+
return uri;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
- (NSURL *)getAudioUri:(NSString *)_type
|
|
1283
|
+
fileBundle:(NSString *)fileBundle
|
|
1284
|
+
fileBundleExt:(NSString *)fileBundleExt
|
|
1285
|
+
fileSysWithExt:(NSString *)fileSysWithExt
|
|
1286
|
+
fileSysPath:(NSString *)fileSysPath
|
|
1287
|
+
uriBundle:(NSURL **)uriBundle
|
|
1288
|
+
uriDefault:(NSURL **)uriDefault
|
|
1289
|
+
{
|
|
1290
|
+
NSString *type = _type;
|
|
1291
|
+
if ([type isEqualToString:@"_BUNDLE_"]) {
|
|
1292
|
+
if (*uriBundle == nil) {
|
|
1293
|
+
*uriBundle = [[NSBundle mainBundle] URLForResource:fileBundle withExtension:fileBundleExt];
|
|
1294
|
+
if (*uriBundle == nil) {
|
|
1295
|
+
// NSLog(@"RNInCallManager.getAudioUri(): %@.%@ not found in bundle.", fileBundle, fileBundleExt);
|
|
1296
|
+
type = fileSysWithExt;
|
|
1297
|
+
} else {
|
|
1298
|
+
return *uriBundle;
|
|
1299
|
+
}
|
|
1300
|
+
} else {
|
|
1301
|
+
return *uriBundle;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
if (*uriDefault == nil) {
|
|
1306
|
+
NSString *target = [NSString stringWithFormat:@"%@/%@", fileSysPath, type];
|
|
1307
|
+
*uriDefault = [self getSysFileUri:target];
|
|
1308
|
+
}
|
|
1309
|
+
return *uriDefault;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
- (NSURL *)getSysFileUri:(NSString *)target
|
|
1313
|
+
{
|
|
1314
|
+
NSURL *url = [[NSURL alloc] initFileURLWithPath:target isDirectory:NO];
|
|
1315
|
+
|
|
1316
|
+
if (url != nil) {
|
|
1317
|
+
NSString *path = url.path;
|
|
1318
|
+
if (path != nil) {
|
|
1319
|
+
NSFileManager *fileManager = [[NSFileManager alloc] init];
|
|
1320
|
+
BOOL isTargetDirectory;
|
|
1321
|
+
if ([fileManager fileExistsAtPath:path isDirectory:&isTargetDirectory]) {
|
|
1322
|
+
if (!isTargetDirectory) {
|
|
1323
|
+
return url;
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
// NSLog(@"RNInCallManager.getSysFileUri(): can not get url for %@", target);
|
|
1329
|
+
return nil;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
#pragma mark - AVAudioPlayerDelegate
|
|
1333
|
+
|
|
1334
|
+
// --- this only called when all loop played. it means, an infinite (numberOfLoops = -1) loop will never into here.
|
|
1335
|
+
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player
|
|
1336
|
+
successfully:(BOOL)flag
|
|
1337
|
+
{
|
|
1338
|
+
NSString *filename = player.url.URLByDeletingPathExtension.lastPathComponent;
|
|
1339
|
+
// NSLog(@"RNInCallManager.audioPlayerDidFinishPlaying(): finished playing: %@", filename);
|
|
1340
|
+
if ([filename isEqualToString:_bundleBusytoneUri.URLByDeletingPathExtension.lastPathComponent]
|
|
1341
|
+
|| [filename isEqualToString:_defaultBusytoneUri.URLByDeletingPathExtension.lastPathComponent]) {
|
|
1342
|
+
//[self stopBusytone];
|
|
1343
|
+
// NSLog(@"RNInCallManager.audioPlayerDidFinishPlaying(): busytone finished, invoke stop()");
|
|
1344
|
+
[self stop:@""];
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player
|
|
1349
|
+
error:(NSError *)error
|
|
1350
|
+
{
|
|
1351
|
+
NSString *filename = player.url.URLByDeletingPathExtension.lastPathComponent;
|
|
1352
|
+
// NSLog(@"RNInCallManager.audioPlayerDecodeErrorDidOccur(): player=%@, error=%@", filename, error.localizedDescription);
|
|
1353
|
+
}
|
|
1354
|
+
@end
|