Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is/re attach call #355

Merged
merged 15 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/src/main/java/com/telnyx/webrtc/sdk/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,7 @@ class MainActivity : AppCompatActivity() {
override fun onStop() {
super.onStop()
Timber.d("onStop")
disconnectPressed()
//disconnectPressed()
}

override fun onNewIntent(intent: Intent?) {
Expand Down
16 changes: 8 additions & 8 deletions telnyx_rtc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -255,22 +255,22 @@ dependencies {

// Testing - Instrumentation
androidTestImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
testImplementation 'androidx.test:rules:1.4.0'
androidTestImplementation 'androidx.test:runner:1.6.2'
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
testImplementation 'androidx.test:rules:1.6.1'
androidTestImplementation 'androidx.test.ext:truth:1.4.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.work:work-testing:2.7.1'
androidTestImplementation "io.mockk:mockk-android:1.12.5"
debugImplementation 'androidx.fragment:fragment-testing:1.5.2'
debugImplementation 'androidx.test:core-ktx:1.4.0'
debugImplementation 'androidx.test:core-ktx:1.6.1'

testImplementation "org.mockito:mockito-inline:4.8.0"
testImplementation "org.mockito:mockito-inline:5.2.0"
androidTestImplementation "org.mockito:mockito-android:4.8.0"

androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'

def lifecycle_version = "2.7.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
Expand Down
2 changes: 1 addition & 1 deletion telnyx_rtc/src/main/java/com/telnyx/webrtc/sdk/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
package com.telnyx.webrtc.sdk

internal object Config {
const val TELNYX_PROD_HOST_ADDRESS = "rtc.telnyx.com"
const val TELNYX_PROD_HOST_ADDRESS = "rtcdev.telnyx.com"
const val TELNYX_DEV_HOST_ADDRESS = "rtcdev.telnyx.com"
const val TELNYX_PORT = 443
const val DEFAULT_TURN = "turn:turn.telnyx.com:3478?transport=tcp"
Expand Down
80 changes: 72 additions & 8 deletions telnyx_rtc/src/main/java/com/telnyx/webrtc/sdk/TelnyxClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import android.media.AudioManager
import android.media.MediaPlayer
import android.net.ConnectivityManager
import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.os.PowerManager
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
Expand Down Expand Up @@ -61,6 +63,7 @@ class TelnyxClient(
const val RETRY_REGISTER_TIME = 3
const val RETRY_CONNECT_TIME = 3
const val GATEWAY_RESPONSE_DELAY: Long = 3000
const val RECONNECT_DELAY: Long = 1000

}

Expand Down Expand Up @@ -326,6 +329,7 @@ class TelnyxClient(
override fun onNetworkAvailable() {
Timber.d("[%s] :: There is a network available", [email protected])
// User has been logged in
resetGatewayCounters()
if (reconnecting && credentialSessionConfig != null || tokenSessionConfig != null) {
runBlocking { reconnectToSocket() }
reconnecting = false
Expand All @@ -338,7 +342,16 @@ class TelnyxClient(
[email protected]
)
reconnecting = true
socketResponseLiveData.postValue(SocketResponse.error("No Network Connection"))

Handler(Looper.getMainLooper()).postDelayed(Runnable {
if(!ConnectivityHelper.isNetworkEnabled(context)){
socketResponseLiveData.postValue(SocketResponse.error("No Network Connection"))
}else {
//Network is switched here. Either from Wifi to LTE or vice-versa
runBlocking { reconnectToSocket() }
reconnecting = false
}
}, RECONNECT_DELAY)
}
}

Expand All @@ -348,6 +361,12 @@ class TelnyxClient(
* @see [TelnyxConfig]
*/
private suspend fun reconnectToSocket() = withContext(Dispatchers.Default) {

//Disconnect active calls for reconnection
getActiveCalls()?.forEach { (_, call) ->
call?.peerConnection?.disconnect()
}

// Create new socket connection
socketReconnection = TxSocket(
socket.host_address,
Expand Down Expand Up @@ -1133,6 +1152,8 @@ class TelnyxClient(
}
}



GatewayState.NOREG.state -> {
invalidateGatewayResponseTimer()
socketResponseLiveData.postValue(SocketResponse.error("Gateway registration has timed out"))
Expand All @@ -1143,7 +1164,7 @@ class TelnyxClient(
socketResponseLiveData.postValue(SocketResponse.error("Gateway registration has failed"))
}

GatewayState.FAIL_WAIT.state -> {
(GatewayState.FAIL_WAIT.state),(GatewayState.DOWN.state) -> {
if (autoReconnectLogin && connectRetryCounter < RETRY_CONNECT_TIME) {
connectRetryCounter++
Timber.d(
Expand Down Expand Up @@ -1369,9 +1390,12 @@ class TelnyxClient(
val params = jsonObject.getAsJsonObject("params")
val offerCallId = UUID.fromString(params.get("callID").asString)
val remoteSdp = params.get("sdp").asString
val voiceSdkID = params.get("voice_sdk_id")?.asString
val voiceSdkID = jsonObject.getAsJsonPrimitive("voice_sdk_id")?.asString
if (voiceSdkID != null) {
Timber.d("Voice SDK ID _ $voiceSdkID")
[email protected] = voiceSdkID
}else {
Timber.e("No Voice SDK ID")
}

val callerName = params.get("caller_id_name").asString
Expand All @@ -1391,6 +1415,12 @@ class TelnyxClient(
override fun onIceCandidate(p0: IceCandidate?) {
super.onIceCandidate(p0)
peerConnection?.addIceCandidate(p0)
Timber.d("On IceCandidate Added")
}

override fun onRenegotiationNeeded() {
super.onRenegotiationNeeded()
Timber.d("Renegotiation Needed")
}
}
)
Expand Down Expand Up @@ -1510,19 +1540,51 @@ class TelnyxClient(
}

override fun onAttachReceived(jsonObject: JsonObject) {
val params = jsonObject.getAsJsonObject("params")
val callId = UUID.fromString(params.get("callID").asString)
val attachCall = calls[callId]
attachCall?.apply {
/* val params = jsonObject.getAsJsonObject("params")
val callId = UUID.fromString(params.get("callID").asString)*/

val attachCall = call!!.copy(
context = context,
client = this,
socket = socket,
sessionId = sessid,
audioManager = audioManager!!,
providedTurn = providedTurn!!,
providedStun = providedStun!!
).apply {

val params = jsonObject.getAsJsonObject("params")
val offerCallId = UUID.fromString(params.get("callID").asString)
val remoteSdp = params.get("sdp").asString
val voiceSdkID = jsonObject.getAsJsonPrimitive("voice_sdk_id")?.asString
if (voiceSdkID != null) {
Timber.d("Voice SDK ID _ $voiceSdkID")
[email protected] = voiceSdkID
}else {
Timber.e("No Voice SDK ID")
}

// val callerName = params.get("caller_id_name").asString
val callerNumber = params.get("caller_id_number").asString
telnyxSessionId = UUID.fromString(params.get("telnyx_session_id").asString)
telnyxLegId = UUID.fromString(params.get("telnyx_leg_id").asString)

// Set global callID
callId = offerCallId


peerConnection = Peer(
context, client, providedTurn, providedStun, callId.toString(),
context, client, providedTurn, providedStun, offerCallId.toString(),
object : PeerConnectionObserver() {
override fun onIceCandidate(p0: IceCandidate?) {
super.onIceCandidate(p0)
peerConnection?.addIceCandidate(p0)
Timber.d("On IceCandidate Added")
}

override fun onRenegotiationNeeded() {
super.onRenegotiationNeeded()
Timber.d("Renegotiation Needed")
}
}
)
Expand All @@ -1546,6 +1608,8 @@ class TelnyxClient(
Call.ICE_CANDIDATE_DELAY
)
}

calls[attachCall.callId] = attachCall
}

override fun setCallRecovering() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ enum class GatewayState(var state: String) {
FAILED("FAILED"),
FAIL_WAIT("FAIL_WAIT"),
EXPIRED("EXPIRED"),
NOREG("NOREG")
NOREG("NOREG"),
DOWN("DOWN")

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ open class PeerConnectionObserver : PeerConnection.Observer {
}

override fun onIceCandidate(p0: IceCandidate?) {
Timber.tag("PeerObserver").d("onIceCandidate [%s]", "$p0")
Timber.tag("PeerObserver").d("onIceCandidate Generated [%s]", "$p0")
}

override fun onIceCandidatesRemoved(p0: Array<out IceCandidate>?) {
Expand Down
19 changes: 7 additions & 12 deletions telnyx_rtc/src/main/java/com/telnyx/webrtc/sdk/socket/TxSocket.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class TxSocket(
internal var isPing = false

private lateinit var client: OkHttpClient
private lateinit var socket: WebSocket
private lateinit var webSocket: WebSocket
/**
* Connects to the socket with the provided Host Address and Port which were used to create an instance of TxSocket
* @param listener the [TelnyxClient] used to create an instance of TxSocket that contains our
Expand Down Expand Up @@ -118,7 +118,7 @@ class TxSocket(

Timber.d("request2 : ${request.url.encodedQuery}")

socket = client.newWebSocket(
webSocket = client.newWebSocket(
request,
object : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) {
Expand Down Expand Up @@ -295,14 +295,9 @@ class TxSocket(
* @param dataObject, the data to be send to our subscriber
*/
internal fun send(dataObject: Any?) = runBlocking {
if (isConnected) {
Timber.tag("VERTO")
.d("[%s] Sending [%s]", [email protected], gson.toJson(dataObject))
socket.send(gson.toJson(dataObject))
} else {
Timber.tag("VERTO")
.d("Message cannot be sent. There is no established WebSocket connection")
}
Timber.tag("VERTO")
.d("[%s] Sending [%s]", [email protected], gson.toJson(dataObject))
webSocket.send(gson.toJson(dataObject))
}

/**
Expand All @@ -312,8 +307,8 @@ class TxSocket(
isConnected = false
isLoggedIn = false
ongoingCall = false
if (this::socket.isInitialized) {
socket.cancel()
if (this::webSocket.isInitialized) {
webSocket.cancel()
// socket.close(1000, "Websocket connection was asked to close")
}
job.cancel("Socket was destroyed, cancelling attached job")
Expand Down
14 changes: 13 additions & 1 deletion telnyx_rtc/src/test/java/com/telnyx/webrtc/sdk/CallTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,11 @@ class CallTest : BaseTest() {

@Test
fun `test hold pressed during call`() {
val newCall = Call(mockContext, client, socket, "123", audioManager)
val newCall = Call(mockContext, client, client.socket, "123", audioManager)
client.socket.connect(client)

// Sleep to give time to connect
Thread.sleep(3000)
newCall.onHoldUnholdPressed(UUID.randomUUID())
assertEquals(newCall.getIsOnHoldStatus().getOrAwaitValue(), true)
}
Expand Down Expand Up @@ -153,6 +157,10 @@ class CallTest : BaseTest() {
)
)

client.socket.connect(client)
Thread.sleep(3000)


call = Mockito.spy(
Call(mockContext, client, client.socket, "123", audioManager)
)
Expand Down Expand Up @@ -208,6 +216,10 @@ class CallTest : BaseTest() {
port = 14938,
)
)
client.socket.connect(client)

// Sleep to give time to connect
Thread.sleep(3000)

call = Mockito.spy(
Call(mockContext, client, client.socket, "123", audioManager)
Expand Down
Loading
Loading