feat: adding remainder of basic functionality to services and CallManager.kt

This commit is contained in:
jubb
2021-11-05 16:35:40 +11:00
parent f069d35b14
commit 3755315b4c
13 changed files with 165 additions and 286 deletions

View File

@@ -141,10 +141,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
return (ApplicationContext) context.getApplicationContext(); return (ApplicationContext) context.getApplicationContext();
} }
public CallComponent getCallComponent() {
return EntryPoints.get(getApplicationContext(), CallComponent.class);
}
public DatabaseComponent getDatabaseComponent() { public DatabaseComponent getDatabaseComponent() {
return EntryPoints.get(getApplicationContext(), DatabaseComponent.class); return EntryPoints.get(getApplicationContext(), DatabaseComponent.class);
} }

View File

@@ -43,10 +43,6 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
const val ACTION_ANSWER = "answer" const val ACTION_ANSWER = "answer"
const val ACTION_END = "end-call" const val ACTION_END = "end-call"
const val EXTRA_SDP = "WebRtcTestsActivity_EXTRA_SDP"
const val EXTRA_ADDRESS = "WebRtcTestsActivity_EXTRA_ADDRESS"
const val EXTRA_CALL_ID = "WebRtcTestsActivity_EXTRA_CALL_ID"
const val BUSY_SIGNAL_DELAY_FINISH = 5500L const val BUSY_SIGNAL_DELAY_FINISH = 5500L
} }
@@ -59,13 +55,9 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
private lateinit var callAddress: Address private lateinit var callAddress: Address
private lateinit var callId: UUID private lateinit var callId: UUID
override fun onBackPressed() {
endCall()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) { if (item.itemId == android.R.id.home) {
endCall() finish()
return true return true
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
@@ -94,227 +86,19 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
} }
} }
local_renderer.run {
setEnableHardwareScaler(true)
init(eglBase.eglBaseContext, null)
}
remote_renderer.run {
setEnableHardwareScaler(true)
init(eglBase.eglBaseContext, null)
}
end_call_button.setOnClickListener {
endCall()
}
switch_camera_button.setOnClickListener {
videoCapturer?.switchCamera(null)
}
switch_audio_button.setOnClickListener {
}
// create either call or answer
callId = intent.getStringExtra(EXTRA_CALL_ID).let(UUID::fromString)
if (intent.action == ACTION_ANSWER) {
callAddress = intent.getParcelableExtra(EXTRA_ADDRESS) ?: run { finish(); return }
val offerSdp = intent.getStringArrayExtra(EXTRA_SDP)!![0]
peerConnection.setRemoteDescription(this, SessionDescription(SessionDescription.Type.OFFER, offerSdp))
peerConnection.createAnswer(this, MediaConstraints())
} else {
callAddress = intent.getParcelableExtra(EXTRA_ADDRESS) ?: run { finish(); return }
peerConnection.createOffer(this, MediaConstraints())
}
lifecycleScope.launchWhenCreated {
while (this.isActive) {
val answer = synchronized(WebRtcUtils.callCache) {
WebRtcUtils.callCache[callId]?.firstOrNull { it.type == SignalServiceProtos.CallMessage.Type.ANSWER }
}
if (answer != null) {
peerConnection.setRemoteDescription(
this@WebRtcCallActivity,
SessionDescription(SessionDescription.Type.ANSWER, answer.sdps[0])
)
break
}
delay(2_000L)
}
}
registerReceiver(object: BroadcastReceiver() { registerReceiver(object: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
endCall() finish()
} }
}, IntentFilter(ACTION_END)) }, IntentFilter(ACTION_END))
lifecycleScope.launchWhenResumed {
while (this.isActive) {
delay(2_000L)
peerConnection.getStats(this@WebRtcCallActivity)
synchronized(WebRtcUtils.callCache) {
val set = WebRtcUtils.callCache[callId] ?: mutableSetOf()
set.filter { it.hashCode() !in acceptedCallMessageHashes
&& it.type == SignalServiceProtos.CallMessage.Type.ICE_CANDIDATES }.forEach { callMessage ->
callMessage.iceCandidates().forEach { candidate ->
peerConnection.addIceCandidate(candidate)
}
acceptedCallMessageHashes.add(callMessage.hashCode())
}
}
}
}
} }
private fun initializeResources() { private fun initializeResources() {
} }
private fun endCall() {
if (isFinishing) return
val uuid = callId
MessageSender.sendNonDurably(
CallMessage.endCall(uuid),
callAddress
)
peerConnection.close()
finish()
}
override fun onDestroy() {
super.onDestroy()
endCall()
}
private fun setupStreams() { private fun setupStreams() {
val videoSource = connectionFactory.createVideoSource(false)
videoCapturer?.initialize(surfaceHelper, local_renderer.context, videoSource.capturerObserver) ?: run {
finish()
return
}
videoCapturer?.startCapture(HD_VIDEO_WIDTH, HD_VIDEO_HEIGHT, 10)
val audioTrack = connectionFactory.createAudioTrack(LOCAL_TRACK_ID + "_audio", audioSource)
val videoTrack = connectionFactory.createVideoTrack(LOCAL_TRACK_ID, videoSource)
videoTrack.addSink(local_renderer)
val stream = connectionFactory.createLocalMediaStream(LOCAL_STREAM_ID)
stream.addTrack(videoTrack)
stream.addTrack(audioTrack)
peerConnection.addStream(stream)
}
override fun onSignalingChange(p0: PeerConnection.SignalingState?) {
Log.d("Loki-RTC", "onSignalingChange: $p0")
}
override fun onIceConnectionChange(p0: PeerConnection.IceConnectionState?) {
Log.d("Loki-RTC", "onIceConnectionChange: $p0")
}
override fun onIceConnectionReceivingChange(p0: Boolean) {
Log.d("Loki-RTC", "onIceConnectionReceivingChange: $p0")
}
override fun onIceGatheringChange(p0: PeerConnection.IceGatheringState?) {
Log.d("Loki-RTC", "onIceGatheringChange: $p0")
}
override fun onIceCandidate(iceCandidate: IceCandidate?) {
Log.d("Loki-RTC", "onIceCandidate: $iceCandidate")
if (iceCandidate == null) return
// TODO: in a lokinet world, these might have to be filtered specifically to drop anything that is not .loki
peerConnection.addIceCandidate(iceCandidate)
candidates.add(iceCandidate)
iceDebouncer.publish {
MessageSender.sendNonDurably(
CallMessage(SignalServiceProtos.CallMessage.Type.ICE_CANDIDATES,
candidates.map { it.sdp },
candidates.map { it.sdpMLineIndex },
candidates.map { it.sdpMid },
callId
),
callAddress
)
}
}
override fun onIceCandidatesRemoved(p0: Array<out IceCandidate>?) {
Log.d("Loki-RTC", "onIceCandidatesRemoved: $p0")
peerConnection.removeIceCandidates(p0)
}
override fun onAddStream(remoteStream: MediaStream?) {
Log.d("Loki-RTC", "onAddStream: $remoteStream")
if (remoteStream == null) {
return
}
remoteStream.videoTracks.firstOrNull()?.addSink(remote_renderer)
}
override fun onRemoveStream(p0: MediaStream?) {
Log.d("Loki-RTC", "onRemoveStream: $p0")
}
override fun onDataChannel(p0: DataChannel?) {
Log.d("Loki-RTC", "onDataChannel: $p0")
}
override fun onRenegotiationNeeded() {
Log.d("Loki-RTC", "onRenegotiationNeeded")
}
override fun onAddTrack(p0: RtpReceiver?, p1: Array<out MediaStream>?) {
Log.d("Loki-RTC", "onAddTrack: $p0: $p1")
}
override fun onCreateSuccess(sdp: SessionDescription) {
Log.d("Loki-RTC", "onCreateSuccess: ${sdp.type}")
when (sdp.type) {
SessionDescription.Type.OFFER -> {
peerConnection.setLocalDescription(this, sdp)
MessageSender.sendNonDurably(
CallMessage(SignalServiceProtos.CallMessage.Type.OFFER,
listOf(sdp.description),
listOf(),
listOf(),
callId
),
callAddress
)
}
SessionDescription.Type.ANSWER -> {
peerConnection.setLocalDescription(this, sdp)
MessageSender.sendNonDurably(
CallMessage(SignalServiceProtos.CallMessage.Type.ANSWER,
listOf(sdp.description),
listOf(),
listOf(),
callId
),
callAddress
)
}
null, SessionDescription.Type.PRANSWER -> TODO("do the PR answer create success handling") // MessageSender.send()
}
}
override fun onSetSuccess() {
Log.d("Loki-RTC", "onSetSuccess")
}
override fun onCreateFailure(p0: String?) {
Log.d("Loki-RTC", "onCreateFailure: $p0")
}
override fun onSetFailure(p0: String?) {
Log.d("Loki-RTC", "onSetFailure: $p0")
} }
} }

