mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-24 22:17:25 +00:00
feat: adding remainder of basic functionality to services and CallManager.kt
This commit is contained in:
@@ -141,10 +141,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
||||
return (ApplicationContext) context.getApplicationContext();
|
||||
}
|
||||
|
||||
public CallComponent getCallComponent() {
|
||||
return EntryPoints.get(getApplicationContext(), CallComponent.class);
|
||||
}
|
||||
|
||||
public DatabaseComponent getDatabaseComponent() {
|
||||
return EntryPoints.get(getApplicationContext(), DatabaseComponent.class);
|
||||
}
|
||||
|
@@ -43,10 +43,6 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
|
||||
const val ACTION_ANSWER = "answer"
|
||||
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
|
||||
}
|
||||
|
||||
@@ -59,13 +55,9 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
|
||||
private lateinit var callAddress: Address
|
||||
private lateinit var callId: UUID
|
||||
|
||||
override fun onBackPressed() {
|
||||
endCall()
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (item.itemId == android.R.id.home) {
|
||||
endCall()
|
||||
finish()
|
||||
return true
|
||||
}
|
||||
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() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
endCall()
|
||||
finish()
|
||||
}
|
||||
}, 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 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() {
|
||||
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")
|
||||
}
|
||||
|
||||
}
|
@@ -187,17 +187,10 @@ object ConversationMenuHelper {
|
||||
.setTitle("Call")
|
||||
.setMessage("Use relay?")
|
||||
.setPositiveButton("Use Relay") { d, w ->
|
||||
val intent = Intent(context, WebRtcCallActivity::class.java)
|
||||
intent.putExtra(WebRtcCallActivity.EXTRA_CALL_ID, UUID.randomUUID().toString())
|
||||
intent.putExtra(WebRtcCallActivity.EXTRA_ADDRESS, thread.address)
|
||||
val activity = context as AppCompatActivity
|
||||
activity.startActivity(intent)
|
||||
TODO()
|
||||
}
|
||||
.setNeutralButton("P2P only") { d, w ->
|
||||
val intent = Intent(context, WebRtcCallActivity::class.java)
|
||||
intent.putExtra(WebRtcCallActivity.EXTRA_ADDRESS, thread.address)
|
||||
val activity = context as AppCompatActivity
|
||||
activity.startActivity(intent)
|
||||
TODO()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
@@ -5,19 +5,19 @@ import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ServiceComponent
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.android.scopes.ServiceScoped
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import org.session.libsession.database.CallDataProvider
|
||||
import org.thoughtcrime.securesms.database.Storage
|
||||
import org.thoughtcrime.securesms.webrtc.CallManager
|
||||
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
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
abstract class CallModule {
|
||||
object CallModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@@ -25,11 +25,7 @@ abstract class CallModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideCallManager(@ApplicationContext context: Context, storage: Storage, audioManagerCompat: AudioManagerCompat) =
|
||||
fun provideCallManager(@ApplicationContext context: Context, audioManagerCompat: AudioManagerCompat) =
|
||||
CallManager(context, audioManagerCompat)
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun bindCallDataProvider(sessionCallDataProvider: SessionCallDataProvider): CallDataProvider
|
||||
|
||||
}
|
@@ -14,7 +14,6 @@ import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider
|
||||
import org.thoughtcrime.securesms.database.*
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||
import org.thoughtcrime.securesms.webrtc.data.SessionCallDataProvider
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
|
@@ -28,7 +28,8 @@ import org.thoughtcrime.securesms.webrtc.*
|
||||
import org.thoughtcrime.securesms.webrtc.CallManager.CallState.*
|
||||
import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger
|
||||
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.util.*
|
||||
import java.util.concurrent.ExecutionException
|
||||
@@ -37,7 +38,7 @@ import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class WebRtcCallService: Service() {
|
||||
class WebRtcCallService: Service(), PeerConnection.Observer {
|
||||
|
||||
@Inject lateinit var callManager: CallManager
|
||||
|
||||
@@ -62,7 +63,6 @@ class WebRtcCallService: Service() {
|
||||
|
||||
const val ACTION_RESPONSE_MESSAGE = "RESPONSE_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_REMOTE_HANGUP = "REMOTE_HANGUP"
|
||||
const val ACTION_REMOTE_BUSY = "REMOTE_BUSY"
|
||||
@@ -118,6 +118,7 @@ class WebRtcCallService: Service() {
|
||||
|
||||
private var callReceiver: IncomingPstnCallReceiver? = null
|
||||
private var wiredHeadsetStateReceiver: WiredHeadsetStateReceiver? = null
|
||||
private var uncaughtExceptionHandlerManager: UncaughtExceptionHandlerManager? = null
|
||||
|
||||
@Synchronized
|
||||
private fun terminate() {
|
||||
@@ -155,7 +156,7 @@ class WebRtcCallService: Service() {
|
||||
action == ACTION_REMOTE_VIDEO_MUTE -> handleRemoteVideoMute(intent)
|
||||
action == ACTION_RESPONSE_MESSAGE -> handleResponseMessage(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_CHECK_TIMEOUT -> handleCheckTimeout(intent)
|
||||
action == ACTION_IS_IN_CALL_QUERY -> handleIsInCallQuery(intent)
|
||||
@@ -166,15 +167,18 @@ class WebRtcCallService: Service() {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
// create audio manager
|
||||
callManager.registerListener(this)
|
||||
registerIncomingPstnCallReceiver()
|
||||
registerWiredHeadsetStateReceiver()
|
||||
getSystemService(TelephonyManager::class.java)
|
||||
.listen(hangupOnCallAnswered, PhoneStateListener.LISTEN_CALL_STATE)
|
||||
// reset call notification
|
||||
// register uncaught exception handler
|
||||
// register network receiver
|
||||
// telephony listen to call state
|
||||
registerUncaughtExceptionHandler()
|
||||
}
|
||||
|
||||
private fun registerUncaughtExceptionHandler() {
|
||||
uncaughtExceptionHandlerManager = UncaughtExceptionHandlerManager().apply {
|
||||
registerHandler(ProximityLockRelease(lockManager))
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerIncomingPstnCallReceiver() {
|
||||
@@ -215,7 +219,7 @@ class WebRtcCallService: Service() {
|
||||
private fun handleBusyMessage(intent: Intent) {
|
||||
val recipient = getRemoteRecipient(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...")
|
||||
return
|
||||
}
|
||||
@@ -412,10 +416,25 @@ class WebRtcCallService: Service() {
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
callManager.unregisterListener(this)
|
||||
callReceiver?.let { receiver ->
|
||||
unregisterReceiver(receiver)
|
||||
}
|
||||
callReceiver = null
|
||||
// unregister exception handler
|
||||
uncaughtExceptionHandlerManager?.unregister()
|
||||
callManager.onDestroy()
|
||||
super.onDestroy()
|
||||
// shutdown audiomanager
|
||||
// unregister network receiver
|
||||
// unregister power button
|
||||
@@ -553,4 +574,37 @@ class WebRtcCallService: Service() {
|
||||
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>?) {}
|
||||
}
|
@@ -10,6 +10,12 @@ open class AudioManagerCommand: Parcelable {
|
||||
@Parcelize
|
||||
object Initialize: AudioManagerCommand()
|
||||
|
||||
@Parcelize
|
||||
object Shutdown: AudioManagerCommand()
|
||||
|
||||
@Parcelize
|
||||
object UpdateAudioDeviceState: AudioManagerCommand()
|
||||
|
||||
@Parcelize
|
||||
data class StartOutgoingRinger(val type: OutgoingRinger.Type): AudioManagerCommand()
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package org.thoughtcrime.securesms.webrtc
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.telephony.TelephonyManager
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
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 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))
|
||||
val audioEvents = _audioEvents.asSharedFlow()
|
||||
private val _videoEvents = MutableStateFlow(StateEvent.VideoEnabled(false))
|
||||
@@ -183,47 +192,47 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne
|
||||
}
|
||||
|
||||
override fun onSignalingChange(newState: PeerConnection.SignalingState) {
|
||||
|
||||
peerConnectionObservers.forEach { listener -> listener.onSignalingChange(newState) }
|
||||
}
|
||||
|
||||
override fun onIceConnectionChange(newState: PeerConnection.IceConnectionState) {
|
||||
|
||||
peerConnectionObservers.forEach { listener -> listener.onIceConnectionChange(newState) }
|
||||
}
|
||||
|
||||
override fun onIceConnectionReceivingChange(receiving: Boolean) {
|
||||
|
||||
peerConnectionObservers.forEach { listener -> listener.onIceConnectionReceivingChange(receiving) }
|
||||
}
|
||||
|
||||
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?) {
|
||||
|
||||
peerConnectionObservers.forEach { listener -> listener.onAddStream(p0) }
|
||||
}
|
||||
|
||||
override fun onRemoveStream(p0: MediaStream?) {
|
||||
|
||||
peerConnectionObservers.forEach { listener -> listener.onRemoveStream(p0) }
|
||||
}
|
||||
|
||||
override fun onDataChannel(p0: DataChannel?) {
|
||||
|
||||
peerConnectionObservers.forEach { listener -> listener.onDataChannel(p0) }
|
||||
}
|
||||
|
||||
override fun onRenegotiationNeeded() {
|
||||
|
||||
peerConnectionObservers.forEach { listener -> listener.onRenegotiationNeeded() }
|
||||
}
|
||||
|
||||
override fun onAddTrack(p0: RtpReceiver?, p1: Array<out MediaStream>?) {
|
||||
|
||||
peerConnectionObservers.forEach { listener -> listener.onAddTrack(p0, p1) }
|
||||
}
|
||||
|
||||
override fun onBufferedAmountChange(l: Long) {
|
||||
@@ -476,4 +485,8 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne
|
||||
}
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
signalAudioManager.handleCommand(AudioManagerCommand.Shutdown)
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,6 +8,7 @@ import android.telephony.TelephonyManager
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.service.WebRtcCallService
|
||||
import org.thoughtcrime.securesms.webrtc.locks.LockManager
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@@ -26,11 +27,11 @@ class HangUpRtcOnPstnCallAnsweredListener(private val hangupListener: ()->Unit):
|
||||
}
|
||||
}
|
||||
|
||||
@AndroidEntryPoint
|
||||
//@AndroidEntryPoint
|
||||
class NetworkReceiver: BroadcastReceiver() {
|
||||
|
||||
@Inject
|
||||
lateinit var callManager: CallManager
|
||||
// @Inject
|
||||
// lateinit var callManager: CallManager
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
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 {
|
||||
private val TAG = Log.tag(ProximityLockRelease::class.java)
|
||||
}
|
||||
override fun uncaughtException(t: Thread, e: Throwable) {
|
||||
Log.e(TAG,"Uncaught exception - releasing proximity lock", e)
|
||||
// lockManager update phone state
|
||||
lockManager.updatePhoneState(LockManager.PhoneState.IDLE)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -37,7 +37,7 @@ class SignalAudioManager(private val context: Context,
|
||||
private val androidAudioManager: AudioManagerCompat) {
|
||||
|
||||
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)
|
||||
|
||||
@@ -69,6 +69,8 @@ class SignalAudioManager(private val context: Context,
|
||||
handler.post {
|
||||
when (command) {
|
||||
is AudioManagerCommand.Initialize -> initialize()
|
||||
is AudioManagerCommand.Shutdown -> shutdown()
|
||||
is AudioManagerCommand.UpdateAudioDeviceState -> updateAudioDeviceState()
|
||||
is AudioManagerCommand.Start -> start()
|
||||
is AudioManagerCommand.Stop -> stop(command.playDisconnect)
|
||||
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")
|
||||
|
||||
if (state == State.UNINITIALIZED) {
|
||||
commandAndControlThread = HandlerThread("call-audio").apply { start() }
|
||||
handler = SignalAudioHandler(commandAndControlThread!!.looper)
|
||||
|
||||
savedAudioMode = androidAudioManager.mode
|
||||
savedIsSpeakerPhoneOn = androidAudioManager.isSpeakerphoneOn
|
||||
savedIsMicrophoneMute = androidAudioManager.isMicrophoneMute
|
||||
|
@@ -9,6 +9,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.webrtc.AudioManagerCommand
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
@@ -181,7 +182,7 @@ class SignalBluetoothManager(
|
||||
}
|
||||
|
||||
private fun updateAudioDeviceState() {
|
||||
audioManager.updateAudioDeviceState()
|
||||
audioManager.handleCommand(AudioManagerCommand.UpdateAudioDeviceState)
|
||||
}
|
||||
|
||||
private fun startTimer() {
|
||||
|
@@ -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 {
|
||||
|
||||
}
|
Reference in New Issue
Block a user