Rate this page:

Android v3 migration guide

Voximplant Android SDK v3 has introduced major breaking changes to provide more functionality and improve the SDK scalability. This guide explains how to smoothly migrate the application code base to use the new API.

Contents

Copy URL

Add Voximplant SDK to your project

Copy URL

Voximplant Android SDK v3 comes with the BoM (Bill of Materials) that allows developers to manage the Voximplant libraries according to the application needs (i.e. import only those that are required).

Voximplant Android SDK v3 BoM contains the following modules:

  • com.voximplant.android-sdk-core — provides API to connect and authenticate the Voximplant users in an android application and manage audio devices.

  • com.voximplant.android-sdk-calls — provides API to make, receive, and manage calls and conferences

  • com.voximplant.android-sdk-messaging — provides API to implement the chat functionality

  • com.voximplant.android-sdk-renderer-compose — provides a composable function to renderer a video stream on an application UI built with Jetpack Compose

From v2 (Kotlin DSL):

implementation("com.voximplant:voximplant-sdk:2.42.0")

To v3 (Kotlin DSL):

implementation(platform("com.voximplant:android-sdk-bom:3.1.0"))
implementation("com:voximplant.android-sdk-core")
implementation("com.voximplant:android-sdk-calls")
implementation("com.voximplant:android-sdk-renderer-compose")
implementation("com:voximplant:android-sdk-messaging")

SDK initialization

Copy URL

Voximplant Android SDK is required to be initialized with the Android application context before any API method call. Use VICore.initialize API.

Executor on which all Voximplant Android SDK events are received is now created by the SDK as a single thread executor and may be manually configured via VICore.callbackExecutor property.

From v2:

val client = Voximplant.getClientInstance(
    /* executor = */ Executors.newSingleThreadExecutor(),
    /* context = */ applicationContext,
    /* clientConfig = */ ClientConfig(),
)

To v3:

VICore.initialize(applicationContext)

Connect and authenticate the Voximplant users

Copy URL

The Client API is now the object and can be accessed from anywhere. The API to connect and log in the users are redesigned and provided with the callbacks with the extended error descriptions.

To establish the connection to the Voximplant cloud it is required to specify the node the Voximplant account belongs to via the ConnectOptions.

From v2:

import com.voximplant.sdk.client.AuthParams
import com.voximplant.sdk.client.IClient
import com.voximplant.sdk.client.IClientLoginListener
import com.voximplant.sdk.client.IClientSessionListener
import com.voximplant.sdk.client.Node

class SomeClass : IClientSessionListener, IClientLoginListener {
    private lateinit var client: IClient
    // ctor and other logic here
    // Note: you also need to implement other methods from
    // IClientLoginListener and IClientSessionListener

    override fun onConnectionEstablished() {
        Log.i(TAG, "Connection established")
        client.login("myuser@myapp.myaccount.voximplant.com", "mypass")
    }

    override fun onLoginSuccessful(
        displayName: String,
        authParams: AuthParams?,
    ) {
        Log.i(TAG, "Login succeeded")
    }

    fun connectToVoximplant() {
        client.setClientSessionListener(this)
        client.setClientLoginListener(this)
        client.connect(Node)
    }
}

To v3:

import com.voximplant.android.sdk.core.AuthParams
import com.voximplant.android.sdk.core.Client
import com.voximplant.android.sdk.core.ClientSessionListener
import com.voximplant.android.sdk.core.ConnectOptions
import com.voximplant.android.sdk.core.ConnectionCallback
import com.voximplant.android.sdk.core.ConnectionError
import com.voximplant.android.sdk.core.DisconnectReason
import com.voximplant.android.sdk.core.LoginCallback
import com.voximplant.android.sdk.core.LoginError
import com.voximplant.android.sdk.core.Node

class SomeClass {
    val clientSessionListener = object : ClientSessionListener {
        override fun onConnectionClosed(reason: DisconnectReason) {
            Log.w(TAG, "Connection closed")
            Client.setClientSessionListener(null)
        }
    }