View File

@@ -187,17 +187,10 @@ object ConversationMenuHelper {
.setTitle("Call") .setTitle("Call")
.setMessage("Use relay?") .setMessage("Use relay?")
.setPositiveButton("Use Relay") { d, w -> .setPositiveButton("Use Relay") { d, w ->
val intent = Intent(context, WebRtcCallActivity::class.java) TODO()
intent.putExtra(WebRtcCallActivity.EXTRA_CALL_ID, UUID.randomUUID().toString())
intent.putExtra(WebRtcCallActivity.EXTRA_ADDRESS, thread.address)
val activity = context as AppCompatActivity
activity.startActivity(intent)
} }
.setNeutralButton("P2P only") { d, w -> .setNeutralButton("P2P only") { d, w ->
val intent = Intent(context, WebRtcCallActivity::class.java) TODO()
intent.putExtra(WebRtcCallActivity.EXTRA_ADDRESS, thread.address)
val activity = context as AppCompatActivity
activity.startActivity(intent)
} }
.show() .show()
} }

View File

@@ -5,19 +5,19 @@ import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.components.ServiceComponent
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.android.scopes.ServiceScoped
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import org.session.libsession.database.CallDataProvider import org.session.libsession.database.CallDataProvider
import org.thoughtcrime.securesms.database.Storage import org.thoughtcrime.securesms.database.Storage
import org.thoughtcrime.securesms.webrtc.CallManager import org.thoughtcrime.securesms.webrtc.CallManager
import org.thoughtcrime.securesms.webrtc.audio.AudioManagerCompat import org.thoughtcrime.securesms.webrtc.audio.AudioManagerCompat
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager
import org.thoughtcrime.securesms.webrtc.data.SessionCallDataProvider
import javax.inject.Singleton import javax.inject.Singleton
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
abstract class CallModule { object CallModule {
@Provides @Provides
@Singleton @Singleton
@@ -25,11 +25,7 @@ abstract class CallModule {
@Provides @Provides
@Singleton @Singleton
fun provideCallManager(@ApplicationContext context: Context, storage: Storage, audioManagerCompat: AudioManagerCompat) = fun provideCallManager(@ApplicationContext context: Context, audioManagerCompat: AudioManagerCompat) =
CallManager(context, audioManagerCompat) CallManager(context, audioManagerCompat)
@Binds
@Singleton
abstract fun bindCallDataProvider(sessionCallDataProvider: SessionCallDataProvider): CallDataProvider
} }

View File

@@ -14,7 +14,6 @@ import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider
import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider
import org.thoughtcrime.securesms.database.* import org.thoughtcrime.securesms.database.*
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.thoughtcrime.securesms.webrtc.data.SessionCallDataProvider
import javax.inject.Singleton import javax.inject.Singleton
@Module @Module

View File

@@ -28,7 +28,8 @@ import org.thoughtcrime.securesms.webrtc.*
import org.thoughtcrime.securesms.webrtc.CallManager.CallState.* import org.thoughtcrime.securesms.webrtc.CallManager.CallState.*
import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger
import org.thoughtcrime.securesms.webrtc.locks.LockManager import org.thoughtcrime.securesms.webrtc.locks.LockManager
import org.webrtc.SessionDescription import org.webrtc.*
import org.webrtc.PeerConnection.IceConnectionState.*
import java.lang.AssertionError import java.lang.AssertionError
import java.util.* import java.util.*
import java.util.concurrent.ExecutionException import java.util.concurrent.ExecutionException
@@ -37,7 +38,7 @@ import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class WebRtcCallService: Service() { class WebRtcCallService: Service(), PeerConnection.Observer {
@Inject lateinit var callManager: CallManager @Inject lateinit var callManager: CallManager
@@ -62,7 +63,6 @@ class WebRtcCallService: Service() {
const val ACTION_RESPONSE_MESSAGE = "RESPONSE_MESSAGE" const val ACTION_RESPONSE_MESSAGE = "RESPONSE_MESSAGE"
const val ACTION_ICE_MESSAGE = "ICE_MESSAGE" const val ACTION_ICE_MESSAGE = "ICE_MESSAGE"
const val ACTION_ICE_CANDIDATE = "ICE_CANDIDATE"
const val ACTION_CALL_CONNECTED = "CALL_CONNECTED" const val ACTION_CALL_CONNECTED = "CALL_CONNECTED"
const val ACTION_REMOTE_HANGUP = "REMOTE_HANGUP" const val ACTION_REMOTE_HANGUP = "REMOTE_HANGUP"
const val ACTION_REMOTE_BUSY = "REMOTE_BUSY" const val ACTION_REMOTE_BUSY = "REMOTE_BUSY"
@@ -118,6 +118,7 @@ class WebRtcCallService: Service() {
private var callReceiver: IncomingPstnCallReceiver? = null private var callReceiver: IncomingPstnCallReceiver? = null
private var wiredHeadsetStateReceiver: WiredHeadsetStateReceiver? = null private var wiredHeadsetStateReceiver: WiredHeadsetStateReceiver? = null
private var uncaughtExceptionHandlerManager: UncaughtExceptionHandlerManager? = null
@Synchronized @Synchronized
private fun terminate() { private fun terminate() {
@@ -155,7 +156,7 @@ class WebRtcCallService: Service() {
action == ACTION_REMOTE_VIDEO_MUTE -> handleRemoteVideoMute(intent) action == ACTION_REMOTE_VIDEO_MUTE -> handleRemoteVideoMute(intent)
action == ACTION_RESPONSE_MESSAGE -> handleResponseMessage(intent) action == ACTION_RESPONSE_MESSAGE -> handleResponseMessage(intent)
action == ACTION_ICE_MESSAGE -> handleRemoteIceCandidate(intent) action == ACTION_ICE_MESSAGE -> handleRemoteIceCandidate(intent)
action == ACTION_ICE_CANDIDATE -> handleLocalIceCandidate(intent) action == ACTION_ICE_CONNECTED -> handleIceConnected(intent)
action == ACTION_CALL_CONNECTED -> handleCallConnected(intent) action == ACTION_CALL_CONNECTED -> handleCallConnected(intent)
action == ACTION_CHECK_TIMEOUT -> handleCheckTimeout(intent) action == ACTION_CHECK_TIMEOUT -> handleCheckTimeout(intent)
action == ACTION_IS_IN_CALL_QUERY -> handleIsInCallQuery(intent) action == ACTION_IS_IN_CALL_QUERY -> handleIsInCallQuery(intent)
@@ -166,15 +167,18 @@ class WebRtcCallService: Service() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
// create audio manager callManager.registerListener(this)
registerIncomingPstnCallReceiver() registerIncomingPstnCallReceiver()
registerWiredHeadsetStateReceiver() registerWiredHeadsetStateReceiver()
getSystemService(TelephonyManager::class.java) getSystemService(TelephonyManager::class.java)
.listen(hangupOnCallAnswered, PhoneStateListener.LISTEN_CALL_STATE) .listen(hangupOnCallAnswered, PhoneStateListener.LISTEN_CALL_STATE)
// reset call notification registerUncaughtExceptionHandler()
// register uncaught exception handler }
// register network receiver
// telephony listen to call state private fun registerUncaughtExceptionHandler() {
uncaughtExceptionHandlerManager = UncaughtExceptionHandlerManager().apply {
registerHandler(ProximityLockRelease(lockManager))
}
} }
private fun registerIncomingPstnCallReceiver() { private fun registerIncomingPstnCallReceiver() {
@@ -215,7 +219,7 @@ class WebRtcCallService: Service() {
private fun handleBusyMessage(intent: Intent) { private fun handleBusyMessage(intent: Intent) {
val recipient = getRemoteRecipient(intent) val recipient = getRemoteRecipient(intent)
val callId = getCallId(intent) val callId = getCallId(intent)
if (callManager.currentConnectionState != STATE_DIALING || callManager.callId != callManager.callId || callManager.recipient != callManager.recipient) { if (callManager.currentConnectionState != STATE_DIALING || callManager.callId != callId || callManager.recipient != recipient) {
Log.w(TAG,"Got busy message for inactive session...") Log.w(TAG,"Got busy message for inactive session...")
return return
} }
@@ -412,10 +416,25 @@ class WebRtcCallService: Service() {
} }
private fun handleRemoteIceCandidate(intent: Intent) { private fun handleRemoteIceCandidate(intent: Intent) {
val callId = getCallId(intent)
val sdpMids = intent.getStringArrayExtra(EXTRA_ICE_SDP_MID) ?: return
val sdpLineIndexes = intent.getIntArrayExtra(EXTRA_ICE_SDP_LINE_INDEX) ?: return
val sdps = intent.getStringArrayExtra(EXTRA_ICE_SDP) ?: return
if (sdpMids.size != sdpLineIndexes.size || sdpLineIndexes.size != sdps.size) {
Log.w(TAG,"sdp info not of equal length")
return
}
val iceCandidates = (0 until sdpMids.size).map { index ->
IceCandidate(
sdpMids[index],
sdpLineIndexes[index],
sdps[index]
)
}
callManager.handleRemoteIceCandidate(iceCandidates, callId)
} }
private fun handleLocalIceCandidate(intent: Intent) { private fun handleIceConnected(intent: Intent) {
} }
@@ -469,12 +488,14 @@ class WebRtcCallService: Service() {
System.currentTimeMillis() - intent.getLongExtra(EXTRA_TIMESTAMP, -1) > TimeUnit.MINUTES.toMillis(2) System.currentTimeMillis() - intent.getLongExtra(EXTRA_TIMESTAMP, -1) > TimeUnit.MINUTES.toMillis(2)
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() callManager.unregisterListener(this)
callReceiver?.let { receiver -> callReceiver?.let { receiver ->
unregisterReceiver(receiver) unregisterReceiver(receiver)
} }
callReceiver = null callReceiver = null
// unregister exception handler uncaughtExceptionHandlerManager?.unregister()
callManager.onDestroy()
super.onDestroy()
// shutdown audiomanager // shutdown audiomanager
// unregister network receiver // unregister network receiver
// unregister power button // unregister power button
@@ -553,4 +574,37 @@ class WebRtcCallService: Service() {
return expectedState == currentState && expectedCallId == currentCallId return expectedState == currentState && expectedCallId == currentCallId
} }
override fun onSignalingChange(p0: PeerConnection.SignalingState?) {}
override fun onIceConnectionChange(newState: PeerConnection.IceConnectionState?) {
if (newState in arrayOf(CONNECTED, COMPLETED)) {
val intent = Intent(this, WebRtcCallService::class.java)
.setAction(ACTION_ICE_CONNECTED)
startService(intent)
} else if (newState == FAILED) {
val intent = Intent(this, WebRtcCallService::class.java)
.setAction(ACTION_REMOTE_HANGUP)
.putExtra(EXTRA_CALL_ID, callManager.callId)
startService(intent)
}
}
override fun onIceConnectionReceivingChange(p0: Boolean) {}
override fun onIceGatheringChange(p0: PeerConnection.IceGatheringState?) {}
override fun onIceCandidate(p0: IceCandidate?) {}
override fun onIceCandidatesRemoved(p0: Array<out IceCandidate>?) {}
override fun onAddStream(p0: MediaStream?) {}
override fun onRemoveStream(p0: MediaStream?) {}
override fun onDataChannel(p0: DataChannel?) {}
override fun onRenegotiationNeeded() {}
override fun onAddTrack(p0: RtpReceiver?, p1: Array<out MediaStream>?) {}
} }

View File

@@ -10,6 +10,12 @@ open class AudioManagerCommand: Parcelable {
@Parcelize @Parcelize
object Initialize: AudioManagerCommand() object Initialize: AudioManagerCommand()
@Parcelize
object Shutdown: AudioManagerCommand()
@Parcelize
object UpdateAudioDeviceState: AudioManagerCommand()
@Parcelize @Parcelize
data class StartOutgoingRinger(val type: OutgoingRinger.Type): AudioManagerCommand() data class StartOutgoingRinger(val type: OutgoingRinger.Type): AudioManagerCommand()

View File

@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.webrtc package org.thoughtcrime.securesms.webrtc
import android.content.Context import android.content.Context
import android.content.Intent
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asSharedFlow
@@ -64,6 +63,16 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne
private val signalAudioManager: SignalAudioManager = SignalAudioManager(context, this, audioManager) private val signalAudioManager: SignalAudioManager = SignalAudioManager(context, this, audioManager)
private val peerConnectionObservers = mutableSetOf<PeerConnection.Observer>()
fun registerListener(listener: PeerConnection.Observer) {
peerConnectionObservers.add(listener)
}
fun unregisterListener(listener: PeerConnection.Observer) {
peerConnectionObservers.remove(listener)
}
private val _audioEvents = MutableStateFlow(StateEvent.AudioEnabled(false)) private val _audioEvents = MutableStateFlow(StateEvent.AudioEnabled(false))
val audioEvents = _audioEvents.asSharedFlow() val audioEvents = _audioEvents.asSharedFlow()
private val _videoEvents = MutableStateFlow(StateEvent.VideoEnabled(false)) private val _videoEvents = MutableStateFlow(StateEvent.VideoEnabled(false))
@@ -183,47 +192,47 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne
} }
override fun onSignalingChange(newState: PeerConnection.SignalingState) { override fun onSignalingChange(newState: PeerConnection.SignalingState) {
peerConnectionObservers.forEach { listener -> listener.onSignalingChange(newState) }
} }
override fun onIceConnectionChange(newState: PeerConnection.IceConnectionState) { override fun onIceConnectionChange(newState: PeerConnection.IceConnectionState) {
peerConnectionObservers.forEach { listener -> listener.onIceConnectionChange(newState) }
} }
override fun onIceConnectionReceivingChange(receiving: Boolean) { override fun onIceConnectionReceivingChange(receiving: Boolean) {
peerConnectionObservers.forEach { listener -> listener.onIceConnectionReceivingChange(receiving) }
} }
override fun onIceGatheringChange(newState: PeerConnection.IceGatheringState) { override fun onIceGatheringChange(newState: PeerConnection.IceGatheringState) {
peerConnectionObservers.forEach { listener -> listener.onIceGatheringChange(newState) }
} }
override fun onIceCandidate(p0: IceCandidate?) { override fun onIceCandidate(iceCandidate: IceCandidate?) {
peerConnectionObservers.forEach { listener -> listener.onIceCandidate(iceCandidate) }
} }
override fun onIceCandidatesRemoved(p0: Array<out IceCandidate>?) { override fun onIceCandidatesRemoved(candidates: Array<out IceCandidate>?) {
peerConnectionObservers.forEach { listener -> listener.onIceCandidatesRemoved(candidates) }
} }
override fun onAddStream(p0: MediaStream?) { override fun onAddStream(p0: MediaStream?) {
peerConnectionObservers.forEach { listener -> listener.onAddStream(p0) }
} }
override fun onRemoveStream(p0: MediaStream?) { override fun onRemoveStream(p0: MediaStream?) {
peerConnectionObservers.forEach { listener -> listener.onRemoveStream(p0) }
} }
override fun onDataChannel(p0: DataChannel?) { override fun onDataChannel(p0: DataChannel?) {
peerConnectionObservers.forEach { listener -> listener.onDataChannel(p0) }
} }
override fun onRenegotiationNeeded() { override fun onRenegotiationNeeded() {
peerConnectionObservers.forEach { listener -> listener.onRenegotiationNeeded() }
} }
override fun onAddTrack(p0: RtpReceiver?, p1: Array<out MediaStream>?) { override fun onAddTrack(p0: RtpReceiver?, p1: Array<out MediaStream>?) {
peerConnectionObservers.forEach { listener -> listener.onAddTrack(p0, p1) }
} }
override fun onBufferedAmountChange(l: Long) { override fun onBufferedAmountChange(l: Long) {
@@ -476,4 +485,8 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne
} }
} }
fun onDestroy() {
signalAudioManager.handleCommand(AudioManagerCommand.Shutdown)
}
} }

View File

@@ -0,0 +1,42 @@
package org.thoughtcrime.securesms.webrtc;
import org.session.libsignal.utilities.Log;
import java.util.ArrayList;
import java.util.List;
/**
* Allows multiple default uncaught exception handlers to be registered
*
* Calls all registered handlers in reverse order of registration.
* Errors in one handler do not prevent subsequent handlers from being called.
*/
public class UncaughtExceptionHandlerManager implements Thread.UncaughtExceptionHandler {
private final Thread.UncaughtExceptionHandler originalHandler;
private final List<Thread.UncaughtExceptionHandler> handlers = new ArrayList<Thread.UncaughtExceptionHandler>();
public UncaughtExceptionHandlerManager() {
originalHandler = Thread.getDefaultUncaughtExceptionHandler();
registerHandler(originalHandler);
Thread.setDefaultUncaughtExceptionHandler(this);
}
public void registerHandler(Thread.UncaughtExceptionHandler handler) {
handlers.add(handler);
}
public void unregister() {
Thread.setDefaultUncaughtExceptionHandler(originalHandler);
}
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
for (int i = handlers.size() - 1; i >= 0; i--) {
try {
handlers.get(i).uncaughtException(thread, throwable);
} catch(Throwable t) {
Log.e("UncaughtExceptionHandlerManager", "Error in uncaught exception handling", t);
}
}
}
}

View File

@@ -8,6 +8,7 @@ import android.telephony.TelephonyManager
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.service.WebRtcCallService import org.thoughtcrime.securesms.service.WebRtcCallService
import org.thoughtcrime.securesms.webrtc.locks.LockManager
import javax.inject.Inject import javax.inject.Inject
@@ -26,11 +27,11 @@ class HangUpRtcOnPstnCallAnsweredListener(private val hangupListener: ()->Unit):
} }
} }
@AndroidEntryPoint //@AndroidEntryPoint
class NetworkReceiver: BroadcastReceiver() { class NetworkReceiver: BroadcastReceiver() {
@Inject // @Inject
lateinit var callManager: CallManager // lateinit var callManager: CallManager
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
TODO("Not yet implemented") TODO("Not yet implemented")
@@ -47,13 +48,13 @@ class PowerButtonReceiver : BroadcastReceiver() {
} }
} }
class ProximityLockRelease: Thread.UncaughtExceptionHandler { class ProximityLockRelease(private val lockManager: LockManager): Thread.UncaughtExceptionHandler {
companion object { companion object {
private val TAG = Log.tag(ProximityLockRelease::class.java) private val TAG = Log.tag(ProximityLockRelease::class.java)
} }
override fun uncaughtException(t: Thread, e: Throwable) { override fun uncaughtException(t: Thread, e: Throwable) {
Log.e(TAG,"Uncaught exception - releasing proximity lock", e) Log.e(TAG,"Uncaught exception - releasing proximity lock", e)
// lockManager update phone state lockManager.updatePhoneState(LockManager.PhoneState.IDLE)
} }
} }

