nimeet Docs
中文

Android SDK Guide

Install, join a channel, publish and subscribe, events and platform-specific notes.

Interface sections generated from the public SDK definitions

Version v1.1.0 · Updated 2026-10-26 · revision 1

The Android surface has the native engine shape: an RtcEngine singleton plus IRtcEngineEventHandler callbacks, rather than the Web track object model. Publishing and subscribing are controlled by ChannelMediaOptions on joinChannel and by the muteLocal* family of methods.

Prerequisites

  • JDK 17, Android SDK 35, Gradle 8.x.
  • Min SDK: see the library manifest (capture and screen sharing use MediaProjection, which needs API 21+).
  • The host app must request CAMERA and RECORD_AUDIO at runtime (the library only declares them; it does not request them for you).
  • You already have an appId and a token service (see Enable services and get credentials).

Install

kotlin
dependencies {
    implementation(project(":sdk:android")) // in this codebase
    // planned Maven coordinate: implementation("com.nimeet.rtc:nimeet-rtc:0.1.0")
}

Get a token

An Android client must not hold customerSecret. The recommended setup has the host app's backend issue tokens, and the client obtains them through CallbackTokenProvider (which delegates to your session endpoint) or EndpointTokenProvider (a direct connection during development; never put the secret in the APK):

kotlin
val tokenProvider = FallbackTokenProvider(listOf(
    CallbackTokenProvider { channel, uid, role -> yourBackend.getRtcToken(channel, uid, role) },
    StaticTokenProvider(BuildConfig.NIMEET_TEST_TOKEN), // tests only
))

Join a channel

kotlin
class MeetingActivity : AppCompatActivity() {
    private var rtc: RtcEngine? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        rtc = RtcEngine.create(this, BuildConfig.NIMEET_APP_ID, object : IRtcEngineEventHandler() {
            override fun onJoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {
                runOnUiThread { statusText.text = "Joined the channel" }
            }
            override fun onUserJoined(uid: Int, elapsed: Int) {
                runOnUiThread { addTile(uid) }
            }
            override fun onUserOffline(uid: Int, reason: Int) {
                runOnUiThread { removeTile(uid) }
            }
            override fun onTokenPrivilegeWillExpire(token: String?) {
                rtc?.renewToken(fetchFreshToken())
            }
        })

        rtc?.apply {
            setChannelProfile(Constants.CHANNEL_PROFILE_LIVE_BROADCASTING)
            enableVideo()
            setupLocalVideo(VideoCanvas(localView))
            startPreview()
            joinChannel(BuildConfig.RTC_TOKEN, "weekly-sync", "", 10001)
        }
    }
}

joinChannel has four overloads: (token, channelId, optionalInfo, uid), (token, channelId, uid, options), (token, channelId, userAccount, options) and so on; for the complete list and the parameter types see the API reference for this platform (generated at build time from the SDK interface definition).

Publish and subscribe

The native surface has no publish(track): after joining, the camera and microphone are published according to ChannelMediaOptions by default, and you switch them with methods.

kotlin
// Mute / turn off the camera (keeps the ability to publish)
rtc?.muteLocalAudioStream(true)
rtc?.muteLocalVideoStream(true)

// Stop/resume local video capture
rtc?.enableLocalVideo(false)

// Subscribe to audio only (saves bandwidth on an audience client)
val options = ChannelMediaOptions().apply {
    autoSubscribeAudio = true
    autoSubscribeVideo = false
    clientRoleType = Constants.CLIENT_ROLE_AUDIENCE
}
rtc?.updateChannelMediaOptions(options)

Events

The callback interface is IRtcEngineEventHandler (84 on* methods). The most commonly used ones:

CallbackWhen it firesTypical handling
onJoinChannelSuccess(channel, uid, elapsed)Join succeededSwitch the UI, start the timer
onUserJoined(uid, elapsed)A remote user joinedAllocate a video container
onFirstRemoteVideoDecoded(uid, width, height, elapsed)The first remote frame was decodedRender the remote video
onUserOffline(uid, reason)A remote user leftRelease the container
onTokenPrivilegeWillExpire(token)The privilege is about to expireRenew, then renewToken
onError(err)A runtime errorRoute by error number
onConnectionStateChanged(state, reason)The connection state changedDo not release resources while RECONNECTING