    fun connect() {
        Client.connect(
            options = ConnectOptions(node = Node), // Select Node from Voximplant Cloud
            callback = object : ConnectionCallback {
                override fun onFailure(error: ConnectionError) {
                    Log.e(TAG, "Connection failed – $error")
                }

                override fun onSuccess() {
                    Log.i(TAG, "Connection succeeded")
                    Client.setClientSessionListener(clientSessionListener)
                    // You can now log in
                }
            },
        )
    }

    fun login() {
        Client.login(
            username = "myuser@myapp.myaccount.voximplant.com",
            password = "mypass",
            callback = object : LoginCallback {
                override fun onFailure(error: LoginError) {
                    Log.e(TAG, "Login failed – $error")
                }

                override fun onSuccess(displayName: String, authParams: AuthParams?) {
                    Log.i(TAG, "Login succeeded")
                }
            },
        )
    }
}

Local video stream changes

Copy URL

Voximplant Android SDK v3 allows developers to create a local video stream outside an active call or conference. It simplifies the implementation of such functionality as video preview and camera configuration. A local video stream should be created based on a video source.

Each video support provides API for its configuration. The SDK provides support for the following video sources:

  • CameraVideoSource — allows developers to setup and manage cameras on the Android device

  • CustomVideoSource — allows developers to inject video frames created outside the SDK (on the application side) to a call or a conference

  • ScreenCaptureVideoSource — allows developers to capture the Android device screen

A video source starts producing frames (starts capturing) only if at least one the following conditions is met:

  1. a video renderer is added to the local video stream
  2. a local video stream is attached to an active call or a conference
Please note

If a video source requires a system permission, for example a camera permission, it is recommended to request the permission before creating a local video stream.

A video source stops producing frames (stops capturing) if both conditions are met:

  1. a local video stream is not rendered to any renderer
  2. a local video stream is not sent in any call or conference
Warning

If a video call or a conference has ended, but a local video stream still has any renderers, video source does not release its resources. It is important to carefully manage local video streams on the application side to avoid unexpected system indicators for a camera or screen capture.

Create a local video stream based on the camera video source:

val cameraVideoSource = CameraVideoSource
val localVideoStream = LocalVideoStream(cameraVideoSource)

Calls

Copy URL

Voximplant Android SDK v3 has a separate classes that represent a call and a conference. It provides a clearer visibility of the SDK functionality for calls and conferences.

Notable changes:

  • Separated call and conference settings to start a call or a conference

  • Separated call and conferences events

  • Endpoints are now available only for the conferences. Information about another call participant as well as its events is now available via the Call API.

  • Local video stream management before a call/conference — it is now possible to create and render a local video stream before a call or a conference starts. New API provide more flexible way to manage the video stream sources such as camera, custom, or screen sharing video source.

  • Native webrtc libraries are loaded on the calls module initialization

Please note

Before you start using the calls module API, you should initialize the module via the VICalls.initialize API.

Start an outgoing audio call

The VideoFlags API that represents the video settings for a call is replaced with CallSettings.receiveVideo and CallSettings.localVideoStream properties. Video is disabled by default.

From v2:

import com.voximplant.sdk.call.CallException
import com.voximplant.sdk.call.CallSettings
import com.voximplant.sdk.call.ICall
import com.voximplant.sdk.call.VideoFlags

// 1. Prepare callSettings
val callSettings = CallSettings()
callSettings.videoFlags = VideoFlags(false, false)

// 2. Get an ICall instance
val call: ICall? = client.call("Number to call", callSettings)

// 3. Start the call
try {
    call!!.start()
} catch (callException: CallException) {
    // handle error
}

To v3:

import com.voximplant.android.sdk.calls.Call
import com.voximplant.android.sdk.calls.CallException
import com.voximplant.android.sdk.calls.CallSettings
import com.voximplant.android.sdk.calls.VICalls

// 1. Create a Call instance
val call: Call? = VICalls.createCall(
    number = "number to call",
    callSettings = CallSettings(),
)

// 2. Start the call
try {
    call!!.start()
} catch (callException: CallException) {
    // handle error
}

Start an outgoing video call

