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

# C++ quickstart

> Step-by-step C++ code for the SMeeting Windows SDK: initialize the engine, log in, create a meeting, create an ISMeetingChannel and enter, control the camera, microphone, speaker, and screen sharing, host actions, MCU playback, and cleanup. Read this after integration to get a first meeting running.

This page shows how to integrate the SMeeting SDK with C++ on Windows.

## Basic concepts

* **ISMeetingEngine**: the SDK engine class. It handles login, the meeting management HTTP APIs, device enumeration, IM, the resource drive, and the channel object lifecycle.
* **ISMeetingChannel**: each meeting corresponds to one channel object, created by `ISMeetingEngine::createChannel()`. It contains all in-meeting operations and media objects.
* Some APIs can only be called after you enter the meeting.

Because `ISMeetingEngine` / `ISMeetingChannel` and the callbacks are all pure virtual interfaces, **any change to an API signature changes the vtable**. After upgrading the SDK you must recompile your project; replacing only the DLLs is not enough.

***

## Initialize the SDK

```cpp theme={null}
#include "SMeeting.h"

// Initialize the engine
SMeeting::ISMeetingEngine* engine = nullptr;
SMeeting::StatusCode ret = SMeeting::SMeetingEngine_Init(&engine);
if (ret != SMeeting::StatusCode::OK) {
    return ret;
}

// Set the engine-level event handler (the current class must inherit ISMeetingEngineEvent)
engine->setEventHandler(this);
```

### Implement the engine event handler class

```cpp theme={null}
class MyEngineHandler : public SMeeting::ISMeetingEngineEvent {
public:
    void onDeviceChange(SMeeting::DeviceType tp, bool isadd, std::string name) override {
        // Handle device changes
    }

    void onImEnabled(std::string uid, std::string sid) override {
        // IM is enabled
    }

    // ... Implement the other engine-level callbacks you need
};
```

***

## Log in and log out

### Log in

```cpp theme={null}
std::string token = "your_token_here";
engine->login(token, [&](SMeeting::StatusCode status, std::string msg) {
    if (status == SMeeting::StatusCode::OK) {
        // Login succeeded
    } else {
        // Login failed
    }
});
```

### Log out

```cpp theme={null}
engine->logout([&](SMeeting::StatusCode status, std::string msg) {
    if (status == SMeeting::StatusCode::OK) {
        // Logout succeeded
    }
});
```

***

## Create a meeting

```cpp theme={null}
SMeeting::SMeetingCreateMeetingModel model;
model.title = "My meeting";
model.content = "Meeting description";
model.meeting_type = 1;  // 1: instant meeting, 2: scheduled meeting
model.meeting_mode = 1;  // 1: normal

engine->createRoom(model, [&](SMeeting::StatusCode status, std::string msg) {
    if (status == SMeeting::StatusCode::OK) {
        // msg is the meeting number
        std::cout << "Meeting created, meeting number: " << msg << std::endl;
    }
});
```

***

## Enter a meeting

### Create and configure the channel object

```cpp theme={null}
std::string roomno = "123456789";
SMeeting::ISMeetingChannel* channel = nullptr;
SMeeting::StatusCode sc = engine->createChannel(roomno, &channel);
if (sc != SMeeting::StatusCode::OK) {
    return;
}

// Set the channel-level configuration
SMeeting::ISMeetingChannelSetting* csetting = nullptr;
channel->getSetting(&csetting);
if (csetting) {
    csetting->set_stream_model(1);           // Set the streaming mode
    csetting->set_speaker_interval(500);     // Audio level callback interval (ms)
    csetting->set_stat_interval(10000);      // Network statistics callback interval (ms)
    csetting->set_enable_audio_record(1);    // Enable audio recording
    csetting->set_room_name("Alice");         // Display name for entering the meeting
}
```

### Set the channel event handler and enter

```cpp theme={null}
// Set the channel-level event handler (the current class must inherit ISMeetingChannelEvent)
channel->setEventHandler(this);

// Enter the meeting
std::string pass = "";  // Meeting password; empty if there is none
channel->enter(pass, [&](SMeeting::StatusCode status, std::string msg) {
    if (status == SMeeting::StatusCode::OK) {
        // Entered the room successfully
    } else {
        // Failed to enter the room; you still need to call leaveChannel to release the object
    }
});
```

### Implement the channel event handler class

```cpp theme={null}
class MyChannelHandler : public SMeeting::ISMeetingChannelEvent {
public:
    void onDisconnected(SMeeting::DisconnectReason reason,
                        SMeeting::StatusCode code,
                        std::string message) override {
        // Handle the disconnect event
    }

    void onReconnected() override {
        // Reconnected
    }

    void onUserEnter(std::string userdata) override {
        // Handle a user entering
    }

    // ... Implement the other channel-level callbacks you need
};
```

***

## Exit the meeting

```cpp theme={null}
// The channel object is destroyed after you exit; don't use the original pointer again
engine->leaveChannel(channel->getChannelId(), [&](SMeeting::StatusCode status, std::string msg) {
    // Result of exiting the room
});
channel = nullptr;
```

