Troubleshooting

Known Issues

This section provides a concise overview of platform-specific, device-specific and browser-specific known issues that may arise when integrating the Vonage Client SDK into your Web applications.

Client SDK Integration

User Media Devices Not Being Released

An issue has been identified on Safari where user media devices are not released despite the Peer connection being disconnected. This can lead to unexpected behavior and resource usage. Please consider this while implementing your Web applications using the Vonage Client SDK for Web.

This section provides a concise overview of platform-specific and device-specific known issues that may arise when integrating the Vonage Client SDK into your Android applications.

Voice SDK Integration

Handling isIncomingCallPermitted Exception

If you're using the isIncomingCallPermitted method from the TelecomManager, be aware that it may throw exceptions on certain devices, like Xiaomi. To ensure smooth operation, it's recommended to enclose this method call within a try-catch block and set a default value to true in case of an exception. Otherwise, the app might encounter issues while placing incoming calls. Here's how you can implement it:

// Get the TelecomManager instance
val telecomManager = context.getSystemService(AppCompatActivity.TELECOM_SERVICE) as TelecomManager

// Check permissions for incoming calls and handle exceptions
val isIncomingCallPermitted = try {
    telecomManager.isIncomingCallPermitted(phoneAccountHandle)
} catch (_: Exception) {
    // Exception occurred, default to true
    true
}

By adopting this approach, your application can gracefully handle potential exceptions, ensuring uninterrupted functionality, especially on devices where the isIncomingCallPermitted method may throw errors.

ConnectionService Unavailability Workaround

On certain devices, such as Samsung smartphones in airplane mode, the ConnectionService might not be available for handling outgoing calls, leading to potential issues. To address this, we present a workaround that enables making calls despite the unavailability of the ConnectionService.

Workaround for Placing Outgoing Calls

To overcome the unavailability of the ConnectionService, utilize the following code snippet in your application to place outgoing calls:

// Workaround for placing outgoing calls when ConnectionService is not available
private fun placeOutgoingCall(callId: CallId, callee: String) {
    try {
        coreContext.telecomHelper.startOutgoingCall(callId, callee)

        // If ConnectionService does not respond within 3 seconds,
        // we mock an outgoing connection
        TimerManager.startTimer(TimerManager.CONNECTION_SERVICE_TIMER, 3000) {
            mockOutgoingConnection(callId, callee)
        }
    } catch (e: Exception) {
        abortOutboundCall(callId, e.message)
    }
}

/**
 * This method will mock `ConnectionService#onCreateOutgoingConnection`,
 * allowing outgoing calls without direct interaction with the Telecom framework.
 */
private fun mockOutgoingConnection(callId: CallId, to: String): CallConnection {
    showToast(context, "ConnectionService Not Available")

    val connection = CallConnection(callId).apply {
        setAddress(Uri.parse(to), TelecomManager.PRESENTATION_ALLOWED)
        setCallerDisplayName(to, TelecomManager.PRESENTATION_ALLOWED)
        setDialing()
    }

    return connection
}

ConnectionService Implementation

Then, ensure your class implements the necessary ConnectionService methods as shown below:

import android.telecom.Connection
import android.telecom.ConnectionRequest
import android.telecom.PhoneAccountHandle
import android.telecom.ConnectionService
import android.telecom.TelecomManager

// Your class implementing ConnectionService
class YourConnectionService : ConnectionService() {

    override fun onCreateOutgoingConnection(
        connectionManagerPhoneAccount: PhoneAccountHandle?,
        request: ConnectionRequest?
    ): Connection {
        // Cancel the timer set in the workaround
        TimerManager.cancelTimer(TimerManager.CONNECTION_SERVICE_TIMER)

        // Your implementation of ConnectionService onCreateOutgoingConnection method
        // ... (code snippet)

        return connection
    }

    override fun onCreateOutgoingConnectionFailed(connectionManagerPhoneAccount: PhoneAccountHandle?, request: ConnectionRequest?) {
        // Cancel the timer set in the workaround
        TimerManager.cancelTimer(TimerManager.CONNECTION_SERVICE_TIMER)

        // Your implementation of ConnectionService onCreateOutgoingConnectionFailed method
        // ... (code snippet)
    }
}