Error handling

  • Synchronous methods return int: 0 means success, and a negative value is an Agora error number (for example -2 for an invalid parameter, -110 for an invalid token). You must check the return value.
  • Asynchronous errors arrive through the onError callback.
  • Unimplemented capabilities return -4 (ERR_NOT_SUPPORTED) and never succeed silently.
kotlin
val code = rtc?.joinChannel(token, channel, "", uid) ?: -3
if (code < 0) {
    showError(RtcError.fromCode(code))   // RtcError in sdk/ exposes code/sdkCode/message/retryable
}

Troubleshooting

SymptomCauseHandling
joinChannel returns -2Invalid channel name or out-of-range uidChannel name [A-Za-z0-9_-], uid 1..2147483647
Returns -110Invalid token or channel mismatchSelf-check with GET /v1/tokens/verify
Audio works but there is no videoenableVideo() was not called, or setupLocalVideo was not setCall them in the order above and make sure startPreview() runs
Screen sharing shows a black screenThe MediaProjection foreground service was not startedUse the host app's MediaProjection consent flow
Media stops after moving to the backgroundThe app was frozen by the systemUse a foreground service; do not rely on background keep-alive
UnsatisfiedLinkErrorABI mismatchCheck abiFilters and the packaged .so files

Next steps

Platform information

Itemvalue
PlatformAndroid
LanguageKotlin
SDK packagecom.nimeet.rtc
Interface version4.7.0
Compatible Agora APIAgora android API

The public interfaces are aligned with the Agora android API; installation and runtime requirements are listed under Prerequisites above.

Availability

This platform's SDK: Generally available. The examples use the public API; runtime capability follows the published SDK package.

join-channel flow

The method names, parameter types and return values match the API reference for the same platform. Where a method has several overloads, the most common one is shown here; see the API reference for all overloads.

StepInterfaceMethodOverload count
Create instance / initializeIAgoraMusicContentCenterinitialize1
Renew the TokenIAgoraMusicContentCenterrenewToken1
subscribe to remote mediaIBaseSpatialAudioEnginemuteRemoteAudioStream1
enable video and local previewRtcEngineenableVideo1
Join a channelRtcEnginejoinChannel2
Leave a channelRtcEngineleaveChannel2
Channel scenariosRtcEnginesetChannelProfile1
switch rolesRtcEnginesetClientRole2
bind the local videoRtcEnginesetupLocalVideo1
typescript
initialize(configuration: MusicContentCenterConfiguration): int
renewToken(token: String): int
muteRemoteAudioStream(uid: int, mute: boolean): int
enableVideo(): int
joinChannel(token: String, channelId: String, optionalInfo: String, uid: int): int
leaveChannel(): int
setChannelProfile(profile: int): int
setClientRole(role: int): int
setupLocalVideo(local: VideoCanvas): int

Events and callbacks

Callbacks are registered on IRtcEngineEventHandler; naming differs by platform, and the full list is in the API reference for the same platform.

CallbacksSignaturePurpose
onConnectionStateChangedonConnectionStateChanged(state: int, reason: int): voidjoin result / connection-state changes:update the UI accordingly and decide whether to reconnect.
onUserJoinedonUserJoined(uid: int, elapsed: int): voidRemote user joined:allocate the frame container.
onFirstRemoteVideoDecodedonFirstRemoteVideoDecoded(uid: int, width: int, height: int, elapsed: int): voidRemote video status:it can render once the first frame is decoded.
onUserOfflineonUserOffline(uid: int, reason: int): voidRemote user left:release the container and subscription.
onRequestTokenonRequestToken(): voidToken expiring soon:call the server to renew, then `renewToken`.
onErroronError(err: int): voidRuntime errors:`err` is an Agora error number, route by the error-code table.
onNetworkQualityonNetworkQuality(uid: int, txQuality: int, rxQuality: int): voidNetwork quality:report to Analytics or prompt the user.

Error codes

Constantvalue
AUTHENTICATION_FAILED5
INVALID_ARGUMENT2
INVALID_OPERATION3
NETWORK_ERROR4
OK0
STREAM_NOT_FOUND6

the platform REST layer uses REST error codes;the SDK layer maps connection/authentication failures to Agora error numbers, for the mapping table see SDK error identifiers per platform。

Generated by the documentation build pipeline · 2026-10-31 01:24:02 UTC · Documentation center v1.1.0.

Content follows the public API definitions.

ni-meet is a self-hosted RTC PaaS with a LiveKit-based media plane (Apache-2.0) and an Agora-compatible API.