The VideoFlags API that represents the video settings for a call is replaced with CallSettings.receiveVideo and CallSettings.localVideoStream properties. Video is disabled by default.

From v2:

import com.voximplant.sdk.call.CallException
import com.voximplant.sdk.call.CallSettings
import com.voximplant.sdk.call.ICall
import com.voximplant.sdk.call.VideoFlags

// 1. Prepare callSettings
val callSettings = CallSettings()
callSettings.videoFlags = VideoFlags(false, false)

// 2. Get an ICall instance
val call: ICall? = client.call("Number to call", callSettings)

// 3. Start the call
try {
    call!!.start()
} catch (callException: CallException) {
    // handle error
}

To v3:

import com.voximplant.android.sdk.calls.Call
import com.voximplant.android.sdk.calls.CallException
import com.voximplant.android.sdk.calls.CallSettings
import com.voximplant.android.sdk.calls.VICalls

// 1. Create a Call instance
val call: Call? = VICalls.createCall(
    number = "number to call",
    callSettings = CallSettings(),
)

// 2. Start the call
try {
    call!!.start()
} catch (callException: CallException) {
    // handle error
}

Start an outgoing video call

To start an outgoing video call, it is required to create a local video stream first.

Warning

Call cannot be created with a local video stream with screen capture video source. However, it is possible to start sending the screen sharing after the call is connected.

From v2:

import com.voximplant.sdk.call.CallException
import com.voximplant.sdk.call.CallSettings
import com.voximplant.sdk.call.ICall
import com.voximplant.sdk.call.VideoFlags

// 1. Prepare callSettings
val callSettings = CallSettings()
callSettings.videoFlags = VideoFlags(true, true)

// 2. Get an ICall instance
val call: ICall? = client.call(user, callSettings)

// 3. Start the call
try {
    call!!.start()
} catch (callException: CallException) {
    // handle error
}

To v3:

import com.voximplant.android.sdk.calls.Call
import com.voximplant.android.sdk.calls.CallException
import com.voximplant.android.sdk.calls.CallSettings
import com.voximplant.android.sdk.calls.LocalVideoStream
import com.voximplant.android.sdk.calls.VICalls
import com.voximplant.android.sdk.calls.video.CameraVideoSource

// 1. Create a local video stream
val cameraVideoSource = CameraVideoSource
val localVideoStream = LocalVideoStream(cameraVideoSource)

// 2. Prepare the call settings
val callSettings = CallSettings()
callSettings.localVideoStream = localVideoStream
callSettings.receiveVideo = true

// 3. Create a call
val call: Call? = VICalls.createCall(
    number = "number_to_call",
    callSettings = callSettings,
)

// 4. Start the call 
try {
    call!!.start()
} catch (callException: CallException) {
    // handle error
}

Handle incoming calls

To receive the incoming calls it is required to subscribe to IncomingCallListener via the VICalls.setIncomingCallListener API.

From v2:

import com.voximplant.android.sdk.calls.CallException
import com.voximplant.android.sdk.calls.CallSettings
import com.voximplant.sdk.client.IClient
import com.voximplant.sdk.client.IClientIncomingCallListener

class SomeClass : IClientIncomingCallListener {
    private lateinit var client: IClient

    fun subscribeForIncomingCalls() {
        client.setClientLoginListener(this)
    }

    override fun onIncomingCall(
        call: ICall,
        video: Boolean,
        headers: Map<String?, String?>?
    ) {
        try {
            call.answer(CallSettings())
        } catch (callException: CallException) {
            // handle error
        }
    }
}

To v3:

import com.voximplant.android.sdk.calls.Call
import com.voximplant.android.sdk.calls.CallException
import com.voximplant.android.sdk.calls.CallSettings
import com.voximplant.android.sdk.calls.IncomingCallListener

class SomeClass {
    val incomingCallListener = object : IncomingCallListener {
        override fun onIncomingCall(
            call: Call, 
            hasIncomingVideo: Boolean,
            headers: Map<String, String>?,
        ) {
            try {
                call.answer(CallSettings())
            } catch (callException: CallException) {
                // handle error
            }
        }
    }

