Background Handling - Android
When your app goes to the background, Android limits what it can do. The VideoSDK Android SDK does not run a foreground service of its own, so keeping a call alive in the background is up to your app.
What happens without a foreground service:
- Android 15 and later block a backgrounded app's network. The room starts reconnecting a few seconds after the user switches apps, and ends with
onRoomLeft(WEBSOCKET_CONNECTION_ATTEMPTS_EXHAUSTED)if the app stays in the background. A short trip to another app is enough. How fast this happens varies by device. - Android blocks the camera and microphone for a backgrounded app unless a foreground service of the matching type runs.
- Anything that opens another app backgrounds yours. For example, opening the whiteboard URL from
onWhiteboardStartedin a browser has the same effect as switching apps. Load it in aWebViewinside your app instead.
By default, the SDK also turns your camera off about half a second after the call screen goes to the background, and turns it back on with the same settings when it returns. A camera you turned off yourself stays off. Other participants get onStreamDisabled and then onStreamEnabled for your video. The microphone is left on.
To keep the call running in the background, run a foreground service of type camera|microphone while the user is in the room, as shown below. If you'd rather not, Picture-in-Picture (PiP) keeps the app visible in a small window.
Run a Foreground Service
Add these to AndroidManifest.xml. POST_NOTIFICATIONS is a runtime permission on Android 13 and later: request it before the call, or the notification is hidden (the service still runs).
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application>
<service
android:name=".CallService"
android:exported="false"
android:foregroundServiceType="camera|microphone"
android:stopWithTask="true" />
</application>
</manifest>
The service only has to show an ongoing notification while the user is in the room. Start it while your call screen is in the foreground: Android doesn't let a backgrounded app start a camera or microphone foreground service.
package com.example.example
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.content.pm.ServiceInfo
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.app.ServiceCompat
class CallService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val types = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA or ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
} else {
0
}
ServiceCompat.startForeground(this, NOTIFICATION_ID, notification(), types)
return START_NOT_STICKY
}
override fun onBind(intent: Intent?): IBinder? = null
private fun notification(): Notification {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
getSystemService(NotificationManager::class.java).createNotificationChannel(
NotificationChannel(CHANNEL_ID, "Calls", NotificationManager.IMPORTANCE_LOW)
)
}
return NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Call in progress")
.setSmallIcon(android.R.drawable.ic_menu_call)
.setOngoing(true)
.build()
}
companion object {
private const val NOTIFICATION_ID = 1001
private const val CHANNEL_ID = "calls"
}
}
The service keeps the call connected, but the SDK still turns the camera off while the call screen is in the background. To keep sending video, call VideoSDK.setEnableActivityLifecycle(false), for example in Application.onCreate() next to VideoSDK.initialize().
package com.example.example
import android.app.Application
import live.videosdk.rtc.android.VideoSDK
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
VideoSDK.setEnableActivityLifecycle(false)
VideoSDK.initialize(applicationContext)
}
}
Start the service once join() has returned, while the call screen is still in front, and stop it when the participant leaves the room. Android throws a SecurityException if CAMERA and RECORD_AUDIO aren't granted yet. If your app never uses the camera, drop camera from the service types in the manifest and the service.
class RoomActivity : AppCompatActivity() {
private lateinit var room: Room
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_room)
val token = intent.getStringExtra("token") ?: return
val roomId = intent.getStringExtra("roomId") ?: return
lifecycleScope.launch {
try {
room = VideoSDK.createRoom(
roomId = roomId,
token = token,
participantName = "John Doe",
micEnabled = true,
camEnabled = true,
)
room.addEventListener(roomEventListener)
room.join()
ContextCompat.startForegroundService(this@RoomActivity, Intent(this@RoomActivity, CallService::class.java))
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Join failed: ${e.code} ${e.name}")
}
}
}
private val roomEventListener = object : RoomEventListener() {
override fun onRoomLeft(reason: LeaveReason) {
stopService(Intent(this@RoomActivity, CallService::class.java))
}
}
}
Replace the package name com.example.example with yours.
Got a Question? Ask us on discord

