From 0f8830df898c162299d8bf91f657b31da2a41e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Kr=C3=BCger?= Date: Thu, 23 Jun 2022 15:00:13 +0200 Subject: [PATCH 1/6] Use log level exception for exceptions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also log the exception itself instead of the localized message concatinated in the log message. Signed-off-by: Tim Krüger --- .../talk/services/firebase/ChatAndCallMessagingService.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/services/firebase/ChatAndCallMessagingService.kt b/app/src/gplay/java/com/nextcloud/talk/services/firebase/ChatAndCallMessagingService.kt index e9eadfbeb..745a39f57 100644 --- a/app/src/gplay/java/com/nextcloud/talk/services/firebase/ChatAndCallMessagingService.kt +++ b/app/src/gplay/java/com/nextcloud/talk/services/firebase/ChatAndCallMessagingService.kt @@ -161,14 +161,14 @@ class ChatAndCallMessagingService : FirebaseMessagingService() { decryptMessage(privateKey, base64DecodedSubject, subject, signature) } } catch (e1: NoSuchAlgorithmException) { - Log.d(NotificationWorker.TAG, "No proper algorithm to decrypt the message " + e1.localizedMessage) + Log.e(NotificationWorker.TAG, "No proper algorithm to decrypt the message.", e1) } catch (e1: NoSuchPaddingException) { - Log.d(NotificationWorker.TAG, "No proper padding to decrypt the message " + e1.localizedMessage) + Log.e(NotificationWorker.TAG, "No proper padding to decrypt the message.", e1) } catch (e1: InvalidKeyException) { - Log.d(NotificationWorker.TAG, "Invalid private key " + e1.localizedMessage) + Log.e(NotificationWorker.TAG, "Invalid private key.", e1) } } catch (exception: Exception) { - Log.d(NotificationWorker.TAG, "Something went very wrong " + exception.localizedMessage, exception) + Log.e(NotificationWorker.TAG, "Something went very wrong!", exception) } } From c13d23bda263f8213d60198259a97b194e543620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Kr=C3=BCger?= Date: Thu, 23 Jun 2022 15:16:54 +0200 Subject: [PATCH 2/6] Make PendingIntent flag immutable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tim Krüger --- .../talk/services/firebase/ChatAndCallMessagingService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/services/firebase/ChatAndCallMessagingService.kt b/app/src/gplay/java/com/nextcloud/talk/services/firebase/ChatAndCallMessagingService.kt index 745a39f57..b32c3ee7c 100644 --- a/app/src/gplay/java/com/nextcloud/talk/services/firebase/ChatAndCallMessagingService.kt +++ b/app/src/gplay/java/com/nextcloud/talk/services/firebase/ChatAndCallMessagingService.kt @@ -218,7 +218,7 @@ class ChatAndCallMessagingService : FirebaseMessagingService() { 0, fullScreenIntent, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT } else { PendingIntent.FLAG_UPDATE_CURRENT } From 10a4521af934cd7039645f6e8ad248b745daf99d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Kr=C3=BCger?= Date: Thu, 23 Jun 2022 15:20:32 +0200 Subject: [PATCH 3/6] Rename 'WebRtcAudioManger' to 'WebRtcAudioManager' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tim Krüger --- .../talk/activities/CallActivity.java | 25 +++++++++---------- .../talk/ui/dialog/AudioOutputDialog.kt | 24 +++++++++--------- ...dioManger.java => WebRtcAudioManager.java} | 12 ++++----- .../talk/webrtc/WebRtcBluetoothManager.java | 6 ++--- 4 files changed, 33 insertions(+), 34 deletions(-) rename app/src/main/java/com/nextcloud/talk/webrtc/{WebRtcAudioManger.java => WebRtcAudioManager.java} (98%) diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java index 14753579e..9b7dc4f80 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -95,7 +95,7 @@ import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.power.PowerManagerUtils; import com.nextcloud.talk.utils.preferences.AppPreferences; import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder; -import com.nextcloud.talk.webrtc.WebRtcAudioManger; +import com.nextcloud.talk.webrtc.WebRtcAudioManager; import com.nextcloud.talk.webrtc.MagicWebRTCUtils; import com.nextcloud.talk.webrtc.MagicWebSocketInstance; import com.nextcloud.talk.webrtc.PeerConnectionWrapper; @@ -162,7 +162,6 @@ import me.zhanghai.android.effortlesspermissions.OpenAppDetailsDialogFragment; import okhttp3.Cache; import pub.devrel.easypermissions.AfterPermissionGranted; -import static android.app.PendingIntent.FLAG_MUTABLE; import static android.app.PendingIntent.FLAG_MUTABLE; import static com.nextcloud.talk.webrtc.Globals.JOB_ID; import static com.nextcloud.talk.webrtc.Globals.PARTICIPANTS_UPDATE; @@ -189,7 +188,7 @@ public class CallActivity extends CallBaseActivity { public static final String TAG = "CallActivity"; - public WebRtcAudioManger audioManager; + public WebRtcAudioManager audioManager; private static final String[] PERMISSIONS_CALL = { Manifest.permission.CAMERA, @@ -452,16 +451,16 @@ public class CallActivity extends CallBaseActivity { // Create and audio manager that will take care of audio routing, // audio modes, audio device enumeration etc. - audioManager = WebRtcAudioManger.create(getApplicationContext(), isVoiceOnlyCall); + audioManager = WebRtcAudioManager.create(getApplicationContext(), isVoiceOnlyCall); // Store existing audio settings and change audio mode to // MODE_IN_COMMUNICATION for best possible VoIP performance. Log.d(TAG, "Starting the audio manager..."); audioManager.start(this::onAudioManagerDevicesChanged); if (isVoiceOnlyCall) { - setAudioOutputChannel(WebRtcAudioManger.AudioDevice.EARPIECE); + setAudioOutputChannel(WebRtcAudioManager.AudioDevice.EARPIECE); } else { - setAudioOutputChannel(WebRtcAudioManger.AudioDevice.SPEAKER_PHONE); + setAudioOutputChannel(WebRtcAudioManager.AudioDevice.SPEAKER_PHONE); } iceServers = new ArrayList<>(); @@ -495,14 +494,14 @@ public class CallActivity extends CallBaseActivity { microphoneInitialization(); } - public void setAudioOutputChannel(WebRtcAudioManger.AudioDevice selectedAudioDevice) { + public void setAudioOutputChannel(WebRtcAudioManager.AudioDevice selectedAudioDevice) { if (audioManager != null) { audioManager.selectAudioDevice(selectedAudioDevice); updateAudioOutputButton(audioManager.getCurrentAudioDevice()); } } - private void updateAudioOutputButton(WebRtcAudioManger.AudioDevice activeAudioDevice) { + private void updateAudioOutputButton(WebRtcAudioManager.AudioDevice activeAudioDevice) { switch (activeAudioDevice) { case BLUETOOTH: binding.audioOutputButton.getHierarchy().setPlaceholderImage( @@ -796,14 +795,14 @@ public class CallActivity extends CallBaseActivity { } private void onAudioManagerDevicesChanged( - final WebRtcAudioManger.AudioDevice currentDevice, - final Set availableDevices) { + final WebRtcAudioManager.AudioDevice currentDevice, + final Set availableDevices) { Log.d(TAG, "onAudioManagerDevicesChanged: " + availableDevices + ", " + "currentDevice: " + currentDevice); - final boolean shouldDisableProximityLock = (currentDevice.equals(WebRtcAudioManger.AudioDevice.WIRED_HEADSET) - || currentDevice.equals(WebRtcAudioManger.AudioDevice.SPEAKER_PHONE) - || currentDevice.equals(WebRtcAudioManger.AudioDevice.BLUETOOTH)); + final boolean shouldDisableProximityLock = (currentDevice.equals(WebRtcAudioManager.AudioDevice.WIRED_HEADSET) + || currentDevice.equals(WebRtcAudioManager.AudioDevice.SPEAKER_PHONE) + || currentDevice.equals(WebRtcAudioManager.AudioDevice.BLUETOOTH)); if (shouldDisableProximityLock) { powerManagerUtils.updatePhoneState(PowerManagerUtils.PhoneState.WITHOUT_PROXIMITY_SENSOR_LOCK); diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/AudioOutputDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/AudioOutputDialog.kt index ff394bcd8..e4f9105f4 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/AudioOutputDialog.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/AudioOutputDialog.kt @@ -30,7 +30,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog import com.nextcloud.talk.R import com.nextcloud.talk.activities.CallActivity import com.nextcloud.talk.databinding.DialogAudioOutputBinding -import com.nextcloud.talk.webrtc.WebRtcAudioManger +import com.nextcloud.talk.webrtc.WebRtcAudioManager class AudioOutputDialog(val callActivity: CallActivity) : BottomSheetDialog(callActivity) { @@ -47,26 +47,26 @@ class AudioOutputDialog(val callActivity: CallActivity) : BottomSheetDialog(call } fun updateOutputDeviceList() { - if (callActivity.audioManager?.audioDevices?.contains(WebRtcAudioManger.AudioDevice.BLUETOOTH) == false) { + if (callActivity.audioManager?.audioDevices?.contains(WebRtcAudioManager.AudioDevice.BLUETOOTH) == false) { dialogAudioOutputBinding.audioOutputBluetooth.visibility = View.GONE } else { dialogAudioOutputBinding.audioOutputBluetooth.visibility = View.VISIBLE } - if (callActivity.audioManager?.audioDevices?.contains(WebRtcAudioManger.AudioDevice.EARPIECE) == false) { + if (callActivity.audioManager?.audioDevices?.contains(WebRtcAudioManager.AudioDevice.EARPIECE) == false) { dialogAudioOutputBinding.audioOutputEarspeaker.visibility = View.GONE } else { dialogAudioOutputBinding.audioOutputEarspeaker.visibility = View.VISIBLE } - if (callActivity.audioManager?.audioDevices?.contains(WebRtcAudioManger.AudioDevice.SPEAKER_PHONE) == false) { + if (callActivity.audioManager?.audioDevices?.contains(WebRtcAudioManager.AudioDevice.SPEAKER_PHONE) == false) { dialogAudioOutputBinding.audioOutputSpeaker.visibility = View.GONE } else { dialogAudioOutputBinding.audioOutputSpeaker.visibility = View.VISIBLE } if (callActivity.audioManager?.currentAudioDevice?.equals( - WebRtcAudioManger.AudioDevice.WIRED_HEADSET + WebRtcAudioManager.AudioDevice.WIRED_HEADSET ) == true ) { dialogAudioOutputBinding.audioOutputEarspeaker.visibility = View.GONE @@ -81,7 +81,7 @@ class AudioOutputDialog(val callActivity: CallActivity) : BottomSheetDialog(call private fun highlightActiveOutputChannel() { when (callActivity.audioManager?.currentAudioDevice) { - WebRtcAudioManger.AudioDevice.BLUETOOTH -> { + WebRtcAudioManager.AudioDevice.BLUETOOTH -> { dialogAudioOutputBinding.audioOutputBluetoothIcon.setColorFilter( ContextCompat.getColor( context, @@ -94,7 +94,7 @@ class AudioOutputDialog(val callActivity: CallActivity) : BottomSheetDialog(call ) } - WebRtcAudioManger.AudioDevice.SPEAKER_PHONE -> { + WebRtcAudioManager.AudioDevice.SPEAKER_PHONE -> { dialogAudioOutputBinding.audioOutputSpeakerIcon.setColorFilter( ContextCompat.getColor( context, @@ -107,7 +107,7 @@ class AudioOutputDialog(val callActivity: CallActivity) : BottomSheetDialog(call ) } - WebRtcAudioManger.AudioDevice.EARPIECE -> { + WebRtcAudioManager.AudioDevice.EARPIECE -> { dialogAudioOutputBinding.audioOutputEarspeakerIcon.setColorFilter( ContextCompat.getColor( context, @@ -120,7 +120,7 @@ class AudioOutputDialog(val callActivity: CallActivity) : BottomSheetDialog(call ) } - WebRtcAudioManger.AudioDevice.WIRED_HEADSET -> { + WebRtcAudioManager.AudioDevice.WIRED_HEADSET -> { dialogAudioOutputBinding.audioOutputWiredHeadsetIcon.setColorFilter( ContextCompat.getColor( context, @@ -139,17 +139,17 @@ class AudioOutputDialog(val callActivity: CallActivity) : BottomSheetDialog(call private fun initClickListeners() { dialogAudioOutputBinding.audioOutputBluetooth.setOnClickListener { - callActivity.setAudioOutputChannel(WebRtcAudioManger.AudioDevice.BLUETOOTH) + callActivity.setAudioOutputChannel(WebRtcAudioManager.AudioDevice.BLUETOOTH) dismiss() } dialogAudioOutputBinding.audioOutputSpeaker.setOnClickListener { - callActivity.setAudioOutputChannel(WebRtcAudioManger.AudioDevice.SPEAKER_PHONE) + callActivity.setAudioOutputChannel(WebRtcAudioManager.AudioDevice.SPEAKER_PHONE) dismiss() } dialogAudioOutputBinding.audioOutputEarspeaker.setOnClickListener { - callActivity.setAudioOutputChannel(WebRtcAudioManger.AudioDevice.EARPIECE) + callActivity.setAudioOutputChannel(WebRtcAudioManager.AudioDevice.EARPIECE) dismiss() } } diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManger.java b/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java similarity index 98% rename from app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManger.java rename to app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java index 0bf784d49..2c2fd2780 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManger.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java @@ -54,8 +54,8 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; -public class WebRtcAudioManger { - private static final String TAG = WebRtcAudioManger.class.getCanonicalName(); +public class WebRtcAudioManager { + private static final String TAG = WebRtcAudioManager.class.getSimpleName(); private final Context magicContext; private final WebRtcBluetoothManager bluetoothManager; private final boolean useProximitySensor; @@ -79,7 +79,7 @@ public class WebRtcAudioManger { private final PowerManagerUtils powerManagerUtils; - private WebRtcAudioManger(Context context, boolean useProximitySensor) { + private WebRtcAudioManager(Context context, boolean useProximitySensor) { Log.d(TAG, "ctor"); ThreadUtils.checkIsOnMainThread(); magicContext = context; @@ -110,8 +110,8 @@ public class WebRtcAudioManger { /** * Construction. */ - public static WebRtcAudioManger create(Context context, boolean useProximitySensor) { - return new WebRtcAudioManger(context, useProximitySensor); + public static WebRtcAudioManager create(Context context, boolean useProximitySensor) { + return new WebRtcAudioManager(context, useProximitySensor); } public void startBluetoothManager() { @@ -141,7 +141,7 @@ public class WebRtcAudioManger { .SENSOR_NEAR, null, null, null, null)); } else { - setAudioDeviceInternal(WebRtcAudioManger.AudioDevice.SPEAKER_PHONE); + setAudioDeviceInternal(WebRtcAudioManager.AudioDevice.SPEAKER_PHONE); Log.d(TAG, "switched to SPEAKER_PHONE because userSelectedAudioDevice was SPEAKER_PHONE and proximity=far"); EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcBluetoothManager.java b/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcBluetoothManager.java index 0509efc83..d7eb26e72 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcBluetoothManager.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcBluetoothManager.java @@ -66,7 +66,7 @@ public class WebRtcBluetoothManager { // Maximum number of SCO connection attempts. private static final int MAX_SCO_CONNECTION_ATTEMPTS = 2; private final Context apprtcContext; - private final WebRtcAudioManger webRtcAudioManager; + private final WebRtcAudioManager webRtcAudioManager; private final AudioManager audioManager; private final Handler handler; private final BluetoothProfile.ServiceListener bluetoothServiceListener; @@ -82,7 +82,7 @@ public class WebRtcBluetoothManager { private final Runnable bluetoothTimeoutRunnable = this::bluetoothTimeout; private boolean started = false; - protected WebRtcBluetoothManager(Context context, WebRtcAudioManger audioManager) { + protected WebRtcBluetoothManager(Context context, WebRtcAudioManager audioManager) { Log.d(TAG, "ctor"); ThreadUtils.checkIsOnMainThread(); apprtcContext = context; @@ -97,7 +97,7 @@ public class WebRtcBluetoothManager { /** * Construction. */ - static WebRtcBluetoothManager create(Context context, WebRtcAudioManger audioManager) { + static WebRtcBluetoothManager create(Context context, WebRtcAudioManager audioManager) { return new WebRtcBluetoothManager(context, audioManager); } From 174a7e53d82c70dd320393e8c21b1eb2a3585b32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Kr=C3=BCger?= Date: Thu, 23 Jun 2022 15:24:28 +0200 Subject: [PATCH 4/6] Remove unneeded '@SuppressLint("InlinedApi")' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The annotation '@RequiresApi' was already set correctly. Signed-off-by: Tim Krüger --- .../main/java/com/nextcloud/talk/activities/CallActivity.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java index 9b7dc4f80..50086e9f6 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -342,7 +342,6 @@ public class CallActivity extends CallBaseActivity { updateSelfVideoViewPosition(); } - @SuppressLint("InlinedApi") @RequiresApi(api = Build.VERSION_CODES.S) private void requestBluetoothPermission() { if (ContextCompat.checkSelfPermission( From f87e0a2d85946493a1d5c7531ef9e6d222732ce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Kr=C3=BCger?= Date: Thu, 23 Jun 2022 15:34:11 +0200 Subject: [PATCH 5/6] Set PendingIntent flag immutable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tim Krüger --- .../java/com/nextcloud/talk/activities/CallActivity.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java index 50086e9f6..3ab702f73 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -95,10 +95,10 @@ import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.power.PowerManagerUtils; import com.nextcloud.talk.utils.preferences.AppPreferences; import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder; -import com.nextcloud.talk.webrtc.WebRtcAudioManager; import com.nextcloud.talk.webrtc.MagicWebRTCUtils; import com.nextcloud.talk.webrtc.MagicWebSocketInstance; import com.nextcloud.talk.webrtc.PeerConnectionWrapper; +import com.nextcloud.talk.webrtc.WebRtcAudioManager; import com.nextcloud.talk.webrtc.WebSocketConnectionHelper; import com.wooplr.spotlight.SpotlightView; @@ -162,7 +162,7 @@ import me.zhanghai.android.effortlesspermissions.OpenAppDetailsDialogFragment; import okhttp3.Cache; import pub.devrel.easypermissions.AfterPermissionGranted; -import static android.app.PendingIntent.FLAG_MUTABLE; +import static android.app.PendingIntent.FLAG_IMMUTABLE; import static com.nextcloud.talk.webrtc.Globals.JOB_ID; import static com.nextcloud.talk.webrtc.Globals.PARTICIPANTS_UPDATE; import static com.nextcloud.talk.webrtc.Globals.ROOM_TOKEN; @@ -2612,7 +2612,7 @@ public class CallActivity extends CallBaseActivity { int intentFlag; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - intentFlag = FLAG_MUTABLE; + intentFlag = FLAG_IMMUTABLE; } else { intentFlag = 0; } From 834d310eb805b1d877e7a94f82e95bfd6eb66d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Kr=C3=BCger?= Date: Thu, 23 Jun 2022 15:35:42 +0200 Subject: [PATCH 6/6] Use simple class name for logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tim Krüger --- .../java/com/nextcloud/talk/webrtc/WebRtcBluetoothManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcBluetoothManager.java b/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcBluetoothManager.java index d7eb26e72..2655f9ba7 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcBluetoothManager.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcBluetoothManager.java @@ -59,7 +59,7 @@ import java.util.Set; import androidx.core.app.ActivityCompat; public class WebRtcBluetoothManager { - private static final String TAG = WebRtcBluetoothManager.class.getCanonicalName(); + private static final String TAG = WebRtcBluetoothManager.class.getSimpleName(); // Timeout interval for starting or stopping audio to a Bluetooth SCO device. private static final int BLUETOOTH_SCO_TIMEOUT_MS = 4000;