@cometchat/calls-sdk-react-native 4.0.0-beta1
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/README.md +27 -0
- package/android/build.gradle +20 -0
- package/android/src/main/AndroidManifest.xml +8 -0
- package/android/src/main/java/com/CometChatCalls/AudioDeviceHandlerGeneric.java +213 -0
- package/android/src/main/java/com/CometChatCalls/AudioDeviceHandlerLegacy.java +213 -0
- package/android/src/main/java/com/CometChatCalls/AudioModeModule.java +456 -0
- package/android/src/main/java/com/CometChatCalls/BluetoothHeadsetMonitor.java +174 -0
- package/android/src/main/java/com/CometChatCalls/CometChatCallsPackage.java +45 -0
- package/cometchat-calls-sdk-react-native.podspec +21 -0
- package/dist/CometChatErrorConstants.d.ts +124 -0
- package/dist/Constants.d.ts +720 -0
- package/dist/Helper copy.d.ts +1 -0
- package/dist/Helper.d.ts +7 -0
- package/dist/api/APIHandler.d.ts +6 -0
- package/dist/api/endpoints.d.ts +6 -0
- package/dist/api/helper.d.ts +63 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/constants/CallConstants.d.ts +136 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/defaultCallsettings.d.ts +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +128 -0
- package/dist/models/CallAppSettings.d.ts +42 -0
- package/dist/models/CallSettings.d.ts +316 -0
- package/dist/models/CometChatCalls.d.ts +89 -0
- package/dist/models/CometChatCallsComponent.d.ts +13 -0
- package/dist/models/CometChatCallsComponentCore.d.ts +18 -0
- package/dist/models/CometChatCallsException.d.ts +7 -0
- package/dist/models/CometChatPresenterComponent.d.ts +13 -0
- package/dist/models/ErrorModel.d.ts +11 -0
- package/dist/models/Listner.d.ts +64 -0
- package/dist/models/ListnerHandler.d.ts +10 -0
- package/dist/models/MessageComponent.d.ts +7 -0
- package/dist/models/PresenterSettings.d.ts +194 -0
- package/dist/models/RTCUser.d.ts +18 -0
- package/dist/models/index.d.ts +7 -0
- package/dist/types/ICallAppSettings.d.ts +6 -0
- package/dist/types/ICallSettings.d.ts +60 -0
- package/dist/types/RTCUser.d.ts +6 -0
- package/dist/types/callEvents.d.ts +53 -0
- package/dist/types/common.d.ts +17 -0
- package/dist/types/index.d.ts +2 -0
- package/ios/AudioMode.h +11 -0
- package/ios/AudioMode.m +403 -0
- package/ios/JitsiAudioSession+Private.h +25 -0
- package/ios/JitsiAudioSession.h +17 -0
- package/ios/JitsiAudioSession.m +34 -0
- package/ios/LogUtils.h +23 -0
- package/ios/react-native-calls2.xcodeproj/project.pbxproj +269 -0
- package/package.json +122 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
package com.CometChatCalls;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
import android.media.AudioManager;
|
|
5
|
+
import android.os.Build;
|
|
6
|
+
import android.util.Log;
|
|
7
|
+
|
|
8
|
+
import com.facebook.react.bridge.Arguments;
|
|
9
|
+
import com.facebook.react.bridge.Promise;
|
|
10
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
11
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
12
|
+
import com.facebook.react.bridge.ReactMethod;
|
|
13
|
+
import com.facebook.react.bridge.WritableArray;
|
|
14
|
+
import com.facebook.react.bridge.WritableMap;
|
|
15
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
16
|
+
|
|
17
|
+
import java.util.HashMap;
|
|
18
|
+
import java.util.HashSet;
|
|
19
|
+
import java.util.Map;
|
|
20
|
+
import java.util.Set;
|
|
21
|
+
import java.util.concurrent.ExecutorService;
|
|
22
|
+
import java.util.concurrent.Executors;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Module implementing a simple API to select the appropriate audio device for a
|
|
26
|
+
* conference call.
|
|
27
|
+
*
|
|
28
|
+
* Audio calls should use {@code AudioModeModule.AUDIO_CALL}, which uses the
|
|
29
|
+
* builtin earpiece, wired headset or bluetooth headset. The builtin earpiece is
|
|
30
|
+
* the default audio device.
|
|
31
|
+
*
|
|
32
|
+
* Video calls should should use {@code AudioModeModule.VIDEO_CALL}, which uses
|
|
33
|
+
* the builtin speaker, earpiece, wired headset or bluetooth headset. The
|
|
34
|
+
* builtin speaker is the default audio device.
|
|
35
|
+
*
|
|
36
|
+
* Before a call has started and after it has ended the
|
|
37
|
+
* {@code AudioModeModule.DEFAULT} mode should be used.
|
|
38
|
+
*/
|
|
39
|
+
class AudioModeModule extends ReactContextBaseJavaModule {
|
|
40
|
+
public static final String NAME = "AudioMode";
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Constants representing the audio mode.
|
|
44
|
+
* - DEFAULT: Used before and after every call. It represents the default
|
|
45
|
+
* audio routing scheme.
|
|
46
|
+
* - AUDIO_CALL: Used for audio only calls. It will use the earpiece by
|
|
47
|
+
* default, unless a wired or Bluetooth headset is connected.
|
|
48
|
+
* - VIDEO_CALL: Used for video calls. It will use the speaker by default,
|
|
49
|
+
* unless a wired or Bluetooth headset is connected.
|
|
50
|
+
*/
|
|
51
|
+
static final int DEFAULT = 0;
|
|
52
|
+
static final int AUDIO_CALL = 1;
|
|
53
|
+
static final int VIDEO_CALL = 2;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The {@code Log} tag {@code AudioModeModule} is to log messages with.
|
|
57
|
+
*/
|
|
58
|
+
static final String TAG = NAME;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Whether or not the ConnectionService is used for selecting audio devices.
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
private static final boolean supportsConnectionService = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
|
|
65
|
+
private static boolean useConnectionService_ = false;
|
|
66
|
+
|
|
67
|
+
static boolean useConnectionService() {
|
|
68
|
+
return supportsConnectionService && useConnectionService_;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* {@link AudioManager} instance used to interact with the Android audio
|
|
73
|
+
* subsystem.
|
|
74
|
+
*/
|
|
75
|
+
private AudioManager audioManager;
|
|
76
|
+
|
|
77
|
+
private AudioDeviceHandlerInterface audioDeviceHandler;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* {@link ExecutorService} for running all audio operations on a dedicated
|
|
81
|
+
* thread.
|
|
82
|
+
*/
|
|
83
|
+
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Audio mode currently in use.
|
|
87
|
+
*/
|
|
88
|
+
private int mode = -1;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Audio device types.
|
|
92
|
+
*/
|
|
93
|
+
static final String DEVICE_BLUETOOTH = "BLUETOOTH";
|
|
94
|
+
static final String DEVICE_EARPIECE = "EARPIECE";
|
|
95
|
+
static final String DEVICE_HEADPHONES = "HEADPHONES";
|
|
96
|
+
static final String DEVICE_SPEAKER = "SPEAKER";
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Device change event.
|
|
100
|
+
*/
|
|
101
|
+
private static final String DEVICE_CHANGE_EVENT = "org.jitsi.meet:features/audio-mode#devices-update";
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* List of currently available audio devices.
|
|
105
|
+
*/
|
|
106
|
+
private Set<String> availableDevices = new HashSet<>();
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Currently selected device.
|
|
110
|
+
*/
|
|
111
|
+
private String selectedDevice;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* User selected device. When null the default is used depending on the
|
|
115
|
+
* mode.
|
|
116
|
+
*/
|
|
117
|
+
private String userSelectedDevice;
|
|
118
|
+
|
|
119
|
+
private ReactApplicationContext reactContext;
|
|
120
|
+
/**
|
|
121
|
+
* Initializes a new module instance. There shall be a single instance of
|
|
122
|
+
* this module throughout the lifetime of the application.
|
|
123
|
+
*
|
|
124
|
+
* @param reactContext the {@link ReactApplicationContext} where this module
|
|
125
|
+
* is created.
|
|
126
|
+
*/
|
|
127
|
+
public AudioModeModule(ReactApplicationContext reactContext) {
|
|
128
|
+
super(reactContext);
|
|
129
|
+
|
|
130
|
+
this.reactContext = reactContext;
|
|
131
|
+
audioManager = (AudioManager) reactContext.getSystemService(Context.AUDIO_SERVICE);
|
|
132
|
+
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Gets a mapping with the constants this module is exporting.
|
|
137
|
+
*
|
|
138
|
+
* @return a {@link Map} mapping the constants to be exported with their
|
|
139
|
+
* values.
|
|
140
|
+
*/
|
|
141
|
+
@Override
|
|
142
|
+
public Map<String, Object> getConstants() {
|
|
143
|
+
Map<String, Object> constants = new HashMap<>();
|
|
144
|
+
|
|
145
|
+
constants.put("DEVICE_CHANGE_EVENT", DEVICE_CHANGE_EVENT);
|
|
146
|
+
constants.put("AUDIO_CALL", AUDIO_CALL);
|
|
147
|
+
constants.put("DEFAULT", DEFAULT);
|
|
148
|
+
constants.put("VIDEO_CALL", VIDEO_CALL);
|
|
149
|
+
|
|
150
|
+
return constants;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Notifies JS land that the devices list has changed.
|
|
155
|
+
*/
|
|
156
|
+
private void notifyDevicesChanged() {
|
|
157
|
+
runInAudioThread(new Runnable() {
|
|
158
|
+
@Override
|
|
159
|
+
public void run() {
|
|
160
|
+
WritableArray data = Arguments.createArray();
|
|
161
|
+
final boolean hasHeadphones = availableDevices.contains(DEVICE_HEADPHONES);
|
|
162
|
+
Log.e(TAG, "hasHeadphones ? " + hasHeadphones);
|
|
163
|
+
for (String device : availableDevices) {
|
|
164
|
+
if (hasHeadphones && device.equals(DEVICE_EARPIECE)) {
|
|
165
|
+
// Skip earpiece when headphones are plugged in.
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
WritableMap deviceInfo = Arguments.createMap();
|
|
169
|
+
deviceInfo.putString("type", device);
|
|
170
|
+
deviceInfo.putBoolean("selected", device.equals(selectedDevice));
|
|
171
|
+
data.pushMap(deviceInfo);
|
|
172
|
+
}
|
|
173
|
+
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
174
|
+
.emit(DEVICE_CHANGE_EVENT, data);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Gets the name for this module to be used in the React Native bridge.
|
|
181
|
+
*
|
|
182
|
+
* @return a string with the module name.
|
|
183
|
+
*/
|
|
184
|
+
@Override
|
|
185
|
+
public String getName() {
|
|
186
|
+
return NAME;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@Override
|
|
190
|
+
public void initialize() {
|
|
191
|
+
runInAudioThread(new Runnable() {
|
|
192
|
+
@Override
|
|
193
|
+
public void run() {
|
|
194
|
+
setAudioDeviceHandler();
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private void setAudioDeviceHandler() {
|
|
200
|
+
if (audioDeviceHandler != null) {
|
|
201
|
+
audioDeviceHandler.stop();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
205
|
+
audioDeviceHandler = new AudioDeviceHandlerGeneric(audioManager);
|
|
206
|
+
} else {
|
|
207
|
+
audioDeviceHandler = new AudioDeviceHandlerLegacy(audioManager);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
audioDeviceHandler.start(this);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Helper function to run operations on a dedicated thread.
|
|
215
|
+
*
|
|
216
|
+
* @param runnable
|
|
217
|
+
*/
|
|
218
|
+
void runInAudioThread(Runnable runnable) {
|
|
219
|
+
executor.execute(runnable);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Sets the user selected audio device as the active audio device.
|
|
224
|
+
*
|
|
225
|
+
* @param device the desired device which will become active.
|
|
226
|
+
*/
|
|
227
|
+
@ReactMethod
|
|
228
|
+
public void setAudioDevice(final String device) {
|
|
229
|
+
runInAudioThread(new Runnable() {
|
|
230
|
+
@Override
|
|
231
|
+
public void run() {
|
|
232
|
+
Log.e(TAG, "Selected Devices = " + device);
|
|
233
|
+
Log.e(TAG, "Available Devices = " + availableDevices);
|
|
234
|
+
if (availableDevices != null && device != null) {
|
|
235
|
+
if (!availableDevices.contains(device)) {
|
|
236
|
+
userSelectedDevice = null;
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (mode != -1) {
|
|
241
|
+
userSelectedDevice = device;
|
|
242
|
+
updateAudioRoute(mode);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
@ReactMethod
|
|
250
|
+
public void getAllDevices() {
|
|
251
|
+
Log.e("getAllDevices","getAllDevices");
|
|
252
|
+
notifyDevicesChanged();
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Public method to set the current audio mode.
|
|
256
|
+
*
|
|
257
|
+
* @param mode the desired audio mode.
|
|
258
|
+
* @param promise a {@link Promise} which will be resolved if the audio mode
|
|
259
|
+
* could be updated successfully, and it will be rejected
|
|
260
|
+
* otherwise.
|
|
261
|
+
*/
|
|
262
|
+
@ReactMethod
|
|
263
|
+
public void setMode(final int mode, final Promise promise) {
|
|
264
|
+
if (mode != DEFAULT && mode != AUDIO_CALL && mode != VIDEO_CALL) {
|
|
265
|
+
promise.reject("setMode", "Invalid audio mode " + mode);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
runInAudioThread(new Runnable() {
|
|
270
|
+
@Override
|
|
271
|
+
public void run() {
|
|
272
|
+
boolean success;
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
success = updateAudioRoute(mode);
|
|
276
|
+
} catch (Throwable e) {
|
|
277
|
+
success = false;
|
|
278
|
+
}
|
|
279
|
+
if (success) {
|
|
280
|
+
AudioModeModule.this.mode = mode;
|
|
281
|
+
promise.resolve(null);
|
|
282
|
+
} else {
|
|
283
|
+
promise.reject("setMode", "Failed to set audio mode to " + mode);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Sets whether ConnectionService should be used (if available) for setting the
|
|
291
|
+
* audio mode
|
|
292
|
+
* or not.
|
|
293
|
+
*
|
|
294
|
+
* @param use Boolean indicator of where it should be used or not.
|
|
295
|
+
*/
|
|
296
|
+
@ReactMethod
|
|
297
|
+
public void setUseConnectionService(final boolean use) {
|
|
298
|
+
runInAudioThread(new Runnable() {
|
|
299
|
+
@Override
|
|
300
|
+
public void run() {
|
|
301
|
+
useConnectionService_ = use;
|
|
302
|
+
setAudioDeviceHandler();
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Updates the audio route for the given mode.
|
|
309
|
+
*
|
|
310
|
+
* @param mode the audio mode to be used when computing the audio route.
|
|
311
|
+
* @return {@code true} if the audio route was updated successfully;
|
|
312
|
+
* {@code false}, otherwise.
|
|
313
|
+
*/
|
|
314
|
+
private boolean updateAudioRoute(int mode) {
|
|
315
|
+
|
|
316
|
+
if (!audioDeviceHandler.setMode(mode)) {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (mode == DEFAULT) {
|
|
321
|
+
selectedDevice = null;
|
|
322
|
+
userSelectedDevice = null;
|
|
323
|
+
|
|
324
|
+
notifyDevicesChanged();
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
boolean bluetoothAvailable = availableDevices.contains(DEVICE_BLUETOOTH);
|
|
329
|
+
boolean headsetAvailable = availableDevices.contains(DEVICE_HEADPHONES);
|
|
330
|
+
|
|
331
|
+
// Pick the desired device based on what's available and the mode.
|
|
332
|
+
String audioDevice;
|
|
333
|
+
if (bluetoothAvailable) {
|
|
334
|
+
audioDevice = DEVICE_BLUETOOTH;
|
|
335
|
+
} else if (headsetAvailable) {
|
|
336
|
+
audioDevice = DEVICE_HEADPHONES;
|
|
337
|
+
} else {
|
|
338
|
+
audioDevice = DEVICE_SPEAKER;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Consider the user's selection
|
|
342
|
+
if (userSelectedDevice != null && availableDevices.contains(userSelectedDevice)) {
|
|
343
|
+
audioDevice = userSelectedDevice;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// If the previously selected device and the current default one
|
|
347
|
+
// match, do nothing.
|
|
348
|
+
if (selectedDevice != null && selectedDevice.equals(audioDevice)) {
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
selectedDevice = audioDevice;
|
|
353
|
+
|
|
354
|
+
audioDeviceHandler.setAudioRoute(audioDevice);
|
|
355
|
+
|
|
356
|
+
notifyDevicesChanged();
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Gets the currently selected audio device.
|
|
362
|
+
*
|
|
363
|
+
* @return The selected audio device.
|
|
364
|
+
*/
|
|
365
|
+
String getSelectedDevice() {
|
|
366
|
+
return selectedDevice;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Resets the current device selection.
|
|
371
|
+
*/
|
|
372
|
+
void resetSelectedDevice() {
|
|
373
|
+
selectedDevice = null;
|
|
374
|
+
userSelectedDevice = null;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Adds a new device to the list of available devices.
|
|
379
|
+
*
|
|
380
|
+
* @param device The new device.
|
|
381
|
+
*/
|
|
382
|
+
void addDevice(String device) {
|
|
383
|
+
availableDevices.add(device);
|
|
384
|
+
resetSelectedDevice();
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Removes a device from the list of available devices.
|
|
389
|
+
*
|
|
390
|
+
* @param device The old device to the removed.
|
|
391
|
+
*/
|
|
392
|
+
void removeDevice(String device) {
|
|
393
|
+
availableDevices.remove(device);
|
|
394
|
+
resetSelectedDevice();
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Replaces the current list of available devices with a new one.
|
|
399
|
+
*
|
|
400
|
+
* @param devices The new devices list.
|
|
401
|
+
*/
|
|
402
|
+
void replaceDevices(Set<String> devices) {
|
|
403
|
+
availableDevices = devices;
|
|
404
|
+
resetSelectedDevice();
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Re-sets the current audio route. Needed when devices changes have happened.
|
|
409
|
+
*/
|
|
410
|
+
void updateAudioRoute() {
|
|
411
|
+
if (mode != -1) {
|
|
412
|
+
updateAudioRoute(mode);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Needed on the legacy handler...
|
|
418
|
+
*
|
|
419
|
+
* @return Context for the application.
|
|
420
|
+
*/
|
|
421
|
+
Context getContext() {
|
|
422
|
+
return getReactApplicationContext();
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Interface for the modules implementing the actual audio device management.
|
|
427
|
+
*/
|
|
428
|
+
interface AudioDeviceHandlerInterface {
|
|
429
|
+
/**
|
|
430
|
+
* Start detecting audio device changes.
|
|
431
|
+
*
|
|
432
|
+
* @param audioModeModule Reference to the main {@link AudioModeModule}.
|
|
433
|
+
*/
|
|
434
|
+
void start(AudioModeModule audioModeModule);
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Stop audio device detection.
|
|
438
|
+
*/
|
|
439
|
+
void stop();
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Set the appropriate route for the given audio device.
|
|
443
|
+
*
|
|
444
|
+
* @param device Audio device for which the route must be set.
|
|
445
|
+
*/
|
|
446
|
+
void setAudioRoute(String device);
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Set the given audio mode.
|
|
450
|
+
*
|
|
451
|
+
* @param mode The new audio mode to be used.
|
|
452
|
+
* @return Whether the operation was successful or not.
|
|
453
|
+
*/
|
|
454
|
+
boolean setMode(int mode);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
|
|
2
|
+
package com.CometChatCalls;
|
|
3
|
+
|
|
4
|
+
import android.bluetooth.BluetoothAdapter;
|
|
5
|
+
import android.bluetooth.BluetoothHeadset;
|
|
6
|
+
import android.bluetooth.BluetoothProfile;
|
|
7
|
+
import android.content.BroadcastReceiver;
|
|
8
|
+
import android.content.Context;
|
|
9
|
+
import android.content.Intent;
|
|
10
|
+
import android.content.IntentFilter;
|
|
11
|
+
import android.media.AudioManager;
|
|
12
|
+
import android.util.Log;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Helper class to detect and handle Bluetooth device changes. It monitors
|
|
16
|
+
* Bluetooth headsets being connected / disconnected and notifies the module
|
|
17
|
+
* about device changes when this occurs.
|
|
18
|
+
*/
|
|
19
|
+
class BluetoothHeadsetMonitor {
|
|
20
|
+
private final static String TAG = BluetoothHeadsetMonitor.class.getSimpleName();
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The {@link Context} in which this module executes.
|
|
24
|
+
*/
|
|
25
|
+
private final Context context;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Reference to the {@link BluetoothAdapter} object, used to access Bluetooth functionality.
|
|
29
|
+
*/
|
|
30
|
+
private BluetoothAdapter adapter;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Reference to a proxy object which allows us to query connected devices.
|
|
34
|
+
*/
|
|
35
|
+
private BluetoothHeadset headset;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* receiver registered for receiving Bluetooth connection state changes.
|
|
39
|
+
*/
|
|
40
|
+
private BroadcastReceiver receiver;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Listener for receiving Bluetooth device change events.
|
|
44
|
+
*/
|
|
45
|
+
private Listener listener;
|
|
46
|
+
|
|
47
|
+
public BluetoothHeadsetMonitor(Context context, Listener listener) {
|
|
48
|
+
this.context = context;
|
|
49
|
+
this.listener = listener;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private boolean getBluetoothHeadsetProfileProxy() {
|
|
53
|
+
adapter = BluetoothAdapter.getDefaultAdapter();
|
|
54
|
+
|
|
55
|
+
if (adapter == null) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// XXX: The profile listener listens for system services of the given
|
|
60
|
+
// type being available to the application. That is, if our Bluetooth
|
|
61
|
+
// adapter has the "headset" profile.
|
|
62
|
+
BluetoothProfile.ServiceListener listener
|
|
63
|
+
= new BluetoothProfile.ServiceListener() {
|
|
64
|
+
@Override
|
|
65
|
+
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
|
66
|
+
if (profile == BluetoothProfile.HEADSET) {
|
|
67
|
+
headset = (BluetoothHeadset) proxy;
|
|
68
|
+
updateDevices();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@Override
|
|
73
|
+
public void onServiceDisconnected(int profile) {
|
|
74
|
+
// The logic is the same as the logic of onServiceConnected.
|
|
75
|
+
onServiceConnected(profile, /* proxy */ null);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return adapter.getProfileProxy(context, listener, BluetoothProfile.HEADSET);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private void onBluetoothReceiverReceive(Context context, Intent intent) {
|
|
83
|
+
final String action = intent.getAction();
|
|
84
|
+
|
|
85
|
+
if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
|
|
86
|
+
// XXX: This action will be fired when a Bluetooth headset is
|
|
87
|
+
// connected or disconnected to the system. This is not related to
|
|
88
|
+
// audio routing.
|
|
89
|
+
int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, -99);
|
|
90
|
+
|
|
91
|
+
switch (state) {
|
|
92
|
+
case BluetoothHeadset.STATE_CONNECTED:
|
|
93
|
+
case BluetoothHeadset.STATE_DISCONNECTED:
|
|
94
|
+
Log.d(TAG , " BT headset connection state changed: " + state);
|
|
95
|
+
updateDevices();
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
} else if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) {
|
|
99
|
+
// XXX: This action will be fired when the connection established
|
|
100
|
+
// with a Bluetooth headset (called a SCO connection) changes state.
|
|
101
|
+
// When the SCO connection is active we route audio to it.
|
|
102
|
+
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -99);
|
|
103
|
+
|
|
104
|
+
switch (state) {
|
|
105
|
+
case AudioManager.SCO_AUDIO_STATE_CONNECTED:
|
|
106
|
+
case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
|
|
107
|
+
Log.d(TAG , " BT SCO connection state changed: " + state);
|
|
108
|
+
updateDevices();
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private void registerBluetoothReceiver() {
|
|
115
|
+
receiver = new BroadcastReceiver() {
|
|
116
|
+
@Override
|
|
117
|
+
public void onReceive(Context context, Intent intent) {
|
|
118
|
+
onBluetoothReceiverReceive(context, intent);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
IntentFilter filter = new IntentFilter();
|
|
123
|
+
filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
|
|
124
|
+
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
|
|
125
|
+
|
|
126
|
+
context.registerReceiver(receiver, filter);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Detects if there are new devices connected / disconnected and fires the
|
|
131
|
+
* {@link Listener} registered event.
|
|
132
|
+
*/
|
|
133
|
+
private void updateDevices() {
|
|
134
|
+
boolean headsetAvailable = (headset != null) && !headset.getConnectedDevices().isEmpty();
|
|
135
|
+
listener.onBluetoothDeviceChange(headsetAvailable);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
public void start() {
|
|
139
|
+
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
|
140
|
+
|
|
141
|
+
if (!audioManager.isBluetoothScoAvailableOffCall()) {
|
|
142
|
+
Log.w(TAG , " Bluetooth SCO is not available");
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (!getBluetoothHeadsetProfileProxy()) {
|
|
147
|
+
Log.w(TAG , " Couldn't get BT profile proxy");
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
registerBluetoothReceiver();
|
|
152
|
+
|
|
153
|
+
// Initial detection.
|
|
154
|
+
updateDevices();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public void stop() {
|
|
158
|
+
if (receiver != null) {
|
|
159
|
+
context.unregisterReceiver(receiver);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (adapter != null && headset != null) {
|
|
163
|
+
adapter.closeProfileProxy(BluetoothProfile.HEADSET, headset);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
receiver = null;
|
|
167
|
+
headset = null;
|
|
168
|
+
adapter = null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
interface Listener {
|
|
172
|
+
void onBluetoothDeviceChange(boolean deviceAvailable);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2017 Henry Lin @zxcpoiu
|
|
3
|
+
*
|
|
4
|
+
* Permission to use, copy, modify, and distribute this software for any
|
|
5
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
6
|
+
* copyright notice and this permission notice appear in all copies.
|
|
7
|
+
*
|
|
8
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
9
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
10
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
11
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
12
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
13
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
14
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
package com.CometChatCalls;
|
|
18
|
+
|
|
19
|
+
import com.facebook.react.ReactPackage;
|
|
20
|
+
import com.facebook.react.bridge.JavaScriptModule;
|
|
21
|
+
import com.facebook.react.bridge.NativeModule;
|
|
22
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
23
|
+
import com.facebook.react.uimanager.ViewManager;
|
|
24
|
+
|
|
25
|
+
import java.util.Collections;
|
|
26
|
+
import java.util.List;
|
|
27
|
+
|
|
28
|
+
public class CometChatCallsPackage implements ReactPackage {
|
|
29
|
+
|
|
30
|
+
@Override
|
|
31
|
+
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
|
32
|
+
return Collections.<NativeModule>singletonList(new AudioModeModule(reactContext));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Deprecated RN 0.47
|
|
36
|
+
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
|
37
|
+
return Collections.emptyList();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@Override
|
|
41
|
+
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
|
42
|
+
return Collections.emptyList();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "cometchat-calls-sdk-react-native"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.homepage = package["homepage"]
|
|
10
|
+
s.license = package["license"]
|
|
11
|
+
s.authors = package["author"]
|
|
12
|
+
|
|
13
|
+
s.platforms = { :ios => "10.0" }
|
|
14
|
+
s.source = { :git => "https://github.com/cometchat-team/cometchat-pro-call-react-native", :tag => "#{s.version}" }
|
|
15
|
+
|
|
16
|
+
s.source_files = "ios/**/*.{h,m,mm}"
|
|
17
|
+
|
|
18
|
+
s.dependency "React-Core"
|
|
19
|
+
|
|
20
|
+
s.dependency "react-native-webrtc"
|
|
21
|
+
end
|