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

# Virtual background

> Virtual background in the SMeeting Swift SDK: person segmentation for background blur or replacement, no license key needed. Covers why it's a device-level setting, why camera switches and restarts need no re-apply, two frame-rate parameters for low-end devices, and the 1.3.0 OS requirements.

Virtual background performs person segmentation in the camera capture pipeline and replaces everything outside the person with blur or a specified image. It's an in-house component, and installing it **doesn't require a license key**.

<Note>
  The APIs are on `SMeetingEngine`, but the state is **device-level**: virtual background applies to the single shared camera capture pipeline in the process, so the setting applies to all meetings and channels at once. When you're in multiple rooms at the same time, there's no way to "turn on virtual background for just one room."

  During the meeting, **you don't need to re-apply anything after switching cameras, turning the camera off and on again, or reconnecting after a disconnect**—the capture pipeline reads the effect for every frame, so rebuilding the track doesn't lose it.
</Note>

<Warning>
  Starting with `1.3.0`, the minimum system requirements are raised to **iOS 16.0 / macOS 14.0** (previously iOS 13 / macOS 10.15). Projects below this minimum can't resolve 1.3.0 or later. For details, see [Integration](/en/meeting/swift/integration).

  The inference runtime `onnxruntime` is statically linked into the audio and video layer's `SRTC.xcframework`, so you don't need to declare any extra dependencies.
</Warning>

***

### Step 1: **Install the virtual background component**

We recommend installing it before you need virtual background, for example when entering the meeting page. Pass `nil` for `modelPath` to use the SDK's built-in person segmentation model.

```swift theme={null}
/// Installing loads the model and creates an inference session, taking hundreds of milliseconds—don't call it on the main thread or the capture thread
Task.detached(priority: .userInitiated) {
    do {
        try meeting.installVirtualBackground()       // Pass nil for modelPath to use the built-in model
    } catch {
        print("Failed to install virtual background:", error.localizedDescription)
    }
}
```

Errors thrown (`SRTCError` from the audio and video layer):

| **Error** | **Description** |
| - | - |
| `virtualBackgroundAlreadyInstalled` | The component is already installed; this call is discarded |
| `virtualBackgroundModelNotFound(String)` | The model file doesn't exist; check `modelPath` |
| `virtualBackgroundSessionFailed(String)` | Failed to create the inference session; this is a runtime environment problem |

***

### Step 2: **Set the background effect**

Background blur and background replacement are **mutually exclusive; the later call wins**. Both APIs are remembered even if called before installation and take effect automatically once installation completes, so you don't need to care about their order relative to `installVirtualBackground()`.

```swift theme={null}
/// Set background blur; level ranges from 1 to 10, default 5 (out-of-range values are clamped to the boundary)
meeting.setVirtualBackgroundBlur(level: 5)

/// Set background replacement, cropped to cover without stretching; pass nil to cancel replacement and go back to blur
meeting.setVirtualBackgroundImage(SRTCNativeImage(named: "background"))
```

`SRTCNativeImage` is an alias for the platform's native image type (`UIImage` on iOS, `NSImage` on macOS).

***

### Step 3: **Turn virtual background on or off**

After installation, it's **off** by default and must be turned on explicitly. When off, frames pass straight through with zero overhead, and no inference runs.

```swift theme={null}
try meeting.enableVirtualBackground(true)

/// Query whether it's on
let enabled = meeting.isVirtualBackgroundEnabled
```

Calling the switch before the component is installed throws `virtualBackgroundNotInstalled`. Turning it off clears the inter-frame state, so the next time it's turned on it converges again from the first frame and doesn't flash a stale mask.

<Note>
  Virtual background is local preprocessing and has nothing to do with meeting state: **you can set it before or after entering the meeting**, and it isn't affected by permission actions such as the host muting you or turning off your camera. Settings made while the camera is off are also remembered, and you see the effect once the camera is on.
</Note>

***

### Step 4: **Keep the frame rate up on low-end devices (optional)**

By default, person segmentation runs on every frame. On low-end devices, you can increase the inference interval, trading mask reuse for frame rate; then turn on mask sync as needed to eliminate trailing artifacts.

```swift theme={null}
/// Run segmentation every N frames (compositing still runs every frame); default 1
meeting.setVirtualBackgroundInferenceInterval(2)

/// Mask sync; default false
meeting.setVirtualBackgroundMaskSync(true)
```

| **Parameter** | **Default** | **Description** |
| - | :-: | - |
| `inferenceInterval` | `1` | Run segmentation every N frames; values below 1 are treated as 1. Increasing it lowers inference overhead, at the cost of the mask following more slowly during fast motion |
| `maskSync` | `false` | When on, non-inference frames aren't recomposited, so the video and the mask always come from the same moment, eliminating misaligned trails when waving; the cost is that the video update rate drops to the mask rate |

<Note>
  When `inferenceInterval` is `1`, turning `setVirtualBackgroundMaskSync(_:)` on or off makes no difference at all—it only takes effect after you increase the inference interval.
</Note>

***

### Step 5: **Uninstall the virtual background component**

Uninstall it when no longer needed to release the inference session and related buffers. Effect parameters you've set aren't cleared and still apply after the next installation.

```swift theme={null}
meeting.uninstallVirtualBackground()
```

***

### Frames are dropped on errors, so the real background never flashes

When segmentation fails or the output buffer pool is exhausted, the SDK **drops that frame** instead of sending the unprocessed raw camera frame—which would flash your real background to other members. The cost is a brief stutter in the video others see.

The dropped-frame count and read-only state are on `meeting.virtualBackground` (`droppedFrameCount`, `isInstalled`, `isEnabled`, `effect`, `blurLevel`), which you can use to populate panel controls with the SDK's actual state:

```swift theme={null}
print(meeting.virtualBackground.droppedFrameCount)
```

***

### Consistency between local preview and the published stream

When virtual background is on, the local preview shows the processed video, which is the same data other members see; when it's off, the local preview goes back to the raw camera video.

For lower-level usage (attaching virtual background to a custom video track, clearing inter-frame state when you take over capture yourself), see [Virtual background](/en/rtc/swift/advanced/virtual-background) in the audio and video layer.

***

### Related pages

* [Integration](/en/meeting/swift/integration)—system requirements and integration steps
* [SMeetingEngine](/en/meeting/swift/api-reference/SMeetingEngine#virtual-background)—full signatures and parameters
* [Virtual background in the audio and video layer](/en/rtc/swift/advanced/virtual-background)—diagnostics and custom track usage
