@cloudflare/realtimekit-react-native 0.2.1 → 0.2.2-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/android/build.gradle +0 -2
- package/android/src/main/java/com/cloudflare/realtimekit/CoreModule.java +19 -0
- package/android/src/main/java/com/cloudflare/realtimekit/ForegroundService.java +2 -4
- package/android/src/main/java/com/cloudflare/realtimekit/RTKHelperModule.java +1 -2
- package/android/src/main/java/com/cloudflare/realtimekit/RTKLogger.java +116 -0
- package/android/src/main/java/com/cloudflare/realtimekit/incallmanager/AppRTCBluetoothManager.java +75 -74
- package/android/src/main/java/com/cloudflare/realtimekit/incallmanager/AppRTCUtils.java +10 -9
- package/android/src/main/java/com/cloudflare/realtimekit/incallmanager/InCallManagerModule.java +175 -872
- package/android/src/main/java/com/cloudflare/realtimekit/incallmanager/InCallProximityManager.java +9 -8
- package/android/src/main/java/com/cloudflare/realtimekit/incallmanager/InCallWakeLockUtils.java +8 -7
- package/ios/BroadcastEventEmitter.m +9 -0
- package/ios/Core.h +9 -1
- package/ios/Core.m +42 -0
- package/ios/RNInCallManager.m +639 -700
- package/ios/RTKLogger.h +51 -0
- package/ios/RTKLogger.m +107 -0
- package/ios/RTKRNBackgroundTimer.m +8 -7
- package/ios/RTKRNPermissionHandlerNotifications.m +12 -0
- package/ios/RTKRNPermissions.m +24 -1
- package/ios/RTKScreensharePickerView.m +6 -0
- package/ios/screenshare/RTKScreenshareHandler.swift +1 -1
- package/ios/screenshare/RTKScreenshareUploader.swift +3 -3
- package/ios/screenshare/RTKSocketConnection.swift +8 -8
- package/lib/commonjs/LocalMediaHandler.js +82 -24
- package/lib/commonjs/LocalMediaHandler.js.map +1 -1
- package/lib/commonjs/LocalMediaUtils.js +60 -5
- package/lib/commonjs/LocalMediaUtils.js.map +1 -1
- package/lib/commonjs/NativeAudioManager.js +7 -3
- package/lib/commonjs/NativeAudioManager.js.map +1 -1
- package/lib/commonjs/utils/version.js +1 -1
- package/lib/commonjs/utils/version.js.map +1 -1
- package/lib/module/LocalMediaHandler.js +82 -24
- package/lib/module/LocalMediaHandler.js.map +1 -1
- package/lib/module/LocalMediaUtils.js +60 -5
- package/lib/module/LocalMediaUtils.js.map +1 -1
- package/lib/module/NativeAudioManager.js +7 -3
- package/lib/module/NativeAudioManager.js.map +1 -1
- package/lib/module/utils/version.js +1 -1
- package/lib/module/utils/version.js.map +1 -1
- package/lib/typescript/LocalMediaHandler.d.ts +1 -0
- package/lib/typescript/LocalMediaUtils.d.ts +1 -0
- package/lib/typescript/NativeAudioManager.d.ts +1 -0
- package/lib/typescript/utils/version.d.ts +1 -1
- package/package.json +2 -4
package/android/build.gradle
CHANGED
|
@@ -13,6 +13,8 @@ import com.facebook.react.module.annotations.ReactModule;
|
|
|
13
13
|
import java.security.NoSuchAlgorithmException;
|
|
14
14
|
import java.security.SecureRandom;
|
|
15
15
|
|
|
16
|
+
import com.cloudflare.realtimekit.RTKLogger;
|
|
17
|
+
|
|
16
18
|
@ReactModule(name = CoreModule.NAME)
|
|
17
19
|
public class CoreModule extends ReactContextBaseJavaModule {
|
|
18
20
|
public static final String NAME = "Core";
|
|
@@ -46,4 +48,21 @@ public class CoreModule extends ReactContextBaseJavaModule {
|
|
|
46
48
|
|
|
47
49
|
return Base64.encodeToString(data, Base64.NO_WRAP);
|
|
48
50
|
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Enable debug logging for RealtimeKit Android module.
|
|
54
|
+
* Logs will be visible in logcat with tag "RealtimeKit".
|
|
55
|
+
*/
|
|
56
|
+
@ReactMethod
|
|
57
|
+
public void enableLogging() {
|
|
58
|
+
RTKLogger.enable();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Disable debug logging for RealtimeKit Android module.
|
|
63
|
+
*/
|
|
64
|
+
@ReactMethod
|
|
65
|
+
public void disableLogging() {
|
|
66
|
+
RTKLogger.disable();
|
|
67
|
+
}
|
|
49
68
|
}
|
|
@@ -3,11 +3,9 @@ package com.cloudflare.realtimekit;
|
|
|
3
3
|
import android.app.Notification;
|
|
4
4
|
import android.app.Service;
|
|
5
5
|
import android.content.Intent;
|
|
6
|
-
import android.content.Context;
|
|
7
|
-
import android.content.pm.ServiceInfo;
|
|
8
6
|
import android.os.Build;
|
|
9
7
|
import android.os.IBinder;
|
|
10
|
-
import android.
|
|
8
|
+
import android.content.pm.ServiceInfo;
|
|
11
9
|
import android.app.Activity;
|
|
12
10
|
import android.widget.Toast;
|
|
13
11
|
import com.cloudflare.realtimekit.RTKHolder;
|
|
@@ -33,7 +31,7 @@ public class ForegroundService extends Service {
|
|
|
33
31
|
startForeground(notificationHelper.NOTIFICATION_ID, notification);
|
|
34
32
|
}
|
|
35
33
|
} catch (RuntimeException e) {
|
|
36
|
-
|
|
34
|
+
RTKLogger.w("ForegroundService", "Failed to start ForegroundService due to: " + e.getMessage());
|
|
37
35
|
}
|
|
38
36
|
}
|
|
39
37
|
}
|
|
@@ -9,7 +9,6 @@ import android.content.pm.ActivityInfo;
|
|
|
9
9
|
import android.os.Build;
|
|
10
10
|
import android.os.Handler;
|
|
11
11
|
import android.os.PowerManager;
|
|
12
|
-
import android.util.Log;
|
|
13
12
|
import android.view.WindowManager;
|
|
14
13
|
|
|
15
14
|
import com.cloudflare.realtimekit.ForegroundService;
|
|
@@ -111,7 +110,7 @@ public class RTKHelperModule extends ReactContextBaseJavaModule {
|
|
|
111
110
|
} catch (RuntimeException e) {
|
|
112
111
|
// Avoid crashing due to ForegroundServiceStartNotAllowedException (API level 31).
|
|
113
112
|
// See: https://developer.android.com/guide/components/foreground-services#background-start-restrictions
|
|
114
|
-
|
|
113
|
+
RTKLogger.w("RTKHelper", "Media projection service not started: " + e.getMessage());
|
|
115
114
|
return;
|
|
116
115
|
}
|
|
117
116
|
if (mediaService != null) {
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
package com.cloudflare.realtimekit;
|
|
2
|
+
|
|
3
|
+
import android.util.Log;
|
|
4
|
+
|
|
5
|
+
public class RTKLogger {
|
|
6
|
+
private static final String BASE_TAG = "RealtimeKit";
|
|
7
|
+
private static boolean isEnabled = false;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Enable logging for RealtimeKit module
|
|
11
|
+
*/
|
|
12
|
+
public static void enable() {
|
|
13
|
+
isEnabled = true;
|
|
14
|
+
Log.i(BASE_TAG, "RealtimeKit logging enabled");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Disable logging for RealtimeKit module
|
|
19
|
+
*/
|
|
20
|
+
public static void disable() {
|
|
21
|
+
isEnabled = false;
|
|
22
|
+
Log.i(BASE_TAG, "RealtimeKit logging disabled");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Check if logging is enabled
|
|
27
|
+
*/
|
|
28
|
+
public static boolean isEnabled() {
|
|
29
|
+
return isEnabled;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Log debug message
|
|
34
|
+
*/
|
|
35
|
+
public static void d(String message) {
|
|
36
|
+
if (isEnabled) {
|
|
37
|
+
Log.d(BASE_TAG, message);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Log debug message with tag suffix
|
|
43
|
+
*/
|
|
44
|
+
public static void d(String tagSuffix, String message) {
|
|
45
|
+
if (isEnabled) {
|
|
46
|
+
Log.d(BASE_TAG + ":" + tagSuffix, message);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Log info message
|
|
52
|
+
*/
|
|
53
|
+
public static void i(String message) {
|
|
54
|
+
if (isEnabled) {
|
|
55
|
+
Log.i(BASE_TAG, message);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Log info message with tag suffix
|
|
61
|
+
*/
|
|
62
|
+
public static void i(String tagSuffix, String message) {
|
|
63
|
+
if (isEnabled) {
|
|
64
|
+
Log.i(BASE_TAG + ":" + tagSuffix, message);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Log warning message (always logged regardless of isEnabled)
|
|
70
|
+
*/
|
|
71
|
+
public static void w(String message) {
|
|
72
|
+
Log.w(BASE_TAG, message);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Log warning message with tag suffix (always logged)
|
|
77
|
+
*/
|
|
78
|
+
public static void w(String tagSuffix, String message) {
|
|
79
|
+
Log.w(BASE_TAG + ":" + tagSuffix, message);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Log error message (always logged regardless of isEnabled)
|
|
84
|
+
*/
|
|
85
|
+
public static void e(String message) {
|
|
86
|
+
Log.e(BASE_TAG, message);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Log error message with tag suffix (always logged)
|
|
91
|
+
*/
|
|
92
|
+
public static void e(String tagSuffix, String message) {
|
|
93
|
+
Log.e(BASE_TAG + ":" + tagSuffix, message);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Log error message with exception (always logged)
|
|
98
|
+
*/
|
|
99
|
+
public static void e(String message, Throwable throwable) {
|
|
100
|
+
Log.e(BASE_TAG, message, throwable);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Log error message with tag suffix and exception (always logged)
|
|
105
|
+
*/
|
|
106
|
+
public static void e(String tagSuffix, String message, Throwable throwable) {
|
|
107
|
+
Log.e(BASE_TAG + ":" + tagSuffix, message, throwable);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Format a message with arguments
|
|
112
|
+
*/
|
|
113
|
+
public static String format(String format, Object... args) {
|
|
114
|
+
return String.format(format, args);
|
|
115
|
+
}
|
|
116
|
+
}
|
package/android/src/main/java/com/cloudflare/realtimekit/incallmanager/AppRTCBluetoothManager.java
CHANGED
|
@@ -33,6 +33,7 @@ import androidx.annotation.RequiresApi;
|
|
|
33
33
|
import java.util.List;
|
|
34
34
|
import java.util.Set;
|
|
35
35
|
import java.util.ArrayList;
|
|
36
|
+
import com.cloudflare.realtimekit.RTKLogger;
|
|
36
37
|
import com.cloudflare.realtimekit.incallmanager.AppRTCUtils;
|
|
37
38
|
import com.cloudflare.realtimekit.incallmanager.ThreadUtils;
|
|
38
39
|
import com.cloudflare.realtimekit.incallmanager.InCallManagerModule;
|
|
@@ -107,10 +108,10 @@ public class AppRTCBluetoothManager {
|
|
|
107
108
|
if (profile != BluetoothProfile.HEADSET || bluetoothState == State.UNINITIALIZED) {
|
|
108
109
|
return;
|
|
109
110
|
}
|
|
110
|
-
|
|
111
|
+
RTKLogger.d("BluetoothManager", "BluetoothServiceListener.onServiceConnected: BT state=" + bluetoothState);
|
|
111
112
|
// Android only supports one connected Bluetooth Headset at a time.
|
|
112
113
|
bluetoothHeadset = (BluetoothHeadset) proxy;
|
|
113
|
-
|
|
114
|
+
RTKLogger.d("BluetoothManager", "onServiceConnected done: BT state=" + bluetoothState);
|
|
114
115
|
updateAudioDeviceState();
|
|
115
116
|
}
|
|
116
117
|
@Override
|
|
@@ -119,13 +120,13 @@ public class AppRTCBluetoothManager {
|
|
|
119
120
|
if (profile != BluetoothProfile.HEADSET || bluetoothState == State.UNINITIALIZED) {
|
|
120
121
|
return;
|
|
121
122
|
}
|
|
122
|
-
|
|
123
|
+
RTKLogger.d("BluetoothManager", "BluetoothServiceListener.onServiceDisconnected: BT state=" + bluetoothState);
|
|
123
124
|
stopScoAudio();
|
|
124
125
|
bluetoothHeadset = null;
|
|
125
126
|
bluetoothDevice = null;
|
|
126
127
|
bluetoothState = State.HEADSET_UNAVAILABLE;
|
|
127
128
|
updateAudioDeviceState();
|
|
128
|
-
|
|
129
|
+
RTKLogger.d("BluetoothManager", "onServiceDisconnected done: BT state=" + bluetoothState);
|
|
129
130
|
}
|
|
130
131
|
}
|
|
131
132
|
|
|
@@ -165,7 +166,7 @@ public class AppRTCBluetoothManager {
|
|
|
165
166
|
return;
|
|
166
167
|
}
|
|
167
168
|
final String action = intent.getAction();
|
|
168
|
-
|
|
169
|
+
RTKLogger.i("BluetoothManager", "BLE Action: " + action);
|
|
169
170
|
// Change in connection state of the Headset profile. Note that the
|
|
170
171
|
// change does not tell us anything about whether we're streaming
|
|
171
172
|
// audio to BT over SCO. Typically received when user turns on a BT
|
|
@@ -173,11 +174,11 @@ public class AppRTCBluetoothManager {
|
|
|
173
174
|
if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
|
|
174
175
|
final int state =
|
|
175
176
|
intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_DISCONNECTED);
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
177
|
+
RTKLogger.d("BluetoothManager", "BluetoothHeadsetBroadcastReceiver.onReceive: "
|
|
178
|
+
+ "a=ACTION_CONNECTION_STATE_CHANGED, "
|
|
179
|
+
+ "s=" + stateToString(state) + ", "
|
|
180
|
+
+ "sb=" + isInitialStickyBroadcast() + ", "
|
|
181
|
+
+ "BT state: " + bluetoothState);
|
|
181
182
|
if (state == BluetoothHeadset.STATE_CONNECTED) {
|
|
182
183
|
scoConnectionAttempts = 0;
|
|
183
184
|
updateAudioDeviceState();
|
|
@@ -196,42 +197,42 @@ public class AppRTCBluetoothManager {
|
|
|
196
197
|
final int state = intent.getIntExtra(
|
|
197
198
|
BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
|
|
198
199
|
updateAudioDeviceState();
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
200
|
+
RTKLogger.d("BluetoothManager", "BluetoothHeadsetBroadcastReceiver.onReceive: "
|
|
201
|
+
+ "a=ACTION_AUDIO_STATE_CHANGED, "
|
|
202
|
+
+ "s=" + stateToString(state) + ", "
|
|
203
|
+
+ "sb=" + isInitialStickyBroadcast() + ", "
|
|
204
|
+
+ "BT state: " + bluetoothState);
|
|
204
205
|
if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
|
|
205
206
|
cancelTimer();
|
|
206
207
|
if (bluetoothState == State.SCO_CONNECTING) {
|
|
207
|
-
|
|
208
|
+
RTKLogger.d("BluetoothManager", "+++ Bluetooth audio SCO is now connected");
|
|
208
209
|
bluetoothState = State.SCO_CONNECTED;
|
|
209
210
|
scoConnectionAttempts = 0;
|
|
210
211
|
updateAudioDeviceState();
|
|
211
212
|
} else {
|
|
212
|
-
|
|
213
|
+
RTKLogger.w("BluetoothManager", "Unexpected state BluetoothHeadset.STATE_AUDIO_CONNECTED");
|
|
213
214
|
}
|
|
214
215
|
} else if (state == BluetoothHeadset.STATE_AUDIO_CONNECTING) {
|
|
215
|
-
|
|
216
|
+
RTKLogger.d("BluetoothManager", "+++ Bluetooth audio SCO is now connecting...");
|
|
216
217
|
} else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
|
|
217
|
-
|
|
218
|
+
RTKLogger.d("BluetoothManager", "+++ Bluetooth audio SCO is now disconnected");
|
|
218
219
|
if (isInitialStickyBroadcast()) {
|
|
219
|
-
|
|
220
|
+
RTKLogger.d("BluetoothManager", "Ignore STATE_AUDIO_DISCONNECTED initial sticky broadcast.");
|
|
220
221
|
return;
|
|
221
222
|
}
|
|
222
223
|
updateAudioDeviceState();
|
|
223
224
|
}
|
|
224
225
|
}
|
|
225
|
-
|
|
226
|
+
RTKLogger.d("BluetoothManager", "onReceive done: BT state=" + bluetoothState);
|
|
226
227
|
}
|
|
227
228
|
}
|
|
228
229
|
/** Construction. */
|
|
229
230
|
public static AppRTCBluetoothManager create(Context context, InCallManagerModule audioManager) {
|
|
230
|
-
|
|
231
|
+
RTKLogger.d("BluetoothManager", "create" + AppRTCUtils.getThreadInfo());
|
|
231
232
|
return new AppRTCBluetoothManager(context, audioManager);
|
|
232
233
|
}
|
|
233
234
|
protected AppRTCBluetoothManager(Context context, InCallManagerModule audioManager) {
|
|
234
|
-
|
|
235
|
+
RTKLogger.d("BluetoothManager", "ctor");
|
|
235
236
|
ThreadUtils.checkIsOnMainThread();
|
|
236
237
|
apprtcContext = context;
|
|
237
238
|
apprtcAudioManager = audioManager;
|
|
@@ -265,14 +266,14 @@ public class AppRTCBluetoothManager {
|
|
|
265
266
|
@SuppressLint("MissingPermission")
|
|
266
267
|
public void start() {
|
|
267
268
|
ThreadUtils.checkIsOnMainThread();
|
|
268
|
-
|
|
269
|
+
RTKLogger.d("BluetoothManager", "start");
|
|
269
270
|
String p = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? android.Manifest.permission.BLUETOOTH_CONNECT : android.Manifest.permission.BLUETOOTH;
|
|
270
271
|
if (!hasPermission(apprtcContext, p)) {
|
|
271
|
-
|
|
272
|
+
RTKLogger.w("BluetoothManager", "Process (pid=" + Process.myPid() + ") lacks BLUETOOTH permission");
|
|
272
273
|
return;
|
|
273
274
|
}
|
|
274
275
|
if (bluetoothState != State.UNINITIALIZED) {
|
|
275
|
-
|
|
276
|
+
RTKLogger.w("BluetoothManager", "Invalid BT state");
|
|
276
277
|
return;
|
|
277
278
|
}
|
|
278
279
|
bluetoothHeadset = null;
|
|
@@ -281,20 +282,20 @@ public class AppRTCBluetoothManager {
|
|
|
281
282
|
// Get a handle to the default local Bluetooth adapter.
|
|
282
283
|
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
|
283
284
|
if (bluetoothAdapter == null) {
|
|
284
|
-
|
|
285
|
+
RTKLogger.w("BluetoothManager", "Device does not support Bluetooth");
|
|
285
286
|
return;
|
|
286
287
|
}
|
|
287
288
|
// Ensure that the device supports use of BT SCO audio for off call use cases.
|
|
288
289
|
if (!audioManager.isBluetoothScoAvailableOffCall()) {
|
|
289
|
-
|
|
290
|
+
RTKLogger.e("BluetoothManager", "Bluetooth SCO audio is not available off call");
|
|
290
291
|
return;
|
|
291
292
|
}
|
|
292
|
-
|
|
293
|
+
logBluetoothAdapterInfo(bluetoothAdapter);
|
|
293
294
|
// Establish a connection to the HEADSET profile (includes both Bluetooth Headset and
|
|
294
295
|
// Hands-Free) proxy object and install a listener.
|
|
295
296
|
if (!getBluetoothProfileProxy(
|
|
296
297
|
apprtcContext, bluetoothServiceListener, BluetoothProfile.HEADSET)) {
|
|
297
|
-
|
|
298
|
+
RTKLogger.e("BluetoothManager", "BluetoothAdapter.getProfileProxy(HEADSET) failed");
|
|
298
299
|
return;
|
|
299
300
|
}
|
|
300
301
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
@@ -307,17 +308,17 @@ public class AppRTCBluetoothManager {
|
|
|
307
308
|
// Register receiver for change in audio connection state of the Headset profile.
|
|
308
309
|
bluetoothHeadsetFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
|
|
309
310
|
registerReceiver(bluetoothHeadsetReceiver, bluetoothHeadsetFilter);
|
|
310
|
-
|
|
311
|
-
|
|
311
|
+
RTKLogger.d("BluetoothManager", "HEADSET profile state: "
|
|
312
|
+
+ stateToString(bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET)));
|
|
312
313
|
}
|
|
313
|
-
|
|
314
|
+
RTKLogger.d("BluetoothManager", "Bluetooth proxy for headset profile has started");
|
|
314
315
|
bluetoothState = State.HEADSET_UNAVAILABLE;
|
|
315
|
-
|
|
316
|
+
RTKLogger.d("BluetoothManager", "start done: BT state=" + bluetoothState);
|
|
316
317
|
}
|
|
317
318
|
/** Stops and closes all components related to Bluetooth audio. */
|
|
318
319
|
public void stop() {
|
|
319
320
|
ThreadUtils.checkIsOnMainThread();
|
|
320
|
-
|
|
321
|
+
RTKLogger.d("BluetoothManager", "stop: BT state=" + bluetoothState);
|
|
321
322
|
if (bluetoothAdapter == null) {
|
|
322
323
|
return;
|
|
323
324
|
}
|
|
@@ -340,7 +341,7 @@ public class AppRTCBluetoothManager {
|
|
|
340
341
|
bluetoothAdapter = null;
|
|
341
342
|
bluetoothDevice = null;
|
|
342
343
|
bluetoothState = State.UNINITIALIZED;
|
|
343
|
-
|
|
344
|
+
RTKLogger.d("BluetoothManager", "stop done: BT state=" + bluetoothState);
|
|
344
345
|
}
|
|
345
346
|
/**
|
|
346
347
|
* Starts Bluetooth SCO connection with remote device.
|
|
@@ -357,26 +358,26 @@ public class AppRTCBluetoothManager {
|
|
|
357
358
|
*/
|
|
358
359
|
public boolean startScoAudio() {
|
|
359
360
|
ThreadUtils.checkIsOnMainThread();
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
361
|
+
RTKLogger.d("BluetoothManager", "startSco: BT state=" + bluetoothState + ", "
|
|
362
|
+
+ "attempts: " + scoConnectionAttempts + ", "
|
|
363
|
+
+ "SCO is on: " + isScoOn());
|
|
363
364
|
if (scoConnectionAttempts >= MAX_SCO_CONNECTION_ATTEMPTS) {
|
|
364
|
-
|
|
365
|
+
RTKLogger.e("BluetoothManager", "BT SCO connection fails - no more attempts");
|
|
365
366
|
return false;
|
|
366
367
|
}
|
|
367
368
|
if (bluetoothState != State.HEADSET_AVAILABLE) {
|
|
368
|
-
|
|
369
|
+
RTKLogger.e("BluetoothManager", "BT SCO connection fails - no headset available");
|
|
369
370
|
return false;
|
|
370
371
|
}
|
|
371
372
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
372
373
|
if (bluetoothAudioDevice != null) {
|
|
373
374
|
audioManager.setCommunicationDevice(bluetoothAudioDevice);
|
|
374
375
|
bluetoothState = State.SCO_CONNECTED;
|
|
375
|
-
|
|
376
|
-
|
|
376
|
+
RTKLogger.d("BluetoothManager", "Set bluetooth audio device as communication device: "
|
|
377
|
+
+ "id=" + bluetoothAudioDevice.getId());
|
|
377
378
|
} else {
|
|
378
379
|
bluetoothState = State.SCO_DISCONNECTING;
|
|
379
|
-
|
|
380
|
+
RTKLogger.d("BluetoothManager", "Cannot find any bluetooth SCO device to set as communication device");
|
|
380
381
|
}
|
|
381
382
|
updateAudioDeviceState();
|
|
382
383
|
} else {
|
|
@@ -384,14 +385,14 @@ public class AppRTCBluetoothManager {
|
|
|
384
385
|
// connection to be available when the method returns but instead register to receive the
|
|
385
386
|
// intent ACTION_SCO_AUDIO_STATE_UPDATED and wait for the state to be SCO_AUDIO_STATE_CONNECTED.
|
|
386
387
|
// Start BT SCO channel and wait for ACTION_AUDIO_STATE_CHANGED.
|
|
387
|
-
|
|
388
|
+
RTKLogger.d("BluetoothManager", "Starting Bluetooth SCO and waits for ACTION_AUDIO_STATE_CHANGED...");
|
|
388
389
|
bluetoothState = State.SCO_CONNECTING;
|
|
389
390
|
startTimer();
|
|
390
391
|
audioManager.startBluetoothSco();
|
|
391
392
|
audioManager.setBluetoothScoOn(true);
|
|
392
393
|
scoConnectionAttempts++;
|
|
393
|
-
|
|
394
|
-
|
|
394
|
+
RTKLogger.d("BluetoothManager", "startScoAudio done: BT state=" + bluetoothState + ", "
|
|
395
|
+
+ "SCO is on: " + isScoOn());
|
|
395
396
|
}
|
|
396
397
|
return true;
|
|
397
398
|
}
|
|
@@ -411,8 +412,8 @@ public class AppRTCBluetoothManager {
|
|
|
411
412
|
/** Stops Bluetooth SCO connection with remote device. */
|
|
412
413
|
public void stopScoAudio() {
|
|
413
414
|
ThreadUtils.checkIsOnMainThread();
|
|
414
|
-
|
|
415
|
-
|
|
415
|
+
RTKLogger.d("BluetoothManager", "stopScoAudio: BT state=" + bluetoothState + ", "
|
|
416
|
+
+ "SCO is on: " + isScoOn());
|
|
416
417
|
if (bluetoothState != State.SCO_CONNECTING && bluetoothState != State.SCO_CONNECTED) {
|
|
417
418
|
return;
|
|
418
419
|
}
|
|
@@ -424,8 +425,8 @@ public class AppRTCBluetoothManager {
|
|
|
424
425
|
audioManager.setBluetoothScoOn(false);
|
|
425
426
|
}
|
|
426
427
|
bluetoothState = State.SCO_DISCONNECTING;
|
|
427
|
-
|
|
428
|
-
|
|
428
|
+
RTKLogger.d("BluetoothManager", "stopScoAudio done: BT state=" + bluetoothState + ", "
|
|
429
|
+
+ "SCO is on: " + isScoOn());
|
|
429
430
|
}
|
|
430
431
|
/**
|
|
431
432
|
* Use the BluetoothHeadset proxy object (controls the Bluetooth Headset
|
|
@@ -439,13 +440,13 @@ public class AppRTCBluetoothManager {
|
|
|
439
440
|
if (bluetoothState == State.UNINITIALIZED || bluetoothHeadset == null) {
|
|
440
441
|
return;
|
|
441
442
|
}
|
|
442
|
-
|
|
443
|
+
RTKLogger.d("BluetoothManager", "updateDevice");
|
|
443
444
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
444
445
|
bluetoothAudioDevice = getScoDevice();
|
|
445
446
|
if (bluetoothAudioDevice != null) {
|
|
446
447
|
bluetoothState = State.HEADSET_AVAILABLE;
|
|
447
|
-
|
|
448
|
-
|
|
448
|
+
RTKLogger.d("BluetoothManager", "Connected bluetooth headset: "
|
|
449
|
+
+ "name=" + bluetoothAudioDevice.getProductName());
|
|
449
450
|
} else {
|
|
450
451
|
bluetoothState = State.HEADSET_UNAVAILABLE;
|
|
451
452
|
}
|
|
@@ -457,18 +458,18 @@ public class AppRTCBluetoothManager {
|
|
|
457
458
|
if (devices.isEmpty()) {
|
|
458
459
|
bluetoothDevice = null;
|
|
459
460
|
bluetoothState = State.HEADSET_UNAVAILABLE;
|
|
460
|
-
|
|
461
|
+
RTKLogger.d("BluetoothManager", "No connected bluetooth headset");
|
|
461
462
|
} else {
|
|
462
463
|
// Always use first device in list. Android only supports one device.
|
|
463
464
|
bluetoothDevice = devices.get(0);
|
|
464
465
|
bluetoothState = State.HEADSET_AVAILABLE;
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
466
|
+
RTKLogger.d("BluetoothManager", "Connected bluetooth headset: "
|
|
467
|
+
+ "name=" + bluetoothDevice.getName() + ", "
|
|
468
|
+
+ "state=" + stateToString(bluetoothHeadset.getConnectionState(bluetoothDevice))
|
|
469
|
+
+ ", SCO audio=" + bluetoothHeadset.isAudioConnected(bluetoothDevice));
|
|
469
470
|
}
|
|
470
471
|
}
|
|
471
|
-
|
|
472
|
+
RTKLogger.d("BluetoothManager", "updateDevice done: BT state=" + bluetoothState);
|
|
472
473
|
}
|
|
473
474
|
/**
|
|
474
475
|
* Stubs for test mocks.
|
|
@@ -506,7 +507,7 @@ public class AppRTCBluetoothManager {
|
|
|
506
507
|
/** Logs the state of the local Bluetooth adapter. */
|
|
507
508
|
@SuppressLint({"HardwareIds", "MissingPermission"})
|
|
508
509
|
protected void logBluetoothAdapterInfo(BluetoothAdapter localAdapter) {
|
|
509
|
-
|
|
510
|
+
RTKLogger.d("BluetoothManager", "BluetoothAdapter: "
|
|
510
511
|
+ "enabled=" + localAdapter.isEnabled() + ", "
|
|
511
512
|
+ "state=" + stateToString(localAdapter.getState()) + ", "
|
|
512
513
|
+ "name=" + localAdapter.getName() + ", "
|
|
@@ -514,29 +515,29 @@ public class AppRTCBluetoothManager {
|
|
|
514
515
|
// Log the set of BluetoothDevice objects that are bonded (paired) to the local adapter.
|
|
515
516
|
Set<BluetoothDevice> pairedDevices = localAdapter.getBondedDevices();
|
|
516
517
|
if (!pairedDevices.isEmpty()) {
|
|
517
|
-
|
|
518
|
+
RTKLogger.d("BluetoothManager", "paired devices:");
|
|
518
519
|
for (BluetoothDevice device : pairedDevices) {
|
|
519
|
-
|
|
520
|
+
RTKLogger.d("BluetoothManager", " name=" + device.getName() + ", address=" + device.getAddress() + ", deviceClass=" + String.valueOf(device.getBluetoothClass().getDeviceClass()) + ", deviceMajorClass=" + String.valueOf(device.getBluetoothClass().getMajorDeviceClass()));
|
|
520
521
|
}
|
|
521
522
|
}
|
|
522
523
|
}
|
|
523
524
|
/** Ensures that the audio manager updates its list of available audio devices. */
|
|
524
525
|
private void updateAudioDeviceState() {
|
|
525
526
|
ThreadUtils.checkIsOnMainThread();
|
|
526
|
-
|
|
527
|
+
RTKLogger.d("BluetoothManager", "updateAudioDeviceState");
|
|
527
528
|
updateDevice();
|
|
528
529
|
apprtcAudioManager.updateAudioDeviceState();
|
|
529
530
|
}
|
|
530
531
|
/** Starts timer which times out after BLUETOOTH_SCO_TIMEOUT_MS milliseconds. */
|
|
531
532
|
private void startTimer() {
|
|
532
533
|
ThreadUtils.checkIsOnMainThread();
|
|
533
|
-
|
|
534
|
+
RTKLogger.d("BluetoothManager", "startTimer");
|
|
534
535
|
handler.postDelayed(bluetoothTimeoutRunnable, BLUETOOTH_SCO_TIMEOUT_MS);
|
|
535
536
|
}
|
|
536
537
|
/** Cancels any outstanding timer tasks. */
|
|
537
538
|
private void cancelTimer() {
|
|
538
539
|
ThreadUtils.checkIsOnMainThread();
|
|
539
|
-
|
|
540
|
+
RTKLogger.d("BluetoothManager", "cancelTimer");
|
|
540
541
|
handler.removeCallbacks(bluetoothTimeoutRunnable);
|
|
541
542
|
}
|
|
542
543
|
/**
|
|
@@ -550,11 +551,11 @@ public class AppRTCBluetoothManager {
|
|
|
550
551
|
return;
|
|
551
552
|
}
|
|
552
553
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
553
|
-
|
|
554
|
+
RTKLogger.w("BluetoothManager", "Invalid state, the timeout should not be running on the version: " + Build.VERSION.SDK_INT);
|
|
554
555
|
} else {
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
556
|
+
RTKLogger.d("BluetoothManager", "bluetoothTimeout: BT state=" + bluetoothState + ", "
|
|
557
|
+
+ "attempts: " + scoConnectionAttempts + ", "
|
|
558
|
+
+ "SCO is on: " + isScoOn());
|
|
558
559
|
if (bluetoothState != State.SCO_CONNECTING) {
|
|
559
560
|
return;
|
|
560
561
|
}
|
|
@@ -564,10 +565,10 @@ public class AppRTCBluetoothManager {
|
|
|
564
565
|
if (devices.size() > 0) {
|
|
565
566
|
bluetoothDevice = devices.get(0);
|
|
566
567
|
if (bluetoothHeadset.isAudioConnected(bluetoothDevice)) {
|
|
567
|
-
|
|
568
|
+
RTKLogger.d("BluetoothManager", "SCO connected with " + bluetoothDevice.getName());
|
|
568
569
|
scoConnected = true;
|
|
569
570
|
} else {
|
|
570
|
-
|
|
571
|
+
RTKLogger.d("BluetoothManager", "SCO is not connected with " + bluetoothDevice.getName());
|
|
571
572
|
}
|
|
572
573
|
}
|
|
573
574
|
if (scoConnected) {
|
|
@@ -576,12 +577,12 @@ public class AppRTCBluetoothManager {
|
|
|
576
577
|
scoConnectionAttempts = 0;
|
|
577
578
|
} else {
|
|
578
579
|
// Give up and "cancel" our request by calling stopBluetoothSco().
|
|
579
|
-
|
|
580
|
+
RTKLogger.w("BluetoothManager", "BT failed to connect after timeout");
|
|
580
581
|
stopScoAudio();
|
|
581
582
|
}
|
|
582
583
|
}
|
|
583
584
|
updateAudioDeviceState();
|
|
584
|
-
|
|
585
|
+
RTKLogger.d("BluetoothManager", "bluetoothTimeout done: BT state=" + bluetoothState);
|
|
585
586
|
}
|
|
586
587
|
/** Checks whether audio uses Bluetooth SCO. */
|
|
587
588
|
private boolean isScoOn() {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
package com.cloudflare.realtimekit.incallmanager;
|
|
11
11
|
import android.os.Build;
|
|
12
12
|
import android.util.Log;
|
|
13
|
+
import com.cloudflare.realtimekit.RTKLogger;
|
|
13
14
|
/**
|
|
14
15
|
* AppRTCUtils provides helper functions for managing thread safety.
|
|
15
16
|
*/
|
|
@@ -28,14 +29,14 @@ public final class AppRTCUtils {
|
|
|
28
29
|
}
|
|
29
30
|
/** Information about the current build, taken from system properties. */
|
|
30
31
|
public static void logDeviceInfo(String tag) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
RTKLogger.d(tag, "Android SDK: " + Build.VERSION.SDK_INT + ", "
|
|
33
|
+
+ "Release: " + Build.VERSION.RELEASE + ", "
|
|
34
|
+
+ "Brand: " + Build.BRAND + ", "
|
|
35
|
+
+ "Device: " + Build.DEVICE + ", "
|
|
36
|
+
+ "Id: " + Build.ID + ", "
|
|
37
|
+
+ "Hardware: " + Build.HARDWARE + ", "
|
|
38
|
+
+ "Manufacturer: " + Build.MANUFACTURER + ", "
|
|
39
|
+
+ "Model: " + Build.MODEL + ", "
|
|
40
|
+
+ "Product: " + Build.PRODUCT);
|
|
40
41
|
}
|
|
41
42
|
}
|