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

# media-tracks

> API reference for the Web SDK's local and remote track classes: the class hierarchy, BaseTrack metadata, capture and device switching, playback and play views, picture-in-picture and pop-out windows, simulcast sub-tracks, processors, mirroring, and jitter buffer control.

### Class hierarchy

```typescript theme={null}
BaseTrack
├── LocalAudioTrack           ← Local audio base class (custom audio stream)
│   ├── LocalMicTrack         ← Microphone stream
│   └── LocalScreenAudioTrack ← System audio stream that comes with screen sharing
├── LocalVideoTrack           ← Local video base class (custom video stream)
│   ├── LocalCameraTrack      ← Camera stream
│   └── LocalScreenTrack      ← Screen sharing video stream
├── RemoteAudioTrack          ← Single remote audio stream
│   └── RemoteAudioMixTrack   ← Remote channel-wide mixed audio stream
└── RemoteVideoTrack          ← Remote video stream
```

***

## BaseTrack

Base class of all tracks, providing access to track metadata.

#### id

```typescript theme={null}
get id(): string
```

Track ID, uniquely identifying the track within the channel.

#### kind

```typescript theme={null}
get kind(): TrackKind
```

Track type: `'audio'` or `'video'`.

#### desc

```typescript theme={null}
get desc(): string
```

Track description, specified when publishing, such as `'camera_big'` or `'screen'`.

#### getInfo

Gets the full track info, such as resolution, bitrate, and sample rate.

```typescript theme={null}
getInfo(): TrackInfo
```

