Skip to content

Upgrade to Kaleyra Video SDK v4.x

Federico Marin edited this page Dec 6, 2024 · 14 revisions

Upgrade to v4.+

This new version comes with general improvements, comes with APIs that have been simplified to let the SDK integration be easier for third part apps.

The new version of the SDK brings a lot of new features and simplifies the integration flow by a huge margin.


Updated Requirements

UI fully re-written in compose

  • For more details you can view the open-sourced code of this repo

APIs changes

The APIs will no longer be made with Java-flavored. They will be fully developed in Kotlin and for it only.

| N.B. The SDK will continue to work with Java projects, it just will not be beautiful when used in java.

Configure the KaleyraVideo (previously BandyerSDK)

  • The SDK configuration has been changed and must be now implemented using the new API on the BandyerSDK singleton that follows:
v4 v3
val configuration = Configuration(
	"mAppId_xxx",  
	Environment.Sandbox,
	Region.Europe, // or Region.India or Region.US
        // httpStack,  
        // logger
)
KaleyraVideo.configure(configuration)
val configuration = BandyerSDKConfiguration.Builder(
	"mAppId",
	Environment.Sandbox,
	Region.Eu) 
// .httpStack(okHttpClient)
// .logger(logger)
  .build()
BandyerSDK.getInstance().configure(configuration)

Connect

v4 v3
KaleyraVideo.connect("userA",  { expiresAt ->
    Result.success("fetchedTokenFromYourServer") // or Result.fail()
}) // returns a Deferred<User>
val session = Session("userA",object :AccessTokenProvider{
   override fun provideAccessToken(userId: String, completion: Completion<String>) {
   	completion.success("fetchedTokenFromYourServer") // completion.fail()
   }
})
BandyerSDK.getInstance().connect(session)

Connect Access Link

v4 v3
KaleyraVideo.connect("https://") // returns a Deferred<User>
var callIntent = BandyerIntent.Builder().startFromJoinCallUrl(currentActivity,"https://....").build()
startActivity(callIntent)

Disconnect

v4 v3
KaleyraVideo.disconnect(clearSavedData = false)
BandyerSDK.getInstance().disconnect(clearSavedData = true) // or BandyerSDK.getInstance().disconnect()

Reset

v4 v3
KaleyraVideo.reset()
BandyerSDK.getInstance().reset()

Handle push notifications

You no longer need to give any payload to the KaleyraVideo. You are only required to configure & connect the KaleyraVideo.

Please follow the client side requirements as specified here.

N.B. After the connect the KaleyraVideo will auto sync with the incoming calls and chat messages

Start a call

v4 v3
KaleyraVideo.conference.call(listOf("userB")) { // vararg
  preferredType = Call.PreferredType.audioOnly() // audioUpgradable(), audioVideo()
    // recordingType = Call.Recording.Type.manual() // Call.Recording.Type.automatic()
    // maxDuration = 60L // in seconds >= 60
}: Result<Call>
var callIntent = BandyerIntent.Builder().startWithAudioCall(activity) //  startWithAudioUpgradableCall, startWithAudioVideoCall
     .with(arrayListOf("userB"))
     .build()

startActivity(callIntent)

Call properties

// call.id
// call.creationDate
// call.state
// call.preferredType
// call.participants
// call.time.maxDuration, call.time.elapsed, call.time.remaining
// call.inputs
// call.effects
// call.recording.state, call.recording.type
// call.whiteboard
// call.sharedFolder

Join a call

v4 v3
KaleyraVideo.conference.joinUrl("https://....") : Result<Call>
var callIntent = BandyerIntent.Builder().startFromJoinCallUrl(currentActivity,"https://....").build()
startActivity(callIntent)

Start a chat

v4 v3
// this will create the unique chat between logged user and "userB"
KaleyraVideo.conversation.chat(currentActivity, userId = "userB") : Result<Chat>

// this will create the unique chat between logged user, "userB" and "userC"
KaleyraVideo.conversation.chat(currentActivity, userIds = listOf("userB", "userC")): Result<ChatUI> 

// this will always create a new group chat between logged user, "userB" and "userC" with the 
// group chat friendly name set as "soccer team!"
KaleyraVideo.conversation.chat(currentActivity, userIds = listOf("userB", "userC"), friendlyName = "soccer team!"): Result<ChatUI> 
var chatIntent =  BandyerIntent.Builder().startWithChat(currentActivity).with("userB").build()
startActivity(chatIntent)

Advanced

Call UI tools/actions

SDK actions definition has been strongly simplified

v4 v3
KaleyraVideo.conference.callActions 
    = CallUI.Action.default + FileShare
val callOptions: CallOptions = CallOptions()
           .withRecordingEnabled(AUTOMATIC)
           .withBackCameraAsDefault()
           .withProximitySensorDisabled()
           .withFeedbackEnabled()

val callCapabilitySet = CustomCapabilitySet(
   CustomChatConfiguration(),
   CustomFileShareConfiguration(),
   CustomScreenShareConfiguration(),
   CustomWhiteboardConfiguration()
)

val customCallConfiguration = CustomCallConfiguration(callCapabilitySet, callOptions)

BandyerSDK.getInstance().configure(
   BandyerSDKConfiguration.Builder("mAppId", Environment.Sandbox, Region.Eu).tools {
       withCall {
           callConfiguration = customCallConfiguration
       }
   }.build()
)

Chat UI tools/actions

v4 v3
KaleyraVideo.conversation.chatActions 
    = ChatUI.Action.default
val callOptions = CallOptions()
   .withRecordingEnabled(CallRecordingType.AUTOMATIC) 
   .withBackCameraAsDefault()
   .withProximitySensorDisabled()
   .withFeedbackEnabled();

