[refactor] migrate clients to unified MiniRTC APIs

This commit is contained in:
dijunkun
2026-11-07 00:41:25 +08:00
parent 1a12a1d7d5
commit 84466ccea4
39 changed files with 498 additions and 498 deletions
+34 -34
View File
@@ -50,8 +50,8 @@ struct CallbackContext { Session* owner; bool controller; };
struct Session {
jobject owner = nullptr;
jmethodID event_method, audio_method, frame_method;
PeerPtr* identity = nullptr;
PeerPtr* controller = nullptr;
MiniRtcPeerPtr* identity = nullptr;
MiniRtcPeerPtr* controller = nullptr;
CallbackContext identity_context{this, false}, controller_context{this, true};
std::string host, log_path, identity_login, controller_login, remote;
int port;
@@ -78,7 +78,7 @@ struct Session {
android_controller::FileTransferSession files{
[this](const char* stream, const char* data, size_t size) {
return controller && !stopping
? SendReliableDataFrame(controller, data, size, stream) : -1;
? MiniRtcSendReliableDataFrame(controller, data, size, stream) : -1;
},
[this](const std::string& name, double progress, bool sending, const std::string& path) {
Event(10, {{"name", name}, {"progress", progress}, {"sending", sending}, {"path", path}});
@@ -100,7 +100,7 @@ struct Session {
}
void Send(const char* stream, const std::string& data) {
if (controller && !stopping && !data.empty())
SendReliableDataFrame(controller, data.data(), data.size(), stream);
MiniRtcSendReliableDataFrame(controller, data.data(), data.size(), stream);
}
void Surface(JNIEnv* env, jobject surface) {
std::lock_guard<std::mutex> lock(render_mutex);
@@ -131,25 +131,25 @@ struct Session {
stopping = true;
renderer.Stop();
if (controller) {
LeaveConnection(controller, remote.c_str());
DestroyPeer(&controller);
MiniRtcLeaveConnection(controller, remote.c_str());
MiniRtcDestroyPeer(&controller);
}
if (identity) DestroyPeer(&identity);
if (identity) MiniRtcDestroyPeer(&identity);
Environment scope;
Surface(scope.env, nullptr);
if (scope.env) scope.env->DeleteGlobalRef(owner);
}
};
void Signal(SignalStatus status, const char*, size_t, void* user) {
void Signal(MiniRtcSignalStatus status, const char*, size_t, void* user) {
auto* ctx = static_cast<CallbackContext*>(user);
if (!ctx->controller && status == SignalStatus::SignalConnected &&
if (!ctx->controller && status == MiniRtcSignalStatus::MiniRtcSignalConnected &&
!ctx->owner->stopping && ctx->owner->identity) {
// Report after every identity login, including reconnects. The server
// ignores client_info sent through the temporary C- controller peer.
constexpr char info[] =
R"({"type":"client_info","version":"android-native","platform":"android"})";
SendSignalMessage(ctx->owner->identity, info, sizeof(info) - 1);
MiniRtcSendSignalMessage(ctx->owner->identity, info, sizeof(info) - 1);
}
if (!ctx->controller && ctx->owner->signal_status.exchange(status) != status)
++ctx->owner->signal_generation;
@@ -169,14 +169,14 @@ void SignalMessage(const char* data, size_t size, void* user) {
ctx->owner->Event(9, message);
}
}
void Connection(ConnectionStatus status, const char*, size_t, void* user) {
void Connection(MiniRtcConnectionStatus status, const char*, size_t, void* user) {
auto* ctx = static_cast<CallbackContext*>(user);
if (ctx->controller) ctx->owner->Event(2, {{"status", status}});
}
void Network(const char* id, size_t size, TraversalMode mode,
void Network(const char* id, size_t size, MiniRtcTraversalMode mode,
const MiniRtcNetTrafficStats* stats, const char*, size_t, void* user) {
auto* ctx = static_cast<CallbackContext*>(user);
if (!ctx->controller && mode == UnknownMode && id && size) {
if (!ctx->controller && mode == MiniRtcTraversalUnknown && id && size) {
ctx->owner->Event(3, id, size);
} else if (ctx->controller && stats) {
ctx->owner->Event(7, android_controller::NetworkReport(*stats, mode));
@@ -250,7 +250,7 @@ void RenderVideo(Session* s, VideoPicture picture) {
s->Event(5, {{"width", w}, {"height", h}});
}
// Measure through display submission, using MiniRTC's calibrated capture clock.
const auto now = GetSystemTimeMicros(s->controller);
const auto now = MiniRtcGetSystemTimeMicros(s->controller);
const double latency = android_controller::VideoLatencyMilliseconds(
picture.captured_us, picture.received_us, now);
Environment scope;
@@ -259,8 +259,8 @@ void RenderVideo(Session* s, VideoPicture picture) {
if (scope.env->ExceptionCheck()) scope.env->ExceptionClear();
}
}
Params Parameters(Session* s, bool controller) {
Params p{};
MiniRtcParams Parameters(Session* s, bool controller) {
MiniRtcParams p{};
std::snprintf(p.signal_server_ip, sizeof(p.signal_server_ip), "%s", s->host.c_str());
std::snprintf(p.log_path, sizeof(p.log_path), "%s", s->log_path.c_str());
p.signal_server_port = s->port;
@@ -268,12 +268,12 @@ Params Parameters(Session* s, bool controller) {
// MediaCodec returns retained Surface buffers; software fallback returns
// pooled CPU NV12 with the same ownership contract.
p.native_video_output = controller;
p.turn_mode = TurnAutoUdpTcp;
p.turn_mode = MiniRtcTurnAutoUdpTcp;
p.enable_srtp = true;
p.video_content_type = VideoContentType::ScreenContent;
p.video_quality = QualityMedium;
p.video_content_type = MiniRtcVideoContentType::ScreenContent;
p.video_quality = MiniRtcVideoQualityMedium;
p.video_frame_rate = 30;
p.video_degradation_preference = VideoDegradationPreference::Balanced;
p.video_degradation_preference = MiniRtcVideoDegradationPreference::Balanced;
p.on_signal_status = Signal; p.on_connection_status = Connection;
p.on_signal_message = SignalMessage;
p.on_net_status_report = Network; p.on_receive_data_buffer = Data;
@@ -344,8 +344,8 @@ extern "C" JNIEXPORT jlong JNICALL JNI_METHOD(nCreate)(
if (MiniRtcConfigureLogging(MiniRtcLogOff, nullptr, nullptr) != 0)
throw std::runtime_error("Unable to configure MiniRTC logging");
auto params = Parameters(s.get(), false);
s->identity = CreatePeer(&params);
if (!s->identity || Init(s->identity) != 0) return 0;
s->identity = MiniRtcCreatePeer(&params);
if (!s->identity || MiniRtcInit(s->identity) != 0) return 0;
return reinterpret_cast<jlong>(s.release());
} catch (const std::exception&) { return 0; }
}
@@ -356,15 +356,15 @@ extern "C" JNIEXPORT jboolean JNICALL JNI_METHOD(nConnect)(
s->controller_login = "C-" + String(env, identity);
s->remote = String(env, remote);
auto params = Parameters(s, true);
s->controller = CreatePeer(&params);
s->controller = MiniRtcCreatePeer(&params);
if (!s->controller) return false;
AddAudioStream(s->controller, kAudioStream);
AddDataStream(s->controller, kDataStream, false);
MiniRtcAddAudioStream(s->controller, kAudioStream);
MiniRtcAddDataStream(s->controller, kDataStream, false);
for (const char* name : {kMouseStream, kKeyboardStream, kControlStream,
kClipboardStream, kFileStream, kFileFeedbackStream}) AddDataStream(s->controller, name, true);
if (Init(s->controller) != 0) return false;
kClipboardStream, kFileStream, kFileFeedbackStream}) MiniRtcAddDataStream(s->controller, name, true);
if (MiniRtcInit(s->controller) != 0) return false;
const auto join = s->remote + "@" + String(env, password);
return JoinConnection(s->controller, join.c_str()) == 0;
return MiniRtcJoinConnection(s->controller, join.c_str()) == 0;
}
extern "C" JNIEXPORT void JNICALL JNI_METHOD(nReady)(JNIEnv*, jclass, jlong handle) {
auto* s = From(handle); if (!s || !s->controller) return;
@@ -420,13 +420,13 @@ extern "C" JNIEXPORT jboolean JNICALL JNI_METHOD(nVideoSettings)(
if (!s || !s->controller || s->stopping || request_id < 0 || request_id > UINT32_MAX) return false;
const auto data = android_controller::VideoSettingsMessage(quality, rate, preference, static_cast<uint32_t>(request_id));
if (data.empty()) return false;
return SendReliableDataFrame(s->controller, data.data(), data.size(), kControlStream) == 0;
return MiniRtcSendReliableDataFrame(s->controller, data.data(), data.size(), kControlStream) == 0;
}
extern "C" JNIEXPORT jboolean JNICALL JNI_METHOD(nSecureAttention)(JNIEnv*, jclass, jlong handle) {
auto* s = From(handle);
if (!s || !s->controller || s->stopping) return false;
const auto data = android_controller::SecureAttentionMessage();
return SendReliableDataFrame(s->controller, data.data(), data.size(), kControlStream) == 0;
return MiniRtcSendReliableDataFrame(s->controller, data.data(), data.size(), kControlStream) == 0;
}
extern "C" JNIEXPORT jboolean JNICALL JNI_METHOD(nPrivacy)(
JNIEnv*, jclass, jlong handle, jint flag, jboolean block_input) {
@@ -434,7 +434,7 @@ extern "C" JNIEXPORT jboolean JNICALL JNI_METHOD(nPrivacy)(
if (!s || !s->controller || s->stopping) return false;
const auto data = android_controller::PrivacyMessage(flag, block_input);
return !data.empty() &&
SendReliableDataFrame(s->controller, data.data(), data.size(), kControlStream) == 0;
MiniRtcSendReliableDataFrame(s->controller, data.data(), data.size(), kControlStream) == 0;
}
extern "C" JNIEXPORT void JNICALL JNI_METHOD(nFileDirectory)(JNIEnv* env, jclass, jlong handle, jstring directory) {
auto* s = From(handle); if (s) s->files.SetDirectory(String(env, directory));
@@ -466,7 +466,7 @@ extern "C" JNIEXPORT jboolean JNICALL JNI_METHOD(nAnnouncementRequest)(
auto message = json::parse(bytes, nullptr, false);
if (!message.is_object() || !message.contains("type") ||
!message["type"].is_string() || message["type"] != "announcements_list") return false;
return SendSignalMessage(s->identity, bytes.data(), bytes.size()) == 0;
return MiniRtcSendSignalMessage(s->identity, bytes.data(), bytes.size()) == 0;
}
extern "C" JNIEXPORT jboolean JNICALL JNI_METHOD(nPresenceRequest)(
JNIEnv* env, jclass, jlong handle, jbyteArray data) {
@@ -483,7 +483,7 @@ extern "C" JNIEXPORT jboolean JNICALL JNI_METHOD(nPresenceRequest)(
!message.contains("user_id") || !message["user_id"].is_string() ||
!message.contains("devices") || !message["devices"].is_array() ||
!message.contains("subscribe") || message["subscribe"] != true) return false;
return SendSignalMessage(s->identity, bytes.data(), bytes.size()) == 0;
return MiniRtcSendSignalMessage(s->identity, bytes.data(), bytes.size()) == 0;
}
extern "C" JNIEXPORT void JNICALL JNI_METHOD(nClipboard)(
JNIEnv* env, jclass, jlong handle, jbyteArray data) {
@@ -498,7 +498,7 @@ extern "C" JNIEXPORT void JNICALL JNI_METHOD(nSurface)(JNIEnv* env, jclass, jlon
if (auto* s = From(handle)) {
s->Surface(env, surface);
if (surface && s->controller && !s->stopping)
RequestVideoKeyFrame(s->controller, MakeDisplayStreamId(s->display.load()).c_str());
MiniRtcRequestVideoKeyFrame(s->controller, MakeDisplayStreamId(s->display.load()).c_str());
}
}
extern "C" JNIEXPORT void JNICALL JNI_METHOD(nDestroy)(JNIEnv*, jclass, jlong handle) { delete From(handle); }
@@ -27,13 +27,13 @@ int main() {
stats.data_inbound_stats.bitrate = 2000; stats.data_outbound_stats.bitrate = 3000;
stats.total_inbound_stats.bitrate = UINT32_MAX; stats.total_outbound_stats.bitrate = 131'000;
stats.total_inbound_stats.loss_rate = 1.2f; stats.rtt_ms = 40; stats.srtp_active = true;
auto json = android_controller::NetworkReport(stats, Relay);
auto json = android_controller::NetworkReport(stats, MiniRtcTraversalRelay);
assert(json.at("mode") == 1 && json.at("srtp") == true && json.at("rtt") == 40);
assert(json.at("video").at("inbound") == 8'000'000 && json.at("audio").at("outbound") == 128'000);
assert(json.at("data").at("inbound") == 2000 && json.at("data").at("outbound") == 3000);
assert(json.at("total").at("inbound").get<uint32_t>() == UINT32_MAX);
assert(std::abs(json.at("total").at("loss").get<double>() - 1.2) < .001);
stats.rtt_ms = -1; stats.srtp_active = false;
json = android_controller::NetworkReport(stats, UnknownMode);
json = android_controller::NetworkReport(stats, MiniRtcTraversalUnknown);
assert(json.at("mode") == 2 && json.at("srtp") == false && json.at("rtt") == -1);
}
+2 -2
View File
@@ -44,7 +44,7 @@ The output queue is bounded to 64 messages and 8 MiB; a blocked output pipe term
`connect` returns immediately after initiating transport. Poll `status` until `state == "ready"`; this requires a frame from the current display generation. Status includes `transport_state`, `geometry_epoch`, `frame_age_ms`, `source_size`, `control_allowed`, `human_paused`, host platform, displays and transport diagnostics.
During initial `registering`, `SignalReconnecting` keeps the existing signaling peer and its backoff worker alive within the original 30-second connection deadline. Expiry in that phase reports `signaling_timeout`; expiry after submitting a device join reports `connection_timeout`. Certificate validation and login rejection terminate the attempt immediately. A signaling interruption after join submission also terminates the attempt. Explicit cancellation closes the peer and its retry worker. The MCP adapter forwards recognized status errors as an optional `error.reason` alongside its public error category.
During initial `registering`, `MiniRtcSignalReconnecting` keeps the existing signaling peer and its backoff worker alive within the original 30-second connection deadline. Expiry in that phase reports `signaling_timeout`; expiry after submitting a device join reports `connection_timeout`. Certificate validation and login rejection terminate the attempt immediately. A signaling interruption after join submission also terminates the attempt. Explicit cancellation closes the peer and its retry worker. The MCP adapter forwards recognized status errors as an optional `error.reason` alongside its public error category.
## Live video
@@ -87,7 +87,7 @@ NV12 retains one latest picture in the I/O handoff and at most one unacknowledge
`status.video_output` includes `transport`, `viewers`, I/O handoff `queued` / `queued_bytes`, aggregate `unacknowledged_bytes`, and `dropped` (handoff replacements plus per-viewer congestion skips). These diagnostics contain no video payload. The original receive-tap SPS/PPS and keyframe state remain available for H.264.
The MiniRTC `Params` structure appends `on_receive_encoded_video`, changing its ABI size. Rebuild consumers and MiniRTC together; zero-initialize `Params`. The callback borrows frame bytes on the receive/decode queue and must not retain the pointer. Returning nonzero requests a remote keyframe. No remote wire-protocol change is required.
The MiniRTC `MiniRtcParams` structure appends `on_receive_encoded_video`, changing its ABI size. Rebuild consumers and MiniRTC together; zero-initialize `MiniRtcParams`. The callback borrows frame bytes on the receive/decode queue and must not retain the pointer. Returning nonzero requests a remote keyframe. No remote wire-protocol change is required.
## Images and observations
+1 -1
View File
@@ -7,7 +7,7 @@ CLI 从独立开发目录整合到 CrossDesk,入口、打包脚本、npm 启
- `ControllerSession` 的流名称、HostInformation 和输入参考 Android `rtc_bridge.cpp`;身份使用单 Peer 的 `cli` 临时注册协议;终端适配不依赖 JNI、Surface 或 GuiRuntime。
- 帧缓存遵守 `MiniRtcVideoFrame` 回调借用契约,直接复制到有界 CPU 存储,不跨回调保留 native 指针。
- PreviewSubscription 复用 wire 实现与对端 capability 字段,不新增被控端协议。
- MCP 实时面板新增 MiniRTC 的 `on_receive_encoded_video` 回调,转发解码前的完整 H.264 Annex B 帧;回调及关键帧请求由当前子模块源码提供。`Params` 新增字段改变 ABI 大小,CLI 与 MiniRTC 必须一起重建;发布时同步记录包含该改动的子模块提交。
- MCP 实时面板新增 MiniRTC 的 `on_receive_encoded_video` 回调,转发解码前的完整 H.264 Annex B 帧;回调及关键帧请求由当前子模块源码提供。`MiniRtcParams` 新增字段改变 ABI 大小,CLI 与 MiniRTC 必须一起重建;发布时同步记录包含该改动的子模块提交。
- 自动化图像编码复用 MiniRTC 已有的 libyuv 2025.8.14,并通过 Xmake 固定静态 libpng v1.6.59;libpng 的压缩依赖沿用平台 zlib。新增依赖的许可证和对应源码也应纳入正式发行的依赖材料。
MiniRTC 已在提交 `b9ee1fa7fe038fdf771f5dec1b1d561d78273f15` 中合入凭据日志脱敏:Join、排队 Join、取消 Join、Leave 四个日志点只记录 `@` 前的 ID,不记录密码。`apps/cli/scripts/prepare-deps.sh` 仅按主仓库记录初始化子模块,不再应用独立补丁;更新 MiniRTC 时只需更新子模块提交。共享子模块中的脱敏同样适用于桌面程序;该修改没有改变鉴权、TLS、TURN 或媒体协议。
+2 -2
View File
@@ -35,9 +35,9 @@ crossdesk-cli 123456789 --server your-server.example --port 9099
需先部署支持 `cli` 注册的新版 crossdesk-server;旧服务端会登录失败,本客户端不会回退为普通设备身份。桥接 `status.client_id` 返回服务端分配的 ID。
流程为创建主控 Peer、注册流 → 以 `cli` 注册 → SignalConnected 返回 `cli-xxxxxxxxx` → Join → Connected → 现有 HostInformation 握手 → 显示器选择、能力协商 → 视频。Init 返回 0 不是远端连接成功。连接总超时默认 30 秒;信令断开后结束本次会话,用户重新连接,不自动循环重试密码。
流程为创建主控 Peer、注册流 → 以 `cli` 注册 → SignalConnected 返回 `cli-xxxxxxxxx` → Join → Connected → 现有 HostInformation 握手 → 显示器选择、能力协商 → 视频。MiniRtcInit 返回 0 不是远端连接成功。连接总超时默认 30 秒;信令断开后结束本次会话,用户重新连接,不自动循环重试密码。
交互界面区分 `Connecting to server`(连接信令)、`Connecting to device`(连接设备)、`Connected, waiting for first frame`(已连接,等待首帧)和 `Displaying`(正在显示)。首帧前显示居中的等待提示及秒数;连接阶段从发起连接计时,首帧等待阶段从连接成功重新计时。首帧完整写入终端后才切换到 `Displaying` 并清除等待提示。已连接但暂时没有画面不会因此判为连接失败,也不代表中继未启用。状态栏右侧为接收视频码率,收到网络统计后显示 `P2P` 或 `RELAY`,码率按 bps、kbps、Mbps 显示;初始码率为零或很低时仍继续等待视频。
交互界面区分 `MiniRtcConnectionConnecting to server`(连接信令)、`MiniRtcConnectionConnecting to device`(连接设备)、`MiniRtcConnectionConnected, waiting for first frame`(已连接,等待首帧)和 `Displaying`(正在显示)。首帧前显示居中的等待提示及秒数;连接阶段从发起连接计时,首帧等待阶段从连接成功重新计时。首帧完整写入终端后才切换到 `Displaying` 并清除等待提示。已连接但暂时没有画面不会因此判为连接失败,也不代表中继未启用。状态栏右侧为接收视频码率,收到网络统计后显示 `MiniRtcTraversalP2P` 或 `RELAY`,码率按 bps、kbps、Mbps 显示;初始码率为零或很低时仍继续等待视频。
保留 MiniRTC WSS 证书链与主机名验证、TURN 临时凭据下发及 SRTP 协商。未提供跳过证书检查的参数。SRTP 是否实际协商成功通过状态统计呈现;沿用现有 MiniRTC 对旧端的兼容性,不宣称所有旧端必然启用 SRTP。自建证书问题应修复证书/系统信任链。
+2 -2
View File
@@ -617,8 +617,8 @@ int View(SessionOptions options, const std::string &device,
const auto bps = st["network"]["video_bps"].get<uint64_t>();
const auto traversal = st["network"]["traversal"].get<int>();
bar.network =
std::string(traversal == P2P ? "P2P "
: traversal == Relay ? "RELAY "
std::string(traversal == MiniRtcTraversalP2P ? "P2P "
: traversal == MiniRtcTraversalRelay ? "RELAY "
: "Video ") +
(bps < 1000 ? std::to_string(bps) + " bps"
: bps < 1000000 ? std::to_string(bps / 1000) + " kbps"
@@ -495,25 +495,25 @@ std::optional<int> ParsePort(const slint::SharedString& text) {
return port;
}
std::string ConnectionStatusText(ConnectionStatus status, int language) {
std::string ConnectionStatusText(MiniRtcConnectionStatus status, int language) {
switch (status) {
case ConnectionStatus::Connected:
case MiniRtcConnectionStatus::MiniRtcConnectionConnected:
return localization::p2p_connected[language];
case ConnectionStatus::Connecting:
case MiniRtcConnectionStatus::MiniRtcConnectionConnecting:
return localization::p2p_connecting[language];
case ConnectionStatus::Gathering:
case MiniRtcConnectionStatus::MiniRtcConnectionGathering:
return localization::p2p_gathering[language];
case ConnectionStatus::Disconnected:
case MiniRtcConnectionStatus::MiniRtcConnectionDisconnected:
return localization::p2p_disconnected[language];
case ConnectionStatus::NoSuchTransmissionId:
case MiniRtcConnectionStatus::MiniRtcConnectionNoSuchTransmissionId:
return localization::no_such_id[language];
case ConnectionStatus::IncorrectPassword:
case MiniRtcConnectionStatus::MiniRtcConnectionIncorrectPassword:
return localization::reinput_password[language];
case ConnectionStatus::Closed:
case MiniRtcConnectionStatus::MiniRtcConnectionClosed:
return localization::p2p_closed[language];
case ConnectionStatus::RemoteUnavailable:
case MiniRtcConnectionStatus::MiniRtcConnectionRemoteUnavailable:
return localization::device_offline[language];
case ConnectionStatus::Failed:
case MiniRtcConnectionStatus::MiniRtcConnectionFailed:
default:
return localization::p2p_failed[language];
}
@@ -1913,7 +1913,7 @@ void GuiApplication::BindMainCallbacks(bool gallery_window) {
main->on_recent_disconnect([this](slint::SharedString id) {
const std::string remote_id(id);
if (auto props = FindRemoteSession(remote_id);
props && props->connection_status_ == ConnectionStatus::Connected &&
props && props->connection_status_ == MiniRtcConnectionStatus::MiniRtcConnectionConnected &&
!props->closing_) {
CloseStreamTab(props->remote_id_);
SyncMainWindow();
@@ -2057,9 +2057,9 @@ void GuiApplication::BindMainCallbacks(bool gallery_window) {
main->on_connection_acknowledge([this] {
const auto props = FindRemoteSession(ui_->connection_dialog_remote_id);
if (props) {
const ConnectionStatus status = props->connection_status_.load();
if (status == ConnectionStatus::NoSuchTransmissionId ||
status == ConnectionStatus::RemoteUnavailable) {
const MiniRtcConnectionStatus status = props->connection_status_.load();
if (status == MiniRtcConnectionStatus::MiniRtcConnectionNoSuchTransmissionId ||
status == MiniRtcConnectionStatus::MiniRtcConnectionRemoteUnavailable) {
CloseStreamTab(props->remote_id_);
re_enter_remote_id_ = true;
}
@@ -2216,13 +2216,13 @@ void GuiApplication::BindStreamCallbacks() {
action.type = ControlType::display_id;
action.d = index;
const std::string message = action.to_json();
SendReliableDataFrame(props->peer_, message.c_str(), message.size(),
MiniRtcSendReliableDataFrame(props->peer_, message.c_str(), message.size(),
props->control_data_label_.c_str());
});
stream->on_send_shortcut([this](slint::SharedString shortcut) {
auto props = SelectedSession();
if (!props || !props->peer_ || !props->control_mouse_ ||
props->connection_status_.load() != ConnectionStatus::Connected) {
props->connection_status_.load() != MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
return;
}
const std::string name(shortcut);
@@ -2237,13 +2237,13 @@ void GuiApplication::BindStreamCallbacks() {
? ServiceCommandFlag::send_sas
: ServiceCommandFlag::lock_workstation;
const std::string message = action.to_json();
SendReliableDataFrame(props->peer_, message.c_str(), message.size(),
MiniRtcSendReliableDataFrame(props->peer_, message.c_str(), message.size(),
props->control_data_label_.c_str());
});
const auto send_privacy = [this](bool relock) {
auto props = SelectedSession();
if (!props || !props->peer_ || (!relock && !props->control_mouse_) ||
props->connection_status_.load() != ConnectionStatus::Connected) return;
props->connection_status_.load() != MiniRtcConnectionStatus::MiniRtcConnectionConnected) return;
RemoteAction action{};
action.type = ControlType::privacy_command;
{
@@ -2265,7 +2265,7 @@ void GuiApplication::BindStreamCallbacks() {
props->privacy_request_revision_ = status.revision;
}
const auto message = action.to_json();
if (SendReliableDataFrame(props->peer_, message.data(), message.size(),
if (MiniRtcSendReliableDataFrame(props->peer_, message.data(), message.size(),
props->control_data_label_.c_str()) != 0) {
std::lock_guard lock(props->privacy_status_mutex_);
props->privacy_command_pending_ = false;
@@ -2295,7 +2295,7 @@ void GuiApplication::BindStreamCallbacks() {
int preference) {
auto props = SelectedSession();
if (!props || !props->peer_ ||
props->connection_status_.load() != ConnectionStatus::Connected)
props->connection_status_.load() != MiniRtcConnectionStatus::MiniRtcConnectionConnected)
return;
RemoteAction action{};
action.type = ControlType::video_settings;
@@ -2308,7 +2308,7 @@ void GuiApplication::BindStreamCallbacks() {
if (!props->video_settings_supported_) return;
action.vs.request_id = props->video_settings_.request_id + 1;
const auto message = action.to_json();
if (SendReliableDataFrame(props->peer_, message.data(), message.size(),
if (MiniRtcSendReliableDataFrame(props->peer_, message.data(), message.size(),
props->control_data_label_.c_str()) != 0)
return;
props->video_settings_ = action.vs;
@@ -2773,7 +2773,7 @@ void GuiApplication::ShareLocalCursorState() {
std::shared_lock lock(connection_status_mutex_);
connected_controllers.reserve(connection_status_.size());
for (const auto& [remote_id, status] : connection_status_) {
if (status == ConnectionStatus::Connected) {
if (status == MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
connected_controllers.push_back(remote_id);
}
}
@@ -2997,7 +2997,7 @@ bool GuiApplication::RequestPasswordChange(const std::string &password) {
{"request_id", request_id},
{"new_password", password}};
const std::string message = request.dump();
if (SendSignalMessage(peer_, message.data(), message.size()) != 0) {
if (MiniRtcSendSignalMessage(peer_, message.data(), message.size()) != 0) {
{
std::lock_guard<std::mutex> lock(password_change_mutex_);
password_change_pending_ = false;
@@ -3128,7 +3128,7 @@ void GuiApplication::HandleCredentialRecovery() {
}
const auto message = nlohmann::json{{"type", "change_password"},
{"request_id", request_id}, {"new_password", password}}.dump();
if (SendSignalMessage(peer_, message.data(), message.size()) != 0) {
if (MiniRtcSendSignalMessage(peer_, message.data(), message.size()) != 0) {
std::lock_guard lock(password_change_mutex_);
password_change_result_ready_ = true;
password_change_result_uncertain_ = true;
@@ -3204,7 +3204,7 @@ void GuiApplication::SyncAnnouncements() {
const auto request = announcements_.TakePendingRequest();
if (!request.is_null()) {
const auto payload = request.dump();
if (!peer_ || SendSignalMessage(peer_, payload.data(), payload.size()) != 0)
if (!peer_ || MiniRtcSendSignalMessage(peer_, payload.data(), payload.size()) != 0)
announcements_.Failed(request["request_id"]);
}
if (ui_->announcement_version == announcements_.Version()) return;
@@ -3315,7 +3315,7 @@ void GuiApplication::SyncMainWindow() {
main->set_signal_connected(signal_online);
main->set_signal_reconnecting(signal_reconnecting);
main->set_signal_tls_error(signal_status_ ==
SignalStatus::SignalTlsCertError);
MiniRtcSignalStatus::MiniRtcSignalTlsCertError);
main->set_update_available(update_available_);
switch (update_checker_->status()) {
case UpdateChecker::Status::Idle:
@@ -3389,7 +3389,7 @@ void GuiApplication::SyncMainWindow() {
}
const auto is_connected = [this](const std::string& id) {
const auto props = FindRemoteSession(id);
return props && props->connection_status_ == ConnectionStatus::Connected &&
return props && props->connection_status_ == MiniRtcConnectionStatus::MiniRtcConnectionConnected &&
!props->closing_;
};
const auto preview_size = ui_->recent_preview_resolution.Update(
@@ -3512,8 +3512,8 @@ void GuiApplication::SyncConnectionDialog() {
ui_->connection_password_initialized = false;
}
ui_->connection_dialog_remote_id = props->remote_id_;
const ConnectionStatus status = props->connection_status_.load();
if (status == ConnectionStatus::Connected && !ui_->gallery_auth_id.empty()) {
const MiniRtcConnectionStatus status = props->connection_status_.load();
if (status == MiniRtcConnectionStatus::MiniRtcConnectionConnected && !ui_->gallery_auth_id.empty()) {
ui_->gallery_auth_id.clear();
show_connection_status_window_ = false;
ui_->main->set_connection_dialog_open(false);
@@ -3522,9 +3522,9 @@ void GuiApplication::SyncConnectionDialog() {
}
const auto auth = props->connection_auth_.Get();
const bool password_required = auth.password_required ||
(status == ConnectionStatus::IncorrectPassword && auth.validating);
(status == MiniRtcConnectionStatus::MiniRtcConnectionIncorrectPassword && auth.validating);
const bool pending = !password_required &&
(status == ConnectionStatus::Connecting || status == ConnectionStatus::Gathering);
(status == MiniRtcConnectionStatus::MiniRtcConnectionConnecting || status == MiniRtcConnectionStatus::MiniRtcConnectionGathering);
std::string text;
if (password_required) {
text = auth.validating
@@ -3855,7 +3855,7 @@ void GuiApplication::SyncStreamWindow() {
tab.title = UiText(
props->remote_host_name_.empty() ? id : props->remote_host_name_);
tab.connected =
props->connection_status_.load() == ConnectionStatus::Connected;
props->connection_status_.load() == MiniRtcConnectionStatus::MiniRtcConnectionConnected;
tabs_by_id.emplace(id, std::move(tab));
}
}
@@ -3905,10 +3905,10 @@ void GuiApplication::SyncStreamWindow() {
if (!props) {
return;
}
const ConnectionStatus status = props->connection_status_.load();
const MiniRtcConnectionStatus status = props->connection_status_.load();
bool remote_update_available = false;
HostPlatform remote_platform = HostPlatform::Unknown;
if (status == ConnectionStatus::Connected) {
if (status == MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
std::lock_guard lock(props->remote_version_mutex_);
remote_platform = props->remote_platform_;
// Wait for host_info: a version still in transit is not a legacy peer.
@@ -3925,14 +3925,14 @@ void GuiApplication::SyncStreamWindow() {
SetStreamKeyboardFocus(false);
}
const bool waiting_for_frame =
status == ConnectionStatus::Connected &&
status == MiniRtcConnectionStatus::MiniRtcConnectionConnected &&
!(*ui_->stream)->get_has_frame();
// Once the peer is connected, the frame-waiting hint replaces the
// connection status. Keeping these states mutually exclusive also avoids a
// transient overlap when both properties are synchronized in one tick.
(*ui_->stream)
->set_status_text(UiText(
status == ConnectionStatus::Connected
status == MiniRtcConnectionStatus::MiniRtcConnectionConnected
? std::string{}
: ConnectionStatusText(status, localization_language_index_)));
(*ui_->stream)
@@ -3949,7 +3949,7 @@ void GuiApplication::SyncStreamWindow() {
status, props->privacy_status_received_, props->privacy_command_pending_,
now - props->privacy_status_tick_, now - props->privacy_command_tick_);
const bool connected =
props->connection_status_.load() == ConnectionStatus::Connected;
props->connection_status_.load() == MiniRtcConnectionStatus::MiniRtcConnectionConnected;
(*ui_->stream)->set_privacy_unlock_visible(connected && props->privacy_unlock_notice_);
(*ui_->stream)->set_privacy_can_lock(connected && props->privacy_desktop_available_ &&
props->privacy_status_received_ && status.supported &&
@@ -3977,7 +3977,7 @@ void GuiApplication::SyncStreamWindow() {
{
std::lock_guard lock(props->remote_cursor_state_mutex_);
remote_cursor_active =
status == ConnectionStatus::Connected && props->control_mouse_ &&
status == MiniRtcConnectionStatus::MiniRtcConnectionConnected && props->control_mouse_ &&
props->remote_cursor_state_received_;
if (remote_cursor_active) {
remote_cursor_shape = static_cast<int>(
@@ -3998,7 +3998,7 @@ void GuiApplication::SyncStreamWindow() {
props->video_settings_.request_id = request_id;
}
(*ui_->stream)
->set_video_settings_enabled(status == ConnectionStatus::Connected &&
->set_video_settings_enabled(status == MiniRtcConnectionStatus::MiniRtcConnectionConnected &&
props->video_settings_supported_);
(*ui_->stream)
->set_video_settings_feedback(UiText(
@@ -4035,13 +4035,13 @@ void GuiApplication::SyncStreamWindow() {
const auto net = props->net_traffic_stats_.Load();
const auto codecs = props->net_traffic_stats_.LoadVideoCodecs();
(*ui_->stream)->set_stats_encoder(UiText(
status == ConnectionStatus::Connected && !codecs.remote_encoder.empty()
status == MiniRtcConnectionStatus::MiniRtcConnectionConnected && !codecs.remote_encoder.empty()
? codecs.remote_encoder : "—"));
(*ui_->stream)->set_stats_decoder(UiText(
status == ConnectionStatus::Connected && !codecs.local_decoder.empty()
status == MiniRtcConnectionStatus::MiniRtcConnectionConnected && !codecs.local_decoder.empty()
? codecs.local_decoder : "—"));
(*ui_->stream)->set_stats_encryption_enabled(
status == ConnectionStatus::Connected && net.srtp_active);
status == MiniRtcConnectionStatus::MiniRtcConnectionConnected && net.srtp_active);
std::vector<ui::NetworkStatsRow> stats_rows;
stats_rows.reserve(4);
const auto append_stats_row = [&](const std::string& label,
@@ -4067,7 +4067,7 @@ void GuiApplication::SyncStreamWindow() {
props->video_height_)));
(*ui_->stream)
->set_stats_connection_mode(
UiText(props->traversal_mode_ == TraversalMode::P2P
UiText(props->traversal_mode_ == MiniRtcTraversalMode::MiniRtcTraversalP2P
? localization::connection_mode_direct
[localization_language_index_]
: localization::connection_mode_relay
@@ -4095,7 +4095,7 @@ void GuiApplication::SyncStreamWindow() {
}
(*ui_->stream)->set_stats_fps(UiText(std::to_string(props->fps_)));
if (!props->net_traffic_stats_button_pressed_ ||
status != ConnectionStatus::Connected) {
status != MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
props->video_latency_snapshot_.reset();
} else if (refresh_stats) {
props->video_latency_snapshot_ = props->video_latency_->Get(fps_now);
@@ -4109,7 +4109,7 @@ void GuiApplication::SyncStreamWindow() {
: "—"));
const auto display_rtt = props->net_traffic_stats_.SmoothedRttMs(fps_now);
const bool rtt_available = props->net_traffic_stats_button_pressed_ &&
status == ConnectionStatus::Connected &&
status == MiniRtcConnectionStatus::MiniRtcConnectionConnected &&
display_rtt.has_value();
std::string connection_latency = "—";
if (rtt_available) {
@@ -4119,7 +4119,7 @@ void GuiApplication::SyncStreamWindow() {
: std::to_string(static_cast<int>(std::lround(*display_rtt))) + " ms";
}
(*ui_->stream)->set_stats_connection_latency(UiText(connection_latency));
if (refresh_stats && status == ConnectionStatus::Connected) {
if (refresh_stats && status == MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
LOG_DEBUG("Latency stats: remote={} video_ms={} video_samples={} "
"rtt_raw_ms={} rtt_display_ms={}",
props->remote_id_, latency ? latency->average_ms : -1,
@@ -4416,7 +4416,7 @@ void GuiApplication::SyncServerWindow() {
has_connected_controller =
std::any_of(connection_status_.begin(), connection_status_.end(),
[](const auto& entry) {
return entry.second == ConnectionStatus::Connected;
return entry.second == MiniRtcConnectionStatus::MiniRtcConnectionConnected;
});
}
@@ -4478,7 +4478,7 @@ void GuiApplication::SyncServerWindow() {
std::shared_lock lock(connection_status_mutex_);
controllers.reserve(connection_status_.size());
for (const auto& [id, status] : connection_status_) {
if (status != ConnectionStatus::Connected) continue;
if (status != MiniRtcConnectionStatus::MiniRtcConnectionConnected) continue;
const auto host = connection_host_names_.find(id);
const std::string name =
host != connection_host_names_.end() && !host->second.empty()
@@ -5033,12 +5033,12 @@ void GuiApplication::ApplySettingsFromConfig(bool reconnect) {
} else {
const bool av1 = config_center_->GetVideoEncodeFormat() ==
ConfigCenter::VIDEO_ENCODE_FORMAT::AV1;
const auto turn = static_cast<TurnMode>(config_center_->GetTurnMode());
const auto turn = static_cast<MiniRtcTurnMode>(config_center_->GetTurnMode());
if (av1 != params_.av1_encoding || turn != params_.turn_mode) {
// Update the listening peer for incoming connections and the template
// copied by ConnectTo for outgoing connections. Existing sessions retain
// the codec/ICE snapshot with which they negotiated.
if (!peer_ || UpdateConnectionSettings(peer_, true, av1, turn) == 0) {
if (!peer_ || MiniRtcUpdateConnectionSettings(peer_, true, av1, turn) == 0) {
params_.av1_encoding = av1;
params_.turn_mode = turn;
} else {
@@ -5139,7 +5139,7 @@ void GuiApplication::SelectStreamTab(int index) {
start_keyboard_capturer_ = selected_session &&
selected_session->control_mouse_ &&
selected_session->connection_status_.load() ==
ConnectionStatus::Connected;
MiniRtcConnectionStatus::MiniRtcConnectionConnected;
}
if (clipboard_resumed) {
// Flush a copy made in another local app before the next paste shortcut,
@@ -5366,7 +5366,7 @@ void GuiApplication::SendKeyInput(const std::string& text, bool pressed,
(void)meta;
auto props = SelectedSession();
if (!props || !props->peer_ || !props->control_mouse_ ||
props->connection_status_.load() != ConnectionStatus::Connected) {
props->connection_status_.load() != MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
return;
}
@@ -5423,7 +5423,7 @@ void GuiApplication::SyncAudioPlayback() {
std::shared_lock lock(remote_sessions_mutex_);
for (const auto& [id, props] : remote_sessions_) {
const bool allowed = !props->closing_ &&
props->connection_status_ == ConnectionStatus::Connected &&
props->connection_status_ == MiniRtcConnectionStatus::MiniRtcConnectionConnected &&
props->audio_capture_button_pressed_ &&
((wall_visible && props->wall_managed_) ||
(stream_active && props->tab_opened_ && props->tab_selected_));
@@ -5898,7 +5898,7 @@ void GuiApplication::GalleryAction(const std::string& action,
auto props = FindRemoteSession(value);
if (value != ui_->gallery_focus || !props || !props->peer_ ||
props->closing_ ||
props->connection_status_ != ConnectionStatus::Connected)
props->connection_status_ != MiniRtcConnectionStatus::MiniRtcConnectionConnected)
return;
{
std::lock_guard lock(props->gallery_frame_mutex_);
@@ -5955,7 +5955,7 @@ void GuiApplication::GalleryAction(const std::string& action,
for (const auto& id : ids) {
if (auto props = FindRemoteSession(id);
props && !props->closing_ &&
props->connection_status_ == ConnectionStatus::Connected) {
props->connection_status_ == MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
if (action == "mute") {
MuteRemoteAudio(props);
} else {
@@ -6236,7 +6236,7 @@ void GuiApplication::SyncGallery() {
// control. Followers can report different shapes without replacing it.
auto controlled = FindRemoteSession(ui_->gallery_control_id);
if (!visible || !controlled || controlled->closing_ ||
controlled->connection_status_ != ConnectionStatus::Connected) {
controlled->connection_status_ != MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
ReleaseControl();
} else {
HostPlatform platform;
@@ -6330,7 +6330,7 @@ void GuiApplication::SyncGallery() {
std::shared_lock lock(remote_sessions_mutex_);
for (const auto& [id, props] : remote_sessions_)
if (props && !props->lan_session_ && !props->closing_ &&
props->connection_status_ == ConnectionStatus::Connected)
props->connection_status_ == MiniRtcConnectionStatus::MiniRtcConnectionConnected)
connected_ids.push_back(id);
}
std::sort(connected_ids.begin(), connected_ids.end());
@@ -6338,15 +6338,15 @@ void GuiApplication::SyncGallery() {
for (const auto& id : connected_ids) {
const auto props = FindRemoteSession(id);
if (!props || props->closing_ ||
props->connection_status_ != ConnectionStatus::Connected)
props->connection_status_ != MiniRtcConnectionStatus::MiniRtcConnectionConnected)
continue;
ui::GalleryNetworkDevice device{};
device.name = UiText(name(id));
device.id = UiText(FormatPeerId(id.c_str()));
const auto mode = props->traversal_mode_.load();
device.mode = UiText(mode == TraversalMode::P2P
device.mode = UiText(mode == MiniRtcTraversalMode::MiniRtcTraversalP2P
? tr("直连")
: mode == TraversalMode::UnknownMode
: mode == MiniRtcTraversalMode::MiniRtcTraversalUnknown
? tr("等待统计")
: tr("中继"));
device.inbound = device.outbound = device.loss = "—";
@@ -6374,7 +6374,7 @@ void GuiApplication::SyncGallery() {
// Missing/stale reports cannot confirm either encrypted or plaintext.
device.encryption_known = has_report;
device.encryption_enabled = has_report && stats.srtp_active;
if (mode != TraversalMode::UnknownMode && has_report) {
if (mode != MiniRtcTraversalMode::MiniRtcTraversalUnknown && has_report) {
device.inbound = UiText(FormatBitrate(stats.total_inbound_stats.bitrate));
device.outbound = UiText(FormatBitrate(stats.total_outbound_stats.bitrate));
// MiniRTC's total loss is a sum of media fractions, not an aggregate.
@@ -6416,14 +6416,14 @@ void GuiApplication::SyncGallery() {
MuteRemoteAudio(props);
}
const auto status = props ? props->connection_status_.load()
: ConnectionStatus::Closed;
: MiniRtcConnectionStatus::MiniRtcConnectionClosed;
const bool usable = props && props->peer_ && !props->closing_;
const bool connecting = usable &&
(status == ConnectionStatus::Connecting ||
status == ConnectionStatus::Gathering);
(status == MiniRtcConnectionStatus::MiniRtcConnectionConnecting ||
status == MiniRtcConnectionStatus::MiniRtcConnectionGathering);
if (!signal_connected_)
operation.state = OperationState::Finished;
else if (!(usable && status == ConnectionStatus::Connected) &&
else if (!(usable && status == MiniRtcConnectionStatus::MiniRtcConnectionConnected) &&
(!connecting || operation.password)) {
std::string password = operation.password.value_or("");
bool remember = operation.remember_password;
@@ -6449,7 +6449,7 @@ void GuiApplication::SyncGallery() {
operation.password.reset();
}
} else if (!props || !props->peer_ ||
props->connection_status_ != ConnectionStatus::Connected) {
props->connection_status_ != MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
operation.state = OperationState::Finished;
} else if (operation.action == "file") {
if (!transfers_.ProcessSelectedFile(operation.file, props,
@@ -6472,12 +6472,12 @@ void GuiApplication::SyncGallery() {
else if (operation.action == "connect") {
const auto status = props->connection_status_.load();
const auto auth = props->connection_auth_.Get();
if (status == ConnectionStatus::Connected)
if (status == MiniRtcConnectionStatus::MiniRtcConnectionConnected)
operation.state = OperationState::Finished;
else if (auth.password_required && !auth.validating)
operation.state = OperationState::AwaitingPassword;
else if (status != ConnectionStatus::Connecting &&
status != ConnectionStatus::Gathering && !auth.validating)
else if (status != MiniRtcConnectionStatus::MiniRtcConnectionConnecting &&
status != MiniRtcConnectionStatus::MiniRtcConnectionGathering && !auth.validating)
operation.state = OperationState::Finished;
else if (operation.state == OperationState::AwaitingPassword) {
operation.state = OperationState::Running;
@@ -6486,7 +6486,7 @@ void GuiApplication::SyncGallery() {
operation.state = OperationState::Finished;
CloseStreamTab(operation.id);
}
} else if (props->connection_status_ != ConnectionStatus::Connected)
} else if (props->connection_status_ != MiniRtcConnectionStatus::MiniRtcConnectionConnected)
operation.state = OperationState::Finished;
else if (operation.action == "file") {
std::lock_guard lock(props->file_transfer_.file_transfer_list_mutex_);
@@ -6594,7 +6594,7 @@ void GuiApplication::SyncGallery() {
tile.host_name = UiText(props->remote_host_name_);
}
tile.connected = props &&
props->connection_status_ == ConnectionStatus::Connected &&
props->connection_status_ == MiniRtcConnectionStatus::MiniRtcConnectionConnected &&
!props->closing_;
const auto online = device_presence_cache_.GetOnline(id);
tile.online = tile.connected || online.value_or(false);
@@ -6648,7 +6648,7 @@ void GuiApplication::SyncGallery() {
};
for (size_t i = 0; i < ids.size(); ++i) {
const auto props = FindRemoteSession(ids[i]);
if (props && props->connection_status_ == ConnectionStatus::Connected &&
if (props && props->connection_status_ == MiniRtcConnectionStatus::MiniRtcConnectionConnected &&
!props->closing_) {
++connected;
}
@@ -6684,7 +6684,7 @@ void GuiApplication::SyncGallery() {
device.name = UiText(name(id));
const auto props = FindRemoteSession(id);
device.connected = props && !props->closing_ &&
props->connection_status_ == ConnectionStatus::Connected;
props->connection_status_ == MiniRtcConnectionStatus::MiniRtcConnectionConnected;
if (device.connected) {
selected_audio_available = true;
selected_audio_muted &= !props->audio_capture_button_pressed_;
@@ -6738,7 +6738,7 @@ void GuiApplication::SyncGallery() {
props->gallery_rgba_.reset();
}
if (props->preview_subscription_supported_ &&
props->connection_status_ == ConnectionStatus::Connected) {
props->connection_status_ == MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
if (wall_mode && !ui_->gallery_hidden_active_ids.count(id))
props->wall_managed_ = true;
// Keep session quality and audio; wall bandwidth, resolution and
@@ -6814,7 +6814,7 @@ void GuiApplication::SyncGallery() {
demand.request_id = ++props->preview_request_;
if (!demand.request_id) demand.request_id = ++props->preview_request_;
const auto message = demand.ToJson().dump();
if (SendReliableDataFrame(props->peer_, message.data(), message.size(),
if (MiniRtcSendReliableDataFrame(props->peer_, message.data(), message.size(),
props->control_data_label_.c_str()) == 0)
props->preview_requested_ = demand;
props->preview_request_at_ = now;
@@ -359,7 +359,7 @@ void ClipboardController::SendDeferredLocalText() {
return;
}
const int ret = SendReliableDataFrame(
const int ret = MiniRtcSendReliableDataFrame(
session->peer_, last_text_.data(), last_text_.size(),
session->clipboard_label_.c_str());
if (ret != 0) {
@@ -388,7 +388,7 @@ int ClipboardController::SendToPeers(const std::string &text) {
}
const int ret =
SendReliableDataFrame(props->peer_, text.data(), text.size(),
MiniRtcSendReliableDataFrame(props->peer_, text.data(), text.size(),
props->clipboard_label_.c_str());
if (ret != 0) {
LOG_WARN("Failed to send clipboard data to peer [{}], ret={}",
@@ -48,9 +48,9 @@ SessionDeviceManager::SessionDeviceManager(GuiRuntime &owner)
frame.size = size;
for (const auto& id : owner_.ConnectedControllers())
owner_.WithController(
id, [&](PeerPtr* peer, const std::string& wire) {
frame.captured_timestamp = GetSystemTimeMicros(peer);
return SendAudioFrameToPeer(peer, &frame,
id, [&](MiniRtcPeerPtr* peer, const std::string& wire) {
frame.captured_timestamp = MiniRtcGetSystemTimeMicros(peer);
return MiniRtcSendAudioFrameToPeer(peer, &frame,
owner_.audio_label_.c_str(),
wire.data(), wire.size());
});
@@ -239,11 +239,11 @@ int SessionDeviceManager::InitializeScreenCapturer() {
if (!owner_.preview_subscriptions_.ShouldSend(remote_id, now_time,
stream_id)) continue;
if (owner_.WithController(
remote_id, [&](PeerPtr* peer, const std::string& wire) {
remote_id, [&](MiniRtcPeerPtr* peer, const std::string& wire) {
if (resumed_after_gap || stream_changed)
RequestVideoKeyFrame(peer, stream_id.c_str());
frame.captured_timestamp = GetSystemTimeMicros(peer);
return SendVideoFrameToPeer(peer, &frame, stream_id.c_str(),
MiniRtcRequestVideoKeyFrame(peer, stream_id.c_str());
frame.captured_timestamp = MiniRtcGetSystemTimeMicros(peer);
return MiniRtcSendVideoFrameToPeer(peer, &frame, stream_id.c_str(),
wire.data(), wire.size());
}) != 0)
++send_errors;
@@ -285,7 +285,7 @@ bool SessionDeviceManager::ShouldCaptureCursor() const {
std::shared_lock lock(owner_.connection_status_mutex_);
return std::any_of(owner_.connection_status_.begin(),
owner_.connection_status_.end(), [](const auto& entry) {
return entry.second == ConnectionStatus::Connected &&
return entry.second == MiniRtcConnectionStatus::MiniRtcConnectionConnected &&
entry.first.find("web") != std::string::npos;
});
}
@@ -294,7 +294,7 @@ bool SessionDeviceManager::HasConnectedController() const {
std::shared_lock lock(owner_.connection_status_mutex_);
return std::any_of(owner_.connection_status_.begin(),
owner_.connection_status_.end(), [](const auto& entry) {
return entry.second == ConnectionStatus::Connected;
return entry.second == MiniRtcConnectionStatus::MiniRtcConnectionConnected;
});
}
@@ -108,7 +108,7 @@ void FileTransferManager::ProcessQueue(std::shared_ptr<RemoteSession> props) {
workers_.push_back(std::async(std::launch::async, [this, props, file] {
auto& state = state_for(props);
const auto id = file.file_id;
PeerPtr* peer;
MiniRtcPeerPtr* peer;
std::shared_ptr<PeerEventHandler> events;
{
std::shared_lock lock(owner_.remote_sessions_mutex_);
@@ -126,7 +126,7 @@ void FileTransferManager::ProcessQueue(std::shared_ptr<RemoteSession> props) {
auto callback = events->EnterCallback();
if (!callback || !events->DataAllowed()) return -1;
const auto wire_id = events->WireId(file.remote_id);
return SendReliableDataFrameToPeer(
return MiniRtcSendReliableDataFrameToPeer(
peer, data, size, file.file_label.c_str(),
wire_id.data(), wire_id.size());
}, file_transfer::Session::Progress{});
@@ -176,7 +176,7 @@ void FileTransferManager::ProcessQueue(std::shared_ptr<RemoteSession> props) {
// Release that reservation even though no data chunk was ever sent.
const auto packet = EncodeFileCancel(id, 0);
const auto wire_id = events->WireId(file.remote_id);
SendReliableDataFrameToPeer(peer, packet.data(), packet.size(),
MiniRtcSendReliableDataFrameToPeer(peer, packet.data(), packet.size(),
file.file_label.c_str(), wire_id.data(), wire_id.size());
}
}
@@ -347,7 +347,7 @@ void FileTransferManager::UpdateReceiveProgress(
std::shared_ptr<FileReceiver> FileTransferManager::ReceiverFor(
PeerEventHandler* handler, const std::string& remote) {
const auto props = owner_.FindRemoteSession(remote);
PeerPtr* peer;
MiniRtcPeerPtr* peer;
std::shared_ptr<PeerEventHandler> events;
{
std::shared_lock lock(owner_.remote_sessions_mutex_);
@@ -382,7 +382,7 @@ std::shared_ptr<FileReceiver> FileTransferManager::ReceiverFor(
if (!callback || !events->DataAllowed()) return -1;
const auto bytes = EncodeFileTransferAck(ack);
const auto wire_id = events->WireId(remote);
return SendReliableDataFrameToPeer(
return MiniRtcSendReliableDataFrameToPeer(
peer, bytes.data(), bytes.size(), kFileFeedbackStream,
wire_id.data(), wire_id.size());
});
@@ -529,11 +529,11 @@ bool FileTransferManager::SendBrowser(const std::string& remote, const FileBrows
if (!events) return false;
auto callback = events->EnterCallback();
if (!callback || !events->DataAllowed()) return false;
PeerPtr* peer = events->IsDirect() ? events->DirectPeer() : props ? props->peer_ : owner_.peer_;
MiniRtcPeerPtr* peer = events->IsDirect() ? events->DirectPeer() : props ? props->peer_ : owner_.peer_;
const auto data = message.dump(-1, ' ', false, FileBrowser::Json::error_handler_t::replace);
if (!peer || data.size() > 60000) return false;
const auto wire_id = events->WireId(remote);
return SendReliableDataFrameToPeer(peer, data.data(), data.size(),
return MiniRtcSendReliableDataFrameToPeer(peer, data.data(), data.size(),
owner_.control_data_label_.c_str(), wire_id.data(), wire_id.size()) == 0;
}
@@ -22,7 +22,7 @@ namespace crossdesk {
class VideoLatencyStats;
// Travels with the exact queued pixels, including native frames. Its clock is
// translated once at the receive callback; rendering needs no live PeerPtr.
// translated once at the receive callback; rendering needs no live MiniRtcPeerPtr.
struct VideoLatencyFrame {
using Clock = std::chrono::steady_clock;
std::shared_ptr<VideoLatencyStats> stats;
@@ -32,8 +32,8 @@ bool GuiRuntime::HasActiveSession() {
std::shared_lock lock(connection_status_mutex_);
return std::any_of(connection_status_.begin(), connection_status_.end(),
[](const auto& entry) {
return entry.second == ConnectionStatus::Connecting ||
entry.second == ConnectionStatus::Connected;
return entry.second == MiniRtcConnectionStatus::MiniRtcConnectionConnecting ||
entry.second == MiniRtcConnectionStatus::MiniRtcConnectionConnected;
});
}
@@ -57,7 +57,7 @@ void GuiRuntime::UnmuteRemoteAudio(const std::shared_ptr<RemoteSession>& props)
action.type = ControlType::audio_capture;
action.a = true;
const auto message = action.to_json();
SendReliableDataFrame(props->peer_, message.data(), message.size(),
MiniRtcSendReliableDataFrame(props->peer_, message.data(), message.size(),
props->control_data_label_.c_str());
}
@@ -79,7 +79,7 @@ void GuiRuntime::HandleConnectionStatusChange() {
const auto message =
BuildDevicePresenceRequest(client_id_, recent_connection_ids_, true, {},
gallery_presence_ids_).dump();
if (SendSignalMessage(peer_, message.data(), message.size()) == 0) {
if (MiniRtcSendSignalMessage(peer_, message.data(), message.size()) == 0) {
next_presence_refresh_at_ = now + kPresenceRefreshInterval;
} else {
need_to_send_recent_connections_ = true;
@@ -207,7 +207,7 @@ void GuiRuntime::HandleServerControllerDisconnected(
codec_status_controllers_.erase(remote_id);
privacy_sessions_.Disconnected(remote_id);
for (const auto& [id, status] : connection_status_) {
if (status != ConnectionStatus::Connected) {
if (status != MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
continue;
}
has_connected_controller = true;
@@ -296,7 +296,7 @@ int GuiRuntime::RequestSingleDevicePresence(const std::string& remote_id,
gallery_presence_ids_)
.dump();
int ret = SendSignalMessage(peer_, s.data(), s.size());
int ret = MiniRtcSendSignalMessage(peer_, s.data(), s.size());
if (ret != 0) {
std::lock_guard<std::mutex> lock(pending_presence_probe_mutex_);
pending_presence_probe_ = false;
@@ -315,7 +315,7 @@ int GuiRuntime::ForceSignalReconnect() {
LOG_WARN("Signal reconnect requested with no connection peer");
return -1;
}
return ReconnectSignal(peer_);
return MiniRtcReconnectSignal(peer_);
}
void GuiRuntime::CloseRemoteSession(std::shared_ptr<RemoteSession> props) {
@@ -332,7 +332,7 @@ void GuiRuntime::CloseRemoteSession(std::shared_ptr<RemoteSession> props) {
}
props->connection_established_ = false;
props->streaming_ = false;
props->connection_status_.store(ConnectionStatus::Closed);
props->connection_status_.store(MiniRtcConnectionStatus::MiniRtcConnectionClosed);
std::shared_ptr<std::vector<unsigned char>> frame_snapshot;
int video_width = 0;
int video_height = 0;
@@ -365,7 +365,7 @@ void GuiRuntime::CloseRemoteSession(std::shared_ptr<RemoteSession> props) {
video_frame_dirty_.store(true, std::memory_order_release);
}
PeerPtr* peer = nullptr;
MiniRtcPeerPtr* peer = nullptr;
{
// Audio/clipboard senders hold a shared map lock while using this pointer.
std::unique_lock lock(remote_sessions_mutex_);
@@ -384,8 +384,8 @@ void GuiRuntime::CloseRemoteSession(std::shared_ptr<RemoteSession> props) {
if (peer && !props->lan_session_) {
LOG_INFO("[{}] Background leave connection [{}]", props->local_id_,
props->remote_id_);
LeaveConnection(peer, props->remote_id_.c_str());
DestroyPeer(&peer);
MiniRtcLeaveConnection(peer, props->remote_id_.c_str());
MiniRtcDestroyPeer(&peer);
}
if (thumbnail && props->was_connected_) {
const char* nv12 = frame_snapshot && !frame_snapshot->empty()
@@ -430,7 +430,7 @@ void GuiRuntime::CloseServerController(const std::string& remote_id) {
return;
controller_cleanup_tasks_[remote_id] = session_cleanup_queue_.PostTask(
[peer = peer_, transmission_id = std::string(client_id_), remote_id] {
if (DisconnectPeerConnection(peer, transmission_id.c_str(),
if (MiniRtcDisconnectPeerConnection(peer, transmission_id.c_str(),
remote_id.c_str()) != 0) {
LOG_WARN("[{}] Could not queue controller disconnect notification",
remote_id);
@@ -462,8 +462,8 @@ void GuiRuntime::CloseConnectionPeer() {
HandleServerControllerDisconnected(id, "peer_closed");
signal_connected_ = false;
device_presence_cache_.SetSignalConnected(false);
signal_status_ = SignalStatus::SignalClosed;
PeerPtr* peer;
signal_status_ = MiniRtcSignalStatus::MiniRtcSignalClosed;
MiniRtcPeerPtr* peer;
{
std::unique_lock lock(remote_sessions_mutex_);
peer = std::exchange(peer_, nullptr);
@@ -474,8 +474,8 @@ void GuiRuntime::CloseConnectionPeer() {
[peer, handler = peer_events_, id = std::string(client_id_)]() mutable {
handler->Deactivate();
LOG_INFO("[{}] Background connection peer cleanup", id);
LeaveConnection(peer, id.c_str());
DestroyPeer(&peer);
MiniRtcLeaveConnection(peer, id.c_str());
MiniRtcDestroyPeer(&peer);
});
}
@@ -673,9 +673,9 @@ int GuiRuntime::ConnectTo(const std::string& remote_id, const char* password,
if (exists && !stale->closing_.load() &&
!stale->connection_established_) {
const auto status = stale->connection_status_.load();
if (status == ConnectionStatus::Disconnected ||
status == ConnectionStatus::Failed ||
status == ConnectionStatus::Closed) {
if (status == MiniRtcConnectionStatus::MiniRtcConnectionDisconnected ||
status == MiniRtcConnectionStatus::MiniRtcConnectionFailed ||
status == MiniRtcConnectionStatus::MiniRtcConnectionClosed) {
// The recreated session starts with an empty password; callers that
// pass none expect the one stored by the previous attempt to be reused.
const bool keep_stored_password = !password || !*password;
@@ -692,7 +692,7 @@ int GuiRuntime::ConnectTo(const std::string& remote_id, const char* password,
}
if (!exists) {
PeerPtr* peer_to_init = nullptr;
MiniRtcPeerPtr* peer_to_init = nullptr;
std::string local_id;
{
@@ -707,13 +707,13 @@ int GuiRuntime::ConnectTo(const std::string& remote_id, const char* password,
props->control_mouse_ = !background;
props->enable_mouse_control_ = !background;
props->audio_capture_button_pressed_ = !background;
memcpy(&props->params_, &params_, sizeof(Params));
memcpy(&props->params_, &params_, sizeof(MiniRtcParams));
props->params_.user_id = props->local_id_.c_str();
props->peer_events_ = std::make_shared<PeerEventHandler>(*this);
props->params_.user_data = props->peer_events_.get();
props->peer_ = CreatePeer(&props->params_);
props->peer_ = MiniRtcCreatePeer(&props->params_);
props->connection_status_.store(ConnectionStatus::Connecting);
props->connection_status_.store(MiniRtcConnectionStatus::MiniRtcConnectionConnecting);
if (!background) show_connection_status_window_ = true;
if (!props->peer_) {
@@ -724,18 +724,18 @@ int GuiRuntime::ConnectTo(const std::string& remote_id, const char* password,
const auto& displays = devices_.display_info_list();
for (size_t index = 0; index < displays.size(); ++index) {
const std::string stream_id = MakeDisplayStreamId(index);
AddVideoStream(props->peer_, stream_id.c_str());
MiniRtcAddVideoStream(props->peer_, stream_id.c_str());
}
AddAudioStream(props->peer_, props->audio_label_.c_str());
AddDataStream(props->peer_, props->data_label_.c_str(), false);
AddDataStream(props->peer_, props->mouse_label_.c_str(), true);
AddDataStream(props->peer_, props->keyboard_label_.c_str(), true);
AddDataStream(props->peer_, props->control_data_label_.c_str(), true);
AddDataStream(props->peer_, props->file_label_.c_str(), true);
AddDataStream(props->peer_, props->file_feedback_label_.c_str(), true);
AddDataStream(props->peer_, props->clipboard_label_.c_str(), true);
MiniRtcAddAudioStream(props->peer_, props->audio_label_.c_str());
MiniRtcAddDataStream(props->peer_, props->data_label_.c_str(), false);
MiniRtcAddDataStream(props->peer_, props->mouse_label_.c_str(), true);
MiniRtcAddDataStream(props->peer_, props->keyboard_label_.c_str(), true);
MiniRtcAddDataStream(props->peer_, props->control_data_label_.c_str(), true);
MiniRtcAddDataStream(props->peer_, props->file_label_.c_str(), true);
MiniRtcAddDataStream(props->peer_, props->file_feedback_label_.c_str(), true);
MiniRtcAddDataStream(props->peer_, props->clipboard_label_.c_str(), true);
props->connection_status_.store(ConnectionStatus::Connecting);
props->connection_status_.store(MiniRtcConnectionStatus::MiniRtcConnectionConnecting);
peer_to_init = props->peer_;
local_id = props->local_id_;
@@ -744,7 +744,7 @@ int GuiRuntime::ConnectTo(const std::string& remote_id, const char* password,
if (peer_to_init) {
LOG_INFO("[{}] Create peer instance successful", local_id);
Init(peer_to_init);
MiniRtcInit(peer_to_init);
LOG_INFO("[{}] Peer init finish", local_id);
}
}
@@ -773,10 +773,10 @@ int GuiRuntime::ConnectTo(const std::string& remote_id, const char* password,
props->rejoin_ = false;
return 0;
}
props->connection_status_.store(ConnectionStatus::Connecting);
props->connection_status_.store(MiniRtcConnectionStatus::MiniRtcConnectionConnecting);
std::string remote_id_with_pwd = remote_id + "@" + props->remote_password_;
if (props->peer_) {
ret = JoinConnection(props->peer_, remote_id_with_pwd.c_str());
ret = MiniRtcJoinConnection(props->peer_, remote_id_with_pwd.c_str());
if (0 == ret) {
props->rejoin_ = false;
} else {
@@ -6,7 +6,7 @@
#include "runtime/trusted_devices.h"
namespace crossdesk {
int DeviceLogin::Exchange(SignalExchangeStage stage, const nlohmann::json& message,
int DeviceLogin::Exchange(MiniRtcSignalExchangeStage stage, const nlohmann::json& message,
const TrustedDevices* identity, char* response, size_t capacity) {
auto output = [&](const nlohmann::json& reply) {
const auto text = reply.dump();
@@ -14,7 +14,7 @@ int DeviceLogin::Exchange(SignalExchangeStage stage, const nlohmann::json& messa
std::memcpy(response, text.data(), text.size());
return static_cast<int>(text.size());
};
if (stage == SignalExchangeStage::PrepareLogin) {
if (stage == MiniRtcSignalExchangeStage::PrepareLogin) {
phase_ = Phase::Idle;
used_password_ = false;
password_.clear();
+1 -1
View File
@@ -18,7 +18,7 @@ class TrustedDevices;
// One signaling connection's application authentication, owned by its callbacks.
class DeviceLogin {
public:
int Exchange(SignalExchangeStage stage, const nlohmann::json& message,
int Exchange(MiniRtcSignalExchangeStage stage, const nlohmann::json& message,
const TrustedDevices* identity, char* response, size_t capacity);
bool Pending() const { return phase_ != Phase::Idle; }
bool UsedPassword() const { return used_password_; }
@@ -53,8 +53,8 @@ void GuiRuntime::ForgetControllerTrust(const std::string& id, PeerEventHandler*
int GuiRuntime::SendTrustMessage(const std::string& id, const nlohmann::json& message) {
const auto text = message.dump();
return WithController(id, [&](PeerPtr* peer, const std::string& wire) {
return SendReliableDataFrameToPeer(peer, text.data(), text.size(),
return WithController(id, [&](MiniRtcPeerPtr* peer, const std::string& wire) {
return MiniRtcSendReliableDataFrameToPeer(peer, text.data(), text.size(),
control_data_label_.c_str(), wire.data(), wire.size());
}, false);
}
@@ -94,7 +94,7 @@ bool GuiRuntime::HandleDeviceTrustMessage(const std::string& id, PeerEventHandle
const auto wire = events->WireId(id);
const auto proof = trusted_devices_->Prove(message.at("nonce"),
props->local_id_, GetHostName()).dump();
SendReliableDataFrameToPeer(props->peer_, proof.data(), proof.size(),
MiniRtcSendReliableDataFrameToPeer(props->peer_, proof.data(), proof.size(),
control_data_label_.c_str(), wire.data(), wire.size());
} else if (type == "device_trust_proof") {
std::lock_guard lock(controller_trust_mutex_);
@@ -156,7 +156,7 @@ void GuiRuntime::TickControllerTrust() {
remote_input_.Disconnect(action.id);
CloseServerController(action.id);
} else if (action.kind > 0) {
events->ApplyConnectionStatus(ConnectionStatus::Connected, action.id);
events->ApplyConnectionStatus(MiniRtcConnectionStatus::MiniRtcConnectionConnected, action.id);
if (!action.host_info.empty()) {
const auto wire = events->WireId(action.id);
PeerEventHandler::OnReceiveDataBuffer(action.host_info.data(), action.host_info.size(),
+23 -23
View File
@@ -99,7 +99,7 @@ void GuiRuntime::SendRemoteInput(const RemoteAction& action) {
? action.k.flag == KeyFlag::key_up : action.ks.pressed_count == 0;
const auto available = [](const auto& props) {
return props && props->peer_ && !props->closing_ &&
props->connection_status_ == ConnectionStatus::Connected;
props->connection_status_ == MiniRtcConnectionStatus::MiniRtcConnectionConnected;
};
std::shared_lock lock(remote_sessions_mutex_);
const auto source = remote_sessions_.find(target_id);
@@ -121,9 +121,9 @@ void GuiRuntime::SendRemoteInput(const RemoteAction& action) {
// Use the negotiated unreliable stream; clicks and wheel events remain
// on the reliable mouse stream, with their own absolute coordinates.
const int result = mouse_move
? SendDataFrame(props->peer_, message.data(), message.size(),
? MiniRtcSendDataFrame(props->peer_, message.data(), message.size(),
props->data_label_.c_str())
: SendReliableDataFrame(
: MiniRtcSendReliableDataFrame(
props->peer_, message.data(), message.size(),
mouse ? props->mouse_label_.c_str() : props->keyboard_label_.c_str());
if (result != 0)
@@ -256,15 +256,15 @@ int GuiRuntime::CreateConnectionPeer() {
ConfigCenter::VIDEO_ENCODE_FORMAT::AV1
? true
: false;
params_.turn_mode = static_cast<TurnMode>(config_center_->GetTurnMode());
params_.turn_mode = static_cast<MiniRtcTurnMode>(config_center_->GetTurnMode());
params_.enable_srtp = config_center_->IsEnableSrtp();
params_.video_content_type = VideoContentType::ScreenContent;
params_.video_content_type = MiniRtcVideoContentType::ScreenContent;
// Bootstrap outgoing media with fixed defaults. Live overrides come only
// from the authorized controller and apply to its connection on this host.
params_.video_quality = VideoQuality::QualityHigh;
params_.video_quality = MiniRtcVideoQuality::MiniRtcVideoQualityHigh;
params_.video_frame_rate = 60;
params_.video_degradation_preference =
VideoDegradationPreference::MaintainResolution;
MiniRtcVideoDegradationPreference::MaintainResolution;
params_.on_receive_video_buffer = nullptr;
params_.on_receive_audio_buffer = PeerEventHandler::OnReceiveAudioBuffer;
params_.on_receive_data_buffer = PeerEventHandler::OnReceiveDataBuffer;
@@ -284,15 +284,15 @@ int GuiRuntime::CreateConnectionPeer() {
signal_connected_ = false;
device_presence_cache_.SetSignalConnected(false);
need_to_send_recent_connections_ = true;
signal_status_ = SignalStatus::SignalConnecting;
signal_status_ = MiniRtcSignalStatus::MiniRtcSignalConnecting;
{
std::unique_lock lock(remote_sessions_mutex_);
peer_ = CreatePeer(&params_);
peer_ = MiniRtcCreatePeer(&params_);
}
if (peer_) {
LOG_INFO("Create peer instance [{}] successful", client_id_);
Init(peer_);
MiniRtcInit(peer_);
LOG_INFO("Peer [{}] init finish", client_id_);
} else {
LOG_INFO("Create peer [{}] instance failed", client_id_);
@@ -302,19 +302,19 @@ int GuiRuntime::CreateConnectionPeer() {
const auto &displays = devices_.display_info_list();
for (size_t index = 0; index < displays.size(); ++index) {
const std::string stream_id = MakeDisplayStreamId(index);
AddVideoStream(peer_, stream_id.c_str());
MiniRtcAddVideoStream(peer_, stream_id.c_str());
}
AddAudioStream(peer_, audio_label_.c_str());
AddDataStream(peer_, data_label_.c_str(), false);
AddDataStream(peer_, mouse_label_.c_str(), true);
AddDataStream(peer_, keyboard_label_.c_str(), true);
AddDataStream(peer_, control_data_label_.c_str(), true);
AddDataStream(peer_, file_label_.c_str(), true);
AddDataStream(peer_, file_feedback_label_.c_str(), true);
AddDataStream(peer_, clipboard_label_.c_str(), true);
MiniRtcAddAudioStream(peer_, audio_label_.c_str());
MiniRtcAddDataStream(peer_, data_label_.c_str(), false);
MiniRtcAddDataStream(peer_, mouse_label_.c_str(), true);
MiniRtcAddDataStream(peer_, keyboard_label_.c_str(), true);
MiniRtcAddDataStream(peer_, control_data_label_.c_str(), true);
MiniRtcAddDataStream(peer_, file_label_.c_str(), true);
MiniRtcAddDataStream(peer_, file_feedback_label_.c_str(), true);
MiniRtcAddDataStream(peer_, clipboard_label_.c_str(), true);
if (!unattended_host_)
AddDataStream(peer_, web_clipboard::kStream, true);
MiniRtcAddDataStream(peer_, web_clipboard::kStream, true);
return 0;
} else {
return -1;
@@ -390,10 +390,10 @@ void GuiRuntime::SdlCaptureAudioIn(void *userdata, Uint8 *stream, int len) {
uint64_t captured_timestamp = 0;
for (const auto &it : runtime->remote_sessions_) {
auto props = it.second;
if (props->connection_status_.load() == ConnectionStatus::Connected) {
if (props->connection_status_.load() == MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
if (props->peer_) {
if (captured_timestamp == 0) {
const int64_t timestamp_us = GetSystemTimeMicros(props->peer_);
const int64_t timestamp_us = MiniRtcGetSystemTimeMicros(props->peer_);
if (timestamp_us > 0) {
captured_timestamp = static_cast<uint64_t>(timestamp_us);
}
@@ -402,7 +402,7 @@ void GuiRuntime::SdlCaptureAudioIn(void *userdata, Uint8 *stream, int len) {
frame.data = reinterpret_cast<const char *>(stream);
frame.size = static_cast<size_t>(len);
frame.captured_timestamp = captured_timestamp;
SendAudioFrame(props->peer_, &frame,
MiniRtcSendAudioFrame(props->peer_, &frame,
runtime->audio_label_.c_str());
}
}
+2 -2
View File
@@ -60,12 +60,12 @@ class GuiRuntime : protected gui_detail::GuiState {
void TickLan();
void BeginShutdown();
bool ShutdownDrained();
void RegisterStreams(PeerPtr* peer, size_t display_count);
void RegisterStreams(MiniRtcPeerPtr* peer, size_t display_count);
void ConnectLan(const std::string& address, unsigned port,
std::string password, bool remember_password = false);
int WithController(
const std::string& id,
const std::function<int(PeerPtr*, const std::string&)>& operation,
const std::function<int(MiniRtcPeerPtr*, const std::string&)>& operation,
bool require_trusted = true);
int SendControllerData(const std::string& id, const char* data, size_t size,
const char* label);
+20 -20
View File
@@ -7,17 +7,17 @@
#endif
namespace crossdesk {
void GuiRuntime::RegisterStreams(PeerPtr* peer, size_t displays) {
void GuiRuntime::RegisterStreams(MiniRtcPeerPtr* peer, size_t displays) {
for (size_t i = 0; i < displays; ++i) {
const auto id = MakeDisplayStreamId(i);
AddVideoStream(peer, id.c_str());
MiniRtcAddVideoStream(peer, id.c_str());
}
AddAudioStream(peer, audio_label_.c_str());
AddDataStream(peer, data_label_.c_str(), false);
MiniRtcAddAudioStream(peer, audio_label_.c_str());
MiniRtcAddDataStream(peer, data_label_.c_str(), false);
for (const auto& label :
{mouse_label_, keyboard_label_, control_data_label_, file_label_,
file_feedback_label_, clipboard_label_})
AddDataStream(peer, label.c_str(), true);
MiniRtcAddDataStream(peer, label.c_str(), true);
}
void GuiRuntime::InitializeLan() {
if (unattended_host_ || stopping_ || lan_ ||
@@ -37,8 +37,8 @@ void GuiRuntime::InitializeLan() {
auto events = std::make_shared<PeerEventHandler>(*this);
events->BindDirect(session);
// Direct initialization must not depend on cloud login/configuration having
// successfully populated the managed peer's Params snapshot.
Params params{};
// successfully populated the managed peer's MiniRtcParams snapshot.
MiniRtcParams params{};
std::snprintf(params.log_path, sizeof(params.log_path), "%s",
dll_log_path_.c_str());
params.hardware_acceleration = true;
@@ -46,12 +46,12 @@ void GuiRuntime::InitializeLan() {
params.av1_encoding = config_center_->GetVideoEncodeFormat() ==
ConfigCenter::VIDEO_ENCODE_FORMAT::AV1;
params.enable_srtp = true;
params.turn_mode = TurnMode::TurnDisabled;
params.video_content_type = VideoContentType::ScreenContent;
params.video_quality = VideoQuality::QualityHigh;
params.turn_mode = MiniRtcTurnMode::MiniRtcTurnDisabled;
params.video_content_type = MiniRtcVideoContentType::ScreenContent;
params.video_quality = MiniRtcVideoQuality::MiniRtcVideoQualityHigh;
params.video_frame_rate = 60;
params.video_degradation_preference =
VideoDegradationPreference::MaintainResolution;
MiniRtcVideoDegradationPreference::MaintainResolution;
params.on_receive_video_frame = PeerEventHandler::OnReceiveVideoBuffer;
params.on_receive_audio_buffer = PeerEventHandler::OnReceiveAudioBuffer;
params.on_receive_data_buffer = PeerEventHandler::OnReceiveDataBuffer;
@@ -69,7 +69,7 @@ void GuiRuntime::InitializeLan() {
lan::SessionManager::Prepared result;
result.callback_owner = events;
result.drain_callbacks = [events] { events->Deactivate(); };
result.peer = CreatePeer(&params);
result.peer = MiniRtcCreatePeer(&params);
events->SetDirectPeer(result.peer);
if (result.peer) RegisterStreams(result.peer, displays);
return result;
@@ -88,7 +88,7 @@ void GuiRuntime::InitializeLan() {
hooks.connected = [this](const std::shared_ptr<lan::Session>& session) {
auto events =
std::static_pointer_cast<PeerEventHandler>(session->callback_owner);
events->ApplyConnectionStatus(ConnectionStatus::Connected, session->key);
events->ApplyConnectionStatus(MiniRtcConnectionStatus::MiniRtcConnectionConnected, session->key);
events->FlushEarlyData();
};
hooks.closed = [this](const std::shared_ptr<lan::Session>& session) {
@@ -101,7 +101,7 @@ void GuiRuntime::InitializeLan() {
}
if (events) {
if (attached)
events->ApplyConnectionStatus(ConnectionStatus::Closed, session->key);
events->ApplyConnectionStatus(MiniRtcConnectionStatus::MiniRtcConnectionClosed, session->key);
events->StopAccepting();
transfers_.Cancel(events.get());
}
@@ -157,7 +157,7 @@ void GuiRuntime::ConnectLan(const std::string& address, unsigned port,
lan_connecting_ = session;
props->lan_session_ = session;
props->remote_id_ = session->key;
props->connection_status_ = ConnectionStatus::Connecting;
props->connection_status_ = MiniRtcConnectionStatus::MiniRtcConnectionConnecting;
props->connection_auth_.Complete();
{
std::unique_lock lock(remote_sessions_mutex_);
@@ -180,14 +180,14 @@ std::shared_ptr<PeerEventHandler> GuiRuntime::ControllerEvents(
}
int GuiRuntime::WithController(
const std::string& id,
const std::function<int(PeerPtr*, const std::string&)>& operation,
const std::function<int(MiniRtcPeerPtr*, const std::string&)>& operation,
bool require_trusted) {
if (require_trusted && !TrustedControllerAllowed(id)) return -1;
std::shared_lock lock(remote_sessions_mutex_);
auto it = lan_controllers_.find(id);
auto events = it == lan_controllers_.end() ? peer_events_ : it->second.events;
if (it == lan_controllers_.end() && id.rfind("lan/", 0) == 0) return -1;
PeerPtr* peer =
MiniRtcPeerPtr* peer =
it == lan_controllers_.end() ? peer_ : it->second.session->peer;
if (!peer || !events || !events->DataAllowed()) return -1;
auto callback = events->EnterCallback();
@@ -198,8 +198,8 @@ int GuiRuntime::WithController(
}
int GuiRuntime::SendControllerData(const std::string& id, const char* data,
size_t size, const char* label) {
return WithController(id, [&](PeerPtr* peer, const std::string& wire) {
return SendReliableDataFrameToPeer(peer, data, size, label, wire.data(),
return WithController(id, [&](MiniRtcPeerPtr* peer, const std::string& wire) {
return MiniRtcSendReliableDataFrameToPeer(peer, data, size, label, wire.data(),
wire.size());
});
}
@@ -208,7 +208,7 @@ std::vector<std::string> GuiRuntime::ConnectedControllers() {
std::shared_lock lock(connection_status_mutex_);
ids.reserve(connection_status_.size());
for (const auto& [id, status] : connection_status_)
if (status == ConnectionStatus::Connected) ids.push_back(id);
if (status == MiniRtcConnectionStatus::MiniRtcConnectionConnected) ids.push_back(id);
return ids;
}
void GuiRuntime::BeginShutdown() {
@@ -176,7 +176,7 @@ void PeerEventHandler::OnReceiveDataBuffer(
}
const std::string wire_id = handler->WireId(remote_id);
PeerPtr* bound_peer =
MiniRtcPeerPtr* bound_peer =
handler->IsDirect() ? handler->DirectPeer() : runtime->peer_;
std::string json_str(data, size);
if (json_str.find("\"automation\"") != std::string::npos) {
@@ -204,31 +204,31 @@ void PeerEventHandler::OnReceiveDataBuffer(
// their own demand. MiniRTC owns per-peer video/audio pause state.
if (!previous || subscription->IsNewerThan(*previous)) {
if (subscription->fps > 0)
accepted = UpdateVideoSettings(
accepted = MiniRtcUpdateVideoSettings(
bound_peer, wire_id.data(), wire_id.size(),
static_cast<VideoQuality>(subscription->quality),
static_cast<MiniRtcVideoQuality>(subscription->quality),
subscription->frame_rate,
static_cast<VideoDegradationPreference>(
static_cast<MiniRtcVideoDegradationPreference>(
subscription->EncoderPreference())) == 0;
if (accepted && (!previous || previous->max_bitrate_bps.value_or(0) !=
subscription->max_bitrate_bps.value_or(0)))
accepted = UpdateVideoBitrateLimit(
accepted = MiniRtcUpdateVideoBitrateLimit(
bound_peer, wire_id.data(), wire_id.size(),
subscription->max_bitrate_bps.value_or(0)) == 0;
// Rebalancing bandwidth alone must not force every device to send a
// keyframe. The pause API requests its own keyframes on resume.
if (accepted && (!previous || previous->width != subscription->width ||
previous->height != subscription->height))
accepted = UpdateVideoResolution(bound_peer, wire_id.data(),
accepted = MiniRtcUpdateVideoResolution(bound_peer, wire_id.data(),
wire_id.size(), subscription->width,
subscription->height) == 0;
if (accepted)
accepted =
SetVideoSendPaused(bound_peer, wire_id.data(), wire_id.size(),
MiniRtcSetVideoSendPaused(bound_peer, wire_id.data(), wire_id.size(),
subscription->fps == 0) == 0;
if (accepted)
accepted =
SetAudioSendPaused(bound_peer, wire_id.data(), wire_id.size(),
MiniRtcSetAudioSendPaused(bound_peer, wire_id.data(), wire_id.size(),
!subscription->audio) == 0;
if (accepted && subscription->audio)
runtime->devices_.StartSpeakerCapturer();
@@ -240,7 +240,7 @@ void PeerEventHandler::OnReceiveDataBuffer(
{"request_id", subscription->request_id},
{"accepted",
accepted}}.dump();
SendReliableDataFrameToPeer(bound_peer, reply.data(), reply.size(),
MiniRtcSendReliableDataFrameToPeer(bound_peer, reply.data(), reply.size(),
runtime->control_data_label_.c_str(),
wire_id.data(), wire_id.size());
return;
@@ -275,7 +275,7 @@ void PeerEventHandler::OnReceiveDataBuffer(
if (auto props = runtime->FindRemoteSession(remote_id);
props && source_id == props->control_data_label_ &&
!props->closing_ &&
props->connection_status_ == ConnectionStatus::Connected) {
props->connection_status_ == MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
props->net_traffic_stats_.StoreRemoteVideoEncoder(remote_action.vcs.encoder);
}
return;
@@ -314,17 +314,17 @@ void PeerEventHandler::OnReceiveDataBuffer(
return;
const auto& settings = remote_action.vs;
remote_action.vs.accepted =
UpdateVideoSettings(
MiniRtcUpdateVideoSettings(
bound_peer, wire_id.data(), wire_id.size(),
static_cast<VideoQuality>(settings.quality), settings.frame_rate,
static_cast<VideoDegradationPreference>(settings.preference)) == 0;
static_cast<MiniRtcVideoQuality>(settings.quality), settings.frame_rate,
static_cast<MiniRtcVideoDegradationPreference>(settings.preference)) == 0;
LOG_INFO("Video settings: peer={} source={} request={} quality={} fps={} "
"preference={} accepted={}",
remote_id, source_id, settings.request_id, settings.quality,
settings.frame_rate, settings.preference, remote_action.vs.accepted);
remote_action.type = ControlType::video_settings_status;
const auto message = remote_action.to_json();
SendReliableDataFrameToPeer(bound_peer, message.data(), message.size(),
MiniRtcSendReliableDataFrameToPeer(bound_peer, message.data(), message.size(),
runtime->control_data_label_.c_str(),
wire_id.data(), wire_id.size());
return;
@@ -479,7 +479,7 @@ void PeerEventHandler::OnReceiveDataBuffer(
props->video_settings_request_tick_ = SDL_GetTicks();
settings.vs = props->video_settings_;
const auto message = settings.to_json();
SendReliableDataFrame(
MiniRtcSendReliableDataFrame(
handler->IsDirect() ? handler->DirectPeer() : props->peer_,
message.data(), message.size(),
props->control_data_label_.c_str());
@@ -530,7 +530,7 @@ void PeerEventHandler::OnReceiveDataBuffer(
// command arrives after it (e.g. when unmuting an inactive window).
const auto subscription = runtime->preview_subscriptions_.Get(remote_id);
const bool paused = subscription ? !subscription->audio : !remote_action.a;
const int ret = SetAudioSendPaused(bound_peer, wire_id.data(),
const int ret = MiniRtcSetAudioSendPaused(bound_peer, wire_id.data(),
wire_id.size(), paused);
if (remote_action.a)
runtime->devices_.StartSpeakerCapturer();
@@ -65,7 +65,7 @@ bool PeerEventHandler::DataAllowed() const {
return session && session->authorized && !session->closing;
}
void PeerEventHandler::SendClientInfo(PeerPtr* peer,
void PeerEventHandler::SendClientInfo(MiniRtcPeerPtr* peer,
const std::string& client_id) {
if (!peer) {
return;
@@ -75,7 +75,7 @@ void PeerEventHandler::SendClientInfo(PeerPtr* peer,
{"version", CROSSDESK_VERSION},
{"platform", HostPlatformName(kClientPlatform)}};
const std::string payload = message.dump();
if (SendSignalMessage(peer, payload.data(), payload.size()) != 0) {
if (MiniRtcSendSignalMessage(peer, payload.data(), payload.size()) != 0) {
LOG_WARN("[{}] failed to report client information", client_id);
}
}
@@ -84,13 +84,13 @@ PeerEventHandler::PeerEventHandler(GuiRuntime& owner) : owner_(owner) {
owner_.transfers_.Connected(this, "");
}
int PeerEventHandler::OnSignalExchange(SignalExchangeStage stage, const char* message,
int PeerEventHandler::OnSignalExchange(MiniRtcSignalExchangeStage stage, const char* message,
size_t size, char* response, size_t capacity, void* user_data) {
auto* handler = static_cast<PeerEventHandler*>(user_data);
if (!handler || !message) return -1;
auto callback = handler->EnterCallback();
if (!callback) return -1;
if (stage == SignalExchangeStage::IncomingMessage &&
if (stage == MiniRtcSignalExchangeStage::IncomingMessage &&
!handler->device_login_.Pending()) return 0;
try {
return handler->device_login_.Exchange(stage,
@@ -209,7 +209,7 @@ void PeerEventHandler::OnSignalMessage(const char* message, size_t size,
}
}
void PeerEventHandler::OnSignalStatus(SignalStatus status, const char* user_id,
void PeerEventHandler::OnSignalStatus(MiniRtcSignalStatus status, const char* user_id,
size_t user_id_size, void* user_data) {
using RecoveryAction = GuiRuntime::CredentialRecoveryAction;
auto* handler = static_cast<PeerEventHandler*>(user_data);
@@ -220,13 +220,13 @@ void PeerEventHandler::OnSignalStatus(SignalStatus status, const char* user_id,
std::string client_id(user_id, user_id_size);
if (client_id == runtime->client_id_) {
runtime->announcements_.SetConnected(status == SignalStatus::SignalConnected);
runtime->announcements_.SetConnected(status == MiniRtcSignalStatus::MiniRtcSignalConnected);
runtime->signal_status_ = status;
runtime->device_presence_cache_.SetSignalConnected(
status == SignalStatus::SignalConnected);
if (SignalStatus::SignalConnecting == status) {
status == MiniRtcSignalStatus::MiniRtcSignalConnected);
if (MiniRtcSignalStatus::MiniRtcSignalConnecting == status) {
runtime->signal_connected_ = false;
} else if (SignalStatus::SignalConnected == status) {
} else if (MiniRtcSignalStatus::MiniRtcSignalConnected == status) {
runtime->signal_connected_ = true;
runtime->need_to_send_recent_connections_ = true;
LOG_INFO("[{}] connected to signal server", client_id);
@@ -241,20 +241,20 @@ void PeerEventHandler::OnSignalStatus(SignalStatus status, const char* user_id,
runtime->credential_recovery_action_ = RecoveryAction::ClearPending;
}
}
} else if (SignalStatus::SignalFailed == status) {
} else if (MiniRtcSignalStatus::MiniRtcSignalFailed == status) {
runtime->signal_connected_ = false;
std::lock_guard<std::mutex> lock(runtime->password_change_mutex_);
if (runtime->credential_recovery_in_progress_ &&
runtime->credential_recovery_attempt_pending_) {
runtime->credential_recovery_action_ = RecoveryAction::RetryActive;
}
} else if (SignalStatus::SignalClosed == status) {
} else if (MiniRtcSignalStatus::MiniRtcSignalClosed == status) {
runtime->signal_connected_ = false;
} else if (SignalStatus::SignalReconnecting == status) {
} else if (MiniRtcSignalStatus::MiniRtcSignalReconnecting == status) {
runtime->signal_connected_ = false;
} else if (SignalStatus::SignalServerClosed == status) {
} else if (MiniRtcSignalStatus::MiniRtcSignalServerClosed == status) {
runtime->signal_connected_ = false;
} else if (SignalStatus::SignalTlsCertError == status) {
} else if (MiniRtcSignalStatus::MiniRtcSignalTlsCertError == status) {
runtime->signal_connected_ = false;
}
} else {
@@ -266,27 +266,27 @@ void PeerEventHandler::OnSignalStatus(SignalStatus status, const char* user_id,
auto props = runtime->FindRemoteSession(remote_id);
if (!props) return;
props->signal_status_ = status;
if (SignalStatus::SignalConnecting == status) {
if (MiniRtcSignalStatus::MiniRtcSignalConnecting == status) {
props->signal_connected_ = false;
} else if (SignalStatus::SignalConnected == status) {
} else if (MiniRtcSignalStatus::MiniRtcSignalConnected == status) {
props->signal_connected_ = true;
LOG_INFO("[{}] connected to signal server", remote_id);
SendClientInfo(props->peer_, client_id);
} else if (SignalStatus::SignalFailed == status) {
} else if (MiniRtcSignalStatus::MiniRtcSignalFailed == status) {
props->signal_connected_ = false;
} else if (SignalStatus::SignalClosed == status) {
} else if (MiniRtcSignalStatus::MiniRtcSignalClosed == status) {
props->signal_connected_ = false;
} else if (SignalStatus::SignalReconnecting == status) {
} else if (MiniRtcSignalStatus::MiniRtcSignalReconnecting == status) {
props->signal_connected_ = false;
} else if (SignalStatus::SignalServerClosed == status) {
} else if (MiniRtcSignalStatus::MiniRtcSignalServerClosed == status) {
props->signal_connected_ = false;
} else if (SignalStatus::SignalTlsCertError == status) {
} else if (MiniRtcSignalStatus::MiniRtcSignalTlsCertError == status) {
props->signal_connected_ = false;
}
}
}
void PeerEventHandler::OnConnectionStatus(ConnectionStatus status,
void PeerEventHandler::OnConnectionStatus(MiniRtcConnectionStatus status,
const char* user_id, size_t size,
void* context) {
auto* handler = static_cast<PeerEventHandler*>(context);
@@ -300,7 +300,7 @@ void PeerEventHandler::OnConnectionStatus(ConnectionStatus status,
DispatchConnectionStatus(status, user_id, size, context);
}
void PeerEventHandler::DispatchConnectionStatus(ConnectionStatus status,
void PeerEventHandler::DispatchConnectionStatus(MiniRtcConnectionStatus status,
const char* user_id,
const size_t user_id_size,
void* user_data) {
@@ -311,9 +311,9 @@ void PeerEventHandler::DispatchConnectionStatus(ConnectionStatus status,
GuiRuntime* runtime = &handler->owner_;
std::string remote_id = handler->ConnectionKey(user_id, user_id_size);
if (status == ConnectionStatus::Connected) runtime->transfers_.Connected(handler, remote_id);
else if (status == ConnectionStatus::Disconnected || status == ConnectionStatus::Failed ||
status == ConnectionStatus::Closed) runtime->transfers_.Cancel(handler, remote_id);
if (status == MiniRtcConnectionStatus::MiniRtcConnectionConnected) runtime->transfers_.Connected(handler, remote_id);
else if (status == MiniRtcConnectionStatus::MiniRtcConnectionDisconnected || status == MiniRtcConnectionStatus::MiniRtcConnectionFailed ||
status == MiniRtcConnectionStatus::MiniRtcConnectionClosed) runtime->transfers_.Cancel(handler, remote_id);
std::shared_ptr<GuiRuntime::RemoteSession> props;
{
std::shared_lock lock(runtime->remote_sessions_mutex_);
@@ -324,7 +324,7 @@ void PeerEventHandler::DispatchConnectionStatus(ConnectionStatus status,
}
if (!props) {
if (status == ConnectionStatus::Connected) {
if (status == MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
if (!runtime->BeginControllerTrust(remote_id, handler)) return;
} else {
runtime->ForgetControllerTrust(remote_id, handler);
@@ -335,11 +335,11 @@ void PeerEventHandler::DispatchConnectionStatus(ConnectionStatus status,
runtime->is_client_mode_ = true;
if (!props->wall_managed_) runtime->show_connection_status_window_ = true;
props->connection_status_.store(status);
if (status != ConnectionStatus::Connecting && status != ConnectionStatus::Gathering)
if (status != MiniRtcConnectionStatus::MiniRtcConnectionConnecting && status != MiniRtcConnectionStatus::MiniRtcConnectionGathering)
props->connection_auth_.Complete();
switch (status) {
case ConnectionStatus::Connected: {
case MiniRtcConnectionStatus::MiniRtcConnectionConnected: {
runtime->ResetRemoteServiceStatus(*props);
{
std::lock_guard lock(props->remote_cursor_state_mutex_);
@@ -368,7 +368,7 @@ void PeerEventHandler::DispatchConnectionStatus(ConnectionStatus status,
information["device_trust_version"] = 1;
std::string msg = information.dump();
const int ret =
SendReliableDataFrame(props->peer_, msg.data(), msg.size(),
MiniRtcSendReliableDataFrame(props->peer_, msg.data(), msg.size(),
runtime->control_data_label_.c_str());
if (ret != 0) {
LOG_WARN("[{}] host information send failed, ret={}", remote_id,
@@ -386,9 +386,9 @@ void PeerEventHandler::DispatchConnectionStatus(ConnectionStatus status,
if (!props->wall_managed_) runtime->start_keyboard_capturer_ = true;
break;
}
case ConnectionStatus::Disconnected:
case ConnectionStatus::Failed:
case ConnectionStatus::Closed: {
case MiniRtcConnectionStatus::MiniRtcConnectionDisconnected:
case MiniRtcConnectionStatus::MiniRtcConnectionFailed:
case MiniRtcConnectionStatus::MiniRtcConnectionClosed: {
runtime->keyboard_.ReleaseRemotePressedKeys(remote_id,
"connection_closed");
props->connection_established_ = false;
@@ -406,7 +406,7 @@ void PeerEventHandler::DispatchConnectionStatus(ConnectionStatus status,
props->gallery_video_latency_->Reset();
props->gallery_frame_timing_ = {};
}
props->traversal_mode_ = TraversalMode::UnknownMode;
props->traversal_mode_ = MiniRtcTraversalMode::MiniRtcTraversalUnknown;
props->enable_mouse_control_ = false;
props->preview_subscription_supported_ = false;
props->preview_resolution_supported_ = false;
@@ -477,7 +477,7 @@ void PeerEventHandler::DispatchConnectionStatus(ConnectionStatus status,
runtime->focus_on_stream_window_ = false;
if (status == ConnectionStatus::Closed) {
if (status == MiniRtcConnectionStatus::MiniRtcConnectionClosed) {
props->remote_close_pending_.store(true, std::memory_order_release);
}
@@ -491,7 +491,7 @@ void PeerEventHandler::DispatchConnectionStatus(ConnectionStatus status,
runtime->show_connection_status_window_ = true;
{
std::unique_lock lock(runtime->connection_status_mutex_);
if (status == ConnectionStatus::Connected) {
if (status == MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
runtime->disconnect_lock_.Connected(remote_id);
// Local privacy requires explicit desktop capability. Host info may
// arrive before Connected; consume that saved capability here.
@@ -500,19 +500,19 @@ void PeerEventHandler::DispatchConnectionStatus(ConnectionStatus status,
runtime->ApplyPrivacyAdmission(automatic_enable);
}
runtime->connection_status_[remote_id] = status;
if (status == ConnectionStatus::Connected)
if (status == MiniRtcConnectionStatus::MiniRtcConnectionConnected)
runtime->remote_input_.Connect(remote_id);
#if _WIN32
runtime->windows_rdp_handoff_connected_->store(std::any_of(
runtime->connection_status_.begin(), runtime->connection_status_.end(),
[](const auto& entry) { return entry.second == ConnectionStatus::Connected; }),
[](const auto& entry) { return entry.second == MiniRtcConnectionStatus::MiniRtcConnectionConnected; }),
std::memory_order_relaxed);
#endif
runtime->devices_.OnControllerConnectionsChanged();
}
switch (status) {
case ConnectionStatus::Connected: {
case MiniRtcConnectionStatus::MiniRtcConnectionConnected: {
runtime->preview_subscriptions_.Remove(remote_id);
#if _WIN32
runtime->last_windows_service_status_tick_ = 0;
@@ -557,9 +557,9 @@ void PeerEventHandler::DispatchConnectionStatus(ConnectionStatus status,
break;
}
case ConnectionStatus::Disconnected:
case ConnectionStatus::Failed:
case ConnectionStatus::Closed: {
case MiniRtcConnectionStatus::MiniRtcConnectionDisconnected:
case MiniRtcConnectionStatus::MiniRtcConnectionFailed:
case MiniRtcConnectionStatus::MiniRtcConnectionClosed: {
runtime->HandleServerControllerDisconnected(remote_id,
"connection_closed");
break;
@@ -571,7 +571,7 @@ void PeerEventHandler::DispatchConnectionStatus(ConnectionStatus status,
}
void PeerEventHandler::OnNetStatusReport(
const char* client_id, size_t client_id_size, TraversalMode mode,
const char* client_id, size_t client_id_size, MiniRtcTraversalMode mode,
const MiniRtcNetTrafficStats* net_traffic_stats, const char* user_id,
const size_t user_id_size, void* user_data) {
auto* handler = static_cast<PeerEventHandler*>(user_data);
@@ -640,7 +640,7 @@ void PeerEventHandler::OnNetStatusReport(
const auto status = runtime->connection_status_.find(remote_id);
report_codecs = runtime->codec_status_controllers_.count(remote_id) != 0 &&
status != runtime->connection_status_.end() &&
status->second == ConnectionStatus::Connected;
status->second == MiniRtcConnectionStatus::MiniRtcConnectionConnected;
}
if (net_traffic_stats && report_codecs) {
RemoteAction action{};
@@ -37,10 +37,10 @@ public:
std::string WireId(const std::string& key) const;
bool DataAllowed() const;
bool IsDirect() const { return direct_bound_; }
void SetDirectPeer(PeerPtr* peer) { direct_peer_ = peer; }
PeerPtr* DirectPeer() const { return direct_peer_; }
void SetDirectPeer(MiniRtcPeerPtr* peer) { direct_peer_ = peer; }
MiniRtcPeerPtr* DirectPeer() const { return direct_peer_; }
void FlushEarlyData();
void ApplyConnectionStatus(ConnectionStatus status, const std::string& id) {
void ApplyConnectionStatus(MiniRtcConnectionStatus status, const std::string& id) {
DispatchConnectionStatus(status, id.data(), id.size(), this);
}
void StopAccepting() { callbacks_.StopAccepting(); }
@@ -60,30 +60,30 @@ public:
const char *user_id, size_t user_id_size,
const char *src_id, size_t src_id_size,
void *user_data);
static void OnSignalStatus(SignalStatus status, const char *user_id,
static void OnSignalStatus(MiniRtcSignalStatus status, const char *user_id,
size_t user_id_size, void *user_data);
static void OnSignalMessage(const char *message, size_t size,
void *user_data);
static int OnSignalExchange(SignalExchangeStage stage, const char* message,
static int OnSignalExchange(MiniRtcSignalExchangeStage stage, const char* message,
size_t size, char* response, size_t capacity,
void* user_data);
static void OnConnectionStatus(ConnectionStatus status, const char *user_id,
static void OnConnectionStatus(MiniRtcConnectionStatus status, const char *user_id,
size_t user_id_size, void *user_data);
static void OnNetStatusReport(const char *client_id, size_t client_id_size,
TraversalMode mode,
MiniRtcTraversalMode mode,
const MiniRtcNetTrafficStats *net_traffic_stats,
const char *user_id, size_t user_id_size,
void *user_data);
private:
static void DispatchConnectionStatus(ConnectionStatus status, const char* id,
static void DispatchConnectionStatus(MiniRtcConnectionStatus status, const char* id,
size_t size, void* context);
static void SendClientInfo(PeerPtr* peer, const std::string& client_id);
static void SendClientInfo(MiniRtcPeerPtr* peer, const std::string& client_id);
bool QueueEarlyData(const char* data, size_t size, const char* label,
size_t label_size);
std::weak_ptr<lan::Session> direct_;
bool direct_bound_ = false;
PeerPtr* direct_peer_ = nullptr;
MiniRtcPeerPtr* direct_peer_ = nullptr;
std::mutex early_data_mutex_;
std::vector<std::string> early_data_;
size_t early_data_bytes_ = 0;
@@ -51,7 +51,7 @@ void PeerEventHandler::OnReceiveVideoBuffer(
if (props->connection_established_) {
const auto timing_now = VideoLatencyFrame::Clock::now();
// Pair the clocks before preview conversion so its cost is included.
const auto local_now_us = GetSystemTimeMicros(
const auto local_now_us = MiniRtcGetSystemTimeMicros(
handler->IsDirect() ? handler->DirectPeer() : props->peer_);
const auto* received_native = GetNativeVideoFrame(video_frame);
props->received_video_stats_.Record(
@@ -26,7 +26,7 @@ bool GuiRuntime::IsAuthorizedController(const std::string& remote_id) {
std::shared_lock lock(connection_status_mutex_);
const auto found = connection_status_.find(remote_id);
return found != connection_status_.end() &&
found->second == ConnectionStatus::Connected;
found->second == MiniRtcConnectionStatus::MiniRtcConnectionConnected;
}
void GuiRuntime::SetControllerPrivacySupport(const std::string& remote_id,
@@ -34,9 +34,9 @@ void GuiRuntime::SetControllerPrivacySupport(const std::string& remote_id,
std::unique_lock lock(connection_status_mutex_);
const auto found = connection_status_.find(remote_id);
if (found == connection_status_.end()) return;
if (found->second != ConnectionStatus::Connected) {
if (found->second == ConnectionStatus::Connecting ||
found->second == ConnectionStatus::Gathering) {
if (found->second != MiniRtcConnectionStatus::MiniRtcConnectionConnected) {
if (found->second == MiniRtcConnectionStatus::MiniRtcConnectionConnecting ||
found->second == MiniRtcConnectionStatus::MiniRtcConnectionGathering) {
privacy_sessions_.RememberSupport(remote_id, supported);
LOG_INFO("Privacy: retained early controller capability, peer={}, supported={}",
remote_id, supported);
@@ -64,7 +64,7 @@ void GuiRuntime::QueuePrivacyCommand(const std::string& remote_id,
std::shared_lock session_lock(connection_status_mutex_);
const auto found = connection_status_.find(remote_id);
if (found == connection_status_.end() ||
found->second != ConnectionStatus::Connected ||
found->second != MiniRtcConnectionStatus::MiniRtcConnectionConnected ||
!privacy_sessions_.Supports(remote_id)) return;
std::lock_guard lock(privacy_commands_mutex_);
if (privacy_commands_.size() >= 32) return;
@@ -94,7 +94,7 @@ void GuiRuntime::HandlePrivacy() {
std::shared_lock lock(connection_status_mutex_);
const auto found = connection_status_.find(remote_id);
if (found == connection_status_.end() ||
found->second != ConnectionStatus::Connected ||
found->second != MiniRtcConnectionStatus::MiniRtcConnectionConnected ||
!privacy_sessions_.Supports(remote_id)) continue;
if (command.flag == PrivacyCommandFlag::enable) {
if (privacy_sessions_.CanEnable())
@@ -124,7 +124,7 @@ void GuiRuntime::HandlePrivacy() {
privacy_.CancelAutomaticResume();
status = privacy_.Snapshot();
for (const auto& [id, state] : connection_status_)
if (state == ConnectionStatus::Connected &&
if (state == MiniRtcConnectionStatus::MiniRtcConnectionConnected &&
privacy_sessions_.Supports(id))
controllers.push_back(id);
if (!privacy_sessions_.CanEnable()) {
@@ -112,8 +112,8 @@ struct RemoteSession {
std::mutex gallery_conversion_mutex_;
std::vector<unsigned char> gallery_nv12_, gallery_scaled_, gallery_scratch_;
std::shared_ptr<lan::Session> lan_session_;
Params params_;
PeerPtr* peer_ = nullptr;
MiniRtcParams params_;
MiniRtcPeerPtr* peer_ = nullptr;
std::shared_ptr<PeerEventHandler> peer_events_;
std::atomic<bool> closing_{false};
// Transport callbacks request tab closure; only the UI thread destroys it.
@@ -130,7 +130,7 @@ struct RemoteSession {
std::string remote_id_;
bool exit_ = false;
bool signal_connected_ = false;
SignalStatus signal_status_ = SignalStatus::SignalClosed;
MiniRtcSignalStatus signal_status_ = MiniRtcSignalStatus::MiniRtcSignalClosed;
bool connection_established_ = false;
std::atomic<bool> was_connected_{false};
// Transport callbacks publish changes; the UI thread persists history.
@@ -211,8 +211,8 @@ struct RemoteSession {
bool remote_cursor_state_received_ = false;
CursorPresentation cursor_presentation_;
// Shared by minirtc callbacks, Slint rendering and SDL audio callbacks.
std::atomic<ConnectionStatus> connection_status_ = ConnectionStatus::Closed;
std::atomic<TraversalMode> traversal_mode_{TraversalMode::UnknownMode};
std::atomic<MiniRtcConnectionStatus> connection_status_ = MiniRtcConnectionStatus::MiniRtcConnectionClosed;
std::atomic<MiniRtcTraversalMode> traversal_mode_{MiniRtcTraversalMode::MiniRtcTraversalUnknown};
int fps_ = 0;
int frame_count_ = 0;
std::chrono::steady_clock::time_point last_time_;
+5 -5
View File
@@ -67,11 +67,11 @@ struct RecentConnectionsState {
};
struct PeerState {
SignalStatus signal_status_ = SignalStatus::SignalClosed;
MiniRtcSignalStatus signal_status_ = MiniRtcSignalStatus::MiniRtcSignalClosed;
std::string signal_status_str_;
std::atomic<bool> signal_connected_{false};
PeerPtr *peer_ = nullptr;
PeerPtr *peer_reserved_ = nullptr;
MiniRtcPeerPtr *peer_ = nullptr;
MiniRtcPeerPtr *peer_reserved_ = nullptr;
std::string video_primary_label_ = "primary_display";
std::string video_secondary_label_ = "secondary_display";
std::string audio_label_ = "audio";
@@ -83,7 +83,7 @@ struct PeerState {
std::string file_label_ = kFileStream;
std::string file_feedback_label_ = kFileFeedbackStream;
std::string clipboard_label_ = kClipboardStream;
Params params_{};
MiniRtcParams params_{};
};
// OS-specific service and permission state is kept separate from transport
@@ -203,7 +203,7 @@ struct ConnectionState {
std::unordered_map<std::string, PendingReconnect> pending_reconnects_;
std::shared_mutex connection_status_mutex_;
std::unordered_map<std::string, ConnectionStatus> connection_status_;
std::unordered_map<std::string, MiniRtcConnectionStatus> connection_status_;
std::unordered_map<std::string, std::string> connection_host_names_;
std::unordered_set<std::string> codec_status_controllers_;
// Cursor position is sampled asynchronously after remote mouse input has
@@ -83,13 +83,13 @@ void Session::Error(MiniRtcDirectError error, void* context) {
s->failed = true;
}
}
void Session::Status(ConnectionStatus status) {
void Session::Status(MiniRtcConnectionStatus status) {
if (closing) return;
if (status == ConnectionStatus::Connected)
if (status == MiniRtcConnectionStatus::MiniRtcConnectionConnected)
ready = true;
else if (status == ConnectionStatus::Closed ||
status == ConnectionStatus::Failed ||
status == ConnectionStatus::Disconnected)
else if (status == MiniRtcConnectionStatus::MiniRtcConnectionClosed ||
status == MiniRtcConnectionStatus::MiniRtcConnectionFailed ||
status == MiniRtcConnectionStatus::MiniRtcConnectionDisconnected)
failed = true;
}
SessionManager::SessionManager(std::filesystem::path path, Hooks hooks)
@@ -417,9 +417,9 @@ void SessionManager::Prepare(const SessionPtr& s) {
options.send_signal = Session::SendSignal;
options.on_error = Session::Error;
options.context = s.get();
if (InitDirectPeer(prepared.peer, &options) != 0 ||
if (MiniRtcInitDirectPeer(prepared.peer, &options) != 0 ||
(!s->closing &&
StartDirectSession(prepared.peer, !s->incoming) != 0))
MiniRtcStartDirectSession(prepared.peer, !s->incoming) != 0))
s->failed = true;
return prepared;
})});
@@ -560,7 +560,7 @@ void SessionManager::Message(const SessionPtr& s, const std::string& text) {
Check(type == "candidate" &&
(s->phase == Session::AwaitAnswer ||
s->phase == Session::Negotiating || s->phase == Session::Connected));
if (ReceiveDirectSignal(s->peer, text.data(), text.size()) != 0)
if (MiniRtcReceiveDirectSignal(s->peer, text.data(), text.size()) != 0)
Fail(s, "InvalidSignal");
}
void SessionManager::Dispose(const SessionPtr& s) {
@@ -571,8 +571,8 @@ void SessionManager::Dispose(const SessionPtr& s) {
cleanup_jobs_.push_back(
std::async(std::launch::async, [s, peer, owner, drain]() mutable {
if (drain) drain();
CloseDirectSession(peer);
DestroyPeer(&peer);
MiniRtcCloseDirectSession(peer);
MiniRtcDestroyPeer(&peer);
}));
}
void SessionManager::Close(const SessionPtr& s, const std::string& error) {
@@ -43,7 +43,7 @@ struct Session {
bool incoming = false;
uint64_t epoch = 0, receive_seq = 0, send_seq = 0;
std::chrono::steady_clock::time_point deadline;
PeerPtr* peer = nullptr; // Only published/cleared by the manager.
MiniRtcPeerPtr* peer = nullptr; // Only published/cleared by the manager.
std::atomic<bool> closing{false}, authorized{false}, ready{false},
failed{false};
std::atomic<int> failure_code{-1};
@@ -54,7 +54,7 @@ struct Session {
std::function<void()> drain_callbacks;
static int SendSignal(const char* data, size_t size, void* context);
static void Error(MiniRtcDirectError error, void* context);
void Status(ConnectionStatus status);
void Status(MiniRtcConnectionStatus status);
};
// All public methods run on the GUI manager thread. Only Session's bounded
@@ -63,7 +63,7 @@ class SessionManager {
public:
using SessionPtr = std::shared_ptr<Session>;
struct Prepared {
PeerPtr* peer = nullptr;
MiniRtcPeerPtr* peer = nullptr;
std::shared_ptr<void> callback_owner;
std::function<void()> drain_callbacks;
};
@@ -120,7 +120,7 @@ void GuiRuntime::HandleWindowsServiceIntegration() {
std::shared_lock lock(connection_status_mutex_);
return std::any_of(connection_status_.begin(), connection_status_.end(),
[](const auto &entry) {
return entry.second == ConnectionStatus::Connected;
return entry.second == MiniRtcConnectionStatus::MiniRtcConnectionConnected;
});
}();
if (!has_connected_remote) {
@@ -80,7 +80,7 @@ int main() {
ReadFile(repo_root / "apps/desktop/src/gui/application/application_state.h");
bool ok = true;
ok &= ExpectContains("minirtc.h", minirtc_api, "RemoteUnavailable");
ok &= ExpectContains("minirtc.h", minirtc_api, "MiniRtcConnectionRemoteUnavailable");
ok &= ExpectNotContains("minirtc.h", minirtc_api, "DeviceOffline");
ok &= ExpectContains("peer_connection.cpp", peer_connection,
"on_connection_status_(ParseJoinFailure(j).status,");
@@ -88,17 +88,17 @@ int main() {
"IsCurrentPeerConnection");
ok &= ExpectContains(
"peer_connection.cpp", peer_connection,
"on_connection_status_(ConnectionStatus::Closed, remote_user_id.data()");
"on_connection_status_(MiniRtcConnectionStatus::MiniRtcConnectionClosed, remote_user_id.data()");
ok &= ExpectNotContains("peer_connection.cpp", peer_connection,
"\"Device offline\"");
ok &= ExpectNotContains("peer_connection.cpp", peer_connection,
"ConnectionStatus::DeviceOffline");
"MiniRtcConnectionStatus::MiniRtcConnectionDeviceOffline");
ok &= ExpectContains("main_window.slint", main_window,
"in property <bool> connection-dialog-open: false;");
ok &= ExpectContains("main_window.slint", main_window,
"text: root.connection-status-text;");
"text: root.prompt-status-text;");
ok &= ExpectContains("gui_application.cpp", gui_application,
"case ConnectionStatus::RemoteUnavailable:");
"case MiniRtcConnectionStatus::MiniRtcConnectionRemoteUnavailable:");
ok &= ExpectContains("gui_application.cpp", gui_application,
"return localization::device_offline[language];");
ok &= ExpectContains("runtime_state.h", runtime_state_h,
@@ -116,7 +116,7 @@ int main() {
// Reading a terminal transport status to reconnect is valid. This guard
// prohibits synthesizing a failure locally, not comparisons with Failed.
const std::regex synthetic_failure(
R"((connection_status_\s*(=\s*|\.\s*(store|exchange)\s*\(\s*)|OnConnectionStatus\s*\(\s*)ConnectionStatus::Failed\b)");
R"((connection_status_\s*(=\s*|\.\s*(store|exchange)\s*\(\s*)|OnConnectionStatus\s*\(\s*)MiniRtcConnectionStatus::MiniRtcConnectionFailed\b)");
if (std::regex_search(connection_runtime_cpp, synthetic_failure)) {
std::cerr << "connection_runtime.cpp synthesizes a Failed status\n";
ok = false;
@@ -124,7 +124,7 @@ int main() {
ok &= ExpectContains("peer_event_handler.cpp", peer_event_handler_cpp,
"props->connection_status_.store(status);");
ok &= ExpectContains("peer_event_handler.cpp", peer_event_handler_cpp,
"case ConnectionStatus::Failed:");
"case MiniRtcConnectionStatus::MiniRtcConnectionFailed:");
ok &= ExpectContains("connection_runtime.cpp", connection_runtime_cpp,
"HandleServerControllerDisconnected");
ok &= ExpectContains("peer_event_handler.cpp", peer_event_handler_cpp,
+35 -35
View File
@@ -100,23 +100,23 @@ class MobileSession {
if (self->Current(controller, generation)) fn(self, controller);
});
}
static void Signal(SignalStatus status, const char*, size_t, void* user) {
static void Signal(MiniRtcSignalStatus status, const char*, size_t, void* user) {
Dispatch(user, [status](MobileSession* s, bool controller) {
if (!controller) {
s->online_ = status == SignalConnected;
s->online_ = status == MiniRtcSignalConnected;
if (s->signal_status_ != status) {
++s->signal_generation_;
if (s->signal_status_ == SignalConnected) s->signal_started_ = Clock::now();
if (s->signal_status_ == MiniRtcSignalConnected) s->signal_started_ = Clock::now();
}
s->signal_status_ = status;
if (s->online_) {
constexpr char info[] = R"({"type":"client_info","version":"harmony-mobile","platform":"harmonyos"})";
SendSignalMessage(s->identity_, info, sizeof(info)-1);
MiniRtcSendSignalMessage(s->identity_, info, sizeof(info)-1);
}
}
s->Event({{"type", "signal"}, {"controller", controller}, {"status", status},
{"generation", s->signal_generation_}, {"id", s->login_.substr(0, s->login_.find('@'))}});
if (controller && status >= SignalFailed && status != SignalReconnecting) s->Disconnect("远程会话信令连接失败");
if (controller && status >= MiniRtcSignalFailed && status != MiniRtcSignalReconnecting) s->Disconnect("远程会话信令连接失败");
});
}
static void SignalMessage(const char* data, size_t size, void* user) {
@@ -130,29 +130,29 @@ class MobileSession {
s->Event({{"type", "signalMessage"}, {"message", value}, {"generation", s->signal_generation_}});
});
}
static void Connection(ConnectionStatus status, const char* id, size_t size, void* user) {
static void Connection(MiniRtcConnectionStatus status, const char* id, size_t size, void* user) {
const std::string remote(id ? id : "", id ? size : 0);
Dispatch(user, [status, remote](MobileSession* s, bool controller) {
if (!controller) {
// Defense in depth if a server tries to attach a guest to our identity.
if (status == Connected && s->identity_)
DisconnectPeerConnection(s->identity_, s->login_.substr(0,s->login_.find('@')).c_str(), remote.c_str());
if (status == MiniRtcConnectionConnected && s->identity_)
MiniRtcDisconnectPeerConnection(s->identity_, s->login_.substr(0,s->login_.find('@')).c_str(), remote.c_str());
return;
}
s->Event({{"type", "connection"}, {"status", status}}, true);
if (status == Connected && !s->connected_) {
if (status == MiniRtcConnectionConnected && !s->connected_) {
s->connecting_ = false; s->connected_ = true;
auto info = MakeHostInformation("CrossDesk HarmonyOS Mobile", {}, true, s->version_, HostPlatform::HarmonyOS);
info.i.supports_video_codec_status = true;
s->Send(info); FreeRemoteAction(info);
RemoteAction audio{}; audio.type = audio_capture; audio.a = !s->muted_; s->Send(audio);
s->audio_.Start();
} else if (status >= Disconnected) s->Disconnect("");
} else if (status >= MiniRtcConnectionDisconnected) s->Disconnect("");
});
}
static void Network(const char* id, size_t size, TraversalMode mode, const MiniRtcNetTrafficStats* stats,
static void Network(const char* id, size_t size, MiniRtcTraversalMode mode, const MiniRtcNetTrafficStats* stats,
const char*, size_t, void* user) {
if (mode == UnknownMode && id && size) {
if (mode == MiniRtcTraversalUnknown && id && size) {
const std::string login(id, size);
Dispatch(user, [login](MobileSession* s, bool controller) {
if (!controller) {
@@ -198,13 +198,13 @@ class MobileSession {
auto* c = static_cast<Context*>(user); auto* s = c->owner;
if (c->controller && c->generation == s->connection_ && s->connected_ && !s->muted_ && !s->suspended_) s->audio_.Push(data,size);
}
Params Parameters(bool controller) {
Params p{};
MiniRtcParams Parameters(bool controller) {
MiniRtcParams p{};
std::snprintf(p.signal_server_ip,sizeof(p.signal_server_ip),"%s",server_.c_str());
std::snprintf(p.log_path,sizeof(p.log_path),"%s",logs_.c_str());
p.signal_server_port = port_; p.enable_srtp = true; p.turn_mode = TurnAutoUdpTcp;
p.video_content_type = VideoContentType::ScreenContent; p.video_quality = QualityMedium; p.video_frame_rate = 30;
p.video_degradation_preference = VideoDegradationPreference::MaintainResolution;
p.signal_server_port = port_; p.enable_srtp = true; p.turn_mode = MiniRtcTurnAutoUdpTcp;
p.video_content_type = MiniRtcVideoContentType::ScreenContent; p.video_quality = MiniRtcVideoQualityMedium; p.video_frame_rate = 30;
p.video_degradation_preference = MiniRtcVideoDegradationPreference::MaintainResolution;
p.hardware_acceleration = true;
p.user_id = controller ? controller_login_.c_str() : login_.c_str();
p.user_data = controller ? control_context_.get() : identity_context_.get();
@@ -214,7 +214,7 @@ class MobileSession {
}
void Send(const RemoteAction& action, const char* stream = kControlStream) {
if (!controller_) return;
const auto bytes = action.to_json(); SendReliableDataFrame(controller_,bytes.data(),bytes.size(),stream);
const auto bytes = action.to_json(); MiniRtcSendReliableDataFrame(controller_,bytes.data(),bytes.size(),stream);
}
void Release() {
for (int key : keys_) { RemoteAction a{}; a.type=keyboard; a.k={size_t(key),0,false,key_up}; Send(a,kKeyboardStream); }
@@ -236,14 +236,14 @@ class MobileSession {
const bool active = controller_ != nullptr;
Release(); connected_=false; connecting_=false; ++video_generation_;
CancelPreview();
if (controller_) { LeaveConnection(controller_,remote_.c_str()); DestroyPeer(&controller_); }
if (controller_) { MiniRtcLeaveConnection(controller_,remote_.c_str()); MiniRtcDestroyPeer(&controller_); }
files_.reset(); renderer_.Clear(); audio_.Stop();
if (active) Event({{"type","ended"},{"reason",reason}},true);
++connection_; display_=0; frame_id_=0;
}
void Stop() {
Disconnect(""); online_=false;
if (identity_) DestroyPeer(&identity_);
if (identity_) MiniRtcDestroyPeer(&identity_);
++session_; login_.clear(); signal_status_=-1;
}
void Execute(const json& v) {
@@ -260,8 +260,8 @@ class MobileSession {
if (MiniRtcConfigureLogging(MiniRtcLogOff, nullptr, nullptr) != 0)
throw std::runtime_error("Unable to configure MiniRTC logging");
identity_context_=std::make_unique<Context>(Context{this,false,session_});
auto p=Parameters(false); identity_=CreatePeer(&p); signal_started_=Clock::now();
if (!identity_||Init(identity_)!=0) { throw std::runtime_error("Identity initialization failed"); }
auto p=Parameters(false); identity_=MiniRtcCreatePeer(&p); signal_started_=Clock::now();
if (!identity_||MiniRtcInit(identity_)!=0) { throw std::runtime_error("Identity initialization failed"); }
} else if (op=="stop") Stop();
else if (op=="version") {
const auto body=v.at("body").get<std::string>(), current=v.value("version","");
@@ -279,25 +279,25 @@ class MobileSession {
throw std::runtime_error("Invalid remote credentials");
muted_=false; suspended_=false; controller_login_="C-"+login_.substr(0,login_.find('@'));
control_context_=std::make_unique<Context>(Context{this,true,connection_});
auto p=Parameters(true); controller_=CreatePeer(&p); connecting_=true; connection_started_=Clock::now();
auto p=Parameters(true); controller_=MiniRtcCreatePeer(&p); connecting_=true; connection_started_=Clock::now();
if (!controller_) throw std::runtime_error("Peer creation failed");
AddAudioStream(controller_,kAudioStream); AddDataStream(controller_,kDataStream,false);
MiniRtcAddAudioStream(controller_,kAudioStream); MiniRtcAddDataStream(controller_,kDataStream,false);
for (auto stream : {kMouseStream,kKeyboardStream,kControlStream,kClipboardStream,kFileStream,kFileFeedbackStream})
AddDataStream(controller_,stream,true);
MiniRtcAddDataStream(controller_,stream,true);
files_=std::make_unique<mobile_controller::FileTransferSession>(
[this](const char* stream,const char* data,size_t size) { return controller_?SendReliableDataFrame(controller_,data,size,stream):-1; },
[this](const char* stream,const char* data,size_t size) { return controller_?MiniRtcSendReliableDataFrame(controller_,data,size,stream):-1; },
[this](const std::string& name,double progress,bool sending,const std::string& path) {
Event({{"type","file"},{"name",name},{"progress",progress},{"sending",sending},{"path",path}},true);
});
files_->SetDirectory(directory_+"/received");
if (Init(controller_)!=0||JoinConnection(controller_,(remote_+"@"+password).c_str())!=0) Disconnect("无法发起连接");
if (MiniRtcInit(controller_)!=0||MiniRtcJoinConnection(controller_,(remote_+"@"+password).c_str())!=0) Disconnect("无法发起连接");
} else if (op=="disconnect") Disconnect("");
else if (op=="release") Release();
else if (op=="signal" && online_ && identity_) {
auto request=v.at("message"); const auto type=request.value("type","");
if (type!="announcements_list"&&type!="recent_connections_presence") return;
request["user_id"]=login_.substr(0,login_.find('@'));
const auto bytes=request.dump(); const bool ok=SendSignalMessage(identity_,bytes.data(),bytes.size())==0;
const auto bytes=request.dump(); const bool ok=MiniRtcSendSignalMessage(identity_,bytes.data(),bytes.size())==0;
if (!ok) Event({{"type","requestFailed"},{"request",request.value("request_id","")}});
} else if (connected_) {
if (op=="pointer") {
@@ -323,22 +323,22 @@ class MobileSession {
RemoteAction a{}; a.type=audio_capture; a.a=!muted_; Send(a);
} else if (op=="clipboard") {
const auto text=v.at("text").get<std::string>();
if(!text.empty()&&text.size()<=kMaxClipboardBytes) SendReliableDataFrame(controller_,text.data(),text.size(),kClipboardStream);
if(!text.empty()&&text.size()<=kMaxClipboardBytes) MiniRtcSendReliableDataFrame(controller_,text.data(),text.size(),kClipboardStream);
} else if (op=="videoSettings") {
const int q=v.at("quality"),fps=v.at("frameRate"),pref=v.at("preference");
if(q<0||q>2||(fps!=30&&fps!=60)||pref<0||pref>2)return;
auto bytes=mobile_controller::VideoSettingsMessage(q,fps,pref,v.at("request").get<uint32_t>());
if(SendReliableDataFrame(controller_,bytes.data(),bytes.size(),kControlStream)!=0)
if(MiniRtcSendReliableDataFrame(controller_,bytes.data(),bytes.size(),kControlStream)!=0)
Event({{"type","settingsFailed"},{"request",v.at("request")}},true);
} else if (op=="privacy") {
const auto bytes = mobile_controller::PrivacyMessage(
v.at("flag").get<int>(), v.at("blockLocalInput").get<bool>());
if (bytes.empty() ||
SendReliableDataFrame(controller_, bytes.data(), bytes.size(), kControlStream) != 0)
MiniRtcSendReliableDataFrame(controller_, bytes.data(), bytes.size(), kControlStream) != 0)
Event({{"type", "privacyFailed"}, {"request", v.at("request")}}, true);
} else if (op=="sas") {
const auto bytes=mobile_controller::SecureAttentionMessage();
const bool ok=SendReliableDataFrame(controller_,bytes.data(),bytes.size(),kControlStream)==0;
const bool ok=MiniRtcSendReliableDataFrame(controller_,bytes.data(),bytes.size(),kControlStream)==0;
Event({{"type","feedback"},{"text",ok?"已发送 Ctrl+Alt+Del":"指令发送失败,请重试"}},true);
} else if (op=="sendFile") {
const auto path=v.at("path").get<std::string>(),name=v.at("name").get<std::string>();
@@ -368,7 +368,7 @@ class MobileSession {
for(int key:keys_) { if(a.ks.pressed_count>=kMaxKeyboardStateKeys)break; a.ks.pressed_keys[a.ks.pressed_count++]={size_t(key),0,false}; }
Send(a,kKeyboardStream); keyboard_sent_=now;
const auto local=std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count();
const auto rtc=GetSystemTimeMicros(controller_); if(rtc>0)clock_offset_=rtc-local;
const auto rtc=MiniRtcGetSystemTimeMicros(controller_); if(rtc>0)clock_offset_=rtc-local;
}
}
void Run() {
@@ -391,8 +391,8 @@ class MobileSession {
std::atomic<uint64_t> session_{0},connection_{0},video_generation_{1},frame_id_{0};
std::atomic<int64_t> clock_offset_{0};
std::atomic<int> display_{0};
PeerPtr* identity_=nullptr;
PeerPtr* controller_=nullptr;
MiniRtcPeerPtr* identity_=nullptr;
MiniRtcPeerPtr* controller_=nullptr;
std::unique_ptr<Context> identity_context_,control_context_;
std::unique_ptr<mobile_controller::FileTransferSession> files_;
std::string server_,logs_,login_,controller_login_,remote_,directory_,preview_directory_,preview_path_,version_;
+18 -18
View File
@@ -13,10 +13,10 @@
#include <sys/stat.h>
using namespace crossdesk;
struct Fixture {
PeerPtr* peer=nullptr; std::atomic<bool> connected{false}; std::atomic<int> selected{0};
MiniRtcPeerPtr* peer=nullptr; std::atomic<bool> connected{false}; std::atomic<int> selected{0};
std::mutex mutex; std::vector<std::pair<std::string,std::string>> messages;
std::string remote; std::atomic<int> signal{-1}; int keys=0,mouse=0,settings=0,clipboard=0;
void Send(RemoteAction& a) {const auto s=a.to_json();SendReliableDataFrame(peer,s.data(),s.size(),kControlStream);}
void Send(RemoteAction& a) {const auto s=a.to_json();MiniRtcSendReliableDataFrame(peer,s.data(),s.size(),kControlStream);}
};
int main(int argc,char**argv) {
if(argc<3)return 2;umask(0077);
@@ -24,19 +24,19 @@ int main(int argc,char**argv) {
setenv("SSL_CERT_DIR","/etc/security/certificates",1);
#endif
std::string login;{std::ifstream input("fixture-login");input>>login;}
Fixture f;Params p{};snprintf(p.signal_server_ip,sizeof(p.signal_server_ip),"%s",argv[1]);p.signal_server_port=atoi(argv[2]);p.user_id=login.c_str();p.user_data=&f;
p.turn_mode=TurnAutoUdpTcp;p.enable_srtp=true;p.av1_encoding=argc>3;p.video_frame_rate=30;p.video_quality=QualityMedium;
p.video_content_type=VideoContentType::ScreenContent;p.video_degradation_preference=VideoDegradationPreference::MaintainResolution;
p.on_signal_status=[](SignalStatus s,const char*,size_t,void*u){static_cast<Fixture*>(u)->signal=s;};
p.on_net_status_report=[](const char*id,size_t n,TraversalMode mode,const MiniRtcNetTrafficStats*,const char*,size_t,void*){
if(mode==UnknownMode&&id&&n&&std::string(id,n).find('@')!=std::string::npos){std::ofstream out("fixture-login");out.write(id,n);}
Fixture f;MiniRtcParams p{};snprintf(p.signal_server_ip,sizeof(p.signal_server_ip),"%s",argv[1]);p.signal_server_port=atoi(argv[2]);p.user_id=login.c_str();p.user_data=&f;
p.turn_mode=MiniRtcTurnAutoUdpTcp;p.enable_srtp=true;p.av1_encoding=argc>3;p.video_frame_rate=30;p.video_quality=MiniRtcVideoQualityMedium;
p.video_content_type=MiniRtcVideoContentType::ScreenContent;p.video_degradation_preference=MiniRtcVideoDegradationPreference::MaintainResolution;
p.on_signal_status=[](MiniRtcSignalStatus s,const char*,size_t,void*u){static_cast<Fixture*>(u)->signal=s;};
p.on_net_status_report=[](const char*id,size_t n,MiniRtcTraversalMode mode,const MiniRtcNetTrafficStats*,const char*,size_t,void*){
if(mode==MiniRtcTraversalUnknown&&id&&n&&std::string(id,n).find('@')!=std::string::npos){std::ofstream out("fixture-login");out.write(id,n);}
};
p.on_connection_status=[](ConnectionStatus s,const char*id,size_t n,void*u){auto*f=static_cast<Fixture*>(u);std::lock_guard lock(f->mutex);f->remote.assign(id,n);f->connected=s==Connected;if(s==Connected)f->selected=0;};
p.on_connection_status=[](MiniRtcConnectionStatus s,const char*id,size_t n,void*u){auto*f=static_cast<Fixture*>(u);std::lock_guard lock(f->mutex);f->remote.assign(id,n);f->connected=s==MiniRtcConnectionConnected;if(s==MiniRtcConnectionConnected)f->selected=0;};
p.on_receive_data_buffer=[](const char*d,size_t n,const char*,size_t,const char*s,size_t l,void*u){auto*f=static_cast<Fixture*>(u);std::lock_guard lock(f->mutex);f->messages.emplace_back(std::string(s,l),std::string(d,n));};
f.peer=CreatePeer(&p);AddVideoStream(f.peer,"Display1");AddVideoStream(f.peer,"Display2");AddAudioStream(f.peer,kAudioStream);AddDataStream(f.peer,kDataStream,false);
for(auto s:{kKeyboardStream,kMouseStream,kControlStream,kClipboardStream,kFileStream,kFileFeedbackStream})AddDataStream(f.peer,s,true);
if(Init(f.peer))return 3;
mobile_controller::FileTransferSession files([&](const char*s,const char*b,size_t n){return SendReliableDataFrame(f.peer,b,n,s);},
f.peer=MiniRtcCreatePeer(&p);MiniRtcAddVideoStream(f.peer,"Display1");MiniRtcAddVideoStream(f.peer,"Display2");MiniRtcAddAudioStream(f.peer,kAudioStream);MiniRtcAddDataStream(f.peer,kDataStream,false);
for(auto s:{kKeyboardStream,kMouseStream,kControlStream,kClipboardStream,kFileStream,kFileFeedbackStream})MiniRtcAddDataStream(f.peer,s,true);
if(MiniRtcInit(f.peer))return 3;
mobile_controller::FileTransferSession files([&](const char*s,const char*b,size_t n){return MiniRtcSendReliableDataFrame(f.peer,b,n,s);},
[](const std::string&,double p,bool,const std::string&path){if(p==1&&!path.empty())std::ofstream("received-result")<<path;});
files.SetDirectory("received");bool info=false;int iteration=0;
std::vector<uint8_t> pixels(640*360*3/2,128);int16_t pcm[480]{};
@@ -44,27 +44,27 @@ int main(int argc,char**argv) {
while(std::chrono::steady_clock::now()<end){
std::vector<std::pair<std::string,std::string>> messages;{std::lock_guard lock(f.mutex);messages.swap(f.messages);}
if(f.connected&&!info){auto a=MakeHostInformation("Synthetic mobile fixture",{{"Test pattern",0,0,640,360},{"Second display",0,0,640,360}},true,"1.6.1",HostPlatform::Windows);a.i.supports_video_settings=true;f.Send(a);FreeRemoteAction(a);info=true;
const std::string clip="CrossDesk synthetic clipboard";SendReliableDataFrame(f.peer,clip.data(),clip.size(),kClipboardStream);
const std::string clip="CrossDesk synthetic clipboard";MiniRtcSendReliableDataFrame(f.peer,clip.data(),clip.size(),kClipboardStream);
{std::ofstream out("sample.txt");out<<"Synthetic mobile file transfer\n";}files.Start("sample.txt","fixture.txt");}
if(!f.connected)info=false;
for(auto&[stream,bytes]:messages){
if(stream==kFileStream)files.Receive(bytes.data(),bytes.size());else if(stream==kFileFeedbackStream)files.Ack(bytes.data(),bytes.size());
else if(stream==kClipboardStream){f.clipboard++;SendReliableDataFrame(f.peer,bytes.data(),bytes.size(),kClipboardStream);}
else if(stream==kClipboardStream){f.clipboard++;MiniRtcSendReliableDataFrame(f.peer,bytes.data(),bytes.size(),kClipboardStream);}
else {RemoteAction a{};if(!a.from_json(bytes))continue;
if(a.type==host_infomation)info=false;
if(a.type==keyboard)f.keys++;if(a.type==mouse)f.mouse++;if(a.type==display_id)f.selected=a.d;
if(a.type==video_settings){f.settings++;a.type=video_settings_status;a.vs.accepted=true;f.Send(a);}FreeRemoteAction(a);}
}
if(f.connected){
files.Pump();MiniRtcAudioFrame audio{};audio.data=reinterpret_cast<const char*>(pcm);audio.size=sizeof(pcm);SendAudioFrame(f.peer,&audio,kAudioStream);
files.Pump();MiniRtcAudioFrame audio{};audio.data=reinterpret_cast<const char*>(pcm);audio.size=sizeof(pcm);MiniRtcSendAudioFrame(f.peer,&audio,kAudioStream);
if(iteration%3==0){for(int y=0;y<360;y++)for(int x=0;x<640;x++)pixels[y*640+x]=uint8_t(35+(x/80)*24+((y+iteration)%180<12?30:0));
std::fill(pixels.begin()+640*360,pixels.end(),128);for(size_t i=640*360;i<pixels.size();i+=2){pixels[i]=f.selected?80:170;pixels[i+1]=f.selected?170:80;}
MiniRtcVideoFrame frame{};frame.width=640;frame.height=360;frame.size=pixels.size();frame.data=reinterpret_cast<const char*>(pixels.data());
frame.captured_timestamp=std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
SendVideoFrame(f.peer,&frame,f.selected?"Display2":"Display1");}
MiniRtcSendVideoFrame(f.peer,&frame,f.selected?"Display2":"Display1");}
}
if(iteration++%100==0)std::ofstream("fixture-status")<<"signal="<<f.signal<<" connected="<<f.connected<<" mouse="<<f.mouse<<" keys="<<f.keys<<" settings="<<f.settings<<" clipboard="<<f.clipboard<<" display="<<f.selected<<"\n";
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
DestroyPeer(&f.peer);
MiniRtcDestroyPeer(&f.peer);
}
@@ -71,14 +71,14 @@ struct PresenceRequest {
};
struct RTCState {
PeerPtr *identity_peer = nullptr;
PeerPtr *controller_peer = nullptr;
MiniRtcPeerPtr *identity_peer = nullptr;
MiniRtcPeerPtr *controller_peer = nullptr;
CallbackContext identity_context;
CallbackContext controller_context;
std::string signal_host;
int signal_port = 0;
VideoDegradationPreference video_adaptation_policy =
VideoDegradationPreference::MaintainResolution;
MiniRtcVideoDegradationPreference video_adaptation_policy =
MiniRtcVideoDegradationPreference::MaintainResolution;
bool identity_ready = false;
std::deque<PresenceRequest> presence_requests;
bool identity_recovery_attempted = false;
@@ -337,7 +337,7 @@ void DispatchMain(dispatch_block_t block) {
sourceIDSize:(size_t)sourceIDSize
generation:(uint64_t)generation;
- (void)handleStats:(const MiniRtcNetTrafficStats *)stats
mode:(TraversalMode)mode
mode:(MiniRtcTraversalMode)mode
generation:(uint64_t)generation;
- (void)sendMessage:(const std::string &)message
reliable:(BOOL)reliable
@@ -389,7 +389,7 @@ void OnDataBuffer(const char *data, size_t size, const char *, size_t,
}
}
void OnSignalState(SignalStatus status, const char *, size_t, void *user_data) {
void OnSignalState(MiniRtcSignalStatus status, const char *, size_t, void *user_data) {
auto *context = static_cast<CallbackContext *>(user_data);
CrossDeskRTCBridge *owner = context ? context->owner : nil;
if (owner &&
@@ -410,7 +410,7 @@ void OnSignalMessage(const char *message, size_t size, void *user_data) {
}
}
void OnConnectionState(ConnectionStatus status, const char *remote_id,
void OnConnectionState(MiniRtcConnectionStatus status, const char *remote_id,
size_t remote_id_size, void *user_data) {
auto *context = static_cast<CallbackContext *>(user_data);
CrossDeskRTCBridge *owner = context ? context->owner : nil;
@@ -425,12 +425,12 @@ void OnConnectionState(ConnectionStatus status, const char *remote_id,
}
void OnNetworkStats(const char *peer_id, size_t peer_id_size,
TraversalMode mode, const MiniRtcNetTrafficStats *stats,
MiniRtcTraversalMode mode, const MiniRtcNetTrafficStats *stats,
const char *, size_t, void *user_data) {
auto *context = static_cast<CallbackContext *>(user_data);
CrossDeskRTCBridge *owner = context ? context->owner : nil;
if (!owner) return;
if (context->role == PeerRole::Identity && mode == TraversalMode::UnknownMode &&
if (context->role == PeerRole::Identity && mode == MiniRtcTraversalMode::MiniRtcTraversalUnknown &&
peer_id && peer_id_size > 0) {
[owner handleProvisionedIdentity:std::string(peer_id, peer_id_size)
generation:context->generation];
@@ -440,9 +440,9 @@ void OnNetworkStats(const char *peer_id, size_t peer_id_size,
}
}
Params MakeParams(const RTCState &state, const std::string &user_id,
MiniRtcParams MakeParams(const RTCState &state, const std::string &user_id,
CallbackContext *context) {
Params params{};
MiniRtcParams params{};
params.use_cfg_file = false;
CopyCString(params.signal_server_ip, sizeof(params.signal_server_ip),
state.signal_host);
@@ -452,10 +452,10 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
params.hardware_acceleration = true;
params.native_video_output = true;
params.av1_encoding = false;
params.turn_mode = TurnMode::TurnAutoUdpTcp;
params.turn_mode = MiniRtcTurnMode::MiniRtcTurnAutoUdpTcp;
params.enable_srtp = true;
params.video_content_type = VideoContentType::ScreenContent;
params.video_quality = VideoQuality::QualityHigh;
params.video_content_type = MiniRtcVideoContentType::ScreenContent;
params.video_quality = MiniRtcVideoQuality::MiniRtcVideoQualityHigh;
params.video_frame_rate = 60;
params.video_degradation_preference = state.video_adaptation_policy;
params.on_receive_video_buffer = nullptr;
@@ -654,16 +654,16 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
switch (policy) {
case CrossDeskVideoAdaptationPolicyFrameRatePriority:
self->_state->video_adaptation_policy =
VideoDegradationPreference::MaintainFrameRate;
MiniRtcVideoDegradationPreference::MaintainFrameRate;
break;
case CrossDeskVideoAdaptationPolicyBalanced:
self->_state->video_adaptation_policy =
VideoDegradationPreference::Balanced;
MiniRtcVideoDegradationPreference::Balanced;
break;
case CrossDeskVideoAdaptationPolicyQualityPriority:
default:
self->_state->video_adaptation_policy =
VideoDegradationPreference::MaintainResolution;
MiniRtcVideoDegradationPreference::MaintainResolution;
break;
}
});
@@ -685,7 +685,7 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
networking_generation != self->_networkingGeneration.load()) return;
if (self->_state->identity_peer && self->_state->identity_ready &&
!self->_state->identity_base.empty() &&
SendSignalMessage(self->_state->identity_peer,
MiniRtcSendSignalMessage(self->_state->identity_peer,
static_cast<const char *>(payload.bytes), payload.length) == 0) return;
DispatchMain(^{
if (generation != self->_identityGeneration.load() ||
@@ -714,7 +714,7 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
action.vs = {static_cast<int>(quality), static_cast<int>(frameRate),
static_cast<int>(preference), requestID, false};
const auto message = action.to_json();
if (SendReliableDataFrame(self->_state->controller_peer, message.data(),
if (MiniRtcSendReliableDataFrame(self->_state->controller_peer, message.data(),
message.size(), kControlStream) != 0) {
[self notifyVideoSettings:action.vs generation:generation];
}
@@ -771,7 +771,7 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
options:0
error:nil];
if (!payload) return;
if (SendSignalMessage(self->_state->identity_peer,
if (MiniRtcSendSignalMessage(self->_state->identity_peer,
static_cast<const char *>(payload.bytes),
payload.length) == 0) {
// Both old and new servers return snapshots in request order. Retain the
@@ -844,7 +844,7 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
if (self->_state->controller_peer) {
const std::string stream = crossdesk::MakeDisplayStreamId(
static_cast<size_t>(self->_selectedDisplay.load()));
RequestVideoKeyFrame(self->_state->controller_peer, stream.c_str());
MiniRtcRequestVideoKeyFrame(self->_state->controller_peer, stream.c_str());
}
});
}
@@ -896,19 +896,19 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
if (!mapping.valid) continue;
if (mapping.shift) {
const std::string shift_down = KeyJSON(0x10, true);
SendReliableDataFrame(self->_state->controller_peer,
MiniRtcSendReliableDataFrame(self->_state->controller_peer,
shift_down.data(), shift_down.size(),
kKeyboardStream);
}
const std::string key_down = KeyJSON(mapping.key_code, true);
const std::string key_up = KeyJSON(mapping.key_code, false);
SendReliableDataFrame(self->_state->controller_peer, key_down.data(),
MiniRtcSendReliableDataFrame(self->_state->controller_peer, key_down.data(),
key_down.size(), kKeyboardStream);
SendReliableDataFrame(self->_state->controller_peer, key_up.data(),
MiniRtcSendReliableDataFrame(self->_state->controller_peer, key_up.data(),
key_up.size(), kKeyboardStream);
if (mapping.shift) {
const std::string shift_up = KeyJSON(0x10, false);
SendReliableDataFrame(self->_state->controller_peer, shift_up.data(),
MiniRtcSendReliableDataFrame(self->_state->controller_peer, shift_up.data(),
shift_up.size(), kKeyboardStream);
}
}
@@ -1032,7 +1032,7 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
send_result = -1;
break;
}
send_result = SendReliableDataFrame(self->_state->controller_peer,
send_result = MiniRtcSendReliableDataFrame(self->_state->controller_peer,
chunk.data(), chunk.size(),
kFileStream);
offset += bytes_read;
@@ -1063,7 +1063,7 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
static_cast<bool>(blockLocalInput)};
const auto message = action.to_json();
const BOOL success = self->_state->controller_peer &&
SendReliableDataFrame(self->_state->controller_peer, message.data(),
MiniRtcSendReliableDataFrame(self->_state->controller_peer, message.data(),
message.size(), kControlStream) == 0;
DispatchMain(^{
if (![self isControllerGenerationActive:generation]) return;
@@ -1083,7 +1083,7 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
action.c.flag = ServiceCommandFlag::send_sas;
const auto message = action.to_json();
const BOOL success = self->_state->controller_peer &&
SendReliableDataFrame(self->_state->controller_peer, message.data(), message.size(), kControlStream) == 0;
MiniRtcSendReliableDataFrame(self->_state->controller_peer, message.data(), message.size(), kControlStream) == 0;
DispatchMain(^{
if (![self isControllerGenerationActive:generation]) return;
id<CrossDeskRTCBridgeDelegate> delegate = self.delegate;
@@ -1107,11 +1107,11 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
if (![self isControllerGenerationActive:generation] ||
!self->_state->controller_peer) return;
if (reliable) {
SendReliableDataFrame(self->_state->controller_peer,
MiniRtcSendReliableDataFrame(self->_state->controller_peer,
owned_message.data(), owned_message.size(),
owned_stream.c_str());
} else {
SendDataFrame(self->_state->controller_peer, owned_message.data(),
MiniRtcSendDataFrame(self->_state->controller_peer, owned_message.data(),
owned_message.size(), owned_stream.c_str());
}
});
@@ -1134,10 +1134,10 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
- (void)createIdentityPeer {
if (_state->identity_peer || _state->signal_host.empty()) return;
_state->identity_context.generation = _identityGeneration.fetch_add(1) + 1;
Params params = MakeParams(*_state, _state->identity_with_password,
MiniRtcParams params = MakeParams(*_state, _state->identity_with_password,
&_state->identity_context);
_state->identity_peer = CreatePeer(&params);
if (!_state->identity_peer || Init(_state->identity_peer) != 0) {
_state->identity_peer = MiniRtcCreatePeer(&params);
if (!_state->identity_peer || MiniRtcInit(_state->identity_peer) != 0) {
[self destroyIdentityPeer];
[self handleSignalState:CrossDeskSignalStateFailed
role:PeerRole::Identity
@@ -1155,9 +1155,9 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
_state->controller_context.generation = generation;
_activeControllerGeneration.store(generation);
_state->controller_login = "C-" + _state->identity_base;
Params params = MakeParams(*_state, _state->controller_login,
MiniRtcParams params = MakeParams(*_state, _state->controller_login,
&_state->controller_context);
_state->controller_peer = CreatePeer(&params);
_state->controller_peer = MiniRtcCreatePeer(&params);
if (!_state->controller_peer) {
_activeControllerGeneration.store(0);
[self handleConnectionState:CrossDeskConnectionStateFailed
@@ -1168,16 +1168,16 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
// This native iOS peer is controller-only and does not publish a local
// display. Remote display receivers are created from the host's SDP.
AddAudioStream(_state->controller_peer, kAudioStream);
AddDataStream(_state->controller_peer, kDataStream, false);
AddDataStream(_state->controller_peer, kMouseStream, true);
AddDataStream(_state->controller_peer, kKeyboardStream, true);
AddDataStream(_state->controller_peer, kControlStream, true);
AddDataStream(_state->controller_peer, kFileStream, true);
AddDataStream(_state->controller_peer, kFileFeedbackStream, true);
AddDataStream(_state->controller_peer, kClipboardStream, true);
MiniRtcAddAudioStream(_state->controller_peer, kAudioStream);
MiniRtcAddDataStream(_state->controller_peer, kDataStream, false);
MiniRtcAddDataStream(_state->controller_peer, kMouseStream, true);
MiniRtcAddDataStream(_state->controller_peer, kKeyboardStream, true);
MiniRtcAddDataStream(_state->controller_peer, kControlStream, true);
MiniRtcAddDataStream(_state->controller_peer, kFileStream, true);
MiniRtcAddDataStream(_state->controller_peer, kFileFeedbackStream, true);
MiniRtcAddDataStream(_state->controller_peer, kClipboardStream, true);
if (Init(_state->controller_peer) != 0) {
if (MiniRtcInit(_state->controller_peer) != 0) {
[self destroyControllerPeer];
[self handleConnectionState:CrossDeskConnectionStateFailed
remoteID:_state->pending_remote_id
@@ -1186,7 +1186,7 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
}
const std::string join_id = _state->pending_remote_id + "@" +
_state->pending_password;
JoinConnection(_state->controller_peer, join_id.c_str());
MiniRtcJoinConnection(_state->controller_peer, join_id.c_str());
// Joining authenticates with "remote-id@password", while leaving is routed
// by the remote peer ID alone (the same contract used by the desktop app).
@@ -1198,7 +1198,7 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
_presenceGeneration.fetch_add(1);
_state->presence_requests.clear();
if (_state->identity_peer) {
DestroyPeer(&_state->identity_peer);
MiniRtcDestroyPeer(&_state->identity_peer);
}
_state->identity_ready = false;
}
@@ -1207,10 +1207,10 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
_activeControllerGeneration.store(0);
if (_state->controller_peer) {
if (!_state->transmission_id.empty()) {
LeaveConnection(_state->controller_peer,
MiniRtcLeaveConnection(_state->controller_peer,
_state->transmission_id.c_str());
}
DestroyPeer(&_state->controller_peer);
MiniRtcDestroyPeer(&_state->controller_peer);
}
_state->controller_login.clear();
_state->transmission_id.clear();
@@ -1248,7 +1248,7 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
constexpr char client_info[] =
"{\"type\":\"client_info\",\"version\":\"ios-native\","
"\"platform\":\"ios\"}";
SendSignalMessage(self->_state->identity_peer, client_info,
MiniRtcSendSignalMessage(self->_state->identity_peer, client_info,
sizeof(client_info) - 1);
}
if (state == CrossDeskSignalStateFailed &&
@@ -1456,11 +1456,11 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
action.i.right = nullptr;
action.i.bottom = nullptr;
const std::string host_info = action.to_json();
SendReliableDataFrame(self->_state->controller_peer, host_info.data(),
MiniRtcSendReliableDataFrame(self->_state->controller_peer, host_info.data(),
host_info.size(), kControlStream);
const std::string stream = crossdesk::MakeDisplayStreamId(
static_cast<size_t>(self->_selectedDisplay.load()));
RequestVideoKeyFrame(self->_state->controller_peer, stream.c_str());
MiniRtcRequestVideoKeyFrame(self->_state->controller_peer, stream.c_str());
});
}
DispatchMain(^{
@@ -1506,7 +1506,7 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
// Translate the transport's calibrated capture time once, while the peer is
// alive. Carry it with the exact pixels through coalescing and UI submission.
const NSTimeInterval now = NSProcessInfo.processInfo.systemUptime;
const int64_t peer_now = GetSystemTimeMicros(_state->controller_peer);
const int64_t peer_now = MiniRtcGetSystemTimeMicros(_state->controller_peer);
NSTimeInterval capture_uptime = 0;
if (frame->captured_timestamp > 0 && peer_now > 0 &&
frame->captured_timestamp <= static_cast<uint64_t>(peer_now) &&
@@ -2009,7 +2009,7 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
if ([self isControllerGenerationActive:generation] && self->_state->controller_peer) {
const auto encoded_ack =
crossdesk::EncodeFileTransferAck(ack);
SendReliableDataFrame(self->_state->controller_peer,
MiniRtcSendReliableDataFrame(self->_state->controller_peer,
encoded_ack.data(), encoded_ack.size(),
kFileFeedbackStream);
}
@@ -2035,7 +2035,7 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
}
- (void)handleStats:(const MiniRtcNetTrafficStats *)stats
mode:(TraversalMode)mode
mode:(MiniRtcTraversalMode)mode
generation:(uint64_t)generation {
if (!stats) return;
const auto traffic = [](const MiniRtcInboundStats &inbound,
@@ -2049,8 +2049,8 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
traffic(stats->data_inbound_stats, stats->data_outbound_stats),
traffic(stats->total_inbound_stats, stats->total_outbound_stats),
stats->rtt_ms, static_cast<BOOL>(stats->srtp_active),
mode == TraversalMode::P2P ? CrossDeskTraversalModeDirect
: mode == TraversalMode::Relay ? CrossDeskTraversalModeRelay
mode == MiniRtcTraversalMode::MiniRtcTraversalP2P ? CrossDeskTraversalModeDirect
: mode == MiniRtcTraversalMode::MiniRtcTraversalRelay ? CrossDeskTraversalModeRelay
: CrossDeskTraversalModeUnknown};
NSString *decoder = [[NSString alloc]
initWithBytes:stats->video_decoder
+7 -7
View File
@@ -76,9 +76,9 @@ sequenceDiagram
end
```
1. `GuiRuntime::CreateConnectionPeer()` 创建本机的常驻 MiniRTC Peer,`Init()` 连接信令服务并登录。控制另一个设备时,`ConnectTo()` 创建或复用对应的 `RemoteSession` 和控制端 Peer;该会话 Peer 以 `C-<本机ID>` 作为登录身份,使用独立的信令连接。
1. `GuiRuntime::CreateConnectionPeer()` 创建本机的常驻 MiniRTC Peer,`MiniRtcInit()` 连接信令服务并登录。控制另一个设备时,`ConnectTo()` 创建或复用对应的 `RemoteSession` 和控制端 Peer;该会话 Peer 以 `C-<本机ID>` 作为登录身份,使用独立的信令连接。
2. 普通交互连接在需要时进行在线探测;桌面墙后台连接可以直接由 Join 结果判定可用性。没有密码时先在本地弹窗收集,不先发送一次空密码请求。
3. 当前桌面调用为 `JoinConnection(peer, "目标ID@密码")`,MiniRTC 将其放入 `join_transmission` 的 `transmission_id`,经 WSS 提交给信令服务。登录尚未完成时,Join 会等待登录结果。
3. 当前桌面调用为 `MiniRtcJoinConnection(peer, "目标ID@密码")`,MiniRTC 将其放入 `join_transmission` 的 `transmission_id`,经 WSS 提交给信令服务。登录尚未完成时,Join 会等待登录结果。
4. 服务端的加入通知驱动被控端发起 offer,控制端回复 answer;双方通过服务端转发 ICE 候选。支持新版协议的服务端提供每次连接的 ICE 配置及有效期,客户端仍保留旧服务端兼容路径。
5. MiniRTC 根据中继设置、对端能力和网络条件选择直连或中继。数据不通过信令 WebSocket 搬运。当前桌面端始终请求 SRTP;原生 ID 会话仍允许第 4.1 节所述的旧端兼容行为,因此请求 SRTP 不代表所有数据最终都经过加密。
@@ -160,9 +160,9 @@ sequenceDiagram
end
```
IP 直连由**控制端**发起 offer。双方内部 ID 和随机 `session_id` 用于本次会话路由,不需要用户填写设备 ID。协商消息带会话 ID 和严格递增序号;会话管理器检查状态顺序,再调用 `ReceiveDirectSignal()`。MiniRTC 进一步检查 SDP、候选数量、地址和 ICE 标识一致性,并去重候选。
IP 直连由**控制端**发起 offer。双方内部 ID 和随机 `session_id` 用于本次会话路由,不需要用户填写设备 ID。协商消息带会话 ID 和严格递增序号;会话管理器检查状态顺序,再调用 `MiniRtcReceiveDirectSignal()`。MiniRTC 进一步检查 SDP、候选数量、地址和 ICE 标识一致性,并去重候选。
SessionManager 将当前 WSS socket 的本地与对端 IPv4/IPv6 传入 `InitDirectPeer()`,由 MiniRTC 构造 `HostOnly` 策略,启动独立 ICE worker,不执行云端登录。MiniRTC 通过 `SignalSender` 回调把协商消息交给 SessionManager,再由 WSS 发送。
SessionManager 将当前 WSS socket 的本地与对端 IPv4/IPv6 传入 `MiniRtcInitDirectPeer()`,由 MiniRTC 构造 `HostOnly` 策略,启动独立 ICE worker,不执行云端登录。MiniRTC 通过 `SignalSender` 回调把协商消息交给 SessionManager,再由 WSS 发送。
MiniRTC 关闭 STUN/TURN 服务器访问、UPnP、ICE TCP 和公网打洞扩展,仅收集指定本机 IPv4/IPv6 的 UDP host 候选。libnice 的 `direct-peer-address` 补丁同时检查远端候选和入站来源:在解析 STUN 连通性检查、学习新候选或回复数据之前,拒绝不匹配的 IP。ICE 自身的 STUN 检查报文仍会在双方之间使用,这与访问 STUN 服务器是两回事。
@@ -188,7 +188,7 @@ WSS 在连接成功后继续承担心跳和会话关闭消息。当前心跳约
旧 ID 首次升级时,客户端先完成签名证明,再按服务端要求提交原有密码;密码验证成功后仅允许绑定一次公钥,保留 ID 和密码。绑定后撤销旧重连令牌并拒绝密码登录,不能用密码覆盖公钥;尚未完成绑定的旧 ID 按来源 IP 及“来源 IP → 目标 ID”限流,不保留目标 ID 的总失败次数。部署时先升级服务端;新桌面客户端要求签名协议,不自动回退到旧服务端的密码登录。混部或回滚到忽略公钥绑定的旧服务端会失去这项保护。
MiniRTC 的可选 `OnSignalExchange` 回调提供登录请求替换、入站消息处理及回复发送能力,不包含设备密钥、可信名单或 CrossDesk 协议字段。应用层负责签名和协议状态;未配置回调的使用方保留原有登录及内存重连令牌行为。改密中断后,签名登录不代表待定密码已生效,客户端重发持久保存的改密请求,收到成功回复后才更新本地密码。
MiniRTC 的可选 `MiniRtcOnSignalExchange` 回调提供登录请求替换、入站消息处理及回复发送能力,不包含设备密钥、可信名单或 CrossDesk 协议字段。应用层负责签名和协议状态;未配置回调的使用方保留原有登录及内存重连令牌行为。改密中断后,签名登录不代表待定密码已生效,客户端重发持久保存的改密请求,收到成功回复后才更新本地密码。
连接目标设备时,控制端会话 Peer 仍将 `目标ID@目标密码` 放入 Join,由服务端返回成功、凭据错误、限流或繁忙结果。设备签名登录仅证明本机 ID 所有权,不授予控制其他设备的权限。服务端按已验证控制端 B 和“B → A”组合累计失败(分别为 20/5 次),不保留 A 的总失败次数;B 的失败不会触发 C 连接 A 的密码冷却。认证队列和计算额度也按已验证控制端隔离。未验证的旧客户端、Web/CLI 临时身份按来源 IP 处理,无法通过自称 `C-B` 获得 B 的预算。已绑定 B 的 `C-B` 登录必须支持签名协议;同一 NAT 下旧客户端仍共享 IP 限制,显式 IP 风控与服务器资源上限仍然适用。
@@ -249,7 +249,7 @@ MiniRTC 仅通过现有可靠数据通道收发这些应用消息,不提供可
flowchart TD
UI["MainWindow / GuiApplication"] --> ID["GuiRuntime::ConnectTo"]
UI --> IP["GuiRuntime::ConnectLan"]
ID --> Managed["MiniRTC Init / JoinConnection"]
ID --> Managed["MiniRtcInit / MiniRtcJoinConnection"]
IP --> LAN["LAN SessionManager / Transport"]
LAN --> Direct["MiniRTC InitDirectPeer / StartDirectSession"]
Managed --> Common["MiniRtcConnection / IceTransport / IceAgent"]
@@ -265,7 +265,7 @@ flowchart TD
- **业务复用:** `ControllerEvents()`、`WithController()` 等根据会话类型路由到正确 Peer。视频、音频、键鼠、文件、剪贴板仍交给原有回调和功能模块;采集设备按整体连接需求管理。
- **线程分工:** SessionManager 的公开操作和 `Tick()` 在 GUI 管理线程运行;Transport 使用一个共享 Asio 网络线程,回调仅提交有界事件。密码计算、Peer 准备与销毁在后台任务执行,MiniRTC 自身处理 ICE 和媒体工作。
- **数据放行:** LAN 业务回调检查会话授权和关闭状态。加密就绪通知与数据到达可能交错,少量早期控制消息会在有界队列中暂存,授权后按序处理;其他业务数据不因排队而提前获得授权。
- **关闭顺序:** 标记关闭并停止新回调,取消会话相关传输,关闭 WSS;后台排空已有回调,再执行 `CloseDirectSession()` 和 `DestroyPeer()`。网络回调中不直接销毁 Peer。
- **关闭顺序:** 标记关闭并停止新回调,取消会话相关传输,关闭 WSS;后台排空已有回调,再执行 `MiniRtcCloseDirectSession()` 和 `MiniRtcDestroyPeer()`。网络回调中不直接销毁 Peer。
- **资源边界:** 当前管理器最多保留 24 个通道,未认证接入最多 16 个,异步密码验证与 Peer 准备各最多 2 个任务,同时准入的准备中/已认证会话最多 8 个。协商还设有消息数量、字节和阶段超时限制,防止无限队列或等待。
关闭 IP 功能时,运行时等待会话、密码任务、准备任务及清理任务全部结束,再释放 LAN 管理器和网络线程。快速关闭后重新开启会等待旧实例排空;应用退出时不会重新创建监听。
+3 -3
View File
@@ -59,11 +59,11 @@
可靠控制通道的 `deskhub_preview` v2 保留 v1 的 `request_id`、`fps`、`quality`、`frame_rate`、`preference`、`audio` 字段,新增必填 `width`、`height` 整数,单位为物理像素。两个值均为 0 表示恢复源尺寸上限,否则两个值均须在 2~16384 之间;非法或缺失的值不应用。`deskhub_preview_status` 回传请求的协议版本、请求 ID 与 `accepted`。请求 ID 跳过 0,支持 32 位回绕,重复或过期请求不会覆盖新设置。断开会话清除订阅和 15 FPS 协商能力,再连接会重新发送当前需求。15 FPS 扩展通过可选能力 `supports_deskhub_fps15` 协商,沿用 v1/v2 的字段结构,使用 `fps=15, frame_rate=30`,在编码前将实际输入限制为 15 FPS。
带宽扩展沿用 v1/v2,增加可选整数 `max_bitrate_bps`(0~100000000,单位 bps),仅向声明 `supports_deskhub_bandwidth` 的对端发送。0 或缺省表示解除额外的视频预算限制;暂停视频仍使用 `fps=0`。非法字段拒绝整个订阅,断开后清除能力,重连重新协商。MiniRTC 的 `UpdateVideoBitrateLimit(peer, remote_id, remote_id_size, max_bitrate_bps)` 为指定连接的所有视频流设置合计预算,不改变音频与数据发送;返回 0 表示已进入拥塞控制队列,-1 表示参数、连接或传输不支持。
带宽扩展沿用 v1/v2,增加可选整数 `max_bitrate_bps`(0~100000000,单位 bps),仅向声明 `supports_deskhub_bandwidth` 的对端发送。0 或缺省表示解除额外的视频预算限制;暂停视频仍使用 `fps=0`。非法字段拒绝整个订阅,断开后清除能力,重连重新协商。MiniRTC 的 `MiniRtcUpdateVideoBitrateLimit(peer, remote_id, remote_id_size, max_bitrate_bps)` 为指定连接的所有视频流设置合计预算,不改变音频与数据发送;返回 0 表示已进入拥塞控制队列,-1 表示参数、连接或传输不支持。
MiniRTC 新增 `UpdateVideoResolution(peer, remote_id, remote_id_size, width, height)` 接口,返回 0 表示已接受,-1 表示参数、连接或传输类型不支持。它为指定控制端的所有显示流设置独立尺寸上限,切换时丢弃旧设置尚未发出的编码结果,并请求新关键帧;底层自适应也以这个上限作为有效源尺寸。
MiniRTC 新增 `MiniRtcUpdateVideoResolution(peer, remote_id, remote_id_size, width, height)` 接口,返回 0 表示已接受,-1 表示参数、连接或传输类型不支持。它为指定控制端的所有显示流设置独立尺寸上限,切换时丢弃旧设置尚未发出的编码结果,并请求新关键帧;底层自适应也以这个上限作为有效源尺寸。
`SetVideoSendPaused(peer, remote_id, remote_id_size, paused)` 与 `SetAudioSendPaused(peer, remote_id, remote_id_size, paused)` 分别控制指定连接的所有视频/音频发送通道,`true` 暂停、`false` 恢复。重复设置不产生额外操作;返回 0 表示接受,-1 表示参数、连接或传输类型不支持。视频暂停阻止新帧进入编码,废弃旧编码结果,并在发送队列上清除待发视频/重传/纠错包,停止探测和填充;恢复请求新关键帧。音频暂停阻止 PCM 编码并清理待发音频,恢复时仅发送新音频。已交给网络的包无法撤回。API 保留连接、采集源、码率与画质设置以及其他媒体/数据通道,也不改变其他控制端的发送状态。
`MiniRtcSetVideoSendPaused(peer, remote_id, remote_id_size, paused)` 与 `MiniRtcSetAudioSendPaused(peer, remote_id, remote_id_size, paused)` 分别控制指定连接的所有视频/音频发送通道,`true` 暂停、`false` 恢复。重复设置不产生额外操作;返回 0 表示接受,-1 表示参数、连接或传输类型不支持。视频暂停阻止新帧进入编码,废弃旧编码结果,并在发送队列上清除待发视频/重传/纠错包,停止探测和填充;恢复请求新关键帧。音频暂停阻止 PCM 编码并清理待发音频,恢复时仅发送新音频。已交给网络的包无法撤回。API 保留连接、采集源、码率与画质设置以及其他媒体/数据通道,也不改变其他控制端的发送状态。
桌面墙将 `fps=0` 和 `audio=false` 分别映射到上述 API;应用层仅保留低帧率节流,不再使用 `1 bps` 代替视频暂停或在采集回调中过滤静音音频。接收端仍保留静音门控及播放队列清理,以立即停止播放网络中已在途的音频。旧版 `audio_capture` 命令在支持新 API 的传输中也按连接静音,已有订阅的音频状态优先;不支持 API 的旧/Web 传输沿用采集开关回退。
+1 -1
View File
@@ -170,7 +170,7 @@ MainWindow::connect_requested
→ GuiRuntime::ConnectTo
→ 在线状态探测
→ 创建或复用 RemoteSession
→ MiniRTC JoinConnection
→ MiniRtcJoinConnection
→ PeerEventHandler 接收连接状态
→ SyncStreamWindow 创建串流窗口并开始呈现视频
```
+6 -6
View File
@@ -113,12 +113,12 @@ private:
void Enqueue(Event event) noexcept;
void Fail(const char *reason);
void ClosePeers();
Params Parameters();
MiniRtcParams Parameters();
bool Send(const char *stream, const std::string &payload);
bool SendInput(const char *stream, const RemoteAction &action);
void Preview();
static void Signal(SignalStatus, const char *, size_t, void *);
static void Connection(ConnectionStatus, const char *, size_t, void *);
static void Signal(MiniRtcSignalStatus, const char *, size_t, void *);
static void Connection(MiniRtcConnectionStatus, const char *, size_t, void *);
static void Data(const char *, size_t, const char *, size_t, const char *,
size_t, void *);
static void Audio(const char *, size_t, const char *, size_t,
@@ -127,11 +127,11 @@ private:
const char *, size_t, void *);
static int EncodedVideo(const uint8_t *, size_t, int64_t, const char *,
size_t, const char *, size_t, void *);
static void Network(const char *, size_t, TraversalMode,
static void Network(const char *, size_t, MiniRtcTraversalMode,
const MiniRtcNetTrafficStats *, const char *, size_t,
void *);
SessionOptions options_;
PeerPtr *peer_ = nullptr;
MiniRtcPeerPtr *peer_ = nullptr;
std::string state_ = "idle", error_, device_, password_, client_id_;
nlohmann::json remote_capabilities_ = nlohmann::json::object();
uint64_t remote_sequence_ = 0, capability_request_ = 0;
@@ -160,7 +160,7 @@ private:
uint64_t callback_generation_ = 0;
int callback_display_ = 0;
MiniRtcNetTrafficStats network_{};
TraversalMode traversal_ = UnknownMode;
MiniRtcTraversalMode traversal_ = MiniRtcTraversalUnknown;
LatestFrame frames_;
bool audio_enabled_ = false;
size_t audio_bytes_ = 0;
@@ -34,7 +34,7 @@ inline std::string VideoSettingsMessage(int quality, int frame_rate, int prefere
return action.to_json();
}
inline nlohmann::json NetworkReport(const MiniRtcNetTrafficStats& stats, TraversalMode mode) {
inline nlohmann::json NetworkReport(const MiniRtcNetTrafficStats& stats, MiniRtcTraversalMode mode) {
const auto traffic = [](const MiniRtcInboundStats& in, const MiniRtcOutboundStats& out) {
return nlohmann::json{{"inbound", in.bitrate}, {"outbound", out.bitrate}, {"loss", in.loss_rate}};
};
+36 -36
View File
@@ -25,7 +25,7 @@ void ControllerSession::Enqueue(Event e) noexcept {
} catch (...) { /* Allocation failure cannot escape a C callback. */
}
}
void ControllerSession::Signal(SignalStatus s, const char *id, size_t n,
void ControllerSession::Signal(MiniRtcSignalStatus s, const char *id, size_t n,
void *p) {
try {
static_cast<ControllerSession *>(p)->Enqueue(
@@ -33,7 +33,7 @@ void ControllerSession::Signal(SignalStatus s, const char *id, size_t n,
} catch (...) {
}
}
void ControllerSession::Connection(ConnectionStatus s, const char *, size_t,
void ControllerSession::Connection(MiniRtcConnectionStatus s, const char *, size_t,
void *p) {
auto &session = *static_cast<ControllerSession *>(p);
session.Enqueue({1, s, {}});
@@ -73,7 +73,7 @@ void ControllerSession::Video(const MiniRtcVideoFrame *f, const char *, size_t,
} catch (...) {
}
}
void ControllerSession::Network(const char *, size_t, TraversalMode mode,
void ControllerSession::Network(const char *, size_t, MiniRtcTraversalMode mode,
const MiniRtcNetTrafficStats *stats,
const char *, size_t, void *p) {
auto &session = *static_cast<ControllerSession *>(p);
@@ -83,8 +83,8 @@ void ControllerSession::Network(const char *, size_t, TraversalMode mode,
session.traversal_ = mode;
}
}
Params ControllerSession::Parameters() {
Params p{};
MiniRtcParams ControllerSession::Parameters() {
MiniRtcParams p{};
std::snprintf(p.signal_server_ip, sizeof(p.signal_server_ip), "%s",
options_.host.c_str());
std::snprintf(p.log_path, sizeof(p.log_path), "%s",
@@ -93,13 +93,13 @@ Params ControllerSession::Parameters() {
p.hardware_acceleration = options_.hardware_acceleration;
p.native_video_output = true;
p.av1_encoding = false;
p.turn_mode = TurnAutoUdpTcp;
p.turn_mode = MiniRtcTurnAutoUdpTcp;
p.enable_srtp = true;
p.video_content_type = VideoContentType::ScreenContent;
p.video_quality = QualityLow;
p.video_content_type = MiniRtcVideoContentType::ScreenContent;
p.video_quality = MiniRtcVideoQualityLow;
p.video_frame_rate = 30;
p.video_degradation_preference =
VideoDegradationPreference::MaintainResolution;
MiniRtcVideoDegradationPreference::MaintainResolution;
p.on_signal_status = Signal;
p.on_connection_status = Connection;
p.on_net_status_report = Network;
@@ -149,7 +149,7 @@ void ControllerSession::Connect(SessionOptions options, std::string device,
overflow_ = false;
events_.clear();
network_ = {};
traversal_ = UnknownMode;
traversal_ = MiniRtcTraversalUnknown;
callback_generation_ = ++generation_;
callback_display_ = options_.display;
frames_.Reset(generation_);
@@ -160,19 +160,19 @@ void ControllerSession::Connect(SessionOptions options, std::string device,
InitializeControllerDiagnostics(options_.log_directory);
WriteControllerDiagnostic("Session registering");
auto p = Parameters();
peer_ = CreatePeer(&p);
peer_ = MiniRtcCreatePeer(&p);
if (!peer_) {
Fail("media_initialization_failed");
return;
}
AddAudioStream(peer_, kAudioStream);
AddDataStream(peer_, kDataStream, false);
MiniRtcAddAudioStream(peer_, kAudioStream);
MiniRtcAddDataStream(peer_, kDataStream, false);
for (auto stream : {kMouseStream, kKeyboardStream, kControlStream})
AddDataStream(peer_, stream, true);
AddDataStream(peer_, web_clipboard::kStream, true);
AddDataStream(peer_, kFileStream, true);
AddDataStream(peer_, kFileFeedbackStream, true);
if (Init(peer_) != 0)
MiniRtcAddDataStream(peer_, stream, true);
MiniRtcAddDataStream(peer_, web_clipboard::kStream, true);
MiniRtcAddDataStream(peer_, kFileStream, true);
MiniRtcAddDataStream(peer_, kFileFeedbackStream, true);
if (MiniRtcInit(peer_) != 0)
Fail("media_initialization_failed");
}
void ControllerSession::Tick() {
@@ -198,26 +198,26 @@ void ControllerSession::Tick() {
break;
if (e.kind == 0) {
WriteControllerDiagnostic("Signal status: " + std::to_string(e.code));
if (e.code == SignalTlsCertError) {
if (e.code == MiniRtcSignalTlsCertError) {
Fail("tls_certificate_error");
break;
}
if (e.code == SignalFailed) {
if (e.code == MiniRtcSignalFailed) {
Fail("signaling_login_failed");
break;
}
// The initial signaling transport can recover before a remote join is
// sent. Keep its backoff worker alive within the original deadline.
if (e.code == SignalReconnecting && state_ == "registering") {
if (e.code == MiniRtcSignalReconnecting && state_ == "registering") {
WriteControllerDiagnostic("Initial signaling retry within connection deadline");
continue;
}
if (e.code == SignalClosed || e.code == SignalServerClosed ||
e.code == SignalReconnecting) {
if (e.code == MiniRtcSignalClosed || e.code == MiniRtcSignalServerClosed ||
e.code == MiniRtcSignalReconnecting) {
Fail("signaling_disconnected");
break;
}
if (e.code != SignalConnected)
if (e.code != MiniRtcSignalConnected)
continue;
if (state_ == "registering") {
if (e.data.size() != 13 || e.data.rfind("cli-", 0) != 0 ||
@@ -228,14 +228,14 @@ void ControllerSession::Tick() {
client_id_ = e.data;
state_ = "connecting";
const auto join = device_ + "@" + password_;
if (JoinConnection(peer_, join.c_str()) != 0)
if (MiniRtcJoinConnection(peer_, join.c_str()) != 0)
Fail("join_request_failed");
std::fill(password_.begin(), password_.end(), '\0');
password_.clear();
}
} else if (e.kind == 1) {
WriteControllerDiagnostic("Connection status: " + std::to_string(e.code) + " (session " + state_ + ")");
if (e.code == ::Connected && !Connected()) {
if (e.code == MiniRtcConnectionConnected && !Connected()) {
state_ = "connected";
auto hello = MakeHostInformation("CrossDesk CLI", {}, false);
Send(kControlStream, hello.to_json());
@@ -245,15 +245,15 @@ void ControllerSession::Tick() {
mute.a = false;
Send(kControlStream, mute.to_json());
capability_request_ = RequestRemote("capabilities");
} else if (e.code == IncorrectPassword)
} else if (e.code == MiniRtcConnectionIncorrectPassword)
Fail("incorrect_password");
else if (e.code == NoSuchTransmissionId)
else if (e.code == MiniRtcConnectionNoSuchTransmissionId)
Fail("device_not_found");
else if (e.code == RemoteUnavailable)
else if (e.code == MiniRtcConnectionRemoteUnavailable)
Fail("device_offline_or_unavailable");
else if (e.code == Failed)
else if (e.code == MiniRtcConnectionFailed)
Fail(Connected() ? "connection_lost" : "connection_failed");
else if (e.code == Closed || e.code == Disconnected)
else if (e.code == MiniRtcConnectionClosed || e.code == MiniRtcConnectionDisconnected)
Fail("remote_disconnected");
} else if ((e.kind == 4 || e.kind == 5) && Connected()) {
if (files_) files_->Receive(e.data.data(), e.data.size(), e.kind == 5);
@@ -299,7 +299,7 @@ void ControllerSession::Tick() {
if (remote_capabilities_.value("files", json{}) == true)
files_ = std::make_unique<ControllerFiles>([this](const char *stream, const std::string &data) {
if (!peer_ || !Connected()) return false;
return SendReliableDataFrame(peer_, data.data(), data.size(), stream) == 0;
return MiniRtcSendReliableDataFrame(peer_, data.data(), data.size(), stream) == 0;
});
remote_results_.erase(found);
}
@@ -340,7 +340,7 @@ void ControllerSession::Tick() {
}
bool ControllerSession::Send(const char *stream, const std::string &payload) {
return peer_ && Connected() && !payload.empty() &&
SendReliableDataFrame(peer_, payload.data(), payload.size(), stream) ==
MiniRtcSendReliableDataFrame(peer_, payload.data(), payload.size(), stream) ==
0;
}
void ControllerSession::ClosePeers() {
@@ -355,8 +355,8 @@ void ControllerSession::ClosePeers() {
frames_.Reset(generation_);
}
if (peer_) {
LeaveConnection(peer_, device_.c_str());
DestroyPeer(&peer_);
MiniRtcLeaveConnection(peer_, device_.c_str());
MiniRtcDestroyPeer(&peer_);
}
std::fill(password_.begin(), password_.end(), '\0');
password_.clear();
@@ -431,7 +431,7 @@ void ControllerSession::Preview() {
s.frame_rate = options_.fps > 30 ? 60 : 30;
// Preserve desktop text detail at every cadence, including 30 FPS previews.
s.preference =
static_cast<int>(VideoDegradationPreference::MaintainResolution);
static_cast<int>(MiniRtcVideoDegradationPreference::MaintainResolution);
s.audio = audio_enabled_;
s.quality = options_.quality;
if (resolution_) {