feat: hooking up calls and fixing broken dependencies and compile errors

This commit is contained in:
jubb
2021-11-08 17:32:25 +11:00
parent 3755315b4c
commit a0e604dbaf
16 changed files with 141 additions and 134 deletions

View File

@@ -37,10 +37,12 @@ dependencies {
implementation 'androidx.gridlayout:gridlayout:1.0.0' implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'androidx.exifinterface:exifinterface:1.2.0' implementation 'androidx.exifinterface:exifinterface:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.lifecycle:lifecycle-common-java8:2.4.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0' implementation 'androidx.lifecycle:lifecycle-common-java8:2.3.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.0' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'androidx.lifecycle:lifecycle-process:2.3.1'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
implementation 'androidx.activity:activity-ktx:1.2.2' implementation 'androidx.activity:activity-ktx:1.2.2'
implementation 'androidx.fragment:fragment-ktx:1.3.2' implementation 'androidx.fragment:fragment-ktx:1.3.2'
implementation "androidx.core:core-ktx:1.3.2" implementation "androidx.core:core-ktx:1.3.2"
@@ -153,7 +155,7 @@ dependencies {
testImplementation 'org.robolectric:shadows-multidex:4.4' testImplementation 'org.robolectric:shadows-multidex:4.4'
} }
def canonicalVersionCode = 231 def canonicalVersionCode = 232
def canonicalVersionName = "1.11.12" def canonicalVersionName = "1.11.12"
def postFixSize = 10 def postFixSize = 10

View File

