> ## 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.

# IRTCChannelEvent

> API reference for IRTCChannelEvent, the Windows SRTC per-channel callback interface: join success, channel and user updates, stream add/update/remove, custom messages, uplink/downlink levels and statistics, audio levels, disconnection, reconnection, and recording status. Register it before join().

## Description

The channel-level event callback interface. Inherit from it, override the callback methods, and register it with [IRTCChannel::setEventHandler](/en/rtc/windows/api-reference/IRTCChannel#set-the-event-handler).

## Inheritance

None

## Callbacks

Callbacks are registered **per channel**: one `IRTCChannelEvent` instance is bound to one [IRTCChannel](/en/rtc/windows/api-reference/IRTCChannel),
so none of the callbacks **carry** a `channelId` parameter (the channel-level callbacks on the old `IRTCEngineEvent` did).
You can bind the same instance to multiple channels; in that case you need to tell the channels apart yourself.

**You must register it before `IRTCChannel::join()`**; otherwise you don't receive `onJoinChannel`—it's called back before `join()` returns.

### Join channel success callback

```cpp theme={null}
virtual void onJoinChannel(const char* channel, int channelSize, const char* me, int meSize, const char* members, int memberSize, const char* opts, int optSize) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| channel | const char\* | Channel info JSON |
| channelSize | int | Length of the channel info JSON |
| me | const char\* | Your own user info JSON |
| meSize | int | Length of your own user info |
| members | const char\* | JSON array of info for all users in the channel |
| memberSize | int | Length of the user info array |
| opts | const char\* | System configuration parameters |
| optSize | int | Length of the system configuration parameters |

Note: callbacks are registered per channel (`IRTCChannel::setEventHandler`), so `channelId` is no longer passed back. To tell channels apart, use `IRTCChannel::getChannelId()`.

### Channel status update callback

```cpp theme={null}
virtual void onChannelUpdate(const char* props, int propsSize) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| props | const char\* | Channel properties JSON |
| propsSize | int | Length of the properties string |

### User joined callback

```cpp theme={null}
virtual void onUserJoin(const char* user, int userSize) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| user | const char\* | Details JSON of the user who joined |
| userSize | int | Length of the user info string |

### User info update callback

```cpp theme={null}
virtual void onUserUpdate(const char* user, int userSize) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| user | const char\* | Updated user info JSON |
| userSize | int | Length of the user info string |

### User stream added callback

```cpp theme={null}
virtual void onUserStreamAdd(const char* user, const char* stream, int streamSize) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| user | const char\* | User ID |
| stream | const char\* | Stream info JSON |
| streamSize | int | Length of the stream info string |

### User stream updated callback

```cpp theme={null}
virtual void onUserStreamUpdate(const char* user, const char* stream, int streamSize) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| user | const char\* | User ID |
| stream | const char\* | Updated stream info JSON |
| streamSize | int | Length of the stream info string |

### User stream removed callback

```cpp theme={null}
virtual void onUserStreamRemove(const char* user, const char* stream, int streamSize) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| user | const char\* | User ID |
| stream | const char\* | Info JSON of the removed stream |
| streamSize | int | Length of the stream info string |

### User left callback

```cpp theme={null}
virtual void onUserLeave(const char* user, int userSize) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| user | const char\* | Details JSON of the user who left |
| userSize | int | Length of the user info string |

### Custom message callback

```cpp theme={null}
virtual void onCustomMessage2(const char* action, const char* senderid, const char* name, int name_len, const char* message, int messageSize) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| action | const char\* | Message type / action |
| senderid | const char\* | Sender's user ID |
| name | const char\* | Sender's display name |
| name\_len | int | Length of the display name |
| message | const char\* | Message content |
| messageSize | int | Length of the message content |

### Uplink level change callback

```cpp theme={null}
virtual void onUpLevel(int level) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| level | int | Quality level (0: good, 1: fair, 2: poor, 3: very poor) |

### Downlink level change callback

```cpp theme={null}
virtual void onDownLevel(const char* id, int level) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| id | const char\* | The user's ID |
| level | int | Quality level (0: good, 1: fair, 2: poor, 3: very poor) |

### Uplink statistics callback

```cpp theme={null}
virtual void onUpStat(const char* upstat, int upstatsize) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| upstat | const char\* | Uplink statistics JSON |
| upstatsize | int | Length of the uplink statistics |

### Downlink statistics callback

```cpp theme={null}
virtual void onDownStat(const char* downstat, int downstatsize) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| downstat | const char\* | Downlink statistics JSON |
| downstatsize | int | Length of the downlink statistics |

### Frame timeout callback

```cpp theme={null}
virtual void onFrameTimeOut(const char* uid, const char* track_id, const char* track_desc, int loading) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| uid | const char\* | User ID |
| track\_id | const char\* | Track ID |
| track\_desc | const char\* | Track description |
| loading | int | Loading state |

### Audio level callback

```cpp theme={null}
virtual void onSpeakers(const char* Speakers) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| Speakers | const char\* | JSON array of speakers' audio energy data |

### Device status change callback

```cpp theme={null}
virtual void onDeviceStatusChange(int tp, int status) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| tp | int | Device type (1: microphone, 2: speaker, 3: camera) |
| status | int | Status (1: error, 2: recovered) |

### Share target not found callback

```cpp theme={null}
virtual void onShareTargetNotFind() = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |

### Disconnected callback

```cpp theme={null}
virtual void onDisconnected(int reason, StatusCode code, const char* message, size_t message_size) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| reason | int | Disconnect reason (-1: error, 0: unknown, 1: left voluntarily, 2: removed from the channel, 3: replaced by another session with the same uid, 4: heartbeat timeout, 5: channel destroyed) |
| code | StatusCode | Error code |
| message | const char\* | Error description |
| message\_size | size\_t | Length of the error description |

### Reconnected callback

```cpp theme={null}
virtual void onReconnected(const char* options, size_t options_size) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| options | const char\* | Extended reconnection info |
| options\_size | size\_t | Length of the extended info |

### Reconnecting callback

```cpp theme={null}
virtual void onReconnecting() = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |

### Recording status change callback

```cpp theme={null}
virtual void onRecordStatusChange(const char* key, LocalRecordStatusEnum status, const char* msg) = 0;
```

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| key | const char\* | Recording task key |
| status | LocalRecordStatusEnum | Recording status; see [LocalRecordStatusEnum](/en/rtc/windows/enums) |
| msg | const char\* | Status description; the error message when an error occurs |
