Kotlin SDK

Build native Android video applications with Kotlin

Installation

Add BaxCloud SDK to your Android project

Add to build.gradle.kts (module level)

app/build.gradle.kts
1dependencies {
2    implementation("com.baxcloud:client:1.0.0")
3}
All required dependencies are bundled with the SDK

Android Configuration

Required permissions and runtime requests

Add to AndroidManifest.xml

app/src/main/AndroidManifest.xml
1<uses-permission android:name="android.permission.CAMERA" />
2<uses-permission android:name="android.permission.RECORD_AUDIO" />
3<uses-permission android:name="android.permission.INTERNET" />

Request Runtime Permissions

1import android.Manifest
2import android.content.pm.PackageManager
3import androidx.core.app.ActivityCompat
4import androidx.core.content.ContextCompat
5
6fun requestPermissions(activity: Activity) {
7    val permissions = arrayOf(
8        Manifest.permission.CAMERA,
9        Manifest.permission.RECORD_AUDIO
10    )
11    
12    if (permissions.any { 
13        ContextCompat.checkSelfPermission(activity, it) 
14            != PackageManager.PERMISSION_GRANTED 
15    }) {
16        ActivityCompat.requestPermissions(
17            activity, 
18            permissions, 
19            REQUEST_CODE
20        )
21    }
22}

Quick Start

Get started with Kotlin SDK

1. Initialize Client

MainActivity.kt
1import com.baxcloud.client.BaxCloudClient
2import com.baxcloud.client.BaxCloudConfig
3
4val client = BaxCloudClient(
5    context = applicationContext,
6    config = BaxCloudConfig(
7        projectId = "your-project-id",
8        apiKey = "your-api-key"
9    )
10)

2. Connect to a Room

1import kotlinx.coroutines.launch
2import com.baxcloud.client.*
3
4lifecycleScope.launch {
5    try {
6        val room = client.connect(
7            BaxcloudRoomOptions(
8                roomName = "my-room",
9                participant = BaxcloudUser(
10                    userId = "user-123",
11                    name = "John Doe",
12                    isHost = true
13                ),
14                liveType = BaxcloudLiveType.VIDEO_CALL
15            )
16        )
17        
18        println("Connected to room: ${room.name}")
19    } catch (e: Exception) {
20        println("Connection failed: ${e.message}")
21    }
22}

3. Render Video

1import androidx.compose.foundation.background
2import androidx.compose.foundation.layout.*
3import androidx.compose.foundation.lazy.grid.*
4import androidx.compose.material.icons.Icons
5import androidx.compose.material.icons.filled.MicOff
6import androidx.compose.material.icons.filled.Person
7import androidx.compose.material3.*
8import androidx.compose.runtime.Composable
9import androidx.compose.ui.Alignment
10import androidx.compose.ui.Modifier
11import androidx.compose.ui.graphics.Color
12import androidx.compose.ui.unit.dp
13import androidx.compose.ui.viewinterop.AndroidView
14import com.baxcloud.client.Room
15import org.webrtc.SurfaceViewRenderer
16
17@Composable
18fun VideoGrid(room: Room) {
19    val participants = room.participants.values.toList()
20    
21    LazyVerticalGrid(
22        columns = GridCells.Fixed(2),
23        contentPadding = PaddingValues(8.dp),
24        horizontalArrangement = Arrangement.spacedBy(8.dp),
25        verticalArrangement = Arrangement.spacedBy(8.dp)
26    ) {
27        items(participants.size) { index ->
28            val participant = participants[index]
29            val isLocal = participant.identity == room.localParticipant?.identity
30            
31            VideoParticipantItem(
32                participant = participant,
33                isLocal = isLocal
34            )
35        }
36    }
37}
38
39@Composable
40fun VideoParticipantItem(
41    participant: Participant,
42    isLocal: Boolean
43) {
44    Box(
45        modifier = Modifier
46            .aspectRatio(3f / 4f)
47            .background(Color.DarkGray)
48    ) {
49        // Video renderer
50        if (participant.videoTrack != null) {
51            AndroidView(
52                factory = { context ->
53                    SurfaceViewRenderer(context).apply {
54                        participant.videoTrack?.addSink(this)
55                    }
56                },
57                modifier = Modifier.fillMaxSize()
58            )
59        } else {
60            // Placeholder when video is off
61            Icon(
62                imageVector = Icons.Default.Person,
63                contentDescription = "No video",
64                modifier = Modifier
65                    .size(48.dp)
66                    .align(Alignment.Center),
67                tint = Color.White.copy(alpha = 0.5f)
68            )
69        }
70        
71        // Participant name overlay
72        Box(
73            modifier = Modifier
74                .align(Alignment.BottomStart)
75                .padding(8.dp)
76                .background(
77                    Color.Black.copy(alpha = 0.5f),
78                    shape = MaterialTheme.shapes.small
79                )
80                .padding(horizontal = 8.dp, vertical = 4.dp)
81        ) {
82            Row(
83                verticalAlignment = Alignment.CenterVertically,
84                horizontalArrangement = Arrangement.spacedBy(4.dp)
85            ) {
86                if (participant.isMuted) {
87                    Icon(
88                        imageVector = Icons.Default.MicOff,
89                        contentDescription = "Muted",
90                        modifier = Modifier.size(14.dp),
91                        tint = Color.Red
92                    )
93                }
94                
95                Text(
96                    text = "${participant.name}${if (isLocal) " (You)" else ""}",
97                    style = MaterialTheme.typography.labelSmall,
98                    color = Color.White
99                )
100            }
101        }
102    }
103}