TimerManager Utility

The TimerManager used in the workaround is just a custom utility class that allows you to set a timer for a callback function. It ensures that the function is executed if the timer is not canceled before the specified duration.

object TimerManager {
    private val handler: Handler = Handler(Looper.getMainLooper())
    private val timerMap: MutableMap<String, Runnable> = mutableMapOf()

    const val CONNECTION_SERVICE_TIMER = "ConnectionServiceTimer"

    fun startTimer(timerId: String, delayMillis: Long, callback: () -> Unit) {
        val runnable = Runnable {
            callback.invoke()
            timerMap.remove(timerId)
        }
        timerMap[timerId] = runnable
        handler.postDelayed(runnable, delayMillis)
    }

    fun cancelTimer(timerId: String) {
        val runnable = timerMap[timerId]
        if (runnable != null) {
            handler.removeCallbacks(runnable)
            timerMap.remove(timerId)
        }
    }
}

By incorporating this workaround and the TimerManager utility, your application will effectively manage outgoing calls, even on devices where the ConnectionService may not function correctly.

This section provides a concise overview of platform-specific and device-specific known issues that may arise when integrating the Vonage Client SDK into your iOS applications.

Voice SDK Integration

Speakerphone Issues

If you encounter problems with your Speakerphone button during calls, such as crashes or unresponsiveness, ensure that you are not interfering with the AVAudioSession.sharedInstance().

The Client SDK already handles the audio session for you, so avoid manipulating it directly with code like:

AVAudioSession.sharedInstance().setCategory(.playAndRecord)   

Rest assured that the Client SDK takes care of managing the audio session.

For users employing CallKit, it remains necessary to call VGVoiceClient.enableAudio(audioSession) and VGVoiceClient.disableAudio(audioSession) with the audioSession provided by CallKit's delegate methods.

Working with the Vonage CLI

Vonage Application setup

Since you can create multiple Vonage applications, the commands you run refer to the application that was set up. For example, when you create a user, you must make sure to create it on the application you intended.

  • Check the app your CLI refers to by running:
cat vonage_app.json

No Response to Commands

It you run a command and don't get a response:

  • Try making sure that all the JSON objects in you command are closed objects, and not missing any } or ' for example.

JWTs

Remember that a JWT is per user per Vonage Application.

Invalid Token Error

  • Decode your JWT

  • Make sure the "application_id" claim is correct.

  • Make sure the "sub" is correct. Meaning, a user with this user name exists in your Vonage Application.

  • Make sure the JWT hasn't expired:

    • You can find the expiration date on "exp", in Unix time, which is seconds since Jan 01 1970(UTC).

    • You can convert it to human time.

    • Make sure the expiration time is the future, meaning the JWT hasn't expired yet.

Connection Error or Connection Timeout

Getting Connection error or Connection Timeout while trying to login to the SDK:

  • Check the internet connection on your device.

  • Then JWT might be valid on JWT standards, however to have some claims might be incorrect per Vonage requirements. Try generating a new JWT, while ensuring the correctness of your the Vonage specific claims.

Errors while Generating a JWT

  • Make sure the private key file exists. It is generated on the machine you created the application on.

  • In our docs, while using the CLI, we suggest using the path ./private.key.

  • Make sure your private key exists on the machine you are generating the JWT with, and that the path is correct.

  • If you need an new private key:

    • You can obtain one from the Dashboard. On the left hand side menu select Voice → Your Applications → select the application → Edit. On the bottom click on Generate public / private key pair. Remember to click Save changes.

    • Save the file on you machine, and update the path to it when generating the JWT.

Push Notifications

  • Make sure you’ve uploaded the certificate to Vonage's server. You need to have a valid admin JWT, meaning a JWT without the sub claim. You can Decode your JWT to make sure.

  • Make sure that you've enabled push notifications, and that the method client.registerVoipToken() was successful. You can also put a log call or a break point to ensure that the call was successful.

Have more Questions?

Should you have any further questions, issues or feedback, please contact us on devrel@vonage.com or the Vonage Developer Community Slack.