**Returns:** `TrackInfo`; see [Types](/en/rtc/web/types#trackinfo)

> When a local track is published to multiple channels at once, the same track has separate track info in each channel. In that case `getInfo()` throws; use `channel.getPublishInfo(track)` instead to query the track info in a given channel. See [Multi-channel](/en/rtc/web/advanced/multi-channel).

#### getUid

Gets the UID of the user who owns the track.

```typescript theme={null}
getUid(): string
```

#### getMediaStreamTrack

Gets the underlying `MediaStreamTrack`, for scenarios such as the Web Audio API or custom post-processing.

```typescript theme={null}
getMediaStreamTrack(): MediaStreamTrack | undefined
```

***

## LocalAudioTrack

Base class for local audio tracks, also used for custom audio streams, such as the return value of `srtc.createLocalCustomAudioTrack(...)`.

Extends `BaseTrack`.

#### startPlay

Plays the audio, for local monitoring.

```typescript theme={null}
startPlay(opt?: AudioOutputOptions): Promise<void>
```

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `opt` | `AudioOutputOptions` | No | Playback options; can specify the speaker device |

#### stopPlay

Stops playback and releases the playback device.

```typescript theme={null}
stopPlay(): void
```

#### getVolume

Gets the current audio input volume, in the range 0–100.

```typescript theme={null}
getVolume(): number
```

#### isPlaying

Whether it's currently playing.

```typescript theme={null}
isPlaying(): boolean
```

#### setProcessor

Attaches an audio processor (such as RNN noise suppression or voice changing). Call it after `startCapture` has produced a track; when you pass an array, the processors are chained in order. Published tracks can also have processors attached, and the SDK switches without renegotiation; after a device switch, processors are reattached automatically. See [Audio/video processors](/en/rtc/web/advanced/audio-processor).

```typescript theme={null}
setProcessor(processor: TrackProcessor | TrackProcessor[]): Promise<void>
```

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `processor` | `TrackProcessor \| TrackProcessor[]` | Yes | A processor instance, or an array of processors chained in order |

#### removeProcessor

Detaches the attached processor, restores the original captured track, and releases processor resources.

```typescript theme={null}
removeProcessor(): Promise<void>
```

***

## LocalMicTrack

Local microphone track, extends `LocalAudioTrack`, created with `srtc.createLocalMicTrack`.

#### startCapture

Starts capture and requests microphone permission from the user.

```typescript theme={null}
startCapture(opt?: Partial<MicCaptureOptions>): Promise<void>
```

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `opt` | `Partial<MicCaptureOptions>` | No | Capture options; can specify the device ID, echo cancellation, etc. |

#### stopCapture

Stops capture and releases the microphone device.

```typescript theme={null}
stopCapture(): void
```

#### changeDeviceId

Hot-switches the microphone device.

```typescript theme={null}
changeDeviceId(deviceId: string): Promise<void>
```

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `deviceId` | `string` | Yes | Target device ID, available from `getDevices('audioinput')` |

***

## LocalScreenAudioTrack

System audio track that comes with screen sharing, extends `LocalAudioTrack`.

You usually don't create this class manually; get it through `LocalScreenTrack.getAudioTrack()`.

#### stopCapture

Stops system audio capture.

```typescript theme={null}
stopCapture(): void
```

> The other playback methods are inherited from `LocalAudioTrack`, such as `startPlay()`, `stopPlay()`, and `isPlaying()`.

***

## LocalVideoTrack

Base class for local video tracks, also used for custom video streams, such as the return value of `srtc.createLocalCustomVideoTrack(...)`.

Extends `BaseTrack`.

#### addPlayView

Renders the video into the given HTML container element.

```typescript theme={null}
addPlayView(container: HTMLElement): void
```

#### hasPlayView

Checks whether there's already a render container.

```typescript theme={null}
hasPlayView(): boolean
```

#### removePlayView

Removes the given render container.

```typescript theme={null}
removePlayView(container: HTMLElement): void
```

#### removeAllPlayViews

Removes all render containers.

```typescript theme={null}
removeAllPlayViews(): void
```

#### enterPictureInPicture

Puts the video of the given container into picture-in-picture mode.

```typescript theme={null}
enterPictureInPicture(container: HTMLElement, options?: PipOptions): Promise<PipHandle>
```

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `container` | `HTMLElement` | Yes | A video container already bound via `addPlayView` |
| `options` | `PipOptions` | No | Picture-in-picture options; can specify the window size, whether to prefer Document PiP, and whether to hide the original view |

> Document PiP is preferred by default. If the browser doesn't support it, it falls back automatically to the traditional `video.requestPictureInPicture()`.

#### exitPictureInPicture

Exits picture-in-picture mode for the given container.

```typescript theme={null}
exitPictureInPicture(container: HTMLElement): Promise<void>
```

#### isPictureInPicture

Checks whether the given container is in picture-in-picture mode.

```typescript theme={null}
isPictureInPicture(container: HTMLElement): boolean
```

#### popOutToWindow

Pops the video of the given container out to a separate browser window.

```typescript theme={null}
popOutToWindow(container: HTMLElement, options?: PopOutOptions): PopOutHandle
```

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `container` | `HTMLElement` | Yes | A video container already bound via `addPlayView` |
| `options` | `PopOutOptions` | No | Pop-out options; can specify the window size, title, and whether to hide the original view |

#### closePopOutWindow

Closes the pop-out window of the given container.

```typescript theme={null}
closePopOutWindow(container: HTMLElement): void
```

#### isPopOut

Checks whether the given container has been popped out to a separate window.

```typescript theme={null}
isPopOut(container: HTMLElement): boolean
```

#### getSimulcastTrack

Creates or gets a simulcast sub-track based on the given simulcast publish parameters.

```typescript theme={null}
getSimulcastTrack(opt: VideoPublishOptions, owidth?: number, oheight?: number): LocalVideoTrack
```

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `opt` | `VideoPublishOptions` | Yes | Publish parameters of the simulcast sub-track; `desc` can't be empty |
| `owidth` | `number` | No | Original video width, used to compute the encoding scale factor |
| `oheight` | `number` | No | Original video height, used to compute the encoding scale factor |

#### setProcessor

Attaches a video processor (such as a beauty filter or background blur). Call it after `startCapture` has produced a track; when you pass an array, the processors are chained in order. Published tracks can also have processors attached, and the SDK switches without renegotiation; after a device switch, processors are reattached automatically. See [Audio/video processors](/en/rtc/web/advanced/audio-processor).

```typescript theme={null}
setProcessor(processor: TrackProcessor | TrackProcessor[]): Promise<void>
```

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `processor` | `TrackProcessor \| TrackProcessor[]` | Yes | A processor instance, or an array of processors chained in order |

#### removeProcessor

Detaches the attached processor, restores the original captured track, and releases processor resources.

```typescript theme={null}
removeProcessor(): Promise<void>
```

> The PiP / pop-out methods above are all available on `LocalCameraTrack`, `LocalScreenTrack`, and `RemoteVideoTrack`.
>
> When `options.hideOriginView` is `true` (the default):
>
> * `Document PiP` and `pop-out windows` hide the original play view on the main page to avoid double rendering
> * Traditional `video PiP` still relies on the original `video` element, so the original view isn't hidden

***

## LocalCameraTrack

Local camera video track, extends `LocalVideoTrack`, created with `srtc.createLocalCameraTrack`.

#### startCapture

Starts capture and requests camera permission from the user.

```typescript theme={null}
startCapture(opt?: Partial<CameraCaptureOptions>): Promise<void>
```

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `opt` | `Partial<CameraCaptureOptions>` | No | Capture options; can specify the device ID, resolution, and frame rate |

#### stopCapture

Stops capture and releases the camera device.

```typescript theme={null}
stopCapture(): void
```

#### changeDeviceId

Hot-switches the camera device.

```typescript theme={null}
changeDeviceId(deviceId: string): Promise<void>
```

#### switchFacingMode

Switches between the front and rear cameras; only takes effect on mobile.

```typescript theme={null}
switchFacingMode(): Promise<void>
```

#### setMirror

Sets the mirroring switch for the local preview. The front camera is mirrored by default (like looking in a mirror), which you can adjust here; the rear camera doesn't support mirroring, and calling this has no effect.

Mirroring only affects rendering of the local preview (including picture-in-picture and pop-out windows) and **doesn't change the published data or the video remote users see**. Switching between front and rear cameras recalculates the mirroring state automatically and keeps the user's on/off preference for the front camera.

```typescript theme={null}
setMirror(enabled: boolean): void
```

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `enabled` | `boolean` | Yes | Whether to enable mirroring |

#### isMirrored

Returns whether it's currently mirrored (front camera with mirroring on). Always `false` for the rear camera; you can use it to reflect the current mirroring state in the UI.

```typescript theme={null}
isMirrored(): boolean
```

#### isFrontFacing

Checks whether the current camera is the front camera. A `facingMode` specified explicitly at capture is the most reliable; if unspecified, it's treated as front.

```typescript theme={null}
isFrontFacing(): boolean
```

***

## LocalScreenTrack

Local screen sharing video track, extends `LocalVideoTrack`, created with `srtc.createLocalScreenTrack`.

#### startCapture

Starts screen capture; the browser shows a screen picker.

```typescript theme={null}
startCapture(opt?: Partial<ScreenCaptureOptions>): Promise<void>
```

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `opt` | `Partial<ScreenCaptureOptions>` | No | Capture options; can specify resolution, frame rate, `contentHint`, etc. |

#### stopCapture

Stops screen capture.

```typescript theme={null}
stopCapture(): void
```

#### getAudioTrack

Gets the system audio track captured at the same time. Only valid when `audioPreset` was passed to `createLocalScreenTrack` and the browser supports it.

```typescript theme={null}
getAudioTrack(): LocalScreenAudioTrack | undefined
```

> For detailed usage, see [Screen sharing - Capture system audio at the same time](/en/rtc/web/advanced/screen-sharing#capture-system-audio-at-the-same-time)

***

## RemoteAudioTrack

Single remote audio track, subscribed with `srtc.subscribeRemoteAudioTrack`.

Extends `BaseTrack`.

#### startPlay

Plays the remote audio.

```typescript theme={null}
startPlay(opt?: AudioOutputOptions): Promise<void>
```

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `opt` | `AudioOutputOptions` | No | Can specify the speaker device |

#### stopPlay

Stops playback and releases the playback device.

```typescript theme={null}
stopPlay(): void
```

#### isPlaying

Whether it's currently playing.

```typescript theme={null}
isPlaying(): boolean
```

#### setJitterBufferTarget

Sets the target delay of the receiver's jitter buffer, in ms.

```typescript theme={null}
setJitterBufferTarget(ms?: number): void
```

Parameters:

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `ms` | `number` | No | Target delay. `0` prioritizes low latency, while larger values such as `200` to `500` favor smooth playback; omitting it or passing `undefined` clears the setting and returns to the browser's default adaptive strategy. |

Not set by default; the browser adapts on its own. You generally don't need to adjust it; use it only when you have explicit playback latency requirements.

> This relies on the browser's WebRTC receiver implementation. Chrome / Edge prefer `jitterBufferTarget` and remain compatible with the older `playoutDelayHint`; Firefox / Safari silently ignore it when unsupported.

#### getJitterBufferTarget

Gets the currently set target delay of the receiver's jitter buffer.

```typescript theme={null}
getJitterBufferTarget(): number | undefined
```

The return value is the target delay currently set by your app, in ms; `undefined` means it isn't set and the browser's default adaptive strategy is used.

***

## RemoteAudioMixTrack

Remote channel-wide mixed audio track, extends `RemoteAudioTrack`, subscribed with `srtc.subscribeRemoteAudioMixTrack`.

In most scenarios you only need to subscribe to this one mixed track, without subscribing to each user's individual audio stream.

#### getFilterUids

Gets the list of user IDs currently excluded from the mix.

```typescript theme={null}
getFilterUids(): string[]
```

> Playback methods are inherited from `RemoteAudioTrack`, such as `startPlay()`, `stopPlay()`, and `isPlaying()`.

***

## RemoteVideoTrack

Remote video track, subscribed with `srtc.subscribeRemoteVideoTrack`.

Extends `BaseTrack`.

#### setJitterBufferTarget

Sets the target delay of the receiver's jitter buffer, in ms.

```typescript theme={null}
setJitterBufferTarget(ms?: number): void
```

Parameters:

| Parameter | Type | Required | Description |
| - | - | :-: | - |
| `ms` | `number` | No | Target delay. `0` prioritizes low latency, while larger values such as `200` to `500` favor smooth playback; omitting it or passing `undefined` clears the setting and returns to the browser's default adaptive strategy. |

> This relies on the browser's WebRTC receiver implementation. Chrome / Edge prefer `jitterBufferTarget` and remain compatible with the older `playoutDelayHint`; Firefox / Safari silently ignore it when unsupported.

#### getJitterBufferTarget

Gets the currently set target delay of the receiver's jitter buffer.

```typescript theme={null}
getJitterBufferTarget(): number | undefined
```

The return value is the target delay currently set by your app, in ms; `undefined` means it isn't set and the browser's default adaptive strategy is used.

#### addPlayView

Renders the remote video into the given HTML container element.

```typescript theme={null}
addPlayView(container: HTMLElement): void
```

#### hasPlayView

Checks whether there's already a render container.

```typescript theme={null}
hasPlayView(): boolean
```

#### removePlayView

Removes the given render container.

```typescript theme={null}
removePlayView(container: HTMLElement): void
```

#### removeAllPlayViews

Removes all render containers.

```typescript theme={null}
removeAllPlayViews(): void
```

#### enterPictureInPicture

Puts the remote video of the given container into picture-in-picture mode.

```typescript theme={null}
enterPictureInPicture(container: HTMLElement, options?: PipOptions): Promise<PipHandle>
```

#### exitPictureInPicture

Exits picture-in-picture mode for the given container.

```typescript theme={null}
exitPictureInPicture(container: HTMLElement): Promise<void>
```

#### isPictureInPicture

Checks whether the given container is in picture-in-picture mode.

```typescript theme={null}
isPictureInPicture(container: HTMLElement): boolean
```

#### popOutToWindow

Pops the remote video out to a separate window.

```typescript theme={null}
popOutToWindow(container: HTMLElement, options?: PopOutOptions): PopOutHandle
```

#### closePopOutWindow

Closes the pop-out window of the given container.

```typescript theme={null}
closePopOutWindow(container: HTMLElement): void
```

#### isPopOut

Checks whether the given container has been popped out to a separate window.

```typescript theme={null}
isPopOut(container: HTMLElement): boolean
```
