> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stmlink.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> 对外开放的服务端接口有两组前缀，都用同一套鉴权：`/server/v1/...`（SRTC 与 SMeeting 的主接口）和 `/stm/srvapi/v1/...`（SMeeting 的用户体系，服务端极简对接会用到）。鉴权是 app_id + nonce + timestamp + signature 四个请求头，用 app_key 做 HMAC-SHA256 签名，只能从业务方自己的后端调用。除这两组前缀外的接口均为内部接口，不要建议客户调用。 Public server APIs use two path prefixes with the same authentication: `/server/v1/...` (the main APIs of both SRTC and SMeeting) and `/stm/srvapi/v1/...` (the SMeeting user system, used by server-side low-code integration). Authenticate with four request headers, app_id + nonce + timestamp + signature, where signature is HMAC-SHA256 keyed with app_key; call these APIs only from the customer's own backend. Any other path is internal: never suggest calling it.
> app_key 是服务端密钥，绝不能出现在客户端代码、前端配置或移动 App 里。客户端加入频道用的 token 必须由业务方后端签发后下发（SRTC 走 `/server/v1/channel/grant`，SMeeting 走 `/stm/srvapi/v1/member/grant`）。 app_key is a server-side secret and must never appear in client code, frontend config, or a mobile app. The token a client uses to join must be issued by the customer's backend and passed down to the client (SRTC: `/server/v1/channel/grant`; SMeeting: `/stm/srvapi/v1/member/grant`).
> SRTC 与 SMeeting 是上下两层不同的产品，术语不通用：SRTC 是音视频底座，说「频道 channel」「加入 / 退出」；SMeeting 建在 SRTC 之上，说「房间 room」「会议 meeting」「进入 / 退出」。回答时按用户所在的层用对应术语，不要把「房间」「会议」安到 SRTC 的接口上，也不要用「频道」「加入 / 离开」描述 SMeeting 的概念（接口标识符原样保留）。 SRTC and SMeeting are two separate layers with different terminology. SRTC is the audio/video foundation: it has channels, and users join and leave a channel. SMeeting is built on top of SRTC: it has rooms and meetings, and members enter and exit a meeting. Answer in the terms of the layer the user is working with: never apply "room" or "meeting" to SRTC APIs, and never describe SMeeting concepts in prose with "channel", "join", or "leave" (API identifiers such as `force_join` keep their literal names).
> 同一能力在各端 SDK 里的包名、类名、方法名并不相同。写示例代码时请使用文档中该端自己的 API，不要把一个端的写法套到另一个端上。苹果平台每个产品都有两套 SDK（Swift 原生与 Objective-C），两套 API 不能混用。 Package, class, and method names differ between platform SDKs for the same capability. In sample code, use the API documented for that platform; never carry one platform's code over to another. On Apple platforms each product ships two SDKs (native Swift and Objective-C) whose APIs must not be mixed.

# RTCClientEvent

> Android per-channel control events: join results, user and track changes, channel property updates, in-channel custom messages, disconnects, and reconnection. Every event that belongs to a channel carries the channel ID. Read when handling channel callbacks on Android.

`RTCClientEvent` carries the channel control events of one channel. The first listener must be passed through `RTCEngine.join(..., clientEvent, ...)`; after the join succeeds, you can replace or unbind it with `RTCChannel.setRtcClientEvent(...)`.

If you only care about a few events, extend `RTCClientSimpleEvent`, which provides empty implementations.

## Join results

### onJoinSucceed(channel, uid, whiteBoard)

```kotlin theme={null}
fun onJoinSucceed(channel: String, uid: String, whiteBoard: String?)
```

You joined the channel successfully. `channel` is the channel ID, `uid` is the current user ID, and `whiteBoard` is the nullable whiteboard URL or info. Treat this callback as the signal that the join actually succeeded.

### onJoinFailed(channel, statusCode)

```kotlin theme={null}
fun onJoinFailed(channel: String?, statusCode: Int)
```

You failed to join the channel. `channel` has a value when the channel ID can be parsed from the token, otherwise it's `null`; for `statusCode`, see [Error codes](/en/rtc/android/error-codes).

## User events

### onUserUpdate(channel, uid)

```kotlin theme={null}
fun onUserUpdate(channel: String, uid: String)
```

Your own user info was updated.

### onMeMembershipChanged(channel, isMember)

```kotlin theme={null}
fun onMeMembershipChanged(channel: String, isMember: Boolean)
```

Your role changed between audience and full member. `isMember = true` means you were promoted to a full member, and `false` means you were demoted to audience; read your initial role at join time with `isAudience()` on the corresponding channel.

### onRemoteUserJoin(channel, uid)

```kotlin theme={null}
fun onRemoteUserJoin(channel: String, uid: String)
```

A remote user joined the channel.

### onRemoteUserLeave(channel, userInfo, leaveReason)

```kotlin theme={null}
fun onRemoteUserLeave(
    channel: String,
    userInfo: UserInfo,
    leaveReason: LeaveReason
)
```

A remote user left the channel. `userInfo` is the last snapshot of the leaving user's info.

### onRemoteUserUpdate(channel, uid)

```kotlin theme={null}
fun onRemoteUserUpdate(channel: String, uid: String)
```

A remote user's info was updated.

## Track and channel events

### onStreamTrackAdd(uid, channel, trackId, trackDesc)

```kotlin theme={null}
fun onStreamTrackAdd(
    uid: String,
    channel: String,
    trackId: String,
    trackDesc: String
)
```

A remote track was added. Use the `RTCChannel` of the same channel to get and subscribe to the remote track.

### onStreamTrackUpdate(uid, channel, trackId, trackDesc)

```kotlin theme={null}
fun onStreamTrackUpdate(
    uid: String,
    channel: String,
    trackId: String,
    trackDesc: String
)
```

A remote track's info was updated.

### onStreamTrackRemove(uid, channel, trackInfo)

```kotlin theme={null}
fun onStreamTrackRemove(
    uid: String,
    channel: String,
    trackInfo: TrackInfo
)
```

A remote track was removed. For `TrackInfo` fields, see [Types](/en/rtc/android/types).

### onChannelUpdate(channel, props)

```kotlin theme={null}
fun onChannelUpdate(channel: String, props: String?)
```

Channel properties were updated; `props` may be `null`.

### onCustomMessage(channel, uid, sid, name, action, content)

```kotlin theme={null}
fun onCustomMessage(
    channel: String,
    uid: String,
    sid: String,
    name: String,
    action: String,
    content: String
)
```

An in-channel custom message was received. `channel` is the channel the message belongs to; the other parameters are, in order, the sender's user ID, session ID, name, action identifier, and message content.

## Connection events

### onDisconnected(channel, leaveReason, statusCode, message)

```kotlin theme={null}
fun onDisconnected(
    channel: String,
    leaveReason: LeaveReason,
    statusCode: Int,
    message: String
)
```

An unrecoverable disconnect occurred in the channel. You need to call `join(...)` again for this channel; other channels aren't affected.

### onReconnected(channel)

```kotlin theme={null}
fun onReconnected(channel: String)
```

The channel reconnected successfully after a disconnect.

### onReconnecting(channel)

```kotlin theme={null}
fun onReconnecting(channel: String)
```

The channel connection dropped and automatic reconnection started.

:::note
The former `RTCClientEvent.onError(...)` has been removed. Engine-blocking operations and global errors are all reported by [`RTCEngineEvent.onError(...)`](/en/rtc/android/api-reference/RTCEngineEvent).
:::