View File

@@ -37,7 +37,7 @@ 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 val handler = SignalAudioHandler(commandAndControlThread!!.looper) private var handler = SignalAudioHandler(commandAndControlThread!!.looper)
private val signalBluetoothManager = SignalBluetoothManager(context, this, androidAudioManager, handler) private val signalBluetoothManager = SignalBluetoothManager(context, this, androidAudioManager, handler)
@@ -69,6 +69,8 @@ class SignalAudioManager(private val context: Context,
handler.post { handler.post {
when (command) { when (command) {
is AudioManagerCommand.Initialize -> initialize() is AudioManagerCommand.Initialize -> initialize()
is AudioManagerCommand.Shutdown -> shutdown()
is AudioManagerCommand.UpdateAudioDeviceState -> updateAudioDeviceState()
is AudioManagerCommand.Start -> start() is AudioManagerCommand.Start -> start()
is AudioManagerCommand.Stop -> stop(command.playDisconnect) is AudioManagerCommand.Stop -> stop(command.playDisconnect)
is AudioManagerCommand.SetDefaultDevice -> setDefaultAudioDevice(command.device, command.clearUserEarpieceSelection) is AudioManagerCommand.SetDefaultDevice -> setDefaultAudioDevice(command.device, command.clearUserEarpieceSelection)
@@ -84,6 +86,9 @@ class SignalAudioManager(private val context: Context,
Log.i(TAG, "Initializing audio manager state: $state") Log.i(TAG, "Initializing audio manager state: $state")
if (state == State.UNINITIALIZED) { if (state == State.UNINITIALIZED) {
commandAndControlThread = HandlerThread("call-audio").apply { start() }
handler = SignalAudioHandler(commandAndControlThread!!.looper)
savedAudioMode = androidAudioManager.mode savedAudioMode = androidAudioManager.mode
savedIsSpeakerPhoneOn = androidAudioManager.isSpeakerphoneOn savedIsSpeakerPhoneOn = androidAudioManager.isSpeakerphoneOn
savedIsMicrophoneMute = androidAudioManager.isMicrophoneMute savedIsMicrophoneMute = androidAudioManager.isMicrophoneMute

View File

@@ -9,6 +9,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.webrtc.AudioManagerCommand
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
/** /**
@@ -181,7 +182,7 @@ class SignalBluetoothManager(
} }
private fun updateAudioDeviceState() { private fun updateAudioDeviceState() {
audioManager.updateAudioDeviceState() audioManager.handleCommand(AudioManagerCommand.UpdateAudioDeviceState)
} }
private fun startTimer() { private fun startTimer() {

View File

@@ -1,11 +0,0 @@
package org.thoughtcrime.securesms.webrtc.data
import org.session.libsession.database.CallDataProvider
import org.session.libsession.database.StorageProtocol
import org.thoughtcrime.securesms.webrtc.CallManager
import javax.inject.Inject
class SessionCallDataProvider @Inject constructor(private val storage: StorageProtocol,
private val callManager: CallManager): CallDataProvider {
}