val callConfiguration = CustomChatConfiguration.CustomCapabilitySet.CustomCallConfiguration(
   CustomChatConfiguration.CustomCapabilitySet.CustomCallConfiguration.CustomCapabilitySet(
       CustomFileShareConfiguration(),
       CustomScreenShareConfiguration(),
       CustomWhiteboardConfiguration()
   ),
   callOptions
);

val customChatConfiguration = CustomChatConfiguration(
   CustomChatConfiguration.CustomCapabilitySet(
       audioUpgradableCallConfiguration =   callConfiguration, 
       audioVideoCallConfiguration  = callConfiguration
   )
)


BandyerSDK.getInstance().configure(
   BandyerSDKConfiguration.Builder("mAppId", Environment.Sandbox, Region.Eu).tools {
       withChat {
           chatConfiguration = customChatConfiguration
       }
   }.build()
)

Call events

  • CallObserver, CallUIObserver & CallEventBroadcastReceiver have been removed and replaced by state flow property
v4 v3
call.state.onEach { println("callState=$it") }.launchIn(MainScope())
val callObserver = object : CallObserver {
   override fun onCallCreated(call: Call) = println("onCallCreated")
   override fun onCallStarted(call: Call) = println("onCallStarted")
   override fun onCallEnded(call: Call) = println("onCallEnded")
   override fun onCallEndedWithError(call: Call, exception: CallException) = println("onCallEndedWithError")
}
BandyerSDK.getInstance().callModule?.addCallObserver(callObserver)
  • CallRecordingObserver has been removed and replaced by extras.recording.state flow property
v4 v3
call.recording
    .flatMapLatest { it.state }
    .onEach {  println("recordingState=$it") }
    .launchIn(MainScope())
val callRecordingObserver = object : CallRecordingObserver {
   override fun onCallRecordingStateChanged(call: Call, callRecordingState: CallRecordingState) = println("onCallRecordingStateChanged")
   override fun onCallRecordingFailed(call: Call, reason: String) = println("onCallRecordingFailed")
}
call.addCallRecordingObserver(callRecordingObserver)

Chat events

  • ChatObserver & ChatEventBroadcastReceiver have been removed. You can now know the state of the chat by using the state flow property
v4 v3
chat.state.onEach { println("chatState=$it") }.launchIn(MainScope())
val chatObserver = object : ChatObserver {}
BandyerSDK.getInstance().chatModule?.addChatObserver(chatObserver)

Module Observer

v4 v3
// for the call
BandyerSDK.conference.state.onEach { println("conferenceState=$it") }.launchIn(MainScope())
// for the chat
BandyerSDK.conversation.state.onEach { println("conversationState=$it") }.launchIn(MainScope())
val moduleObserver = object : BandyerModuleObserver {
   override fun onModuleReady(module: BandyerModule) = println("onModuleReady")
   override fun onModulePaused(module: BandyerModule)  = println("onModulePaused")
   override fun onModuleFailed(module: BandyerModule, throwable: Throwable) = println("onModuleFailed")
   override fun onModuleStatusChanged(module: BandyerModule, moduleStatus: BandyerModuleStatus) = println("onModuleStatusChanged")
}
BandyerSDK.getInstance().addModuleObserver(moduleObserver)

NotificationListeners

Have been removed as they are not needed.

Extras

FeedbackUI

call.withFeedback = true // or false

DisableProximity

call.disableProximity = true // or false

BackCamera/RearCamera as Default

KaleyraVideo.conference.call.onEach {
  it.inputs.useBackCamera()
}.launchIn(MainScope())

User Identity Verification Has been removed

KaleyraVideoInitializer

Please add and implement abstract class KaleyraVideoInitializer in order to handle edge cases when the connection token expires and the application has been killed from the user or from the system. Add the following metadata to the AndroidManifest.xml inside the application tag. The metadata is needed in order to instantiate your KaleyraVideoInitializer class from within the SDK.

<!-- app manifest -->

<application>

	[...]

	<meta-data
		android:name="kaleyra_video_initializer"
		android:value="com.example.app.AppKaleyraVideoInitializer" /> <!-- path to your KaleyraVideInitializer implementation -->

</application>

Implement the App Initializer as follows:

package com.example.app

// KaleyraVideoInitializer implementation

class AppAppKaleyraVideoInitializer : KaleyraVideoInitializer() {
    
    override fun onRequestKaleyraVideoConfigure() {
        if (KaleyraVideo.isConfigured) return
        val configuration = Configuration(
            "appId",
            Environment.Production,
            Region.Europe
        )
        KaleyraVideo.configure(configuration)
    }
    
    override fun onRequestKaleyraVideoConnect() {
        KaleyraVideo.connect("userId") { requestToken("userId") }
    }
    
}

Client UserDetailsProvider

KaleyraVideo.userDetailsProvider = { userIds: List<String> ->
    Result.success(userIds.map { UserDetails(it,"Alice", Uri.EMPTY) })
}

Theme customization

Server Theme customization

Since every client had to provide a Theme implementation in order to customize the client call and chat UIs, has now been integrated a new convenient and centralized way to achieve the same result.

Client Theme customization

val brandColorSeed = ColorResource(Color(0xFF2A638A).toArgb())
val brandLogoUri = getYourBrandLogoUri()
KaleyraVideo.theme = Theme(
  logo = Theme.Logo(URIResource(brandLogoUri, brandLogoUri)),
  palette = Theme.Palette(seed = brandColorSeed),
  typography = Theme.Typography(fontFamily = KaleyraFontFamily.default),
  config = Theme.Config(style = Theme.Config.Style.System) // or force light mode with Theme.Config.Style.Light and dark with Theme.Config.Style.Dark
)
Clone this wiki locally