Move voip responsibilities from views to WebRtcPeerConnectionManager.
This commit is contained in:
parent
5d476e7259
commit
743ace7e60
@ -46,6 +46,11 @@ interface CallService {
|
|||||||
*/
|
*/
|
||||||
fun sendLocalIceCandidateRemovals(callId: String, roomId: String, candidates: List<IceCandidate>)
|
fun sendLocalIceCandidateRemovals(callId: String, roomId: String, candidates: List<IceCandidate>)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a hangup event
|
||||||
|
*/
|
||||||
|
fun sendHangup(callId: String, roomId: String)
|
||||||
|
|
||||||
fun addCallListener(listener: CallsListener)
|
fun addCallListener(listener: CallsListener)
|
||||||
|
|
||||||
fun removeCallListener(listener: CallsListener)
|
fun removeCallListener(listener: CallsListener)
|
||||||
|
@ -127,6 +127,16 @@ internal class DefaultCallService @Inject constructor(
|
|||||||
override fun sendLocalIceCandidateRemovals(callId: String, roomId: String, candidates: List<IceCandidate>) {
|
override fun sendLocalIceCandidateRemovals(callId: String, roomId: String, candidates: List<IceCandidate>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun sendHangup(callId: String, roomId: String) {
|
||||||
|
val eventContent = CallHangupContent(
|
||||||
|
callId = callId,
|
||||||
|
version = 0
|
||||||
|
)
|
||||||
|
createEventAndLocalEcho(type = EventType.CALL_HANGUP, roomId = roomId, content = eventContent.toContent()).let { event ->
|
||||||
|
roomEventSender.sendEvent(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun addCallListener(listener: CallsListener) {
|
override fun addCallListener(listener: CallsListener) {
|
||||||
if (!callListeners.contains(listener)) callListeners.add(listener)
|
if (!callListeners.contains(listener)) callListeners.add(listener)
|
||||||
}
|
}
|
||||||
|
@ -38,17 +38,14 @@ import im.vector.riotx.core.utils.checkPermissions
|
|||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.subjects.PublishSubject
|
import io.reactivex.subjects.PublishSubject
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import org.webrtc.Camera1Enumerator
|
import kotlinx.android.synthetic.main.activity_call.*
|
||||||
import org.webrtc.Camera2Enumerator
|
|
||||||
import org.webrtc.EglBase
|
import org.webrtc.EglBase
|
||||||
import org.webrtc.IceCandidate
|
import org.webrtc.IceCandidate
|
||||||
import org.webrtc.MediaStream
|
import org.webrtc.MediaStream
|
||||||
import org.webrtc.PeerConnection
|
|
||||||
import org.webrtc.RendererCommon
|
import org.webrtc.RendererCommon
|
||||||
import org.webrtc.SessionDescription
|
import org.webrtc.SessionDescription
|
||||||
import org.webrtc.SurfaceViewRenderer
|
import org.webrtc.SurfaceViewRenderer
|
||||||
import org.webrtc.VideoTrack
|
import org.webrtc.VideoTrack
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@ -69,6 +66,7 @@ class VectorCallActivity : VectorBaseActivity(), WebRtcPeerConnectionManager.Lis
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val callViewModel: VectorCallViewModel by viewModel()
|
private val callViewModel: VectorCallViewModel by viewModel()
|
||||||
|
private lateinit var callArgs: CallArgs
|
||||||
|
|
||||||
@Inject lateinit var peerConnectionManager: WebRtcPeerConnectionManager
|
@Inject lateinit var peerConnectionManager: WebRtcPeerConnectionManager
|
||||||
|
|
||||||
@ -114,10 +112,19 @@ class VectorCallActivity : VectorBaseActivity(), WebRtcPeerConnectionManager.Lis
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
if (intent.hasExtra(MvRx.KEY_ARG)) {
|
||||||
|
callArgs = intent.getParcelableExtra(MvRx.KEY_ARG)!!
|
||||||
|
} else {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
rootEglBase = EglUtils.rootEglBase ?: return Unit.also {
|
rootEglBase = EglUtils.rootEglBase ?: return Unit.also {
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iv_end_call.setOnClickListener { callViewModel.handle(VectorCallViewActions.EndCall) }
|
||||||
|
|
||||||
callViewModel.viewEvents
|
callViewModel.viewEvents
|
||||||
.observe()
|
.observe()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
@ -161,8 +168,9 @@ class VectorCallActivity : VectorBaseActivity(), WebRtcPeerConnectionManager.Lis
|
|||||||
// setSwappedFeeds(true /* isSwappedFeeds */);
|
// setSwappedFeeds(true /* isSwappedFeeds */);
|
||||||
|
|
||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
peerConnectionManager.createPeerConnectionFactory()
|
//peerConnectionManager.createPeerConnectionFactory()
|
||||||
|
|
||||||
|
/*
|
||||||
val cameraIterator = if (Camera2Enumerator.isSupported(this)) Camera2Enumerator(this) else Camera1Enumerator(false)
|
val cameraIterator = if (Camera2Enumerator.isSupported(this)) Camera2Enumerator(this) else Camera1Enumerator(false)
|
||||||
val frontCamera = cameraIterator.deviceNames
|
val frontCamera = cameraIterator.deviceNames
|
||||||
?.firstOrNull { cameraIterator.isFrontFacing(it) }
|
?.firstOrNull { cameraIterator.isFrontFacing(it) }
|
||||||
@ -170,19 +178,12 @@ class VectorCallActivity : VectorBaseActivity(), WebRtcPeerConnectionManager.Lis
|
|||||||
?: return true
|
?: return true
|
||||||
val videoCapturer = cameraIterator.createCapturer(frontCamera, null)
|
val videoCapturer = cameraIterator.createCapturer(frontCamera, null)
|
||||||
|
|
||||||
val iceServers = ArrayList<PeerConnection.IceServer>().apply {
|
|
||||||
listOf("turn:turn.matrix.org:3478?transport=udp", "turn:turn.matrix.org:3478?transport=tcp", "turns:turn.matrix.org:443?transport=tcp").forEach {
|
|
||||||
add(
|
|
||||||
PeerConnection.IceServer.builder(it)
|
|
||||||
.setUsername("xxxxx")
|
|
||||||
.setPassword("xxxxx")
|
|
||||||
.createIceServer()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
peerConnectionManager.createPeerConnection(videoCapturer, iceServers)
|
peerConnectionManager.createPeerConnection(videoCapturer, iceServers)
|
||||||
peerConnectionManager.startCall()
|
*/
|
||||||
|
|
||||||
|
//peerConnectionManager.startCall()
|
||||||
}
|
}
|
||||||
// PeerConnectionFactory.initialize(PeerConnectionFactory
|
// PeerConnectionFactory.initialize(PeerConnectionFactory
|
||||||
// .InitializationOptions.builder(applicationContext)
|
// .InitializationOptions.builder(applicationContext)
|
||||||
@ -322,15 +323,6 @@ class VectorCallActivity : VectorBaseActivity(), WebRtcPeerConnectionManager.Lis
|
|||||||
// Timber.v("## VOIP onCreateFailure $p0")
|
// Timber.v("## VOIP onCreateFailure $p0")
|
||||||
// }
|
// }
|
||||||
// }, constraints)
|
// }, constraints)
|
||||||
iceCandidateSource
|
|
||||||
.buffer(400, TimeUnit.MILLISECONDS)
|
|
||||||
.subscribe {
|
|
||||||
// omit empty :/
|
|
||||||
if (it.isNotEmpty()) {
|
|
||||||
callViewModel.handle(VectorCallViewActions.AddLocalIceCandidate(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.disposeOnDestroy()
|
|
||||||
|
|
||||||
peerConnectionManager.attachViewRenderers(pipRenderer, fullscreenRenderer)
|
peerConnectionManager.attachViewRenderers(pipRenderer, fullscreenRenderer)
|
||||||
return false
|
return false
|
||||||
@ -433,6 +425,6 @@ class VectorCallActivity : VectorBaseActivity(), WebRtcPeerConnectionManager.Lis
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun sendOffer(sessionDescription: SessionDescription) {
|
override fun sendOffer(sessionDescription: SessionDescription) {
|
||||||
callViewModel.handle(VectorCallViewActions.SendOffer(sessionDescription))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package im.vector.riotx.features.call
|
package im.vector.riotx.features.call
|
||||||
|
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
@ -27,16 +26,10 @@ import im.vector.matrix.android.api.session.call.CallsListener
|
|||||||
import im.vector.matrix.android.api.session.room.model.call.CallAnswerContent
|
import im.vector.matrix.android.api.session.room.model.call.CallAnswerContent
|
||||||
import im.vector.matrix.android.api.session.room.model.call.CallHangupContent
|
import im.vector.matrix.android.api.session.room.model.call.CallHangupContent
|
||||||
import im.vector.matrix.android.api.session.room.model.call.CallInviteContent
|
import im.vector.matrix.android.api.session.room.model.call.CallInviteContent
|
||||||
import im.vector.matrix.android.internal.util.awaitCallback
|
|
||||||
import im.vector.riotx.core.extensions.exhaustive
|
import im.vector.riotx.core.extensions.exhaustive
|
||||||
import im.vector.riotx.core.platform.VectorViewEvents
|
import im.vector.riotx.core.platform.VectorViewEvents
|
||||||
import im.vector.riotx.core.platform.VectorViewModel
|
import im.vector.riotx.core.platform.VectorViewModel
|
||||||
import im.vector.riotx.core.platform.VectorViewModelAction
|
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.webrtc.IceCandidate
|
|
||||||
import org.webrtc.SessionDescription
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
data class VectorCallViewState(
|
data class VectorCallViewState(
|
||||||
val callId: String? = null,
|
val callId: String? = null,
|
||||||
@ -45,8 +38,7 @@ data class VectorCallViewState(
|
|||||||
|
|
||||||
sealed class VectorCallViewActions : VectorViewModelAction {
|
sealed class VectorCallViewActions : VectorViewModelAction {
|
||||||
|
|
||||||
data class SendOffer(val sdp: SessionDescription) : VectorCallViewActions()
|
object EndCall : VectorCallViewActions()
|
||||||
data class AddLocalIceCandidate(val iceCandidates: List<IceCandidate>) : VectorCallViewActions()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class VectorCallViewEvents : VectorViewEvents {
|
sealed class VectorCallViewEvents : VectorViewEvents {
|
||||||
@ -57,7 +49,8 @@ sealed class VectorCallViewEvents : VectorViewEvents {
|
|||||||
|
|
||||||
class VectorCallViewModel @AssistedInject constructor(
|
class VectorCallViewModel @AssistedInject constructor(
|
||||||
@Assisted initialState: VectorCallViewState,
|
@Assisted initialState: VectorCallViewState,
|
||||||
val session: Session
|
val session: Session,
|
||||||
|
val webRtcPeerConnectionManager: WebRtcPeerConnectionManager
|
||||||
) : VectorViewModel<VectorCallViewState, VectorCallViewActions, VectorCallViewEvents>(initialState) {
|
) : VectorViewModel<VectorCallViewState, VectorCallViewActions, VectorCallViewEvents>(initialState) {
|
||||||
|
|
||||||
private val callServiceListener: CallsListener = object : CallsListener {
|
private val callServiceListener: CallsListener = object : CallsListener {
|
||||||
@ -90,25 +83,9 @@ class VectorCallViewModel @AssistedInject constructor(
|
|||||||
super.onCleared()
|
super.onCleared()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handle(action: VectorCallViewActions) = withState { state ->
|
override fun handle(action: VectorCallViewActions) = withState {
|
||||||
when (action) {
|
when (action) {
|
||||||
is VectorCallViewActions.SendOffer -> {
|
VectorCallViewActions.EndCall -> webRtcPeerConnectionManager.endCall()
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
|
||||||
awaitCallback<String> {
|
|
||||||
val callId = state.callId ?: UUID.randomUUID().toString().also {
|
|
||||||
setState {
|
|
||||||
copy(callId = it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
session.callService().sendOfferSdp(callId, state.roomId, action.sdp, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is VectorCallViewActions.AddLocalIceCandidate -> {
|
|
||||||
viewModelScope.launch {
|
|
||||||
session.callService().sendLocalIceCandidates(state.callId ?: "", state.roomId, action.iceCandidates)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ import android.content.Intent
|
|||||||
import android.content.ServiceConnection
|
import android.content.ServiceConnection
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.session.call.CallsListener
|
import im.vector.matrix.android.api.session.call.CallsListener
|
||||||
import im.vector.matrix.android.api.session.call.EglUtils
|
import im.vector.matrix.android.api.session.call.EglUtils
|
||||||
import im.vector.matrix.android.api.session.room.model.call.CallAnswerContent
|
import im.vector.matrix.android.api.session.room.model.call.CallAnswerContent
|
||||||
@ -29,6 +30,8 @@ import im.vector.matrix.android.api.session.room.model.call.CallHangupContent
|
|||||||
import im.vector.matrix.android.api.session.room.model.call.CallInviteContent
|
import im.vector.matrix.android.api.session.room.model.call.CallInviteContent
|
||||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||||
import im.vector.riotx.features.call.service.CallHeadsUpService
|
import im.vector.riotx.features.call.service.CallHeadsUpService
|
||||||
|
import io.reactivex.disposables.Disposable
|
||||||
|
import io.reactivex.subjects.PublishSubject
|
||||||
import org.webrtc.AudioSource
|
import org.webrtc.AudioSource
|
||||||
import org.webrtc.AudioTrack
|
import org.webrtc.AudioTrack
|
||||||
import org.webrtc.DefaultVideoDecoderFactory
|
import org.webrtc.DefaultVideoDecoderFactory
|
||||||
@ -47,7 +50,9 @@ import org.webrtc.VideoSource
|
|||||||
import org.webrtc.VideoTrack
|
import org.webrtc.VideoTrack
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
|
import java.util.UUID
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -59,7 +64,7 @@ import javax.inject.Singleton
|
|||||||
class WebRtcPeerConnectionManager @Inject constructor(
|
class WebRtcPeerConnectionManager @Inject constructor(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val sessionHolder: ActiveSessionHolder
|
private val sessionHolder: ActiveSessionHolder
|
||||||
) : CallsListener {
|
) : CallsListener {
|
||||||
|
|
||||||
interface Listener {
|
interface Listener {
|
||||||
fun addLocalIceCandidate(candidates: IceCandidate)
|
fun addLocalIceCandidate(candidates: IceCandidate)
|
||||||
@ -98,8 +103,15 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
|||||||
var localSurfaceRenderer: WeakReference<SurfaceViewRenderer>? = null
|
var localSurfaceRenderer: WeakReference<SurfaceViewRenderer>? = null
|
||||||
var remoteSurfaceRenderer: WeakReference<SurfaceViewRenderer>? = null
|
var remoteSurfaceRenderer: WeakReference<SurfaceViewRenderer>? = null
|
||||||
|
|
||||||
|
private val iceCandidateSource: PublishSubject<IceCandidate> = PublishSubject.create()
|
||||||
|
private var iceCandidateDisposable: Disposable? = null
|
||||||
|
|
||||||
var callHeadsUpService: CallHeadsUpService? = null
|
var callHeadsUpService: CallHeadsUpService? = null
|
||||||
|
|
||||||
|
private var callId: String? = null
|
||||||
|
private var signalingRoomId: String? = null
|
||||||
|
private var participantUserId: String? = null
|
||||||
|
|
||||||
private val serviceConnection = object : ServiceConnection {
|
private val serviceConnection = object : ServiceConnection {
|
||||||
override fun onServiceDisconnected(name: ComponentName?) {
|
override fun onServiceDisconnected(name: ComponentName?) {
|
||||||
}
|
}
|
||||||
@ -109,7 +121,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createPeerConnectionFactory() {
|
private fun createPeerConnectionFactory() {
|
||||||
executor.execute {
|
executor.execute {
|
||||||
if (peerConnectionFactory == null) {
|
if (peerConnectionFactory == null) {
|
||||||
Timber.v("## VOIP createPeerConnectionFactory")
|
Timber.v("## VOIP createPeerConnectionFactory")
|
||||||
@ -142,7 +154,56 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createPeerConnection(videoCapturer: VideoCapturer, iceServers: List<PeerConnection.IceServer>) {
|
private fun createPeerConnection() {
|
||||||
|
val iceServers = ArrayList<PeerConnection.IceServer>().apply {
|
||||||
|
listOf("turn:turn.matrix.org:3478?transport=udp", "turn:turn.matrix.org:3478?transport=tcp", "turns:turn.matrix.org:443?transport=tcp").forEach {
|
||||||
|
add(
|
||||||
|
PeerConnection.IceServer.builder(it)
|
||||||
|
.setUsername("xxxxx")
|
||||||
|
.setPassword("xxxxx")
|
||||||
|
.createIceServer()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Timber.v("## VOIP creating peer connection... ")
|
||||||
|
peerConnection = peerConnectionFactory?.createPeerConnection(
|
||||||
|
iceServers,
|
||||||
|
object : PeerConnectionObserverAdapter() {
|
||||||
|
override fun onIceCandidate(p0: IceCandidate?) {
|
||||||
|
Timber.v("## VOIP onIceCandidate local $p0")
|
||||||
|
p0?.let { iceCandidateSource.onNext(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAddStream(mediaStream: MediaStream?) {
|
||||||
|
Timber.v("## VOIP onAddStream remote $mediaStream")
|
||||||
|
mediaStream?.videoTracks?.firstOrNull()?.let {
|
||||||
|
listener?.addRemoteVideoTrack(it)
|
||||||
|
remoteVideoTrack = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoveStream(mediaStream: MediaStream?) {
|
||||||
|
mediaStream?.let {
|
||||||
|
listener?.removeRemoteVideoStream(it)
|
||||||
|
}
|
||||||
|
remoteSurfaceRenderer?.get()?.let {
|
||||||
|
remoteVideoTrack?.removeSink(it)
|
||||||
|
}
|
||||||
|
remoteVideoTrack = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onIceConnectionChange(p0: PeerConnection.IceConnectionState?) {
|
||||||
|
Timber.v("## VOIP onIceConnectionChange $p0")
|
||||||
|
if (p0 == PeerConnection.IceConnectionState.DISCONNECTED) {
|
||||||
|
listener?.onDisconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO REMOVE THIS FUNCTION
|
||||||
|
private fun createPeerConnection(videoCapturer: VideoCapturer) {
|
||||||
executor.execute {
|
executor.execute {
|
||||||
Timber.v("## VOIP PeerConnectionFactory.createPeerConnection $peerConnectionFactory...")
|
Timber.v("## VOIP PeerConnectionFactory.createPeerConnection $peerConnectionFactory...")
|
||||||
// Following instruction here: https://stackoverflow.com/questions/55085726/webrtc-create-peerconnectionfactory-object
|
// Following instruction here: https://stackoverflow.com/questions/55085726/webrtc-create-peerconnectionfactory-object
|
||||||
@ -183,55 +244,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
|||||||
// }
|
// }
|
||||||
// .disposeOnDestroy()
|
// .disposeOnDestroy()
|
||||||
|
|
||||||
Timber.v("## VOIP creating peer connection... ")
|
|
||||||
peerConnection = peerConnectionFactory?.createPeerConnection(
|
|
||||||
iceServers,
|
|
||||||
object : PeerConnectionObserverAdapter() {
|
|
||||||
override fun onIceCandidate(p0: IceCandidate?) {
|
|
||||||
Timber.v("## VOIP onIceCandidate local $p0")
|
|
||||||
p0?.let {
|
|
||||||
// iceCandidateSource.onNext(it)
|
|
||||||
listener?.addLocalIceCandidate(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAddStream(mediaStream: MediaStream?) {
|
|
||||||
Timber.v("## VOIP onAddStream remote $mediaStream")
|
|
||||||
mediaStream?.videoTracks?.firstOrNull()?.let {
|
|
||||||
listener?.addRemoteVideoTrack(it)
|
|
||||||
remoteVideoTrack = it
|
|
||||||
// remoteSurfaceRenderer?.get()?.let { surface ->
|
|
||||||
// it.setEnabled(true)
|
|
||||||
// it.addSink(surface)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
// runOnUiThread {
|
|
||||||
// mediaStream?.videoTracks?.firstOrNull()?.let { videoTrack ->
|
|
||||||
// remoteVideoTrack = videoTrack
|
|
||||||
// remoteVideoTrack?.setEnabled(true)
|
|
||||||
// remoteVideoTrack?.addSink(fullscreenRenderer)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRemoveStream(mediaStream: MediaStream?) {
|
|
||||||
mediaStream?.let {
|
|
||||||
listener?.removeRemoteVideoStream(it)
|
|
||||||
}
|
|
||||||
remoteSurfaceRenderer?.get()?.let {
|
|
||||||
remoteVideoTrack?.removeSink(it)
|
|
||||||
}
|
|
||||||
remoteVideoTrack = null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onIceConnectionChange(p0: PeerConnection.IceConnectionState?) {
|
|
||||||
Timber.v("## VOIP onIceConnectionChange $p0")
|
|
||||||
if (p0 == PeerConnection.IceConnectionState.DISCONNECTED) {
|
|
||||||
listener?.onDisconnect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
localMediaStream = peerConnectionFactory?.createLocalMediaStream("ARDAMS") // magic value?
|
localMediaStream = peerConnectionFactory?.createLocalMediaStream("ARDAMS") // magic value?
|
||||||
localMediaStream?.addTrack(localVideoTrack)
|
localMediaStream?.addTrack(localVideoTrack)
|
||||||
@ -253,7 +266,22 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startCall() {
|
private fun startCall() {
|
||||||
|
createPeerConnectionFactory()
|
||||||
|
createPeerConnection()
|
||||||
|
|
||||||
|
iceCandidateDisposable = iceCandidateSource
|
||||||
|
.buffer(400, TimeUnit.MILLISECONDS)
|
||||||
|
.subscribe {
|
||||||
|
// omit empty :/
|
||||||
|
if (it.isNotEmpty()) {
|
||||||
|
sessionHolder
|
||||||
|
.getActiveSession()
|
||||||
|
.callService()
|
||||||
|
.sendLocalIceCandidates(callId ?: "", signalingRoomId ?: "", it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
executor.execute {
|
executor.execute {
|
||||||
val constraints = MediaConstraints()
|
val constraints = MediaConstraints()
|
||||||
constraints.mandatory.add(MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"))
|
constraints.mandatory.add(MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"))
|
||||||
@ -273,8 +301,8 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
|||||||
Timber.v("## VOIP onCreateSuccess $sessionDescription")
|
Timber.v("## VOIP onCreateSuccess $sessionDescription")
|
||||||
peerConnection?.setLocalDescription(object : SdpObserverAdapter() {
|
peerConnection?.setLocalDescription(object : SdpObserverAdapter() {
|
||||||
override fun onSetSuccess() {
|
override fun onSetSuccess() {
|
||||||
listener?.sendOffer(sessionDescription)
|
callId = UUID.randomUUID().toString()
|
||||||
// callViewModel.handle(VectorCallViewActions.SendOffer(sessionDescription))
|
sessionHolder.getActiveSession().callService().sendOfferSdp(callId!!, signalingRoomId!!, sessionDescription, object : MatrixCallback<String> {})
|
||||||
}
|
}
|
||||||
}, sessionDescription)
|
}, sessionDescription)
|
||||||
}
|
}
|
||||||
@ -319,6 +347,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
|||||||
peerConnectionFactory?.stopAecDump()
|
peerConnectionFactory?.stopAecDump()
|
||||||
peerConnectionFactory = null
|
peerConnectionFactory = null
|
||||||
}
|
}
|
||||||
|
iceCandidateDisposable?.dispose()
|
||||||
context.stopService(Intent(context, CallHeadsUpService::class.java))
|
context.stopService(Intent(context, CallHeadsUpService::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,12 +375,18 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun startOutgoingCall(context: Context, signalingRoomId: String, participantUserId: String, isVideoCall: Boolean) {
|
fun startOutgoingCall(context: Context, signalingRoomId: String, participantUserId: String, isVideoCall: Boolean) {
|
||||||
|
this.signalingRoomId = signalingRoomId
|
||||||
|
this.participantUserId = participantUserId
|
||||||
startHeadsUpService(signalingRoomId, sessionHolder.getActiveSession().myUserId, false, isVideoCall)
|
startHeadsUpService(signalingRoomId, sessionHolder.getActiveSession().myUserId, false, isVideoCall)
|
||||||
context.startActivity(VectorCallActivity.newIntent(context, signalingRoomId, participantUserId, false, isVideoCall))
|
context.startActivity(VectorCallActivity.newIntent(context, signalingRoomId, participantUserId, false, isVideoCall))
|
||||||
|
|
||||||
|
startCall()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCallInviteReceived(signalingRoomId: String, participantUserId: String, callInviteContent: CallInviteContent) {
|
override fun onCallInviteReceived(signalingRoomId: String, participantUserId: String, callInviteContent: CallInviteContent) {
|
||||||
startHeadsUpService(signalingRoomId, participantUserId, true, callInviteContent.isVideo())
|
startHeadsUpService(signalingRoomId, participantUserId, true, callInviteContent.isVideo())
|
||||||
|
|
||||||
|
startCall()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startHeadsUpService(roomId: String, participantUserId: String, isIncomingCall: Boolean, isVideoCall: Boolean) {
|
private fun startHeadsUpService(roomId: String, participantUserId: String, isIncomingCall: Boolean, isVideoCall: Boolean) {
|
||||||
@ -361,6 +396,13 @@ class WebRtcPeerConnectionManager @Inject constructor(
|
|||||||
context.bindService(Intent(context, CallHeadsUpService::class.java), serviceConnection, 0)
|
context.bindService(Intent(context, CallHeadsUpService::class.java), serviceConnection, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun endCall() {
|
||||||
|
if (callId != null && signalingRoomId != null) {
|
||||||
|
sessionHolder.getActiveSession().callService().sendHangup(callId!!, signalingRoomId!!)
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) {
|
override fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,14 +21,10 @@ import android.os.Build
|
|||||||
import android.telecom.Connection
|
import android.telecom.Connection
|
||||||
import android.telecom.DisconnectCause
|
import android.telecom.DisconnectCause
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import im.vector.riotx.features.call.VectorCallViewActions
|
|
||||||
import im.vector.riotx.features.call.VectorCallViewModel
|
import im.vector.riotx.features.call.VectorCallViewModel
|
||||||
import im.vector.riotx.features.call.WebRtcPeerConnectionManager
|
import im.vector.riotx.features.call.WebRtcPeerConnectionManager
|
||||||
import org.webrtc.Camera1Enumerator
|
|
||||||
import org.webrtc.Camera2Enumerator
|
|
||||||
import org.webrtc.IceCandidate
|
import org.webrtc.IceCandidate
|
||||||
import org.webrtc.MediaStream
|
import org.webrtc.MediaStream
|
||||||
import org.webrtc.PeerConnection
|
|
||||||
import org.webrtc.SessionDescription
|
import org.webrtc.SessionDescription
|
||||||
import org.webrtc.VideoTrack
|
import org.webrtc.VideoTrack
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -91,7 +87,8 @@ import javax.inject.Inject
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun startCall() {
|
private fun startCall() {
|
||||||
peerConnectionManager.createPeerConnectionFactory()
|
/*
|
||||||
|
//peerConnectionManager.createPeerConnectionFactory()
|
||||||
peerConnectionManager.listener = this
|
peerConnectionManager.listener = this
|
||||||
|
|
||||||
val cameraIterator = if (Camera2Enumerator.isSupported(context)) Camera2Enumerator(context) else Camera1Enumerator(false)
|
val cameraIterator = if (Camera2Enumerator.isSupported(context)) Camera2Enumerator(context) else Camera1Enumerator(false)
|
||||||
@ -113,7 +110,8 @@ import javax.inject.Inject
|
|||||||
}
|
}
|
||||||
|
|
||||||
peerConnectionManager.createPeerConnection(videoCapturer, iceServers)
|
peerConnectionManager.createPeerConnection(videoCapturer, iceServers)
|
||||||
peerConnectionManager.startCall()
|
//peerConnectionManager.startCall()
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addLocalIceCandidate(candidates: IceCandidate) {
|
override fun addLocalIceCandidate(candidates: IceCandidate) {
|
||||||
@ -129,6 +127,6 @@ import javax.inject.Inject
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun sendOffer(sessionDescription: SessionDescription) {
|
override fun sendOffer(sessionDescription: SessionDescription) {
|
||||||
callViewModel.handle(VectorCallViewActions.SendOffer(sessionDescription))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user