    init {
        VICalls.setIncomingCallListener(incomingCallListener)
    }
}

Handle call events changes

Call’s and conference’s events are separated into different interface listeners: CallListener and ConferenceListener.

The following call events are renamed:

Remote participant in a call is no more represented via the Endpoint interface. To handle the events related to a remote video stream in a call, it is required to subscribe to the following events:

CallListener.onCallDisconnected now has the disconnectReason parameter that specifies the reason the call has ended.

Conferences

Copy URL

Join a conference with video

From v2:

import com.voximplant.sdk.call.CallException
import com.voximplant.sdk.call.CallSettings
import com.voximplant.sdk.call.ICall
import com.voximplant.sdk.call.VideoFlags

// 1. Prepare callSettings
val callSettings = CallSettings()
callSettings.videoFlags = VideoFlags(true, true)

// 2. Get a ICall instance
val call: ICall? = call.callConference(conferenceName, callSettings)

// 3. Start the call 
try {
    call!!.start()
} catch (callException: CallException) {
    // handle error
}

To v3:

import com.voximplant.android.sdk.calls.CallException
import com.voximplant.android.sdk.calls.Conference
import com.voximplant.android.sdk.calls.ConferenceSettings
import com.voximplant.android.sdk.calls.LocalVideoStream
import com.voximplant.android.sdk.calls.VICalls
import com.voximplant.android.sdk.calls.video.CameraVideoSource

// 1. Create a local video stream
val cameraVideoSource = CameraVideoSource
val localVideoStream = LocalVideoStream(cameraVideoSource)
conferenceSettings.receiveVideo = true

// 2. Prepare the conference settings
val conferenceSettings = ConferenceSettings()
conferenceSettings.localVideoStream = localVideoStream
conferenceSettings.receiveVideo = true

// 3. Create a conference
val conference: Conference? = VICalls.createConference(
    number = "destination",
    conferenceSettings = conferenceSettings,
)

// 4. Join the conference 
try {
    conference!!.join()
} catch (callException: CallException) {
    // handle error
}

Handle conference events changes

Call’s and conference’s events are separated into different interface listeners: CallListener and ConferenceListener.

New conference events:

Other changes:

Composable function to render a video stream

Copy URL

Voximplant Android SDK v3 has a new com.voximplant:android-sdk-renderer-compose module that provides a composable function VideoRenderer to render a local or remote video stream in the application built with Jetpack Compose.

import com.voximplant.android.sdk.calls.RenderScaleType
import com.voximplant.android.sdk.renderer.compose.VideoRenderer

@Composable
fun VideoRendererExample() {
    VideoRenderer(
        modifier = Modifier.wrapContentSize(),
        videoStream = videoStream,
        renderScaleType = RenderScaleType.Balanced,
    )
}

Capture SDK logs

Copy URL

Voximplant Android SDK v3 provides a more flexible interface to capture SDK logs with extended information such as a log timestamp, a thread id, and a throwable for exceptions.

Log collection configuration is done for all modules at once and is recommended on the SDK initialization.

From v2:

import com.voximplant.sdk.Voximplant
import com.voximplant.sdk.client.ILogListener
import com.voximplant.sdk.client.LogLevel

class SDKLogger() : ILogListener {
    init {           
        Voximplant.setLogListener(this)
    }

    override fun onLogMessage(level: LogLevel, log: String) {
        val message = "$level $message"
        // save the log message to a file or send it to a remote service
    }
}

To v3:

import com.voximplant.android.sdk.core.VICore
import com.voximplant.android.sdk.core.logging.LogLevel
import com.voximplant.android.sdk.core.logging.Logger

VICore.logging.logger = object : Logger {
    override fun log(
        level: LogLevel,
        threadId: Int,
        time: Date,
        message: String,
        throwable: Throwable?,
    ) {
        val message = "$time $threadId $message $throwable"
        // save the log message to a file or send it to a remote service
    }
}
VICore.logging.level = LogLevel.Info
VICore.logging.enableLogcat = false