@@ -54,7 +54,6 @@ import org.thoughtcrime.securesms.crypto.KeyPairUtilities;
import org.thoughtcrime.securesms.database.JobDatabase; import org.thoughtcrime.securesms.database.JobDatabase;
import org.thoughtcrime.securesms.database.LokiAPIDatabase; import org.thoughtcrime.securesms.database.LokiAPIDatabase;
import org.thoughtcrime.securesms.database.Storage; import org.thoughtcrime.securesms.database.Storage;
import org.thoughtcrime.securesms.dependencies.CallComponent;
import org.thoughtcrime.securesms.dependencies.DatabaseComponent; import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
import org.thoughtcrime.securesms.dependencies.DatabaseModule; import org.thoughtcrime.securesms.dependencies.DatabaseModule;
import org.thoughtcrime.securesms.groups.OpenGroupManager; import org.thoughtcrime.securesms.groups.OpenGroupManager;
@@ -82,6 +81,7 @@ import org.thoughtcrime.securesms.sskenvironment.TypingStatusRepository;
import org.thoughtcrime.securesms.util.Broadcaster; import org.thoughtcrime.securesms.util.Broadcaster;
import org.thoughtcrime.securesms.util.UiModeUtilities; import org.thoughtcrime.securesms.util.UiModeUtilities;
import org.thoughtcrime.securesms.util.dynamiclanguage.LocaleParseHelper; import org.thoughtcrime.securesms.util.dynamiclanguage.LocaleParseHelper;
import org.thoughtcrime.securesms.webrtc.CallMessageProcessor;
import org.webrtc.PeerConnectionFactory; import org.webrtc.PeerConnectionFactory;
import org.webrtc.PeerConnectionFactory.InitializationOptions; import org.webrtc.PeerConnectionFactory.InitializationOptions;
import org.webrtc.voiceengine.WebRtcAudioManager; import org.webrtc.voiceengine.WebRtcAudioManager;
@@ -134,6 +134,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
@Inject Storage storage; @Inject Storage storage;
@Inject MessageDataProvider messageDataProvider; @Inject MessageDataProvider messageDataProvider;
@Inject JobDatabase jobDatabase; @Inject JobDatabase jobDatabase;
CallMessageProcessor callMessageProcessor;
private volatile boolean isAppVisible; private volatile boolean isAppVisible;
@@ -160,6 +161,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
public void onCreate() { public void onCreate() {
DatabaseModule.init(this); DatabaseModule.init(this);
super.onCreate(); super.onCreate();
callMessageProcessor = new CallMessageProcessor(this, ProcessLifecycleOwner.get().getLifecycle());
Log.i(TAG, "onCreate()"); Log.i(TAG, "onCreate()");
startKovenant(); startKovenant();
initializeSecurityProvider(); initializeSecurityProvider();

View File

@@ -8,28 +8,17 @@ import android.content.IntentFilter
import android.media.AudioManager import android.media.AudioManager
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import android.view.Window
import android.view.WindowManager import android.view.WindowManager
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.android.synthetic.main.activity_webrtc_tests.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import network.loki.messenger.R import network.loki.messenger.R
import org.session.libsession.messaging.messages.control.CallMessage
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.utilities.WebRtcUtils
import org.session.libsession.utilities.Address import org.session.libsession.utilities.Address
import org.session.libsignal.protos.SignalServiceProtos
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.webrtc.CallViewModel import org.thoughtcrime.securesms.webrtc.CallViewModel
import org.webrtc.* import org.webrtc.IceCandidate
import java.util.* import java.util.*
@AndroidEntryPoint @AndroidEntryPoint
@@ -67,7 +56,6 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
super.onCreate(savedInstanceState, ready) super.onCreate(savedInstanceState, ready)
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED) window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
requestWindowFeature(Window.FEATURE_NO_TITLE)
setContentView(R.layout.activity_webrtc_tests) setContentView(R.layout.activity_webrtc_tests)
volumeControlStream = AudioManager.STREAM_VOICE_CALL volumeControlStream = AudioManager.STREAM_VOICE_CALL
@@ -81,16 +69,16 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
.execute() .execute()
lifecycleScope.launch { lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) { // repeat on start or something
viewModel
}
} }
registerReceiver(object: BroadcastReceiver() { registerReceiver(object: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
finish() finish()
} }
}, IntentFilter(ACTION_END)) },IntentFilter(ACTION_END))
} }
private fun initializeResources() { private fun initializeResources() {

View File

@@ -24,7 +24,6 @@ import androidx.core.view.children
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import androidx.loader.app.LoaderManager import androidx.loader.app.LoaderManager
import androidx.loader.content.Loader import androidx.loader.content.Loader
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@@ -457,7 +456,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
} }
private fun setUpLinkPreviewObserver() { private fun setUpLinkPreviewObserver() {
val linkPreviewViewModel = ViewModelProviders.of(this, LinkPreviewViewModel.Factory(LinkPreviewRepository()))[LinkPreviewViewModel::class.java] val linkPreviewViewModel = ViewModelProvider(this, LinkPreviewViewModel.Factory(LinkPreviewRepository()))[LinkPreviewViewModel::class.java]
this.linkPreviewViewModel = linkPreviewViewModel this.linkPreviewViewModel = linkPreviewViewModel
if (!TextSecurePreferences.isLinkPreviewsEnabled(this)) { if (!TextSecurePreferences.isLinkPreviewsEnabled(this)) {
linkPreviewViewModel.onUserCancel(); return linkPreviewViewModel.onUserCancel(); return

View File

@@ -43,10 +43,10 @@ import org.thoughtcrime.securesms.conversation.v2.utilities.NotificationUtils
import org.thoughtcrime.securesms.dependencies.DatabaseComponent import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.groups.EditClosedGroupActivity import org.thoughtcrime.securesms.groups.EditClosedGroupActivity
import org.thoughtcrime.securesms.groups.EditClosedGroupActivity.Companion.groupIDKey import org.thoughtcrime.securesms.groups.EditClosedGroupActivity.Companion.groupIDKey
import org.thoughtcrime.securesms.service.WebRtcCallService
import org.thoughtcrime.securesms.util.BitmapUtil import org.thoughtcrime.securesms.util.BitmapUtil
import org.thoughtcrime.securesms.util.getColorWithID import org.thoughtcrime.securesms.util.getColorWithID
import java.io.IOException import java.io.IOException
import java.util.*
object ConversationMenuHelper { object ConversationMenuHelper {
@@ -183,16 +183,14 @@ object ConversationMenuHelper {
} }
private fun call(context: Context, thread: Recipient) { private fun call(context: Context, thread: Recipient) {
AlertDialog.Builder(context) val service = WebRtcCallService.createCall(context, thread)
.setTitle("Call") context.startService(service)
.setMessage("Use relay?")
.setPositiveButton("Use Relay") { d, w -> val activity = Intent(context, WebRtcCallActivity::class.java).apply {
TODO() flags = Intent.FLAG_ACTIVITY_NEW_TASK
} }
.setNeutralButton("P2P only") { d, w -> context.startActivity(activity)
TODO()
}
.show()
} }
@SuppressLint("StaticFieldLeak") @SuppressLint("StaticFieldLeak")

View File

@@ -148,49 +148,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
} }
this.broadcastReceiver = broadcastReceiver this.broadcastReceiver = broadcastReceiver
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, IntentFilter("blockedContactsChanged")) LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, IntentFilter("blockedContactsChanged"))
lifecycleScope.launchWhenCreated {
// web rtc channel handling
for (message in WebRtcUtils.SIGNAL_QUEUE) {
// TODO: check errors here in the
val sender = Address.fromSerialized(message.sender!!)
val callId = message.callId!!
synchronized(WebRtcUtils.callCache) {
val set = WebRtcUtils.callCache[callId] ?: mutableSetOf()
set += message
WebRtcUtils.callCache[callId] = set
}
when (message.type) {
SignalServiceProtos.CallMessage.Type.OFFER -> {
// show bottom sheet
if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
CallBottomSheet().apply {
arguments = bundleOf(
CallBottomSheet.ARGUMENT_ADDRESS to sender,
CallBottomSheet.ARGUMENT_SDP to message.sdps.toTypedArray(),
CallBottomSheet.ARGUMENT_TYPE to message.type!!.number,
CallBottomSheet.ARGUMENT_CALL_ID to callId.toString()
)
show(this@HomeActivity.supportFragmentManager,"call-sheet")
}
}
}
SignalServiceProtos.CallMessage.Type.END_CALL -> {
// dismiss the call sheet
supportFragmentManager.findFragmentByTag("call-sheet")?.let { callSheet ->
if (callSheet is BottomSheetDialogFragment) {
callSheet.dismiss()
}
}
// clear the callCache for this sender
synchronized(WebRtcUtils.callCache) {
WebRtcUtils.callCache[callId] = mutableSetOf()
}
sendBroadcast(Intent(WebRtcCallActivity.ACTION_END))
}
else -> { /* do nothing */ }
}
}
}
lifecycleScope.launchWhenStarted { lifecycleScope.launchWhenStarted {
launch(Dispatchers.IO) { launch(Dispatchers.IO) {

View File

@@ -86,6 +86,17 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
fun acceptCallIntent(context: Context) = Intent(context, WebRtcCallService::class.java).setAction(ACTION_ANSWER_CALL) fun acceptCallIntent(context: Context) = Intent(context, WebRtcCallService::class.java).setAction(ACTION_ANSWER_CALL)
fun createCall(context: Context, recipient: Recipient) = Intent(context, WebRtcCallService::class.java)
.setAction(ACTION_OUTGOING_CALL)
.putExtra(EXTRA_RECIPIENT_ADDRESS, recipient.address)
fun incomingCall(context: Context, address: Address, sdp: String, callId: UUID) =
Intent(context, WebRtcCallService::class.java)
.setAction(ACTION_INCOMING_CALL)
.putExtra(EXTRA_RECIPIENT_ADDRESS, address)
.putExtra(EXTRA_CALL_ID, callId)
.putExtra(EXTRA_REMOTE_DESCRIPTION, sdp)
fun denyCallIntent(context: Context) = Intent(context, WebRtcCallService::class.java).setAction(ACTION_DENY_CALL) fun denyCallIntent(context: Context) = Intent(context, WebRtcCallService::class.java).setAction(ACTION_DENY_CALL)
fun hangupIntent(context: Context) = Intent(context, WebRtcCallService::class.java).setAction(ACTION_LOCAL_HANGUP) fun hangupIntent(context: Context) = Intent(context, WebRtcCallService::class.java).setAction(ACTION_LOCAL_HANGUP)
@@ -122,15 +133,14 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
@Synchronized @Synchronized
private fun terminate() { private fun terminate() {
stopForeground(true) sendBroadcast(Intent(WebRtcCallActivity.ACTION_END))
callManager.stop() callManager.stop()
stopForeground(true)
} }
private fun isBusy() = callManager.isBusy(this) private fun isBusy() = callManager.isBusy(this)
private fun initializeVideo() { private fun isIdle() = callManager.isIdle()
callManager.initializeVideo(this)
}
override fun onBind(intent: Intent?): IBinder? = null override fun onBind(intent: Intent?): IBinder? = null
@@ -142,7 +152,7 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
action == ACTION_INCOMING_CALL && isBusy() -> handleBusyCall(intent) action == ACTION_INCOMING_CALL && isBusy() -> handleBusyCall(intent)
action == ACTION_REMOTE_BUSY -> handleBusyMessage(intent) action == ACTION_REMOTE_BUSY -> handleBusyMessage(intent)
action == ACTION_INCOMING_CALL -> handleIncomingCall(intent) action == ACTION_INCOMING_CALL -> handleIncomingCall(intent)
action == ACTION_OUTGOING_CALL -> handleOutgoingCall(intent) action == ACTION_OUTGOING_CALL && isIdle() -> handleOutgoingCall(intent)
action == ACTION_ANSWER_CALL -> handleAnswerCall(intent) action == ACTION_ANSWER_CALL -> handleAnswerCall(intent)
action == ACTION_DENY_CALL -> handleDenyCall(intent) action == ACTION_DENY_CALL -> handleDenyCall(intent)
action == ACTION_LOCAL_HANGUP -> handleLocalHangup(intent) action == ACTION_LOCAL_HANGUP -> handleLocalHangup(intent)
@@ -288,12 +298,11 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
callManager.initializeVideo(this) callManager.initializeVideo(this)
callManager.postViewModelState(CallViewModel.State.CALL_OUTGOING) callManager.postViewModelState(CallViewModel.State.CALL_OUTGOING)
// update phone state IN_CALL lockManager.updatePhoneState(LockManager.PhoneState.IN_CALL)
callManager.initializeAudioForCall() callManager.initializeAudioForCall()
callManager.startOutgoingRinger(OutgoingRinger.Type.RINGING) callManager.startOutgoingRinger(OutgoingRinger.Type.RINGING)
// bluetoothStateManager.setWantsConnection(true)
setCallInProgressNotification(TYPE_OUTGOING_RINGING, callManager.recipient) setCallInProgressNotification(TYPE_OUTGOING_RINGING, callManager.recipient)
// DatabaseComponent.get(this).insertOutgoingCall(callManager.recipient!!.address) // TODO: DatabaseComponent.get(this).insertOutgoingCall(callManager.recipient!!.address)
timeoutExecutor.schedule(TimeoutRunnable(callId, this), 2, TimeUnit.MINUTES) timeoutExecutor.schedule(TimeoutRunnable(callId, this), 2, TimeUnit.MINUTES)
val expectedState = callManager.currentConnectionState val expectedState = callManager.currentConnectionState

View File

@@ -54,17 +54,17 @@ class CallBottomSheet: BottomSheetDialogFragment() {
nameTextView.text = recipient.name ?: address.serialize() nameTextView.text = recipient.name ?: address.serialize()
acceptButton.setOnClickListener { acceptButton.setOnClickListener {
val intent = Intent(requireContext(), WebRtcCallActivity::class.java) // val intent = Intent(requireContext(), WebRtcCallActivity::class.java)
val bundle = bundleOf( // val bundle = bundleOf(
WebRtcCallActivity.EXTRA_ADDRESS to address, // WebRtcCallActivity.EXTRA_ADDRESS to address,
WebRtcCallActivity.EXTRA_CALL_ID to callId // WebRtcCallActivity.EXTRA_CALL_ID to callId
) // )
intent.action = WebRtcCallActivity.ACTION_ANSWER // intent.action = WebRtcCallActivity.ACTION_ANSWER
bundle.putStringArray(WebRtcCallActivity.EXTRA_SDP, sdp) // bundle.putStringArray(WebRtcCallActivity.EXTRA_SDP, sdp)
//
intent.putExtras(bundle) // intent.putExtras(bundle)
startActivity(intent) // startActivity(intent)
dismiss() // dismiss()
} }
declineButton.setOnClickListener { declineButton.setOnClickListener {

View File

@@ -147,6 +147,8 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne
fun isBusy(context: Context) = currentConnectionState != CallState.STATE_IDLE fun isBusy(context: Context) = currentConnectionState != CallState.STATE_IDLE
|| context.getSystemService(TelephonyManager::class.java).callState != TelephonyManager.CALL_STATE_IDLE || context.getSystemService(TelephonyManager::class.java).callState != TelephonyManager.CALL_STATE_IDLE
fun isIdle() = currentConnectionState == CallState.STATE_IDLE
fun initializeVideo(context: Context) { fun initializeVideo(context: Context) {
Util.runOnMainSync { Util.runOnMainSync {
val base = EglBase.create() val base = EglBase.create()

View File

@@ -0,0 +1,45 @@
package org.thoughtcrime.securesms.webrtc
import android.content.Context
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.coroutineScope
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.session.libsession.messaging.messages.control.CallMessage
import org.session.libsession.messaging.utilities.WebRtcUtils
import org.session.libsession.utilities.Address
import org.session.libsignal.protos.SignalServiceProtos
import org.session.libsignal.protos.SignalServiceProtos.CallMessage.Type.OFFER
import org.thoughtcrime.securesms.service.WebRtcCallService
import javax.inject.Inject
class CallMessageProcessor(private val context: Context, lifecycle: Lifecycle) {
init {
lifecycle.coroutineScope.launch {
while (isActive) {
val nextMessage = WebRtcUtils.SIGNAL_QUEUE.receive()
when {
// TODO: handle messages as they come in
nextMessage.type == OFFER -> incomingCall(nextMessage)
}
}
}
}
private fun incomingCall(callMessage: CallMessage) {
val recipientAddress = callMessage.recipient ?: return
val callId = callMessage.callId ?: return
val sdp = callMessage.sdps.firstOrNull() ?: return
val incomingIntent = WebRtcCallService.incomingCall(
context = context,
address = Address.fromSerialized(recipientAddress),
sdp = sdp,
callId = callId
)
context.startService(incomingIntent)
}
}

View File

@@ -165,7 +165,7 @@ class PeerConnectionWrapper(context: Context,
fun createOffer(mediaConstraints: MediaConstraints): SessionDescription { fun createOffer(mediaConstraints: MediaConstraints): SessionDescription {
val future = SettableFuture<SessionDescription>() val future = SettableFuture<SessionDescription>()
peerConnection.createAnswer(object:SdpObserver { peerConnection.createOffer(object:SdpObserver {
override fun onCreateSuccess(sdp: SessionDescription?) { override fun onCreateSuccess(sdp: SessionDescription?) {
future.set(sdp) future.set(sdp)
} }

View File

@@ -37,9 +37,9 @@ class SignalAudioManager(private val context: Context,
private val androidAudioManager: AudioManagerCompat) { private val androidAudioManager: AudioManagerCompat) {
private var commandAndControlThread: HandlerThread? = HandlerThread("call-audio").apply { start() } private var commandAndControlThread: HandlerThread? = HandlerThread("call-audio").apply { start() }
private var handler = SignalAudioHandler(commandAndControlThread!!.looper) private var handler: SignalAudioHandler? = null
private val signalBluetoothManager = SignalBluetoothManager(context, this, androidAudioManager, handler) private var signalBluetoothManager: SignalBluetoothManager? = null
private var state: State = State.UNINITIALIZED private var state: State = State.UNINITIALIZED
@@ -66,7 +66,7 @@ class SignalAudioManager(private val context: Context,
private var wiredHeadsetReceiver: WiredHeadsetReceiver? = null private var wiredHeadsetReceiver: WiredHeadsetReceiver? = null
fun handleCommand(command: AudioManagerCommand) { fun handleCommand(command: AudioManagerCommand) {
handler.post { handler?.post {
when (command) { when (command) {
is AudioManagerCommand.Initialize -> initialize() is AudioManagerCommand.Initialize -> initialize()
is AudioManagerCommand.Shutdown -> shutdown() is AudioManagerCommand.Shutdown -> shutdown()
@@ -89,6 +89,10 @@ class SignalAudioManager(private val context: Context,
commandAndControlThread = HandlerThread("call-audio").apply { start() } commandAndControlThread = HandlerThread("call-audio").apply { start() }
handler = SignalAudioHandler(commandAndControlThread!!.looper) handler = SignalAudioHandler(commandAndControlThread!!.looper)
signalBluetoothManager = SignalBluetoothManager(context, this, androidAudioManager, handler!!)
handler!!.post {
savedAudioMode = androidAudioManager.mode savedAudioMode = androidAudioManager.mode
savedIsSpeakerPhoneOn = androidAudioManager.isSpeakerphoneOn savedIsSpeakerPhoneOn = androidAudioManager.isSpeakerphoneOn
savedIsMicrophoneMute = androidAudioManager.isMicrophoneMute savedIsMicrophoneMute = androidAudioManager.isMicrophoneMute
@@ -100,7 +104,7 @@ class SignalAudioManager(private val context: Context,
audioDevices.clear() audioDevices.clear()
signalBluetoothManager.start() signalBluetoothManager!!.start()
updateAudioDeviceState() updateAudioDeviceState()
@@ -112,6 +116,7 @@ class SignalAudioManager(private val context: Context,
Log.d(TAG, "Initialized") Log.d(TAG, "Initialized")
} }
} }
}
private fun start() { private fun start() {
Log.d(TAG, "Starting. state: $state") Log.d(TAG, "Starting. state: $state")
@@ -159,7 +164,7 @@ class SignalAudioManager(private val context: Context,
} }
wiredHeadsetReceiver = null wiredHeadsetReceiver = null
signalBluetoothManager.stop() signalBluetoothManager?.stop()
setSpeakerphoneOn(savedIsSpeakerPhoneOn) setSpeakerphoneOn(savedIsSpeakerPhoneOn)
setMicrophoneMute(savedIsMicrophoneMute) setMicrophoneMute(savedIsMicrophoneMute)
@@ -172,7 +177,7 @@ class SignalAudioManager(private val context: Context,
} }
private fun shutdown() { private fun shutdown() {
handler.post { handler?.post {
stop(false) stop(false)
if (commandAndControlThread != null) { if (commandAndControlThread != null) {
Log.i(TAG, "Shutting down command and control") Log.i(TAG, "Shutting down command and control")
@@ -183,25 +188,25 @@ class SignalAudioManager(private val context: Context,
} }
private fun updateAudioDeviceState() { private fun updateAudioDeviceState() {
handler.assertHandlerThread() handler!!.assertHandlerThread()
Log.i( Log.i(
TAG, TAG,
"updateAudioDeviceState(): " + "updateAudioDeviceState(): " +
"wired: $hasWiredHeadset " + "wired: $hasWiredHeadset " +
"bt: ${signalBluetoothManager.state} " + "bt: ${signalBluetoothManager!!.state} " +
"available: $audioDevices " + "available: $audioDevices " +
"selected: $selectedAudioDevice " + "selected: $selectedAudioDevice " +
"userSelected: $userSelectedAudioDevice" "userSelected: $userSelectedAudioDevice"
) )
if (signalBluetoothManager.state.shouldUpdate()) { if (signalBluetoothManager!!.state.shouldUpdate()) {
signalBluetoothManager.updateDevice() signalBluetoothManager!!.updateDevice()
} }
val newAudioDevices = mutableSetOf(AudioDevice.SPEAKER_PHONE) val newAudioDevices = mutableSetOf(AudioDevice.SPEAKER_PHONE)
if (signalBluetoothManager.state.hasDevice()) { if (signalBluetoothManager!!.state.hasDevice()) {
newAudioDevices += AudioDevice.BLUETOOTH newAudioDevices += AudioDevice.BLUETOOTH
} }
@@ -217,7 +222,7 @@ class SignalAudioManager(private val context: Context,
var audioDeviceSetUpdated = audioDevices != newAudioDevices var audioDeviceSetUpdated = audioDevices != newAudioDevices
audioDevices = newAudioDevices audioDevices = newAudioDevices
if (signalBluetoothManager.state == SignalBluetoothManager.State.UNAVAILABLE && userSelectedAudioDevice == AudioDevice.BLUETOOTH) { if (signalBluetoothManager!!.state == SignalBluetoothManager.State.UNAVAILABLE && userSelectedAudioDevice == AudioDevice.BLUETOOTH) {
userSelectedAudioDevice = AudioDevice.NONE userSelectedAudioDevice = AudioDevice.NONE
} }
@@ -230,33 +235,33 @@ class SignalAudioManager(private val context: Context,
userSelectedAudioDevice = AudioDevice.NONE userSelectedAudioDevice = AudioDevice.NONE
} }
val needBluetoothAudioStart = signalBluetoothManager.state == SignalBluetoothManager.State.AVAILABLE && val needBluetoothAudioStart = signalBluetoothManager!!.state == SignalBluetoothManager.State.AVAILABLE &&
(userSelectedAudioDevice == AudioDevice.NONE || userSelectedAudioDevice == AudioDevice.BLUETOOTH || autoSwitchToBluetooth) (userSelectedAudioDevice == AudioDevice.NONE || userSelectedAudioDevice == AudioDevice.BLUETOOTH || autoSwitchToBluetooth)
val needBluetoothAudioStop = (signalBluetoothManager.state == SignalBluetoothManager.State.CONNECTED || signalBluetoothManager.state == SignalBluetoothManager.State.CONNECTING) && val needBluetoothAudioStop = (signalBluetoothManager!!.state == SignalBluetoothManager.State.CONNECTED || signalBluetoothManager!!.state == SignalBluetoothManager.State.CONNECTING) &&
(userSelectedAudioDevice != AudioDevice.NONE && userSelectedAudioDevice != AudioDevice.BLUETOOTH) (userSelectedAudioDevice != AudioDevice.NONE && userSelectedAudioDevice != AudioDevice.BLUETOOTH)
if (signalBluetoothManager.state.hasDevice()) { if (signalBluetoothManager!!.state.hasDevice()) {
Log.i(TAG, "Need bluetooth audio: state: ${signalBluetoothManager.state} start: $needBluetoothAudioStart stop: $needBluetoothAudioStop") Log.i(TAG, "Need bluetooth audio: state: ${signalBluetoothManager!!.state} start: $needBluetoothAudioStart stop: $needBluetoothAudioStop")
} }
if (needBluetoothAudioStop) { if (needBluetoothAudioStop) {
signalBluetoothManager.stopScoAudio() signalBluetoothManager!!.stopScoAudio()
signalBluetoothManager.updateDevice() signalBluetoothManager!!.updateDevice()
} }
if (!autoSwitchToBluetooth && signalBluetoothManager.state == SignalBluetoothManager.State.UNAVAILABLE) { if (!autoSwitchToBluetooth && signalBluetoothManager!!.state == SignalBluetoothManager.State.UNAVAILABLE) {
autoSwitchToBluetooth = true autoSwitchToBluetooth = true
} }
if (needBluetoothAudioStart && !needBluetoothAudioStop) { if (needBluetoothAudioStart && !needBluetoothAudioStop) {
if (!signalBluetoothManager.startScoAudio()) { if (!signalBluetoothManager!!.startScoAudio()) {
audioDevices.remove(AudioDevice.BLUETOOTH) audioDevices.remove(AudioDevice.BLUETOOTH)
audioDeviceSetUpdated = true audioDeviceSetUpdated = true
} }
} }
if (autoSwitchToBluetooth && signalBluetoothManager.state == SignalBluetoothManager.State.CONNECTED) { if (autoSwitchToBluetooth && signalBluetoothManager!!.state == SignalBluetoothManager.State.CONNECTED) {
userSelectedAudioDevice = AudioDevice.BLUETOOTH userSelectedAudioDevice = AudioDevice.BLUETOOTH
autoSwitchToBluetooth = false autoSwitchToBluetooth = false
} }
@@ -373,7 +378,7 @@ class SignalAudioManager(private val context: Context,
val pluggedIn = intent.getIntExtra("state", 0) == 1 val pluggedIn = intent.getIntExtra("state", 0) == 1
val hasMic = intent.getIntExtra("microphone", 0) == 1 val hasMic = intent.getIntExtra("microphone", 0) == 1
handler.post { onWiredHeadsetChange(pluggedIn, hasMic) } handler?.post { onWiredHeadsetChange(pluggedIn, hasMic) }
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 B

View File

@@ -51,6 +51,6 @@ allprojects {
project.ext { project.ext {
androidMinimumSdkVersion = 23 androidMinimumSdkVersion = 23
androidCompileSdkVersion = 31 androidCompileSdkVersion = 30
} }
} }