***

## End the meeting (host)

```cpp theme={null}
// The host ends the meeting
channel->adminDestroyRoom([&](SMeeting::StatusCode status, std::string msg) {
    // Result of ending the meeting
});
```

***

## Cancel a meeting (outside the meeting)

```cpp theme={null}
std::string meeting_id = "sw46gz";
engine->cancelRoom(meeting_id, [&](SMeeting::StatusCode status, std::string msg) {
    // Result of canceling the meeting
});
```

***

## Get room and member info

```cpp theme={null}
std::string s;

// Get your own info
channel->getMe(s);

// Get the room info
channel->getRoom(s);

// Get info for all members
channel->getMembers(s);

// Get info for a specific member
std::string uid = "user_123";
channel->getMember(uid, s);
```

***

## Update your nickname

```cpp theme={null}
std::string new_name = "New nickname";
channel->updateName(new_name, [&](SMeeting::StatusCode status, std::string msg) {
    // Result of changing the nickname
});
```

***

## Get the device list

```cpp theme={null}
// type: 1 = microphone, 2 = speaker, 3 = camera
std::vector<int> types = {1, 2, 3};
int page = 1;
std::string find_key = "";

engine->listAgent(types, page, find_key, [&](SMeeting::StatusCode status, std::string msg) {
    if (status == SMeeting::StatusCode::OK) {
        // msg is the device list as a JSON string
    }
});
```

***

## Camera operations

### Get the camera object

```cpp theme={null}
SMeeting::IMEETLocalCamera* camera = nullptr;
SMeeting::StatusCode sc = channel->getLocalCamera(&camera);
if (sc != SMeeting::StatusCode::OK) {
    return;
}
```

### Turn on the camera

```cpp theme={null}
// Set the render window (hwnd is the window handle)
camera->addPlayView(hwnd);

// Request to turn on the camera
camera->requestOpenCamera([&](SMeeting::StatusCode status, std::string msg) {
    if (status == SMeeting::StatusCode::OK) {
        // Camera turned on
    }
});
```

### Switch cameras

```cpp theme={null}
std::string camera_name = "Integrated Camera";
int width = 640;
int height = 480;
camera->switchCamera(camera_name, width, height);
```

### Turn off the camera

```cpp theme={null}
camera->closeCamera([&](SMeeting::StatusCode status, std::string msg) {
    // Result of turning off the camera
});
```

***

## Remote video playback

### Get the remote video object

```cpp theme={null}
std::string uid = "user_123";
std::string track_desc = SMeeting::TRACK_DESC_CAMERA_BIG;  // Or TRACK_DESC_CAMERA_SMALL

SMeeting::IMEETRemoteVideo* remote_video = nullptr;
channel->getRemoteVideo(uid, track_desc, &remote_video);
```

### Start playback

```cpp theme={null}
// Set the render window
remote_video->addPlayView(hwnd);

// Start loading the remote video stream
remote_video->loadRemoteVideo();
```

### Stop playback

```cpp theme={null}
remote_video->unLoadRemoteVideo();
remote_video->removeAllPlayView();
```

***

## Microphone operations

### Get the microphone object

```cpp theme={null}
SMeeting::IMEETLocalMic* mic = nullptr;
channel->getLocalMic(&mic);
```

### Turn on the microphone

```cpp theme={null}
mic->requestOpenMic([&](SMeeting::StatusCode status, std::string msg) {
    if (status == SMeeting::StatusCode::OK) {
        // Microphone turned on
    }
});
```

### Switch microphones

```cpp theme={null}
std::string mic_name = "Default Microphone";
mic->switchMic(mic_name);
```

### Turn off the microphone

```cpp theme={null}
mic->closeMic([&](SMeeting::StatusCode status, std::string msg) {
    // Result of turning off the microphone
});
```

***

## Speaker operations

### Get the remote audio object

```cpp theme={null}
SMeeting::IMEETRemoteAudio* audio = nullptr;
channel->getRemoteAudio("", &audio);
```

### Turn on the speaker

```cpp theme={null}
audio->openSpeaker();
```

### Switch speakers

```cpp theme={null}
std::string speaker_name = "Default Speakers";
audio->switchSpeaker(speaker_name);
```

### Turn off the speaker

```cpp theme={null}
audio->closeSpeaker();
```

***

## Screen sharing

### Get the screen sharing object

```cpp theme={null}
SMeeting::IMEETLocalScreen* screen = nullptr;
channel->getLocalScreen(&screen);
```

### Start sharing

```cpp theme={null}
// tp: 1 = screen sharing, 2 = window sharing
// data: screen index or window handle string
int tp = 1;
std::string data = "0,0,1920,1080";  // Primary screen
//std::string data_hwnd = "hwnd:123321";//Window capture

screen->requestShare(tp, data, [&](SMeeting::StatusCode status, std::string msg) {
    if (status == SMeeting::StatusCode::OK) {
        // Sharing started
    }
});
```