4. Disconnect

1client.disconnect()

Usage Examples

Common implementation patterns

VideoCallActivity.kt
1class VideoCallActivity : AppCompatActivity() {
2    private lateinit var client: BaxCloudClient
3    private var room: Room? = null
4
5    override fun onCreate(savedInstanceState: Bundle?) {
6        super.onCreate(savedInstanceState)
7        
8        // Request permissions first
9        requestPermissions()
10        
11        client = BaxCloudClient(
12            context = this,
13            config = BaxCloudConfig(
14                projectId = "your-project-id",
15                apiKey = "your-api-key"
16            )
17        )
18        
19        lifecycleScope.launch {
20            try {
21                room = client.connect(
22                    BaxcloudRoomOptions(
23                        roomName = "video-call-123",
24                        participant = BaxcloudUser(
25                            userId = "user-1",
26                            name = "Alice",
27                            isHost = true
28                        ),
29                        liveType = BaxcloudLiveType.VIDEO_CALL
30                    )
31                )
32                
33                println("Connected to room: ${room?.name}")
34            } catch (e: Exception) {
35                println("Connection failed: ${e.message}")
36            }
37        }
38    }
39    
40    override fun onDestroy() {
41        super.onDestroy()
42        lifecycleScope.launch {
43            client.disconnect()
44        }
45    }
46}

API Reference

Core classes and methods

BaxCloudClient

The main client class with coroutine support.

1// Connect
2val room = client.connect(options)
3
4// Enable camera/microphone
5client.enableCamera()
6client.enableMicrophone()
7
8// Disconnect
9client.disconnect()
10
11// Observe connection state (StateFlow)
12lifecycleScope.launch {
13    client.connectionState.collect { state ->
14        println("State: $state")
15    }
16}

BaxCloudRoomController

Singleton controller for advanced room features.

1val controller = BaxCloudRoomController.instance
2controller.initialize(client, context)
3
4// Host controls
5controller.muteAll()
6controller.kickParticipant("user-2")
7
8// Chat
9controller.sendChatMessage("Hello!")
10
11// Event handlers
12controller.onChatMessage { message ->
13    println("${message.userName}: ${message.message}")
14}

Recording

1// Start recording
2val recording = client.startRecording(
3    BaxcloudStartRecordingOptions(
4        roomName = "my-room",
5        fileType = "MP4"
6    )
7)
8
9// Stop recording
10client.stopRecording(recording.egressId)
11
12// List recordings
13val recordings = client.listRecordings(
14    BaxcloudListRecordingsOptions(
15        status = "COMPLETED",
16        page = 1,
17        limit = 10
18    )
19)

Best Practices

Recommendations for Kotlin/Android development

Use Coroutines

All SDK methods are suspend functions. Use lifecycleScope or viewModelScope

Request Permissions

Always request permissions before connecting (Android 6.0+)

Handle Lifecycle

Disconnect in onDestroy() to clean up resources

Use StateFlow

Observe connectionState using StateFlow for reactive UI updates

Android-Specific Notes

Important considerations for Android development

ProGuard Rules

ProGuard rules are handled internally by the SDK. If using custom ProGuard configuration:

proguard-rules.pro
1-keep class com.baxcloud.client.** { *; }

Picture-in-Picture

Available on Android 8.0+ (API 26+). Requires android:supportsPictureInPicture="true" in manifest

Background Handling

Handle app lifecycle changes. Consider disabling camera/mic when app goes to background