### Stop sharing

```cpp theme={null}
screen->stopShare([&](SMeeting::StatusCode status, std::string msg) {
    // Result of stopping sharing
});
```

***

## Chat messages

### Send a chat message

```cpp theme={null}
// tp: 1 = text, 2 = file, 3 = image, 4 = audio
int msg_type = 1;
std::string msg = "Hello, everyone!";

channel->sendRoomChatMessage(msg_type, msg, [&](SMeeting::StatusCode status, std::string m) {
    // Send result
});
```

***

## Host management APIs

### Ask a member to turn on the camera

```cpp theme={null}
std::string uid = "user_123";
channel->adminRequestUserOpenCamera(uid, [&](SMeeting::StatusCode status, std::string msg) {
    // Request result
});
```

### Turn off a member's camera

```cpp theme={null}
channel->adminCloseUserCamera(uid, [&](SMeeting::StatusCode status, std::string msg) {
    // Operation result
});
```

### Ask a member to turn on the microphone

```cpp theme={null}
channel->adminRequestUserOpenMic(uid, [&](SMeeting::StatusCode status, std::string msg) {
    // Request result
});
```

### Turn off a member's microphone

```cpp theme={null}
channel->adminCloseUserMic(uid, [&](SMeeting::StatusCode status, std::string msg) {
    // Operation result
});
```

### Remove a member

```cpp theme={null}
channel->adminKickUserOut(uid, [&](SMeeting::StatusCode status, std::string msg) {
    // Removal result
});
```

### Set the room's microphone permissions

```cpp theme={null}
bool self_unmute_mic_disabled = true;   // Whether members are prevented from unmuting themselves
bool mic_disabled = true;               // Whether room audio is disabled

channel->adminUpdateRoomMicState(self_unmute_mic_disabled, mic_disabled, 
    [&](SMeeting::StatusCode status, std::string msg) {
        // Result of the setting
    });
```

***

## MCU composite video

### Get the MCU video object

```cpp theme={null}
SMeeting::IMEETRemoteVideo* mcu_video = nullptr;
channel->getMcuVideo(&mcu_video);
```

### Play the composite stream

```cpp theme={null}
mcu_video->addPlayView(hwnd);
mcu_video->loadRemoteVideo();
```

### Stop playback

```cpp theme={null}
mcu_video->unLoadRemoteVideo();
```

***

## Release resources

```cpp theme={null}
// First exit all meetings
engine->leaveAllChannel();

// Release the engine
if (engine) {
    engine->del();
    engine = nullptr;
}
```

***

## Complete example

```cpp theme={null}
#include "SMeeting.h"
#include <iostream>

class MyEngineHandler : public SMeeting::ISMeetingEngineEvent {
public:
    void onDeviceChange(SMeeting::DeviceType tp, bool isadd, std::string name) override {
        // Handle device changes
    }

    void onImEnabled(std::string uid, std::string sid) override {
        // IM is enabled
    }
};

class MyChannelHandler : public SMeeting::ISMeetingChannelEvent {
public:
    void onDisconnected(SMeeting::DisconnectReason reason,
                        SMeeting::StatusCode code,
                        std::string message) override {
        std::cout << "Disconnected: " << (int)code << std::endl;
    }

    void onUserEnter(std::string userdata) override {
        std::cout << "User entered: " << userdata << std::endl;
    }

    // Implement the other callbacks you need...
};

int main() {
    // Initialize the engine
    SMeeting::ISMeetingEngine* engine = nullptr;
    SMeeting::StatusCode ret = SMeeting::SMeetingEngine_Init(&engine);
    if (ret != SMeeting::StatusCode::OK) {
        return -1;
    }

    MyEngineHandler engine_handler;
    engine->setEventHandler(&engine_handler);

    // Log in
    std::string token = "your_token";
    engine->login(token, [&](SMeeting::StatusCode status, std::string msg) {
        if (status != SMeeting::StatusCode::OK) {
            return;
        }

        // Create a meeting
        SMeeting::SMeetingCreateMeetingModel model;
        model.title = "Test meeting";
        engine->createRoom(model, [&](SMeeting::StatusCode status, std::string roomno) {
            if (status != SMeeting::StatusCode::OK) {
                return;
            }

            // Create the channel object
            SMeeting::ISMeetingChannel* channel = nullptr;
            engine->createChannel(roomno, &channel);
            if (!channel) {
                return;
            }

            MyChannelHandler channel_handler;
            channel->setEventHandler(&channel_handler);

            // Enter the meeting
            channel->enter("", [&](SMeeting::StatusCode status, std::string msg) {
                if (status == SMeeting::StatusCode::OK) {
                    std::cout << "Entered the meeting" << std::endl;
                }
            });
        });
    });

    // Wait for the asynchronous operations to complete (a real app should have an event loop)
    std::this_thread::sleep_for(std::chrono::seconds(30));

    // Clean up
    engine->logout();
    engine->del();

    return 0;
}
```
