Compare commits

..

789 Commits

Author SHA1 Message Date
dijunkun ecbec4d301 [ci] use rolling cache keys for xmake dependency caches 2026-04-14 02:16:17 +08:00
dijunkun 21425c7132 [fix] fix system tray icon display issue 2026-04-14 01:54:03 +08:00
dijunkun 3e95a7ba29 [fix] fix startup failure caused by wgc_plugin working directory change 2026-04-14 01:53:20 +08:00
dijunkun c1394db285 [fix] fix missing wgc_plugin.dll in Windows packaging process, refs #76 2026-04-13 23:51:39 +08:00
dijunkun eee6c588bd [fix] fix X11 odd-size captures by aligning dimensions to even values 2026-03-24 00:07:44 +08:00
dijunkun eca68f6c7a [fix] fix keyboard input injection on Linux Wayland sessions 2026-03-23 23:14:05 +08:00
dijunkun f4e28d8774 [fix] fix mac-to-windows symbol key input 2026-03-23 22:30:58 +08:00
dijunkun 21b179e01c [fix] release pressed modifier keys when stream window loses focus 2026-03-23 21:33:01 +08:00
dijunkun 83cacf6f51 [fix] split mouse and keyboard from data channel and use reliable transimission 2026-03-23 21:14:07 +08:00
dijunkun 13c37f01b1 [fix] fix cross-platform key capture and mapping issues 2026-03-23 20:42:48 +08:00
dijunkun 511831ced3 [fix] fix Wayland reconnect black screen by keeping capturer warm and also fix Wayland mouse control 2026-03-23 05:18:56 +08:00
dijunkun 518e1afa58 [feat] add Linux screen capture fallback support for DRM and Wayland 2026-03-22 21:33:50 +08:00
dijunkun 43d03ac081 [fix] fix font path lookup for wqy/dejavu by switching from OpenType to TrueType 2026-03-22 00:39:19 +08:00
dijunkun f7f62c5fe0 [fix] update MiniRTC: refactor IceAgent to improve stability 2026-03-20 15:58:59 +08:00
dijunkun 2bbddbca6b [fix] fix Linux audio fallback when audio devices are unavaliable 2026-03-20 15:14:45 +08:00
dijunkun f0f8f27f4c [fix] fix blocking join() in Linux clipboard monitor thread during shutdown 2026-03-20 15:02:34 +08:00
dijunkun 262af263f2 [fix] move keyboard capturer to a background thread and use poll-based X11 event handling to avoid main-thread blocking 2026-03-20 14:56:40 +08:00
dijunkun 38b7775b1b [fix] fix restart/shutdown races in process monitor 2026-03-20 14:50:42 +08:00
dijunkun 56c0bca62f [chore] adjust hyperlink spacing and alignment 2026-03-20 14:47:33 +08:00
dijunkun 4b1b09fd5b [fix] fix Linux fonts: use opentype instead of truetype 2026-03-20 13:01:13 +08:00
dijunkun 1d6425bbf4 [fix] update MiniRTC: fix compiler warnings by adding missing override specifiers 2026-03-20 04:36:58 +08:00
dijunkun 5ec6552d25 [fix] fix macOS intel CI build failure caused by python 3.13 PGO mismatch 2026-03-20 03:50:19 +08:00
dijunkun 79e4a0790a [fix] fix issue where wgc_plugin was not compiled 2026-03-20 02:59:31 +08:00
dijunkun 1d3cac54ab [feat] load wgc from wgc_plugin.dll at runtime and drop direct'windowsapp' linking, refs #74 2026-03-20 01:36:36 +08:00
dijunkun 2f26334775 [feat] unify UI font loading across platforms and prefer PingFang on macOS 2026-03-19 21:58:14 +08:00
dijunkun 9270d528e3 [feat] update miniRTC: fix compiler warnings caused by missing override specifiers 2026-03-19 21:57:52 +08:00
dijunkun 91db3a7e34 [feat] add Russian language support 2026-03-19 20:04:30 +08:00
dijunkun d017561e54 [fix] fix typo ImGuiChildFlags_Border to ImGuiChildFlags_Borders 2026-03-19 16:16:51 +08:00
dijunkun 8e8a85bae3 [feat] upgrade actions/checkout and actions/cache to v5 for Node 24 compatibility 2026-03-19 15:03:58 +08:00
dijunkun bea89e9111 [feat] crossdesk server image supports Linux ARM64, refs #72 2026-03-19 10:06:57 +08:00
dijunkun 499ce0190a [fix] process mouse events only from the stream window 2026-03-11 16:00:29 +08:00
dijunkun 91bde91238 [feat] probe presence before connect and show warning if offline 2026-03-10 17:46:44 +08:00
dijunkun 3e31ba102d [fix] prevent sending connection requests to offline devices 2026-03-10 10:53:58 +08:00
dijunkun 263c5eefd3 [fix] fix update button lag in release mode by using non-blocking URL opener. 2026-03-10 10:39:05 +08:00
dijunkun b230b851e4 [fix] fix cannot close connection from Server Window when the peer is a web client 2026-03-10 00:39:00 +08:00
dijunkun ff32477ffe [fix] update MiniRTC: fix crash on disconnect 2026-03-10 00:35:33 +08:00
dijunkun c6c60decdb [fix] fix incorrect online status of recently connections 2026-03-09 22:52:05 +08:00
dijunkun 7505adeca8 [feat] update MiniRTC 2026-03-09 22:50:42 +08:00
dijunkun 754f1fba88 [feat] show 'Receiving screen' text before the remote frame arrives 2026-03-09 22:37:50 +08:00
dijunkun 8be46b870a [feat] add cancel button during connecting 2026-03-09 21:35:21 +08:00
dijunkun 81cb1d6c0b [fix] disable clipboard sharing when not in control mode 2026-03-05 17:46:27 +08:00
dijunkun 319416f1b7 [feat] update MiniRTC: optimize video quality and smoothness 2026-03-05 17:30:05 +08:00
dijunkun d679c6251b [feat] update MiniRTC 2026-03-04 10:46:21 +08:00
dijunkun a14baafda7 [fix] fix keyboard event loss due to start_keyboard_capturer_ flag improper setting, fixes #65 2026-03-04 10:36:39 +08:00
dijunkun cfdc7d3106 [fix] update MiniRTC: fix bandwidth degradation caused by ALR-triggered resolution downgrade during static frames 2026-03-03 10:58:38 +08:00
dijunkun 33d51b8ce5 [fix] reset to initial monitor on connection close via ResetToInitialMonitor to fix black screen 2026-03-02 15:42:44 +08:00
dijunkun b13dac2093 [feat] refine display of recent connections presence tooltip 2026-03-02 10:48:16 +08:00
dijunkun a605c95e5a [fix] fix window rounding inconsistency under different DPI scales 2026-03-02 10:38:06 +08:00
dijunkun 9a5553a636 [chore] update fonts 2026-03-02 10:17:06 +08:00
dijunkun ef02403da6 [fix] fix incorrect sizing of the online status indicator on high-DPI displays 2026-03-01 16:47:09 +08:00
dijunkun adfab363c1 [feat] add online presence check before connecting and show offline warning dialog 2026-03-01 16:29:11 +08:00
dijunkun 123d4cf595 [fix] update MiniRTC: fix the macOS hardware decode fail when the server using openH264 encode 2026-03-01 15:40:50 +08:00
dijunkun 19feb8ff49 [feat] show device online/offline status in recent connection tooltip 2026-02-28 17:25:41 +08:00
dijunkun 9223bf9d2d [feat] add online status indicators for recent connections 2026-02-28 17:06:44 +08:00
dijunkun 11b5f87841 [feat] update MiniRTC: add signaling send/receive API support 2026-02-28 17:04:47 +08:00
dijunkun cea59fb453 [feat] update MiniRTC 2026-02-27 17:53:51 +08:00
ZongYangBigPolo 3a179bf480 [feat] add macOS installer icon and optimize packaging script (#70) 2026-02-27 17:37:54 +08:00
dijunkun b9c53024f1 [feat] set video quality to HIGH and enable hardware codec by default 2026-02-27 17:24:04 +08:00
dijunkun 62b37ad698 [fix] resolve failures in the WGC→DXGI→GDI fallback chain 2026-02-27 16:33:57 +08:00
dijunkun de56cd5d3b [feat] update MiniRTC 2026-02-27 16:30:08 +08:00
dijunkun 8d9d78185a [fix] fix issue where client display list was incorrectly merged into the server display list 2026-02-27 16:27:37 +08:00
dijunkun b10a6512fe [feat] add Windows DXGI/GDI screen capture with WGC→DXGI→GDI fallback support 2026-02-27 13:55:41 +08:00
dijunkun a94da8802f [feat] make MainWindow and ServerWindow use rounded corners 2026-02-26 18:06:07 +08:00
dijunkun 4e6f82d00c [feat] restrict the dragging range of the ControlWindow 2026-02-26 15:55:04 +08:00
dijunkun 5e2ad99ec0 [feat] update MiniRTC to resolve color distortion in the OpenH264 decoder 2026-02-25 17:48:30 +08:00
dijunkun 8ab50ea362 [feat] add video resolution and conection mode in NetTrafficStats window 2026-02-25 15:33:17 +08:00
dijunkun 25e9958a69 Merge branch 'file-transfer' of https://github.com/kunkundi/crossdesk into file-transfer 2026-02-24 17:56:21 +08:00
dijunkun 410ea8b96b [feat] update MiniRTC 2026-02-24 17:56:02 +08:00
dijunkun e656664cad [chore] adjust file transfer save path button pos 2026-02-24 14:36:03 +08:00
dijunkun 0e6cee0961 [fix] fix stream window rendering height 2026-02-24 14:31:34 +08:00
dijunkun 42506b8c1d [ci] combine Linux amd64 and arm64 builds into a single job using matrix 2026-02-13 02:31:58 +08:00
dijunkun e35365d162 [feat] disable and style minimize_to_tray checkbox for non-Windows platforms 2026-02-13 02:29:52 +08:00
dijunkun bf1c0f796d [fix] fix Linux system certificate loading failure 2026-02-13 01:56:49 +08:00
dijunkun 547532b28c [fix] fix server window scaling issues on high-DPI displays 2026-02-13 01:26:10 +08:00
dijunkun a91e23abf6 [fix] fix raw pointer issues when closing connections 2026-02-13 01:12:21 +08:00
dijunkun 2b324f636b [fix] fix macOS system certificate loading failure 2026-02-12 22:49:54 +08:00
dijunkun 103b8372e4 [chore] rename packaged executable to CrossDesk.exe in NSIS and portable artifacts 2026-02-12 16:45:41 +08:00
dijunkun f7f1724bf1 [feat] optimize hyperlink opening by replacing system start with CreateProcessW-based URL launch on Winodws 2026-02-12 16:22:57 +08:00
dijunkun 5d70e11f17 [feat] support Windows x64 portable build, refs #54 2026-02-12 16:03:06 +08:00
dijunkun fb7ae90d46 [feat] add configurable file transfer save path in settings window, refs #63 2026-02-12 14:30:14 +08:00
dijunkun 957792a7a0 [feat] remove client certificate dependency 2026-02-11 16:23:43 +08:00
dijunkun 2e8ce6a2f0 [fix] reset default cert fingerprint if mismatch 2026-02-05 18:59:28 +08:00
dijunkun 9927a56b78 [feat] update MiniRTC 2026-02-05 18:05:35 +08:00
dijunkun db3da52f83 [feat] clear cached fingerprint when verification fails 2026-02-05 17:15:59 +08:00
dijunkun 19a7c6978a [feat] update MiniRTC to resolve websocket reconnection and post task issues 2026-01-28 09:45:19 +08:00
dijunkun b5e9ba03a1 [fix] double-buffer video frames and handle stream cleanup on main thread 2026-01-28 09:44:54 +08:00
dijunkun cb5f8b91ad [feat] update update-notification icon 2026-01-27 21:11:26 +08:00
dijunkun f627f60f1a [feat] use tooltips to display server-side file transfer status information 2026-01-27 17:50:21 +08:00
dijunkun e9fce5b8b8 [feat] display remote controller hostname instead of remote id 2026-01-26 22:52:58 +08:00
dijunkun a7820a79db [fix] fix incorrect peer_ usage in SendReliableDataFrame 2026-01-26 21:47:10 +08:00
dijunkun b6a52dbcd4 [feat] add support for displaying multiple controller info and file transfer to controllers 2026-01-26 17:47:31 +08:00
dijunkun 7bbd10a50c [fix] fix rendering issues in stream and server windows when the main window is minimized 2026-01-22 17:56:00 +08:00
dijunkun ee08b231db [fix] fix height when server window is restored from collapsed state 2026-01-20 23:58:43 +08:00
dijunkun 619e54dc0e [feat] add controller info and file transfer in server window 2026-01-20 21:22:20 +08:00
dijunkun 9b69596af1 [fix] fix stream window size recalculation 2026-01-20 01:33:27 +08:00
dijunkun f6e169c013 [feat] add support for server window resizing and dragging 2026-01-20 01:22:14 +08:00
dijunkun fd242d50c1 [feat] show server window in the bottom-right corner of the screen 2026-01-19 17:42:22 +08:00
dijunkun d6d8ecd6c5 [feat] add server window 2026-01-19 00:47:34 +08:00
dijunkun 669fac7f50 [feat] support drag-and-drop file sending, refs #63 2026-01-14 18:13:22 +08:00
dijunkun 92d670916e [fix] fix incorrect data send function used for control data 2026-01-13 18:13:54 +08:00
dijunkun 0155413c12 [feat] use reliable transmission to send control info 2026-01-12 17:28:19 +08:00
dijunkun 8468be6532 [fix] update MiniRTC 2026-01-12 17:27:49 +08:00
dijunkun 78c82f778a [chore] remove SetOnFileComplete() in class FileReceiver 2025-12-29 12:48:14 +08:00
dijunkun ab89a3d41a [fix] fix clipboard copy from remote device to controller 2025-12-29 12:46:19 +08:00
dijunkun 5f320af6e6 [fix] fix macOS clipboard monitoring compilation error using changeCount polling 2025-12-29 01:01:08 +08:00
dijunkun 17b7ba6b72 [feat] support clipboard sharing, refs #35 2025-12-29 00:53:14 +08:00
dijunkun c70ebdfe15 [fix] correct file send rate calculation by using data channel feedback 2025-12-29 00:53:14 +08:00
dijunkun a3e564f160 [feat] support multi-file transfer, refs #45 2025-12-29 00:52:58 +08:00
dijunkun eea37424c9 [feat] use receiver ack to calculate file transfer progress 2025-12-25 18:13:18 +08:00
dijunkun b322181853 [feat] add file transfer window to show file sending info 2025-12-24 18:12:50 +08:00
dijunkun 3ad66f5e0b [fix] fix file transfer 2025-12-24 01:45:59 +08:00
dijunkun 4035e0dd13 [feat] upgrade MiniRTC and expose source ID in data callbacks 2025-12-23 00:53:47 +08:00
dijunkun 832b820096 [fix] update MiniRTC to latest version and add logging for sent file size 2025-12-22 18:33:53 +08:00
dijunkun d337971de0 [feat] update MiniRTC api calling 2025-12-19 18:22:34 +08:00
dijunkun a967dc72d7 [feat] use SendReliableDataFrame() instead of SendDataFrame() 2025-12-19 01:46:16 +08:00
dijunkun 5066fcda48 [feat] implement file transfer module 2025-12-18 18:30:51 +08:00
dijunkun e7bdf42694 [feat] add file transfer button to control bar 2025-12-18 01:54:03 +08:00
dijunkun 875fea88ee [chore] adjust main window title font size 2025-12-18 01:32:38 +08:00
dijunkun b2654ea9db [feat] use fingerprint-based verification for both default and self-hosted servers 2025-12-10 03:46:03 +08:00
dijunkun 8f8e415262 [chore] update README 2025-12-10 03:38:05 +08:00
dijunkun 5ff624f7b2 [feat] use fingerprint-based verification for TLS connection 2025-12-10 03:28:28 +08:00
dijunkun e09243f1ec [chore] update README 2025-12-10 00:23:04 +08:00
dijunkun f5941c7eda [chore] update README 2025-12-10 00:20:26 +08:00
dijunkun 3c2ebe602e [fix] do not save password info into logs 2025-12-10 00:20:10 +08:00
dijunkun 2f64172ead [feat] use new client id and password if server switched 2025-12-10 00:09:49 +08:00
Junkun Di a83206a346 [ci] update issue templates 2025-12-09 17:50:57 +08:00
dijunkun 46e769976f [chore] update README 2025-12-09 00:36:00 +08:00
dijunkun 58c24b798e [chore] update README: refresh self-hosted server setup guide 2025-12-09 00:19:25 +08:00
dijunkun 5cc31e5ba3 [fix] fix self-hosted server configuration being reset when disabling self-hosted mode 2025-12-08 18:27:18 +08:00
dijunkun 74fe9bebf5 [fix] fix server settings window height 2025-12-08 17:42:02 +08:00
dijunkun 1f6a2182be [fix] resolve tab bar dragging issue 2025-12-06 18:46:04 +08:00
dijunkun 1a883f0d6c [fix] fix menu BeginPopup & EndPopup pairing 2025-12-05 17:53:17 +08:00
dijunkun a560b4ca70 [feat] make thumbnail save asynchronous to prevent UI blocking 2025-12-05 17:07:55 +08:00
dijunkun 46f45ed216 [fix] fix tab close button not working in stream window 2025-12-05 15:18:35 +08:00
dijunkun 5c23f1c5e8 [fix] correct tab bar scaling and layout 2025-12-05 15:17:07 +08:00
dijunkun 70ae02549f [fix] correct title bar display 2025-12-05 04:28:33 +08:00
dijunkun 68de995c64 [fix] correct hardware codec setting item display 2025-12-05 00:57:33 +08:00
dijunkun ed5ddb96fd [refactor] update notification window rendering for high-DPI scaling support 2025-12-04 19:00:37 +08:00
dijunkun 436dfafc2a [refactor] update about window rendering for high-DPI scaling support 2025-12-04 17:51:03 +08:00
dijunkun 5221b193e5 [refactor] update settings window rendering for high-DPI scaling support 2025-12-04 17:23:14 +08:00
dijunkun fafced23c2 [refactor] update stream window rendering for high-DPI scaling support 2025-12-04 02:11:06 +08:00
dijunkun 1e48b645ca [refactor] update recent connections panel rendering for high-DPI scaling support 2025-12-04 00:14:09 +08:00
dijunkun 49ed0200e7 [refactor] update connection status window rendering for high-DPI scaling support 2025-12-03 21:54:10 +08:00
dijunkun 24873afe64 [refactor] update remote peer panel rendering for high-DPI scaling support 2025-12-03 21:17:11 +08:00
dijunkun d21e1bd422 [refactor] update remote peer panel rendering for high-DPI scaling support 2025-12-03 17:36:19 +08:00
dijunkun be044c248b [refactor] update local peer panel rendering for high-DPI scaling support 2025-12-03 17:12:35 +08:00
dijunkun 49cbbc3363 [refactor] update status bar rendering for high-DPI scaling support 2025-12-03 12:45:01 +08:00
dijunkun 1e20cb806b [refactor] update title bar rendering for high-DPI scaling support 2025-12-03 04:20:49 +08:00
dijunkun 2e52818f6f fix: correct array deletion and improve state management in WGC screen capturer 2025-12-01 23:06:46 +08:00
dijunkun b50f386713 [fix] fix system_chinese_font_ usage to avoid dangling font pointer after closing stream window 2025-12-01 23:03:45 +08:00
dijunkun 280e011ae4 [fix] update RecentConnectionsWindow layout 2025-12-01 17:16:28 +08:00
dijunkun 8d09bf53c3 [fix] fix UpdateNotificationWindow dpi scaling 2025-12-01 13:52:39 +08:00
dijunkun 131b4f1795 [fix] resolve compilation errors on Linux 2025-12-01 13:07:36 +08:00
dijunkun 7d3ecf789d [fix] fix control bar dpi scaling 2025-12-01 11:30:35 +08:00
dijunkun 37797bf873 [fix] fix DPI scaling issues 2025-12-01 04:54:30 +08:00
dijunkun 91d42b6561 [fix] macOS: fix audio capture, refs #29 2025-11-30 17:13:02 +08:00
dijunkun feb9f2f460 [revert] revert to the pre-lock version 2025-11-28 11:44:08 +08:00
Junkun Di 9c1753c78c [chroe] add issue templates 2025-11-28 11:34:22 +08:00
dijunkun 7370ff5b30 [chore] add HelloGitHub badge 2025-11-28 11:10:41 +08:00
dijunkun f6eda34dbd [fix] fix dead lock during connecting 2025-11-28 10:02:57 +08:00
dijunkun 5d9a0a3ea5 [fix] fix dead lock during peer init 2025-11-28 09:32:21 +08:00
dijunkun 3d8249bffa [fix] use lock and null pointer checks to prevent crashes 2025-11-28 00:41:29 +08:00
dijunkun 82f32cbe8f [fix] fix incorrect peer reference in AddVideoStream call 2025-11-27 23:53:27 +08:00
dijunkun 56da2f99f3 [chore] update Linux log path configuration 2025-11-27 23:20:14 +08:00
dijunkun e6c72fe558 [feat] remove screen capture and accessibility permission when reinstall 2025-11-27 17:35:15 +08:00
dijunkun a964c6bbf5 [fix] call log after log initialzation, refs #36, #29 2025-11-27 16:09:08 +08:00
dijunkun 239da373d0 [feat] attempt to rejoin once per second 2025-11-27 04:20:29 +08:00
dijunkun 217cfb091d [feat] display version info on startup 2025-11-27 04:18:08 +08:00
dijunkun 3c3c7b9ae0 [fix] fix crash when screen recording permission is not granted on macOS, refs #29 2025-11-27 03:32:16 +08:00
dijunkun f14bdb7fe8 [feat] optimize UpdateNotificationWindow UI appearance 2025-11-27 03:07:55 +08:00
dijunkun c0a98f97c3 [feat] optimize RequestPermissionWindow UI appearance 2025-11-27 02:40:33 +08:00
dijunkun 0ab6686eb8 [feat] use DrawToggleSwitch to request permission 2025-11-26 23:32:04 +08:00
dijunkun 76b475450b [feat] request macOS system permissions by showing a prompt on startup 2025-11-26 18:18:40 +08:00
dijunkun 5d1e1b5667 [fix] remove permissions on uninstall and request permissions during installation for MacOS 2025-11-26 16:11:49 +08:00
dijunkun c3b8b1374a [chore] update README 2025-11-25 16:30:14 +08:00
dijunkun 7c940d6b15 [ci] fix tag error in update-version-json.yml 2025-11-25 03:30:28 +08:00
dijunkun 86501b05dd [feat] show notification window if there is a new version avaliable 2025-11-25 01:20:16 +08:00
dijunkun 01ebed9b37 [ci] upload release notes to version.json 2025-11-25 01:19:12 +08:00
dijunkun 2188adb1f1 [chore] disable CROSSDESK_DEBUG in keyboard and mouse control 2025-11-24 16:47:33 +08:00
dijunkun 51409e16c8 [chore] update README 2025-11-23 01:54:54 +08:00
dijunkun 6ca3b58ae2 [fix] update MiniRTC to resolve occasional crash during connection shutdown, refs #29 2025-11-23 01:47:48 +08:00
dijunkun 692e176e34 [ci] use github.sha instead of hashFiles for xmake dependency cache 2025-11-23 00:35:26 +08:00
dijunkun 4fb7acaa61 [feat] set enable TURN by default 2025-11-23 00:02:04 +08:00
dijunkun c0d6429a54 [fix] resolve missing mouse cursor display when web client connects to Linux devices, refs #30 2025-11-22 23:57:49 +08:00
dijunkun 07c7c7f179 [chore] update README 2025-11-21 02:40:51 +08:00
dijunkun c5ceeb0d80 [ci] use China timezone for build date in version number 2025-11-21 02:33:39 +08:00
dijunkun 5ce0a891df [fix] resolve failures in connection destruction 2025-11-21 01:50:08 +08:00
dijunkun f94ef49210 [fix] release keyboard hook after remote control disconnects, refs #23 2025-11-21 00:56:01 +08:00
dijunkun 5d0a4d1385 [fix] fix mouse wheel and touchpad swipe commands, refs #9, #23 2025-11-21 00:55:19 +08:00
dijunkun dd482cee60 [fix] use static linking of libffi in glib to avoid version conflicts, fixes #16 2025-11-20 17:20:15 +08:00
dijunkun e3c2edfb1c [fix] fix daemon not working on Linux 2025-11-20 15:35:37 +08:00
dijunkun f3901d09ea [feat] add tooltip for the daemon option in the settings windows 2025-11-20 14:47:54 +08:00
Junkun Di 2b12749477 [chore] update README_EN.md 2025-11-20 13:05:14 +08:00
Junkun Di 759488f675 [chore] update README.md 2025-11-20 13:04:32 +08:00
dijunkun 4bb4240a9e [chore] update README 2025-11-20 11:15:34 +08:00
dijunkun 1457247a6a [feat] add build option USE_CUDA to enable or disable CUDA-based hardware codec acceleration and USE_CUDA=false by default 2025-11-19 23:15:56 +08:00
dijunkun 97ab9bfca5 [feat] add daemon support with automatic restart on crash 2025-11-19 22:09:51 +08:00
dijunkun 4dd3c3e073 [fix] clean display names by removing non-alphanumeric characters 2025-11-18 17:05:51 +08:00
dijunkun 4ba4f17a6b [feat] capture cursor when connected to a web client 2025-11-18 16:24:28 +08:00
dijunkun f5d0291b5a [fix] fix crash when Unhook KeyboardCapturer on MacOS 2025-11-18 14:07:18 +08:00
dijunkun 1a64c1afef [feat] support auto-start on boot 2025-11-18 13:50:15 +08:00
dijunkun 18f4973d0a [fix] remove duplicate 'v' prefix in GitHub release name 2025-11-14 16:10:00 +08:00
dijunkun 37ede5861c [fix] update MiniRTC to fix crash when multiple peers join to remote server 2025-11-14 14:37:15 +08:00
dijunkun 497454ac51 [ci] remove 'v' prefix from Debian package version 2025-11-13 15:04:24 +08:00
dijunkun 4ebb7a6a4d [chore] update version format 2025-11-13 14:32:35 +08:00
dijunkun 7d1910df71 [ci] append build date to artifact names and write download URLs to version.json 2025-11-13 14:13:54 +08:00
dijunkun 52e70a26f3 [chore] update README 2025-11-13 00:06:14 +08:00
dijunkun adb6cee326 [fix] fix version check issue 2025-11-12 00:21:18 +08:00
dijunkun 941b5e5cdc [ci] update version.json when new tag pushed 2025-11-12 00:11:32 +08:00
dijunkun c602dea58f [chore] update README 2025-11-11 22:30:17 +08:00
dijunkun e9ced9fa4f [ci] switch macos-13 to macos-15-intel due to the macOS-13 based runner images are being deprecated 2025-11-11 22:28:35 +08:00
dijunkun 6ab5e7487f [chore] update README 2025-11-11 21:59:50 +08:00
dijunkun e3143f3e7a [feat] add automatic version check 2025-11-11 15:38:31 +08:00
dijunkun 538c17d182 [feat] disable AV1 encoding when connected to a Web client 2025-11-11 10:52:28 +08:00
dijunkun 2ad32ec2b4 [feat] add VideoQuality configuration option to limit maximum video resolution 2025-11-11 10:07:35 +08:00
dijunkun b28f1dca81 [feat] update MiniRTC module 2025-11-11 01:32:40 +08:00
dijunkun 6947f7e1c3 Merge branch 'self-hosted-server' into libdatachannel 2025-11-11 01:18:24 +08:00
dijunkun b1df10c0de [fix] fix frame rate and video quality settings not being applied correctly, fixes #24 2025-11-11 01:11:33 +08:00
dijunkun 3817b222fd Merge branch 'libdatachannel' of https://github.com/kunkundi/crossdesk into libdatachannel 2025-11-11 01:00:19 +08:00
dijunkun 910cc9b587 [fix] stop devices control and capture when client peer destroyed 2025-11-11 00:59:54 +08:00
dijunkun 2ee3e93afe [feat] do not control mouse in debug mode 2025-11-11 00:56:23 +08:00
dijunkun 8875c6a6a1 [feat] update MiniRTC module 2025-11-11 00:53:10 +08:00
dijunkun 28062f5574 [config] use 60 fps streaming by default 2025-11-10 17:03:14 +08:00
dijunkun 017af3eea4 [feat] support multiple web clients connecting simultaneously 2025-11-10 16:54:56 +08:00
dijunkun 78eb069cc8 [feat] enable speaker capturer by default 2025-11-10 15:02:21 +08:00
dijunkun 0d591f769d [feat] send control commands via JSON 2025-11-06 17:31:06 +08:00
dijunkun d4726355a7 [feat] update minirtc: support web streaming by using libdatachannel 2025-11-06 02:54:03 +08:00
dijunkun b78c9cf7d1 [feat] optimize Windows display device names 2025-11-05 20:36:04 +08:00
dijunkun b3132db785 [fix] resolve issue where configuration settings were not saved 2025-11-03 10:55:19 +08:00
dijunkun 43db021326 [feat] use CROSSDESK_DEBUG compile-time variable to control config file path 2025-10-31 17:31:50 +08:00
dijunkun 2c622bc76e [ci] update GitHub Actions to use macos-13 runner instead of macos-15 for Intel builds 2025-10-27 22:31:23 +08:00
dijunkun b790c7d08e [chore] update README 2025-10-27 22:11:30 +08:00
dijunkun 0ca90d2516 [chore] move minirtc into submodules 2025-10-27 21:36:11 +08:00
dijunkun 401bfe4483 [refactor] add namespace 'crossdesk' to codebase 2025-10-27 21:09:39 +08:00
dijunkun 3b34c26555 [feat] enable custom configuration of Coturn server port 2025-10-27 16:04:40 +08:00
dijunkun b668b3c936 [chore] update README 2025-10-27 13:42:49 +08:00
dijunkun cc19ec125a [ci] update close-issue.yml 2025-10-27 11:04:36 +08:00
dijunkun ffa77fdf44 Merge branch 'run-in-bg' into self-hosted-server 2025-10-27 10:41:16 +08:00
dijunkun 47cf806532 [ci] add permissions to close-issue.yml 2025-10-25 17:06:14 +08:00
dijunkun 911dce2e71 [feat] optimize certificate selection table 2025-10-24 17:39:25 +08:00
dijunkun 9f80d4f69d Merge branch 'self-hosted-server' into run-in-bg 2025-10-24 14:16:18 +08:00
dijunkun cba644f055 [fix] fix TURN server authentication credentials, fixes #8 2025-10-24 11:41:23 +08:00
dijunkun f733fe9e49 Merge branch 'self-hosted-server' into run-in-bg 2025-10-24 11:05:07 +08:00
dijunkun 27263fe1db [ci] fix permission issue in close inactive issues script by updating token usage 2025-10-24 10:57:11 +08:00
dijunkun 698bf72a6c Merge branch 'self-hosted-server' into run-in-bg 2025-10-24 10:05:54 +08:00
dijunkun 0bd27d0b17 [ci] use GITHUB_SHORT_SHA instead of build number in version 2025-10-24 02:09:50 +08:00
dijunkun ee5612da8b [ci] resolve compilation issue 2025-10-23 23:30:52 +08:00
dijunkun c7a2023c88 [ci] add build ID to version number 2025-10-23 23:18:44 +08:00
dijunkun c031a8c145 [fix] adjust settings window height for different platforms 2025-10-23 23:04:31 +08:00
dijunkun 0bf83f07ad [fix] correct version display in about window 2025-10-23 23:01:38 +08:00
dijunkun 3638b712bd [ci] update close-issue.yml 2025-10-23 21:20:10 +08:00
dijunkun b2ab940f20 [feat] use no close select table 2025-10-23 17:55:30 +08:00
dijunkun 17f9536476 [chore] update README 2025-10-23 10:37:45 +08:00
dijunkun 0ef51e3faf [feat] add FAQ.md 2025-10-23 10:33:39 +08:00
dijunkun cccf5dadb2 Merge branch 'run-in-bg' into self-hosted-server 2025-10-22 17:23:08 +08:00
dijunkun 2f0b0ffc22 [feat] add configuration to minimize to system tray when clicking the close button, refs #4 2025-10-22 17:21:47 +08:00
dijunkun c7411b59f1 [chore] update README 2025-10-21 22:51:21 +08:00
dijunkun 8222782522 [chore] update README 2025-10-21 20:54:37 +08:00
dijunkun 5fed09c1aa [ci] only close inactive issues with no labels 2025-10-21 11:37:25 +08:00
dijunkun 8e499772f9 [ci] add GitHub Actions workflow to automatically close inactive issues 2025-10-21 11:29:31 +08:00
dijunkun 0da812e7e9 [chore] update README 2025-10-20 21:51:09 +08:00
dijunkun 3d67b6e9d6 [chore] update README 2025-10-20 11:18:35 +08:00
dijunkun 506b2893c6 [chore] update README 2025-10-20 11:04:41 +08:00
Junkun Di 56abe9e690 [chore] update README 2025-10-20 09:55:59 +08:00
dijunkun ab13fa582d [chore] update README 2025-10-20 01:36:42 +08:00
dijunkun b9e8192eee [feat] support self-hosted service, fixes #3 2025-10-20 01:02:44 +08:00
dijunkun 5590aaeb1e [feat] add support for self-hosted server configuration 2025-10-18 23:41:10 +08:00
dijunkun adfe14809f [ci] switch GitHub-hosted runner from macos-13 to macos-15-intel 2025-10-18 02:40:32 +08:00
dijunkun a21dbc8d69 Merge branch 'sdl3' into self-hosted-server 2025-10-18 02:26:01 +08:00
dijunkun 9d45e497f4 [config] disable SRTP by default 2025-10-18 02:09:40 +08:00
dijunkun e5891eb397 [fix] use static pcre linking to ensure this lib runs on machines without pcre, fixes #5 2025-10-18 01:59:35 +08:00
dijunkun b9c70f54d3 [feat] add self-hosted server configuration section in settings window 2025-10-17 17:22:31 +08:00
dijunkun 9cd617d078 [feat] add self-hosted server config item in settings windows 2025-10-16 17:42:49 +08:00
dijunkun 92fd7f2e89 [feat] remove vc runtime from nsis script since using static linking 2025-10-16 16:03:27 +08:00
dijunkun b8535fff6f [feat] switch to /MT static runtime to improve Windows compatibility 2025-10-16 12:40:53 +08:00
dijunkun 09f34a81ad [feat] add screen capture frame rate option in settings window 2025-10-15 17:28:36 +08:00
dijunkun 22cc552e85 [feat] set screen capture frame rate to 60 fps 2025-10-15 15:42:42 +08:00
dijunkun 69a4dfcbb9 [feat] add fps display in net traffic stats window 2025-10-15 11:26:45 +08:00
dijunkun e1390ca2d3 [chore] update README 2025-10-13 17:12:45 +08:00
dijunkun dccdcd1b6f [chore] update README 2025-10-13 16:48:46 +08:00
dijunkun 276c3a336f [chore] update README 2025-10-13 10:52:01 +08:00
dijunkun 08518a9409 [fix] resolve mouse control issue due to SRTP packet parsing 2025-10-11 23:57:45 +08:00
dijunkun f6b0767bb1 [chore] update README 2025-10-11 23:57:26 +08:00
Junkun Di 641fc84430 [chore] pdate README_EN 2025-10-11 17:50:41 +08:00
Junkun Di 4ce79b87a3 [chore] update README 2025-10-11 17:49:49 +08:00
dijunkun 477b204913 [chore] update README 2025-10-11 17:47:24 +08:00
dijunkun 98f349ea2f [chore] update README 2025-10-11 16:32:42 +08:00
dijunkun 47b1e15eef [chore] update README 2025-10-10 09:16:29 +08:00
dijunkun 590bf50924 [chore] update README 2025-10-09 16:36:41 +08:00
dijunkun 097633e47d [chore] add license 2025-10-09 16:03:05 +08:00
Junkun Di d9ba88107d [chore] update README.md 2025-10-09 15:29:06 +08:00
Junkun Di f6a6ef0b08 [chore] update README_CN.md 2025-10-09 15:28:06 +08:00
Junkun Di a93ee0c19e [chore] update README.md 2025-10-09 15:25:21 +08:00
dijunkun 7e73553aca [fix] fix line drawing in recent connections window 2025-10-09 15:23:37 +08:00
Junkun Di b858bd78c0 [chore] update README.md 2025-10-09 15:07:58 +08:00
dijunkun f10947edf9 Merge branch 'sdl3' of https://github.com/kunkundi/crossdesk into sdl3 2025-10-09 14:47:47 +08:00
dijunkun c723cca8f9 [chore] update README.md 2025-10-09 14:47:33 +08:00
dijunkun b8f8b07ebe [chore] remove password regenerate button 2025-10-01 01:30:04 +08:00
dijunkun f9c6e5a6ef [fix] correct packet loss in network statistics 2025-09-30 17:54:41 +08:00
dijunkun 15bf8ef8c0 [feat] show shield icon when SRTP is enabled 2025-09-30 17:26:42 +08:00
dijunkun 6565816c0e [fix] fix log path issue on first launch 2025-09-30 15:50:22 +08:00
dijunkun 2aa67ccd57 [feat] prompt user to close crossdesk.exe during install/uninstall on Windows 2025-09-30 15:27:34 +08:00
dijunkun 88c75f94e4 [feat] add SRTP switch in settings 2025-09-24 20:27:56 +08:00
dijunkun aea9505c4c [chore] move nvidia-cuda-toolkit from Depends to Recommends in linux amd64 package 2025-09-12 17:42:47 +08:00
dijunkun 646740aab6 [chore] update minirtc to latest 2025-09-12 17:28:39 +08:00
dijunkun a458836e6e [fix] resolve certs file loading failure on linux 2025-09-12 16:29:20 +08:00
dijunkun 5fe7df8ea8 [feat] ensure VC++ Redistributable is installed on Windows during setup 2025-09-12 12:49:35 +08:00
dijunkun fda3743f86 [feat] add run-after-install option for windows installer 2025-09-11 16:23:48 +08:00
dijunkun 9e4170b3a8 [fix] update minirtc to fix startup crash on Windows when CUDA is not supported or not installed by using explicit dynamic loading 2025-09-11 01:01:46 +08:00
dijunkun 43338aaf02 [fix] release all peers when settings modified 2025-09-10 22:53:07 +08:00
dijunkun 274b7fcedc [test] test libstdc++ 2025-09-10 15:46:51 +08:00
dijunkun 01a5660984 [fix] set YUV colorspace to SDL_COLORSPACE_BT601_LIMITED to resolve NV12 texture display issue 2025-09-08 09:52:16 +08:00
dijunkun a45118f785 [feat] remove internet shortcut installing for windows script 2025-09-05 18:51:16 +08:00
dijunkun b6631c3db0 [fix] fix crash due to wrong linux keycode value 2025-09-04 16:31:03 +08:00
dijunkun 84d164c3af [fix] compelete linux x11 keycode map 2025-09-04 15:46:09 +08:00
dijunkun 32815ce25a [feat] use crossdesk/ubuntu20.04:latest as build image to support more users 2025-09-03 18:40:29 +08:00
dijunkun 7c2b3f8c8d [fix] use x64 and amd64 instead of x86_64 in artifact name 2025-09-03 17:10:17 +08:00
dijunkun 309d9d6ed6 [fix] fix linux x86_64 package script no Size information issue 2025-09-03 15:55:16 +08:00
dijunkun 91ab21c5f2 [fix] fix function keys release handling issue 2025-09-02 18:58:54 +08:00
dijunkun b8369c4f0a [feat] remove redundant ImGui ConfigFlags to improve performance 2025-09-02 17:10:55 +08:00
dijunkun a068a32303 [fix] remove SDL3 input audio stream recording 2025-09-02 16:53:55 +08:00
dijunkun b6fe0da581 [feat] use SDL_WaitEventTimeout to refresh frames and reduce CPU usage 2025-09-02 16:45:04 +08:00
dijunkun 6e7e2697b5 [fix] fix dpi scaling 2025-09-02 15:48:05 +08:00
dijunkun 22084072b0 [feat] update icon files 2025-09-01 18:12:47 +08:00
dijunkun d5457373f4 [feat] use squircle icons 2025-08-29 17:53:47 +08:00
dijunkun 01ae299cde [feat] delete old files 2025-08-29 10:16:26 +08:00
dijunkun fbcd4c21cf [feat] use rsync instead of appleboy/scp-action to update artifacts 2025-08-29 09:56:20 +08:00
dijunkun cf9dc0a9a5 [fix] fix artifacts generation path on linux in github actions scripts 2025-08-28 23:29:18 +08:00
dijunkun 1b4f41af46 [feat] upload artifacts to chinese server for download 2025-08-28 19:16:11 +08:00
dijunkun 7f3425519b [fix] fix linux github actions building 2025-08-28 19:14:25 +08:00
dijunkun 434c92deb6 [fix] add crossdesk_128x128.png to icons 2025-08-28 18:37:26 +08:00
dijunkun e5eae1feb4 [feat] update icons 2025-08-28 18:23:02 +08:00
dijunkun 37e37d7d20 [fix] mv deb to /tmp in install process 2025-08-28 17:48:09 +08:00
dijunkun 062568dc96 [fix] fix SDL3 texture display error 2025-08-26 16:26:06 +08:00
dijunkun d60fdf9050 [feat] update SDL2 to SDL3 2025-08-25 19:46:30 +08:00
dijunkun 9912a88a13 [feat] github actions support linux aarch64 platform 2025-08-22 18:43:07 +08:00
dijunkun 8a8f2cd5d7 [feat] update minirtc to support linux aarch64 platform 2025-08-21 20:16:55 +08:00
dijunkun e77e16d9c2 [fix] Add validity check for props 2025-08-20 16:42:31 +08:00
dijunkun 1616d0ec33 [fix] Add validity check for props 2025-08-20 16:37:29 +08:00
dijunkun 374453775f [fix] fix connection status window gui display 2025-08-19 17:47:09 +08:00
dijunkun 6f8fd6a030 [fix] fix crash when transmission id does not exist 2025-08-19 16:33:29 +08:00
dijunkun c7166975b3 [fix] fix version number replace for pages 2025-08-15 20:52:42 +08:00
dijunkun 2ae5e5a969 [feat] do not generate dmg for macOS 2025-08-15 20:34:27 +08:00
dijunkun 85cdc995c5 [fix] fix artifacts name with version number 2025-08-15 20:07:18 +08:00
dijunkun b051c8a059 [fix] fix artifacts name with version number 2025-08-15 19:55:03 +08:00
dijunkun 508b7dc7a1 [feat] add script to update the version number in github pages 2025-08-15 19:41:04 +08:00
dijunkun f203566b81 [feat] use dynamic version number 2025-08-15 19:35:16 +08:00
dijunkun 8360c1725f [feat] add release scripts 2025-08-15 15:41:10 +08:00
dijunkun 3b00fdef71 [fix] fix github actions scripts 2025-08-14 16:58:29 +08:00
dijunkun f2664daaec [feat] add github actions scripts 2025-08-10 00:03:13 +08:00
dijunkun 1a1bbe3e4d [fix] fix cache file and cert file read 2025-08-09 23:59:53 +08:00
dijunkun 4c898c5f07 [fix] save log files into XDG_CACHE_HOME/CrossDesk/logs for Linux platform 2025-07-25 18:11:40 +08:00
dijunkun 5d704edbc8 [fix] use std::filesystem::create_directories instead of std::filesystem::create_directory to create folder 2025-07-24 15:52:52 +08:00
dijunkun b23038bac6 [feat] update signal server domain 2025-07-23 17:30:30 +08:00
dijunkun 147b9b2ddc [fix] fix thumbnail order by using std::vector instead of std::unordered_map 2025-07-23 16:38:29 +08:00
dijunkun 1327b995f2 [fix] fix compile error on MacOSX 2025-07-23 11:31:32 +08:00
dijunkun e8d7ec8daf [feat] save log and cache files into user folder 2025-07-22 18:55:12 +08:00
dijunkun 3bf68a396f [feat] add PathManager class in order to manage config/log/cache file path 2025-07-16 18:22:33 +08:00
kunkundi 29077fad5e Merge branch 'multi-stream' of https://github.com/kunkundi/crossdesk into multi-stream 2025-07-16 17:10:18 +08:00
kunkundi 69367bdadf [fix] fix same memory leak issue 2025-07-16 17:09:51 +08:00
dijunkun f650b5a6ef [feat] use unordered map to store recent connection info so that the most recent connections are shown at the front 2025-07-15 17:34:25 +08:00
kunkundi 75021b74ef [fix] use temp frame to store the audio frame that will be sent 2025-07-15 17:18:00 +08:00
dijunkun 205421621b [fix] fix local id when using as client 2025-07-15 16:35:05 +08:00
dijunkun 4bb5607702 [fix] fix restart audio capturer error on MacOSX 2025-07-15 16:05:57 +08:00
kunkundi 78c54136e2 [fix] fix crash when Stop() called in SpeakerCapturerLinux 2025-07-15 15:38:58 +08:00
kunkundi 8fe8f4fd7e [feat] audio capture supported on Linux 2025-07-11 17:17:05 +08:00
dijunkun c13e2613b6 [feat] audio capture supported on MacOSX 2025-07-02 19:25:21 +08:00
dijunkun e52ec6cde2 [fix] use domain name instead of ip address to enable tls connection 2025-07-01 17:38:24 +08:00
dijunkun ad6a24b230 [feat] add tls cert file path in configure parameters 2025-07-01 13:55:41 +08:00
dijunkun ad60815d83 [fix] fix thumbnails deletion 2025-07-01 11:13:24 +08:00
dijunkun c47a90bf9c [feat] update project name 2025-06-25 17:33:54 +08:00
dijunkun 3901e26c37 [fix] fix thumbnail filename which stores remote id, remote host name and remote password 2025-06-20 18:42:29 +08:00
dijunkun 41c27139a0 [feat] password modification supported 2025-06-20 17:50:04 +08:00
dijunkun a31ca21ef4 [feat] receive id and password when login to server in the first time 2025-06-20 00:57:56 +08:00
dijunkun 57939ccd00 [feat] update submodule info 2025-06-18 00:06:47 +08:00
dijunkun fc14f7b9c6 [fix] register minirtc as submodule properly 2025-06-17 23:29:02 +08:00
dijunkun cfcf6dd9cb [feat] replace submodule projectx with minirtc at new path 2025-06-17 17:11:43 +08:00
dijunkun 854c3a72c7 [feat] modify project name to DeskPort 2025-06-17 14:24:41 +08:00
dijunkun 8004d25ca3 [feat] limit screen capturing to 30 fps 2025-06-07 02:46:51 +08:00
dijunkun b04dfd188a [fix] fix SCStream stop error 2025-06-03 10:44:52 +08:00
dijunkun 383ace2493 [fix] only receive remote host info once 2025-06-03 10:33:32 +08:00
dijunkun 094204361c [feat] enable screen switch on Linux platform 2025-05-29 18:09:34 +08:00
dijunkun d72c6d9df7 [feat] enable mouse dragging for MacOSx 2025-05-29 17:05:56 +08:00
dijunkun 05d73ebe9a [feat] add notification text in stream windows when connection failed/disconnected/closed 2025-05-29 16:51:18 +08:00
dijunkun a8b5e934b8 [feat] implementation for ScreenCapturerSck::Destroy() and ScreenCapturerSck::Stop() 2025-05-29 15:49:42 +08:00
dijunkun 920677a433 [fix] use black to fill the blank areas around the thumbnail 2025-05-29 15:02:43 +08:00
dijunkun b86d3d42ee [fix] fix color space for thumbnail 2025-05-29 14:17:33 +08:00
dijunkun 818dab764f [fix] do not recreate screen capturer when reload configuration file 2025-05-28 19:15:02 +08:00
dijunkun 7ea26854af [fix] fix strncpy error 2025-05-28 17:25:39 +08:00
dijunkun f34b55b88a [fix] do not need to call SDL_CloseAudioDevice() before SDL_Quit() 2025-05-28 16:02:37 +08:00
dijunkun 67168f7735 [fix] destroy screen capturer only when clean up 2025-05-27 10:17:25 +08:00
dijunkun 6e69c37056 [feat] use display name as video stream id 2025-05-26 15:29:46 +08:00
dijunkun 8f5dd21e75 [fix] remove data length check in OnReceiveDataBufferCb 2025-05-22 18:09:23 +08:00
dijunkun e2dfeb1186 [fix] fix RemoteAction read from received data 2025-05-22 17:18:06 +08:00
dijunkun 96c7d3174b [feat] improve the performance of ScreenCapturerSck 2025-05-22 17:17:15 +08:00
dijunkun 97f6c18296 [feat] update ScreenCapturerSck 2025-05-20 19:11:17 +08:00
dijunkun 9138ca771f [fix] do not send mouse click event when cursor is on control bar and display selectable 2025-05-16 19:06:25 +08:00
dijunkun abc6b17a3b [fix] display index shown in control bar should start from 1 2025-05-16 18:51:57 +08:00
dijunkun 8e0524bf60 [feat] display switch supported on MacOSx platform 2025-05-16 18:49:20 +08:00
dijunkun 6ebf583a13 [fix] fix compile error on MacOSx 2025-05-15 19:54:17 +08:00
dijunkun eca4f614c8 [feat] cursor mapping in different displays supported 2025-05-15 19:47:08 +08:00
dijunkun 11358e0b60 [feat] enable mouse control for multi-display 2025-05-15 18:37:59 +08:00
dijunkun 0a1014dded [fix] use serialize and deserialize function to process RemoteAction::HostInfo 2025-05-15 17:52:40 +08:00
dijunkun a6beb48b1f [feat] display switch supported on Windows platform 2025-05-15 16:37:03 +08:00
dijunkun 5eff530ab9 [fix] fix ScreenCapturerWgc crash during clean up 2025-05-15 15:27:44 +08:00
dijunkun e6e237279c [feat] update rtc module 2025-05-13 21:47:05 +08:00
dijunkun 6fe46f6181 [feat] add a=m lines in sdp for multi-stream 2025-05-12 22:09:08 +08:00
dijunkun 9b5023645c [feat] display selection supported on Windows platform 2025-05-09 22:30:56 +08:00
dijunkun c2da4ebcb7 [feat] add remote display selection button in control bar 2025-05-09 17:23:27 +08:00
dijunkun dc05f2405f [feat] add display selection method for Windows platform 2025-05-08 17:40:14 +08:00
dijunkun e2a469ed65 [feat] remove dependence on ffmpeg for MacOSx 2025-05-08 11:33:04 +08:00
dijunkun e89d385f99 [fix] remove redundant link flags on Linux platform 2025-05-08 11:07:04 +08:00
dijunkun 0a61dcc2be [fix] update keyboard converter 2025-05-07 19:47:09 +08:00
dijunkun 250fd49406 [feat] mouse/keyboard control and screen capture supported by using X11 on Linux platform 2025-05-07 19:37:41 +08:00
dijunkun 93bd5b2660 [fix] fix control bar display error in fullscreen mode when multiple connections established 2025-05-06 19:49:08 +08:00
dijunkun d05ff9f905 [fix] update rtc module 2025-05-06 18:58:52 +08:00
dijunkun f3451a5fa1 [fix] fix compile error on Linux 2025-05-06 18:39:30 +08:00
dijunkun a9084ba98d [fix] fix control bar layout and position in stream window 2025-04-30 18:18:55 +08:00
dijunkun 893051f9b3 [fix] fix crash due to invalid iterator 2025-04-30 15:16:32 +08:00
dijunkun dfbd4317b7 [feat] use tab bar to manage stream windows 2025-04-29 22:16:10 +08:00
dijunkun 532ad0eb51 [feat] support multi-stream and enable stream windows docking 2025-04-28 20:49:11 +08:00
dijunkun 184983d857 [fix] fix FindThumbnailPath() 2025-04-27 18:46:45 +08:00
dijunkun c33e4bbe0e [fix] use relative percentage-based mouse mapping instead of absolute positions 2025-04-27 14:02:20 +08:00
dijunkun 4b9e86c424 [fix] fix recent connection deletion 2025-04-27 10:53:44 +08:00
dijunkun f7f8ddd925 [fix] fix log error 2025-04-18 15:39:31 +08:00
dijunkun 188b1758f2 [feat] remove screen resolution info in HostInfo 2025-04-17 16:58:45 +08:00
dijunkun 9705374b9a [feat] save thumbnail as black picture if have not received a full frame 2025-04-16 16:47:30 +08:00
dijunkun 22aed6ea53 [fix] send host info when connected 2025-04-16 16:13:54 +08:00
dijunkun 44c5fde086 [fix] send host info when connected 2025-04-16 15:36:25 +08:00
dijunkun 2cd5a9dd76 [fix] do not send click event if cursor clicks the button which is on control bar 2025-04-16 14:47:44 +08:00
dijunkun fa73447f88 [fix] fix mouse wheel mapping on Windows 2025-04-16 14:33:11 +08:00
dijunkun 536fe17055 [fix] fix wheel event grabbing 2025-04-15 17:32:23 +08:00
dijunkun 662cbbc3cc [feat] mouse middle button and wheel supported 2025-04-15 14:26:34 +08:00
dijunkun 69a8503ee1 [fix] need to DestroyPeer if NoSuchTransmissionId 2025-04-15 10:28:19 +08:00
dijunkun b906bfcafd [fix] fix audio command sending 2025-04-14 17:33:35 +08:00
dijunkun f891a047d6 [fix] flush STREAM_FRASH event when stream closed 2025-04-14 17:15:00 +08:00
dijunkun dce32672a6 [fix] fix cursor mapping 2025-04-14 16:59:48 +08:00
dijunkun 2774991107 [fix] only send hostname and resolution before sending first frame 2025-04-14 16:49:31 +08:00
dijunkun b7ce8b6299 [fix] fix render resolution 2025-04-14 16:31:46 +08:00
dijunkun 700fb2ec14 [feat] send server resolution before sending first frame 2025-04-14 16:12:55 +08:00
dijunkun 62d14587cd [fix] fix compile warning 2025-04-11 16:09:11 +08:00
dijunkun 824d9243cc [fix] fix join problem that when join to a server which does not exist in recent connections 2025-04-10 17:35:21 +08:00
dijunkun 5351b4da0e [fix] do not show stream window if the client is only in server mode 2025-04-10 17:19:19 +08:00
dijunkun fcd0488624 [fix] fix control bar position when stream window created 2025-04-10 16:46:53 +08:00
dijunkun 193e905b28 [fix] save password only when join the connection successfully 2025-04-09 17:31:59 +08:00
dijunkun f48085c69a [fix] fix connection error when reinput password 2025-04-09 17:17:30 +08:00
dijunkun cf078be53f [feat] separate function Run() into several functions 2025-04-09 16:51:33 +08:00
dijunkun badcd6a05c [fix] fix mouse contorl error 2025-04-09 15:47:24 +08:00
dijunkun d828bd736d [feat] use peer map to manage multiple client instances 2025-04-08 17:34:33 +08:00
dijunkun 1e014bdae3 [fix] fix crash due to encoder releasing 2025-03-25 17:37:12 +08:00
dijunkun 334ab182db [fix] fix crash when try to close connection 2025-03-24 17:40:44 +08:00
dijunkun f52de76bfc [feat] update rtc api 2025-03-19 18:38:13 +08:00
dijunkun 6c7d0e8cab [feat] support FIR and NACK 2025-03-07 18:37:26 +08:00
dijunkun 7229ae856e [fix] fix video capture timestamp 2025-02-28 15:53:03 +08:00
dijunkun 597d760d24 [feat] fix crash and update rtc module 2025-02-06 17:37:18 +08:00
dijunkun bcf61e1ada [fix] fix crash due to sub stream window properties 2025-02-05 23:31:33 +08:00
dijunkun 08e596714b [fix] fix h264 rtp packetization error 2025-02-05 17:29:26 +08:00
dijunkun bff577ba34 [feat] update rtc module 2025-01-23 17:29:26 +08:00
dijunkun 4df935b9d2 [fix] fix log name conflict 2025-01-22 17:34:35 +08:00
dijunkun 9bb560314b [fix] use reinterpret_cast to convert u8"x" to const char* 2024-12-18 17:29:13 +08:00
dijunkun 1a0c5e8b42 [feat] use client_properties_ and server_properties_ to store streams properties 2024-12-03 17:22:15 +08:00
dijunkun 011919d0e7 [feat] use SubStreamWindowProperties to store sub stream properties 2024-12-02 17:30:51 +08:00
dijunkun 418ab7a1d2 [fix] fix net traffic stats display 2024-12-02 11:03:55 +08:00
dijunkun 6a2c9af316 [feat] loss rate display supported 2024-12-01 17:00:59 +08:00
dijunkun eaabf478cc [feat] update net statistics module 2024-11-29 17:54:15 +08:00
dijunkun ffe3ca76af [feat] switch rtc module into new branch 'qos' 2024-11-28 18:27:34 +08:00
dijunkun c5a6302220 [fix] update rtc module 2024-11-28 15:16:48 +08:00
dijunkun 9b2f81690f [fix] fix stream window scale error 2024-11-27 20:28:42 +08:00
dijunkun 9621e6b570 [fix] fix right shift key mapping on MacOSX 2024-11-27 17:33:54 +08:00
dijunkun ce3ae03bef [fix] prevent cursor relocation when stream window resized 2024-11-27 17:24:45 +08:00
dijunkun e0457213ea [fix] fix display errors when stream window resized 2024-11-27 16:14:14 +08:00
dijunkun 10cdc440a0 [fix] fix key press/release event 2024-11-27 14:34:54 +08:00
dijunkun ddc62c90bb [fix] fix all unused variables and type conversions on Windows 2024-11-27 11:17:43 +08:00
dijunkun 9e70d0e8fc [fix] fix all unused variables and type conversions on MacOSX 2024-11-27 10:57:09 +08:00
dijunkun 4533d53ba8 [fix] fix all unused variables and type conversions 2024-11-26 23:31:06 +08:00
dijunkun 0caa243006 [fix] fix unused variables and type conversions 2024-11-26 17:31:37 +08:00
dijunkun 1e58abdfdd [feat] rewrite log module 2024-11-26 16:05:28 +08:00
dijunkun 370ac08d09 [fix] use new rtc api 2024-11-26 15:06:55 +08:00
dijunkun 31b6b2736c [fix] fix control and shift keys convertion from Win to MacOSX 2024-11-25 17:29:49 +08:00
dijunkun abd22ab7f1 [fix] fix Win/MacOSX keycodes convertion 2024-11-25 17:15:22 +08:00
dijunkun 5ab68988aa [fix] fix stream window grabbing cannot be released after connection closed 2024-11-22 18:12:36 +08:00
dijunkun ba3edcc02a [feat] keyboard control supported on MacOSX 2024-11-22 18:05:13 +08:00
dijunkun 8414a57a5b [feat] keyboard control supported on Windows 2024-11-22 17:17:33 +08:00
dijunkun 3f777e4662 [fix] fix compile error 2024-11-22 16:45:14 +08:00
dijunkun 52828183a1 [feat] keyboard capture supported on Windows 2024-11-22 16:39:01 +08:00
dijunkun df7489f8e2 [fix] update imgui to v1.91.5-docking to fix: inputText cannot input text after add a space in remote id 2024-11-21 18:40:42 +08:00
dijunkun 4fea7d86e1 [feat] cursor will move into remote id input box automaticlly if the last input remote id does not exist 2024-11-21 16:20:25 +08:00
dijunkun cb17b7c8db [fix] fix setting item [enable turn] 2024-11-21 16:05:10 +08:00
dijunkun cf7ef89bf2 [fix] fix cursor position when stream window initialization 2024-11-21 10:34:04 +08:00
dijunkun 2d2a578800 [fix] fix control window position when stream window size changed 2024-11-20 19:17:33 +08:00
dijunkun 0ba12f3ccf [fix] only display client side net status if connected to itself 2024-11-19 22:33:59 +08:00
dijunkun 5ac603977d [fix] fix net traffic stats display 2024-11-19 17:31:31 +08:00
dijunkun 25d5a80bee [fix] reset net traffic stats after connection closed 2024-11-19 17:26:01 +08:00
dijunkun c9d452a025 [feat] disable settings modification during streaming 2024-11-19 17:21:27 +08:00
dijunkun 8132d62c02 [feat] show net traffic stats in control bar 2024-11-19 16:56:30 +08:00
dijunkun ca32ebeefe [feat] net traffic stats supported 2024-11-18 17:33:09 +08:00
dijunkun 5bf5e9ee25 [feat] change UI layouts 2024-11-18 16:08:54 +08:00
dijunkun bf097008e7 [feat] use SDL_WINDOW_HIDDEN to delay showing the main window to avoid black window during initialization 2024-11-18 15:10:02 +08:00
dijunkun 59b1208321 [feat] load different size fonts in initialization 2024-11-15 18:19:54 +08:00
dijunkun 84194188f8 [fix] fix redundant recent connection cache file due to remember_password_ flag not being set correctly 2024-11-14 17:26:08 +08:00
dijunkun a067441fb9 [feat] change recent connections layout 2024-11-14 17:13:38 +08:00
dijunkun 6eac8380b6 [feat] generate random AES128 key and iv during initialization, save them in cache file and load when program starts 2024-11-14 00:49:30 +08:00
dijunkun 5aed8317ca [feat] quick connecting supported 2024-11-13 23:27:06 +08:00
dijunkun 9aed7a19cf [fix] fix AES encrypt and decrypt 2024-11-13 17:58:59 +08:00
dijunkun c0154be1aa [fix] use APIs in evp.h to encrypt and decrypt 2024-11-13 00:47:54 +08:00
dijunkun f9d024e971 [feat] use AES to encrypt image names 2024-11-12 17:30:28 +08:00
dijunkun 526eb4bb31 [feat] add trash and connect buttons on recent connection images 2024-11-11 17:05:47 +08:00
dijunkun f9347cbd49 [feat] use confirm window to confirm recent connections deletion 2024-11-11 10:49:07 +08:00
dijunkun b6671bdbe7 [feat] delete recent connection supported 2024-11-08 17:52:19 +08:00
dijunkun edcf5d408c [feat] use horizontal scroll bar to show all recent connections 2024-11-08 14:51:58 +08:00
dijunkun 8c8731909e [feat] remote host names will be shown below thumbnails 2024-11-07 17:30:55 +08:00
dijunkun de721ac6e3 [feat] use a list to show thumbnails of recent connections 2024-11-07 16:58:25 +08:00
dijunkun 963f1da1d8 [fix] fix redefinition error on MacOSX 2024-11-07 16:32:35 +08:00
dijunkun 4c6159e4d4 [feat] write and load thumbnails supported 2024-11-07 16:29:02 +08:00
dijunkun e3c2e9ec6d [fix] fix png images write and read 2024-11-07 02:38:35 +08:00
dijunkun 02022bdcdf [feat] add recent connections window 2024-11-06 17:28:11 +08:00
dijunkun 19ea426efc [feat] change UI layouts 2024-11-05 17:29:39 +08:00
dijunkun 863070a8a7 [feat] enable window grab when mouse control enabled 2024-11-04 17:29:26 +08:00
dijunkun 44f9e6a8c9 [fix] fix crash due to multi-context fonts release 2024-11-04 16:13:20 +08:00
dijunkun 087d5d7e52 [feat] use an additional window to show video streams 2024-11-01 20:30:06 +08:00
dijunkun 26fa53f867 [fix] fix imgui layout error 2024-11-01 15:57:15 +08:00
dijunkun d18af6cbc6 [fix] fix client id generation 2024-10-30 17:25:41 +08:00
dijunkun b5bb62bd22 [feat] support new screen capture method by using ScreenCaptureKit on MacOSX 2024-10-18 17:20:52 +08:00
dijunkun 9ed3ab9929 [fix] fix the fullscreen error when closing the connection 2024-09-19 16:41:59 +08:00
dijunkun dca18762e0 [fix] use original screen render resolution to capturing and fix cursor mapping error 2024-09-13 17:08:58 +08:00
dijunkun fed7c3b103 [fix] fix cursor mapping error 2024-09-13 16:04:19 +08:00
dijunkun d246b7a04d [fix] fix the issue where the title bar is displayed incorrectly when in fullscreen mode 2024-09-13 15:10:23 +08:00
dijunkun a49ca813e0 [fix] fix black screen after close the connection 2024-09-13 10:35:53 +08:00
dijunkun 0c688efaee [fix] fix buttons position when control bar in the right 2024-09-12 17:22:13 +08:00
dijunkun be3561d46f [fix] optimize the first graph rendering time when open this program 2024-09-12 17:17:07 +08:00
dijunkun c3af40a3f0 [feat] add close button in control bar 2024-09-12 16:22:02 +08:00
dijunkun d493b9a131 [feat] make the window centered on the screen after closed 2024-09-12 13:57:51 +08:00
dijunkun 4e4e84ae4d [fix] fix window size when closed after resized 2024-09-12 13:51:11 +08:00
dijunkun fea545e5e7 [fix] do not forget to destroy the texture 2024-09-11 17:35:27 +08:00
dijunkun 9096769a85 [fix] fix render stream blurry problem 2024-09-11 11:22:17 +08:00
dijunkun 04ab157ecb [fix] fix crash due to invalid pointer 2024-09-10 17:33:55 +08:00
dijunkun 2331f08283 [fix] fix cursor mapping error due to the client render aspect ratio different from the server screen aspect ratio 2024-09-06 19:36:33 +08:00
dijunkun 9f8f99f21b [fix] fix cursor mapping error due to ffmpeg default screen capture resolution different from the real screen resolution 2024-09-06 19:32:30 +08:00
dijunkun 56dadb6a49 Merge branch 'rt_desk' of github.com:dijunkun/continuous-desk into rt_desk 2024-09-06 17:38:43 +08:00
dijunkun 59c9ca8d53 [fix] fix render area cannot fit the resolution of the receiving video stream 2024-09-06 17:38:09 +08:00
dijunkun f16a4e8aa2 [feat] support original resolution screen capture on MacOSX 2024-09-06 15:20:06 +08:00
dijunkun 890615e13a [fix] fix crash during termination 2024-09-06 13:07:20 +08:00
dijunkun 2f72e3957e [feat] support dynamic resolution codec 2024-09-05 17:29:27 +08:00
dijunkun 1292018f51 [fix] fix crash when signal server close the connection actively 2024-09-04 17:03:40 +08:00
dijunkun 8ae9513104 [feat] only a six-char password will be accepted 2024-09-03 17:29:46 +08:00
dijunkun c1efe2f4ac [feat] do not capture cursor 2024-09-03 17:00:57 +08:00
dijunkun 1210a0b631 [fix] fix crash caused by accessing invalid memory 2024-09-03 16:24:36 +08:00
dijunkun 39863c597e [feat] allow user to set customized password 2024-09-03 15:50:38 +08:00
dijunkun 8a964f0030 [feat] add option 'enable TURN service' in settings menu 2024-09-02 17:29:03 +08:00
dijunkun 74e29f25bf [fix] do not use smart pointer to manage std::thread objects 2024-09-02 16:33:01 +08:00
dijunkun 1e5bea2b1e [feat] put ice agent into ice worker thread and use message queue to handle events 2024-08-28 17:31:27 +08:00
dijunkun d8297ebb74 [feat] use fix random password otherwise user regenerates one 2024-08-28 10:28:11 +08:00
dijunkun 93d7f71cf2 [feat] support use param to control enable TURN or not 2024-08-27 17:06:56 +08:00
dijunkun 887a217828 [fix] fix fonts missing 2024-08-27 17:04:11 +08:00
dijunkun 89b12136e4 [fix] Optimizing video encoding speed for software encoders 2024-08-20 17:18:29 +08:00
dijunkun def7025abf [fix] fix connection status display 2024-08-20 10:21:34 +08:00
dijunkun 35af5aab43 [fix] fix control bar border color 2024-08-19 17:09:19 +08:00
dijunkun 9ea67df0fd [fix] fix title bar icon error when leaves maximized state 2024-08-19 14:16:21 +08:00
dijunkun 72fda8a728 [feat] let keyboard focus on input widget when needs to input password 2024-08-19 11:05:08 +08:00
dijunkun 070b48d7a7 [fix] fix mouse and audio capture buttons cannot be disabled once enabled 2024-08-16 17:30:44 +08:00
dijunkun 6168009cef [feat] support building xcode app on MacOSX 2024-08-16 17:19:17 +08:00
dijunkun 06a7243ac1 [fix] fix mouse click event sending when control bar hovered 2024-08-16 15:06:42 +08:00
dijunkun c8602b0d89 [fix] fix cursor position error 2024-08-16 14:52:44 +08:00
dijunkun e3c730fd5f [fix] fix screen capture error in client mode 2024-08-16 14:22:08 +08:00
dijunkun b252cb6ddd [style] use self-draw icon for mouse and audio_capture disable buttons 2024-08-16 13:55:48 +08:00
dijunkun 8ca1e8e5a1 [style] reset menu bar line size 2024-08-16 09:35:09 +08:00
dijunkun a7d45b78c8 [feat] use self-draw icon for title bar 2024-08-15 17:38:18 +08:00
dijunkun 018231eee4 [feat] add protocol to control audio capture 2024-08-15 14:50:47 +08:00
dijunkun 4704d494ec [feat] add audio capture button in control bar 2024-08-15 11:25:19 +08:00
dijunkun 65927c2091 [feat] support speaker capture on Windows 2024-08-15 11:04:06 +08:00
dijunkun 574b9d10ab [fix] let temproary setting values equal to setting values when loading from cache file 2024-08-14 16:50:49 +08:00
dijunkun ff510a3b44 [fix] fix peer object delete 2024-08-14 16:39:08 +08:00
dijunkun 4d3c864950 [fix] fix client id cannot read from cache file 2024-08-13 17:17:35 +08:00
dijunkun 2cde54cf30 [fix] call memset() before using strncpy() 2024-08-13 17:07:19 +08:00
dijunkun d1f3d11318 [fix] use SDL_RestoreWindow() to reset the window when closed during streaming 2024-08-13 16:32:17 +08:00
dijunkun 436228946b [feat] do not show menu button during streaming 2024-08-13 16:21:31 +08:00
dijunkun 2b4083ee10 [feat] expand control bar by default 2024-08-13 11:26:18 +08:00
dijunkun e3abb4e3de [fix] fix recreate peer failed due to is_create_connection_ flag not reset 2024-08-13 11:15:28 +08:00
dijunkun 4b7cd1005b [fix] fix send error when ice state change from ready to connected 2024-08-09 16:54:14 +08:00
dijunkun 03ea96096d [feat] add space automaticlly for remote id input box 2024-08-09 11:33:13 +08:00
dijunkun 0ea8916426 [fix] fix settings error when load from cache file 2024-08-09 10:56:16 +08:00
dijunkun 43b36eb893 [fix] use proper std::chrono clock 2024-08-09 10:23:51 +08:00
dijunkun 03b6a187b3 [feat] split remote id into chunks of three characters separated by space 2024-08-08 16:34:55 +08:00
dijunkun 664412dd4e [feat] enable Enter key pressing for ImGui::InputText() method 2024-08-08 15:56:20 +08:00
dijunkun b37e08a202 [fix] fix client id empty error when run the program firstly 2024-08-08 15:26:21 +08:00
dijunkun a05d72ec67 [feat] lock the cache file when write/read it 2024-08-08 15:24:54 +08:00
dijunkun f77e9fe6a8 [feat] remove 'I/l/O/o/0' from password generator 2024-08-08 15:22:51 +08:00
dijunkun 1f9614e060 [feat] use h264 codec by default 2024-08-08 15:15:58 +08:00
dijunkun 50d92a763a [fix] fix leave transmission error when exit program 2024-08-07 17:33:05 +08:00
dijunkun ec23656334 [fix] fix client id error when connect to itself 2024-08-07 09:55:59 +08:00
dijunkun 880c2949c3 [feat] Use server to generate transmission id and client id 2024-08-06 17:27:40 +08:00
dijunkun 07f5fe81c8 [fix] fix control bar cannot stick to right side when out of y-axis region 2024-08-06 11:24:10 +08:00
dijunkun 5a992b6589 [fix] fix control bar width 2024-08-06 10:35:25 +08:00
dijunkun 8e03e8e79b [feat] make control bar stick to left/right border 2024-08-05 17:28:39 +08:00
dijunkun ceb3d9fe20 [feat] make control bar can only move along left border of the main window 2024-08-02 17:31:01 +08:00
dijunkun 0dc0b87bc4 [fix] fix control bar initial postion 2024-08-02 16:46:39 +08:00
dijunkun 3a4284fece [fix] fix read cache file failed 2024-08-02 16:15:18 +08:00
dijunkun 502a90f121 [fix] fix program cannot exit when click close button due to screen capture thread is running 2024-08-02 14:38:31 +08:00
dijunkun 88cd4aca4a [fix] fix title bar display error when streaming 2024-08-02 13:57:12 +08:00
dijunkun 3395004f93 [fix] fix compile error on Macosx and Linux 2024-08-02 13:56:22 +08:00
dijunkun e4c05e1f4d [feat] enable movement for control bar 2024-08-02 12:30:50 +08:00
dijunkun d17c70c2c8 [feat] remove menu bar and move menu button to title bar 2024-08-01 17:28:39 +08:00
dijunkun 7b42923418 [feat] use self designed title bar instead of system default title bar 2024-07-31 17:43:02 +08:00
dijunkun 5b6bdee25a [feat] add callback to notify the travsesal mode 2024-07-30 17:32:12 +08:00
dijunkun 05deb73c29 [feat] Support trickle ice 2024-07-29 16:48:22 +08:00
dijunkun 3685acc549 [feat] set window resizable only in streaming state 2024-07-25 10:10:37 +08:00
dijunkun 8f5a53937a [fix] fix control bar display and button postion 2024-07-24 17:10:05 +08:00
dijunkun b9c5db41ab [fix] show connection status windows when connection status changed 2024-07-24 16:27:58 +08:00
dijunkun a99a4230af Add module: speaker capture 2024-07-24 16:16:13 +08:00
dijunkun f446154747 1.Fix texture update crash; 2.Do not show control window when in server mode 2024-07-19 14:54:53 +08:00
dijunkun 5a1e2c5ed9 Use speaker as audio input 2024-07-19 14:10:35 +08:00
dijunkun ff6f295fac Do not use rc file on MacOS 2024-07-18 16:06:35 +08:00
dijunkun 3111b3a641 Add icon 2024-07-18 15:58:28 +08:00
dijunkun 20bb13ce85 Chinese support in connection status window 2024-07-18 14:46:19 +08:00
dijunkun 5aa05f3a13 Redesign elements styles 2024-07-18 11:02:35 +08:00
dijunkun c911aa2eb1 Add about window 2024-07-17 16:22:45 +08:00
dijunkun d0cd2fe9ab Fix log instance mismatch 2024-07-17 14:45:30 +08:00
dijunkun 9702805331 Make control bar scrollable 2024-07-05 16:05:50 +08:00
dijunkun 872152f1be 1.Enable random password; 2.Request user to input password when password is incorrect 2024-07-03 15:07:40 +08:00
dijunkun b822221d7f Add a button which can copy local id to clipboard 2024-07-03 11:03:04 +08:00
dijunkun 95ad605b36 Add signal and p2p connection status windows 2024-07-02 17:29:39 +08:00
dijunkun af32e25149 Use minimized compressed fonts header file 2024-07-02 11:19:50 +08:00
dijunkun e63b384d1e Set dpi scaling to solve display errot when using high dpi displayer 2024-07-01 16:31:39 +08:00
dijunkun 7f25f7426c Fix remote window height size error 2024-07-01 11:24:58 +08:00
dijunkun eed93ea953 Set utf-8 encoding flag in xmake.lua 2024-07-01 10:20:32 +08:00
dijunkun b5f8e92526 Solve the warning of method ImGui::Text() 2024-06-28 15:11:40 +08:00
dijunkun af04b0571e Use UTF-8 to save files 2024-06-28 12:49:56 +08:00
dijunkun 75452a3e76 1.Use compressed OPPOSans-Regular[3500 chinese characters]; 2.Use same layout style on different platforms 2024-06-28 12:30:09 +08:00
dijunkun 3f717f1df2 Use binary font headerfile instead of ttf file 2024-06-28 10:01:34 +08:00
dijunkun ad6f2c2c70 Implementation for menu bar 2024-06-27 17:36:13 +08:00
dijunkun 8076e7f662 Fix stream render with menu bar 2024-06-26 14:58:15 +08:00
dijunkun be78496992 Separate stream window from main window 2024-06-25 14:47:54 +08:00
dijunkun a3f745d441 Use fix ratio to render frame in window 2024-06-25 11:12:10 +08:00
dijunkun e693d920d3 Use sub windows to render main window 2024-06-24 17:35:25 +08:00
dijunkun 0f1b89eda9 Test tabbar in ImGui 2024-06-19 17:33:44 +08:00
dijunkun 172b8836fd Use FontAwesome6 to render icons 2024-06-18 17:28:02 +08:00
dijunkun 71178ffa33 Separate render window from main window 2024-06-17 17:31:57 +08:00
dijunkun 95a014a601 Not allow clicking connect button if remote id is empty 2024-06-14 17:01:58 +08:00
dijunkun 34d6bac345 Update Windows platform layout style 2024-06-14 16:02:55 +08:00
dijunkun 399785409c Use element style header file to control layout 2024-06-14 15:37:16 +08:00
dijunkun 5f1d9b6912 Fix language localization error 2024-06-14 13:55:05 +08:00
dijunkun d963a0cf38 1.The mouse control button allowed to be clicked Only when connection established; 2.Fix display resolution error after exit fullscreen 2024-06-14 10:48:35 +08:00
dijunkun f9c1bc48b4 Add control/release mouse button 2024-06-13 17:36:02 +08:00
dijunkun 2906d05a4b Do not send mouse click event when cursor hovers over subwindows 2024-06-13 16:56:03 +08:00
dijunkun 053a0f86ad Add mouse control flag 2024-06-13 16:36:11 +08:00
dijunkun 6c2363b239 Clear render buffer when connection closed 2024-06-13 16:30:25 +08:00
dijunkun 167514fed8 Do not collapse menu window when connection established 2024-06-13 16:07:22 +08:00
dijunkun 342eb0c386 Reset connection_established_ flag when connection closed 2024-06-13 16:06:02 +08:00
dijunkun 52c7099dbe Fix crash when connecting to local desk 2024-06-13 15:49:26 +08:00
dijunkun 12faf7cd2d Do not reset is_create_connection_ when click disconnect button 2024-06-07 18:13:09 +08:00
dijunkun 6d921a3309 Fix server mode screen capture error 2024-06-07 16:30:18 +08:00
dijunkun 5a690ebbb6 Do not use 'S-' or 'C-' as the prefix for the user id of a peer 2024-06-07 16:27:05 +08:00
dijunkun 4b3839aa34 Only server can capture screen and control mouse 2024-06-07 14:07:22 +08:00
dijunkun efb165b56f 1.Add CreateConnectionPeer method in order to recreate peer instance; 2.Fix settings OK/Cancel button position 2024-06-06 17:19:16 +08:00
dijunkun 0047b4ecc5 Recreate peer instance after settings changed 2024-06-06 15:11:02 +08:00
dijunkun 844710af7c Fix settings button value mismatch 2024-06-06 14:34:16 +08:00
dijunkun 562d54090a Use 'ImGuiWindowFlags_NoSavedSettings' for settings window 2024-06-06 09:57:37 +08:00
dijunkun f7fd37651e Reset settings window position before it is opened 2024-06-06 09:55:08 +08:00
dijunkun 280f59f97d Enable movement of settings window 2024-06-05 17:33:42 +08:00
dijunkun 0683ad9d27 Use Combo instead of RadioButton for settings 2024-06-05 17:30:23 +08:00
dijunkun e061e3b4d7 Support read configure params from input directly 2024-06-04 17:38:55 +08:00
dijunkun eaedcb8d06 Fix crash caused by the release of screen capturer 2024-06-04 16:27:34 +08:00
dijunkun e7e6380adc Start capturing screen when connection established 2024-06-03 23:48:53 +08:00
dijunkun 1f50483b50 Save settings into cache file 2024-06-03 17:02:20 +08:00
dijunkun 6f703c8267 Use OOP to refactor main function 2024-06-03 15:23:37 +08:00
dijunkun d150c374b5 Reset main window width/height ratio automatically when width/height is changed 2024-06-03 11:30:55 +08:00
dijunkun f29b2ee09d Test user date in peer instance and callback functions 2024-05-30 17:27:49 +08:00
dijunkun 0a934e8c01 Fix LNK1561 error on Winodws 2024-05-30 16:33:50 +08:00
dijunkun 2163aa87d4 The connection can use only one peer to realize server and client 2024-05-30 16:12:53 +08:00
dijunkun 5d8408d892 Use abstraction to refactor remote desk gui 2024-05-29 17:33:41 +08:00
dijunkun 93d0e3a5d0 Auto collapse menu bar when connection established 2024-05-28 17:37:06 +08:00
dijunkun b4a5e91bc9 Support fullscreen 2024-05-28 16:27:04 +08:00
dijunkun 759078ef7f 1.Use PingFang.ttc as Chinese default fonts on MacOS;2.Fix link error for FFmpeg 2024-05-28 15:25:16 +08:00
dijunkun 905539a6eb 1.Use Windows font file 'simhei.ttf'; 2.Add test button for fullscreen 2024-05-27 17:06:09 +08:00
dijunkun f1512812ad Support localization(Simplified Chinese[source-han-sans-regular]) 2024-05-24 17:15:44 +08:00
dijunkun 5f1cf89649 Fix crash during termination on windows 2024-05-24 15:48:37 +08:00
dijunkun f291ad189a 1.Remove sdl2 from thirdparty since it is already required by imgui; 2.Update imgui to v1.90.6; 3.Update spdlog to v 1.14.1 2024-05-24 15:10:58 +08:00
dijunkun 8807636372 Fix crash caused by screen capturer or mouse controller init failed on Linux and MacOS 2024-05-23 15:48:10 +08:00
dijunkun 70be1d8afc Update submodule projectx 2024-05-22 16:39:27 +08:00
dijunkun 1f76aa427d Change submodule projectx url 2024-05-22 16:35:30 +08:00
dijunkun 134cbf8b75 Restore ffmpeg dependency for Linux and MacOS due to screen capture needs ffmpeg on these platforms 2024-05-22 14:06:12 +08:00
dijunkun 669b944cfd Remove resampling process during SDL2 capture audio stream 2024-05-21 17:01:08 +08:00
dijunkun 9962829885 Fix ARGB to NV12 error caused by uv stride 2024-05-20 10:47:44 +08:00
dijunkun 1393615f01 Remove dependency on FFmpeg 2024-05-17 17:55:57 +08:00
dijunkun d58ae3a6b1 Fix AV1 codec on MacOS 2024-05-10 14:45:12 +08:00
dijunkun a188729af6 Support AV1 stream transmitting over RTP 2024-05-09 17:05:38 +08:00
dijunkun 422478bd9a Support AV1 codec 2024-04-19 17:37:00 +08:00
dijunkun d8980f0082 WGC screen capturer needs c++17 or above 2023-12-22 16:07:32 +08:00
dijunkun e88bb017fa 1.Using c++14; 2.Using {} to initialize std::atomic 2023-12-22 15:46:54 +08:00
dijunkun 87466d6074 Update thirdparty library 2023-12-22 14:14:08 +08:00
Di Junkun fbbbfc5e6a Update README_CN.md 2023-12-21 15:02:12 +08:00
Di Junkun d2cefd1827 Update README.md 2023-12-21 14:59:44 +08:00
Di Junkun a350e06529 Update README.md 2023-12-21 14:56:18 +08:00
Di Junkun 8c742ffa08 Update README.md 2023-12-21 14:34:11 +08:00
Di Junkun 475005b8a4 Update README.md 2023-12-20 15:54:54 +08:00
dijunkun 4da5188759 Update README.md 2023-12-20 15:19:44 +08:00
Di Junkun d8df4df5ae Update README.md 2023-12-20 15:17:53 +08:00
dijunkun fa05bbc8f8 Update README.md 2023-12-20 13:00:39 +08:00
Di Junkun 927f1a6d49 Update README.md 2023-12-20 09:34:43 +08:00
dijunkun 1d87f61d9f Update README.md 2023-12-19 17:33:16 +08:00
dijunkun ce546b77f5 Hide cursor when remote peer connected 2023-12-18 16:52:49 +08:00
dijunkun b9e69cde51 Remove unused variables 2023-12-18 16:17:55 +08:00
dijunkun e3987b4a42 Fix remote action type undefined error 2023-12-18 16:06:53 +08:00
dijunkun 0034359431 Update submodule 2023-12-18 15:27:11 +08:00
dijunkun cec275bbe0 Add 1 second time interval for retry join transmission 2023-12-18 15:10:41 +08:00
dijunkun fe68464cd2 Fix remote id hint error 2023-12-18 13:43:08 +08:00
dijunkun 181c473625 Use SDL to get screen resolution 2023-12-18 11:15:55 +08:00
dijunkun 2fc89923ae Use factory method to create screen capturer 2023-12-15 17:29:17 +08:00
dijunkun 9276d5bfec Fix compile error 2023-12-14 17:14:52 +08:00
dijunkun 95ef8fe8b9 Use factory method to create mouse controller on MacOS 2023-12-14 17:02:43 +08:00
dijunkun 3ab0e0136e Use factory method to create mouse controller on Windows 2023-12-14 16:40:10 +08:00
dijunkun daecc0d1e9 Use factory method to create mouse controller on Linux 2023-12-14 16:27:13 +08:00
dijunkun bfecf47226 Fix cross platform compile error 2023-12-13 17:32:02 +08:00
dijunkun 09c42dd7ed 1.Add linux mouse control test;2.Fix unused variables warnning 2023-12-13 17:26:08 +08:00
dijunkun a8a3b88514 Use uinput to control mouse and keyboard on Linux 2023-12-07 19:00:34 -08:00
dijunkun 2d6cfb5c76 Support cursor control on MacOS 2023-12-06 15:24:01 +08:00
dijunkun ed8b536ac0 Add signal connection status 'NoSuchTransmissionId' 2023-12-04 14:04:36 +08:00
dijunkun 5e2d27e9d2 Fix ffmpeg link error on MacOS 2023-12-04 11:20:30 +08:00
dijunkun 47a2dc85f9 Fix screen capture on MacOS 2023-12-01 17:16:38 +08:00
dijunkun 5febe99bc2 Support screen capture on MacOS 2023-12-01 16:54:17 +08:00
dijunkun 97bed80088 Fix link flag for MacOS 2023-12-01 10:12:06 +08:00
dijunkun 070f7bd21e Disable ffmpeg openh264 codec 2023-11-29 22:57:29 -08:00
dijunkun 4a65a59803 Enable audio transmission 2023-11-29 22:04:53 -08:00
dijunkun 733434f9b3 Switch rtc core to branch opus 2023-11-21 22:36:36 -08:00
dijunkun 7b7787f638 Add audio capture test 2023-11-21 22:32:06 -08:00
dijunkun b64d399967 Capture full screen and resize to 1280x720 for Linux platform 2023-11-20 23:11:21 -08:00
dijunkun 65f9862929 Enable password checking when login 2023-11-20 22:48:18 -08:00
dijunkun 3065c15631 Save password in cache 2023-11-20 22:24:27 -08:00
dijunkun e28de1fbda Change folder name 2023-11-19 23:41:58 -08:00
dijunkun e802306148 Fix compile error 2023-11-19 23:30:41 -08:00
dijunkun 4a16857da8 Support generate makefile 2023-11-17 00:38:13 -08:00
dijunkun 6776b915da Do not refresh display frame if disconnected 2023-11-16 00:38:29 -08:00
dijunkun 311b94492a Fix received_frame flag error in display client 2023-11-16 00:32:52 -08:00
dijunkun be659f8e49 Fix display error on Linux 2023-11-16 00:27:45 -08:00
dijunkun 375d849786 Add library OpenFEC v1.4.2 2023-11-09 01:00:39 -08:00
dijunkun b347b160e2 Fix x11 screen capture memory leakage 2023-11-08 01:20:02 -08:00
dijunkun 31e5d5025a OpenH264 supports Windows platform 2023-11-07 15:27:57 +08:00
dijunkun 61b2eb2fdb Fix openh264 decode error caused by yuv stride 2023-11-06 19:02:39 -08:00
dijunkun a64655dec9 Implementation for openh264 codec 2023-11-03 02:31:57 -07:00
dijunkun 3399d43501 1.ImGUI display success; 2.To do: fix x264 encode green screen 2023-11-02 02:34:14 -07:00
dijunkun 5fb35ecd77 Fix ffmpeg link error on Linux platform 2023-11-01 21:42:35 -07:00
dijunkun 7a28cab427 Update x11 capture module 2023-10-31 02:35:53 -07:00
dijunkun a114ffdb36 Update linux capture module 2023-10-30 02:33:39 -07:00
dijunkun f766330039 Nice connection supports MacOSx 2023-10-16 13:56:21 +08:00
dijunkun 6b8e33b83c Add callback for connection status 2023-10-11 17:01:14 +08:00
dijunkun 9c16a24867 Not control mouse in DEBUG mode 2023-10-11 16:17:13 +08:00
dijunkun c5f2f6cf82 Add feature password 2023-10-11 16:03:22 +08:00
dijunkun 8064130356 Fix remote id cannot modify error 2023-10-11 15:20:53 +08:00
dijunkun 60c3390203 Fix default display resolution to 720p and change resize strategy 2023-10-11 14:58:04 +08:00
dijunkun f246ab8720 Fix signal server member list error when rejoin same one connection 2023-10-11 14:26:57 +08:00
dijunkun b887fcbf86 Fix ice status check error 2023-10-11 09:45:58 +08:00
dijunkun 7216d318b4 Fix crash during rejoin connection 2023-10-10 17:09:24 +08:00
dijunkun cb842276e8 Add password for connection 2023-10-10 16:21:04 +08:00
dijunkun 1acd613b45 Fix windows compile error 2023-10-10 11:05:15 +08:00
dijunkun 0bfe3bdfd0 Fix MacOSX compile error 2023-10-10 10:59:36 +08:00
dijunkun 610f89a828 Finish remote desk gui 2023-10-10 10:31:32 +08:00
dijunkun 82ef2a161d Combine server and client into a single program 2023-10-09 17:31:55 +08:00
dijunkun 32c8048430 Add ID input gui 2023-10-09 16:31:47 +08:00
dijunkun cb4648ce72 Fix mouse control 2023-10-09 15:05:10 +08:00
dijunkun ea2f5d319d Eable leave connection 2023-10-09 14:11:29 +08:00
dijunkun 45ccbe1637 Add main menu using imgui 2023-10-08 17:39:28 +08:00
dijunkun 0f2f984286 Use imgui 2023-10-08 16:33:53 +08:00
dijunkun 72d669f8bc Remove dependent for vcpkg::sdl2 2023-10-07 17:33:18 +08:00
dijunkun c2b69a0cf2 Fix cursor map error after resize client window 2023-10-07 15:13:24 +08:00
dijunkun 89fa82b165 Fix cursor position error 2023-10-07 15:12:09 +08:00
dijunkun c5f90e1aee Fix error caused by type 'long' has difference size in difference platforms 2023-10-07 14:43:33 +08:00
dijunkun 7618e4bab9 Fix MacOS compile error 2023-10-07 10:07:45 +08:00
dijunkun 1802453dbb Add -ldl link flag for Linux platform 2023-09-22 15:50:40 +08:00
dijunkun 67e7f2e82b Fix compile compatibility 2023-09-22 14:50:37 +08:00
dijunkun 287b7dbc94 Remote desk client supports Linux platform 2023-09-22 14:48:21 +08:00
dijunkun d20fee4a64 Remote desk client supports MacOS 2023-09-19 17:06:00 +08:00
dijunkun 297410b679 Fix data parse error 2023-09-14 16:32:22 +08:00
dijunkun 1f08c80aab Implementation for user data sending 2023-09-13 17:31:02 +08:00
dijunkun 238eef1c93 Implementation for jitter 2023-09-08 17:45:01 +08:00
dijunkun bde35e3b1c Combine Fu-A subframes into complete h264 frame 2023-09-08 16:09:23 +08:00
dijunkun 955182f5a0 Nalu slices test pass 2023-09-07 15:46:26 +08:00
dijunkun b1180f1e93 1.Implementation for rtp session module; 2.Separate signal server from main project 2023-09-06 11:29:34 +08:00
dijunkun d3e9df260a Use one thread to process render and mouse/key events 2023-09-02 00:20:55 +08:00
dijunkun 2088bf190c Use vcpkg static ffmpeg lib for windows 2023-09-01 21:34:08 +08:00
dijunkun 7dd304b686 Fix crash caused by remote desk client leaves 2023-09-01 18:08:56 +08:00
dijunkun c65e6b7af2 Fix kcp transmission error 2023-08-31 17:49:08 +08:00
dijunkun 72d4982f54 Use kcp as QoS module 2023-08-30 17:44:22 +08:00
dijunkun 1e90d99980 Fix sdl2 resize window 2023-08-30 10:02:58 +08:00
dijunkun a2000ddcd6 Use SDL2 to display BGRA frame 2023-08-30 00:29:08 +08:00
dijunkun ae67ad961e Use sdl2 to display capture screen 2023-08-29 17:33:58 +08:00
dijunkun 76a80e6d07 Remove files 2023-08-29 00:21:33 +08:00
dijunkun d4b1ac1fb8 wgc dll test pass 2023-08-28 17:19:46 +08:00
dijunkun e970bdc929 Add wgc demo 2023-08-28 00:53:55 +08:00
dijunkun 2b5c0ee533 Add application folder 2023-08-24 17:36:28 +08:00
689 changed files with 91633 additions and 98124 deletions
+3
View File
@@ -0,0 +1,3 @@
*.h linguist-language=C++
*.cpp linguist-language=C++
*.lua linguist-language=Xmake
+35
View File
@@ -0,0 +1,35 @@
---
name: 问题反馈
about: 请在此提交问题报告,以便持续优化产品。
title: ''
labels: bug
assignees: kunkundi
---
**描述问题**
清晰简洁地描述遇到的错误。
**复现步骤**
复现该问题的步骤:
1. 前往 '...'
2. 点击 '....'
3. 出现错误
**预期行为**
清晰简洁地描述你期望发生的行为。
**截图**
如果适用,请添加截图以帮助说明问题。
**桌面端信息(请填写以下内容):**
- 操作系统: [例如 Windows 11]
- 版本: [例如 v1.1.10]
**移动端信息(请填写以下内容):**
- 设备: [例如 iPhone 17]
- 操作系统: [例如 iOS 26.1]
- 浏览器: [例如 系统浏览器、Safari]
**补充信息**
在此添加与问题相关的其他上下文内容。
+28
View File
@@ -0,0 +1,28 @@
---
name: 需求建议
about: 请在此提交功能需求或改进建议,以便后续迭代参考。
title: ''
labels: enhancement
assignees: kunkundi
---
**功能/改进建议描述**
清晰简洁地描述希望新增的功能或改进的内容。
**使用场景 / 背景**
说明该功能或改进的使用场景,以及解决后带来的价值。
**预期效果**
描述你认为最理想的功能表现或改进效果。
**参考示例(可选)**
提供类似功能截图、参考链接或其他说明,帮助更好理解需求。
**优先级(可选)**
- [ ]
- [ ]
- [ ]
**补充信息(可选)**
其他相关信息或特殊要求。
+397
View File
@@ -0,0 +1,397 @@
name: Build and Release
on:
push:
branches:
- "**"
tags:
- "*"
workflow_dispatch:
permissions:
contents: write
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
build-linux:
name: Build Linux (${{ matrix.arch }})
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- arch: amd64
runner: ubuntu-22.04
image: crossdesk/ubuntu20.04:latest
package_script: ./scripts/linux/pkg_amd64.sh
- arch: arm64
runner: ubuntu-22.04-arm
image: crossdesk/ubuntu20.04-arm64v8:latest
package_script: ./scripts/linux/pkg_arm64.sh
container:
image: ${{ matrix.image }}
options: --user root
steps:
- name: Extract version number
run: |
VERSION="${GITHUB_REF##*/}"
VERSION_NUM="${VERSION#v}"
echo "VERSION_NUM=${VERSION_NUM}" >> $GITHUB_ENV
- name: Set legal Debian version
shell: bash
run: |
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
BUILD_DATE=$(TZ=Asia/Shanghai date +%Y%m%d)
if [[ ! "${VERSION_NUM}" =~ ^[0-9] ]]; then
LEGAL_VERSION="v0.0.0-${VERSION_NUM}-${BUILD_DATE}-${SHORT_SHA}"
else
LEGAL_VERSION="v${VERSION_NUM}-${BUILD_DATE}-${SHORT_SHA}"
fi
echo "LEGAL_VERSION=${LEGAL_VERSION}" >> $GITHUB_ENV
echo "BUILD_DATE=${BUILD_DATE}" >> $GITHUB_ENV
- name: Checkout code
uses: actions/checkout@v5
with:
submodules: recursive
- name: Build CrossDesk
env:
CUDA_PATH: /usr/local/cuda
XMAKE_GLOBALDIR: /data
run: |
xmake f --CROSSDESK_VERSION=${LEGAL_VERSION} --USE_CUDA=true --root -y
xmake b -vy --root crossdesk
- name: Package
run: |
chmod +x ${{ matrix.package_script }}
${{ matrix.package_script }} ${LEGAL_VERSION}
- name: Upload artifact
uses: actions/upload-artifact@v6
with:
name: crossdesk-linux-${{ matrix.arch }}-${{ env.LEGAL_VERSION }}
path: ${{ github.workspace }}/crossdesk-linux-${{ matrix.arch }}-${{ env.LEGAL_VERSION }}.deb
# macOS
build-macos:
name: Build on macOS
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- arch: x64
runner: macos-15-intel
cache-key: intel
out-dir: ./build/macosx/x86_64/release/crossdesk
package_script: ./scripts/macosx/pkg_x64.sh
- arch: arm64
runner: macos-14
cache-key: arm
out-dir: ./build/macosx/arm64/release/crossdesk
package_script: ./scripts/macosx/pkg_arm64.sh
steps:
- name: Extract version number
id: version
run: |
VERSION="${GITHUB_REF##*/}"
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
BUILD_DATE=$(TZ=Asia/Shanghai date +%Y%m%d)
VERSION_NUM="v${VERSION#v}-${BUILD_DATE}-${SHORT_SHA}"
echo "VERSION_NUM=${VERSION_NUM}" >> $GITHUB_ENV
echo "VERSION_NUM=${VERSION_NUM}"
echo "BUILD_DATE=${BUILD_DATE}" >> $GITHUB_ENV
- name: Cache xmake dependencies
uses: actions/cache@v5
with:
path: ~/.xmake/packages
key: "${{ runner.os }}-xmake-deps-${{ matrix.cache-key }}-${{ github.run_id }}"
restore-keys: |
${{ runner.os }}-xmake-deps-${{ matrix.cache-key }}-
- name: Install xmake
run: brew install xmake
- name: Checkout code
uses: actions/checkout@v5
- name: Initialize submodules
run: git submodule update --init --recursive
- name: Build CrossDesk
run: |
xmake f --CROSSDESK_VERSION=${VERSION_NUM} --USE_CUDA=true -y
xmake b -vy crossdesk
- name: Package CrossDesk app
run: |
chmod +x ${{ matrix.package_script }}
${{ matrix.package_script }} ${VERSION_NUM}
- name: Upload build artifacts
uses: actions/upload-artifact@v6
with:
name: crossdesk-macos-${{ matrix.arch }}-${{ env.VERSION_NUM }}
path: crossdesk-macos-${{ matrix.arch }}-${{ env.VERSION_NUM }}.pkg
- name: Move files to release dir
run: |
mkdir -p release
cp crossdesk-macos-${{ matrix.arch }}-${{ env.VERSION_NUM }}.pkg release/
# Windows
build-windows-x64:
name: Build on Windows x64
runs-on: windows-2022
env:
XMAKE_GLOBALDIR: D:\xmake_global
steps:
- name: Extract version number
shell: pwsh
run: |
$ref = $env:GITHUB_REF
$version = $ref -replace '^refs/(tags|heads)/', ''
$version = $version -replace '^v', ''
$version = $version -replace '/', '-'
$SHORT_SHA = $env:GITHUB_SHA.Substring(0,7)
$BUILD_DATE = ([System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId((Get-Date), "China Standard Time")).ToString("yyyyMMdd")
echo "VERSION_NUM=v$version-$BUILD_DATE-$SHORT_SHA" >> $env:GITHUB_ENV
echo "BUILD_DATE=$BUILD_DATE" >> $env:GITHUB_ENV
- name: Cache xmake dependencies
uses: actions/cache@v5
with:
path: D:\xmake_global\.xmake\packages
key: "${{ runner.os }}-xmake-deps-intel-${{ github.run_id }}"
restore-keys: |
${{ runner.os }}-xmake-deps-intel-
- name: Install xmake
run: |
Invoke-Expression (Invoke-Webrequest 'https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.ps1' -UseBasicParsing).Content
echo "C:\Users\runneradmin\xmake" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
xmake create cuda
Set-Location cuda
xmake g --theme=plain
$cudaPath = ""
$packagesPath = "D:\xmake_global\.xmake\packages"
if (Test-Path $packagesPath) {
Write-Host "Packages directory exists: $packagesPath"
try {
$info = xmake require --info "cuda 12.6.3" 2>$null
if ($null -ne $info -and $info -ne "") {
$cudaPath = (($info | Select-String installdir).ToString() -replace '.*installdir:\s*','').Trim()
}
} catch {}
} else {
Write-Host "Packages directory not found: $packagesPath"
Write-Host "Installing CUDA package..."
xmake require -vy "cuda 12.6.3"
$info = xmake require --info "cuda 12.6.3"
$cudaPath = (($info | Select-String installdir).ToString() -replace '.*installdir:\s*','').Trim()
}
echo "CUDA_PATH=$cudaPath" >> $env:GITHUB_ENV
Write-Host "Resolved CUDA_PATH = $cudaPath"
Pop-Location
- name: Download INetC plugin
shell: powershell
run: |
$url = "https://github.com/DigitalMediaServer/NSIS-INetC-plugin/releases/download/v1.0.5.7/InetC.zip"
$out = "$env:RUNNER_TEMP\InetC.zip"
Invoke-WebRequest -Uri $url -OutFile $out
Expand-Archive $out -DestinationPath "$env:RUNNER_TEMP\InetC" -Force
$source = "$env:RUNNER_TEMP\InetC\x86-unicode\INetC.dll"
$target = "C:\Program Files (x86)\NSIS\Plugins\x86-unicode\INetC.dll"
Write-Host "Copying $source to $target"
Copy-Item $source $target -Force
- name: Checkout code
uses: actions/checkout@v5
- name: Initialize submodules
run: git submodule update --init --recursive
- name: Copy nsProcess plugin to NSIS folder
run: |
$nsisPluginDir = "C:\Program Files (x86)\NSIS\Plugins\x86-unicode"
copy "${{ github.workspace }}\scripts\windows\nsProcess.dll" $nsisPluginDir
- name: Build CrossDesk
run: |
xmake f --CROSSDESK_VERSION=${{ env.VERSION_NUM }} --USE_CUDA=true -y
xmake b -vy crossdesk
- name: Package
shell: pwsh
run: |
cd "${{ github.workspace }}\scripts\windows"
makensis /DVERSION=$env:VERSION_NUM nsis_script.nsi
- name: Package Portable
shell: pwsh
run: |
$portableDir = "${{ github.workspace }}\portable"
New-Item -ItemType Directory -Force -Path $portableDir
Copy-Item "${{ github.workspace }}\build\windows\x64\release\crossdesk.exe" "$portableDir\CrossDesk.exe"
Copy-Item "${{ github.workspace }}\build\windows\x64\release\*.dll" $portableDir -Force
Compress-Archive -Path "$portableDir\*" -DestinationPath "${{ github.workspace }}\crossdesk-win-x64-portable-${{ env.VERSION_NUM }}.zip"
- name: Upload artifact
uses: actions/upload-artifact@v6
with:
name: crossdesk-win-x64-${{ env.VERSION_NUM }}
path: ${{ github.workspace }}/scripts/windows/crossdesk-win-x64-${{ env.VERSION_NUM }}.exe
- name: Upload portable artifact
uses: actions/upload-artifact@v6
with:
name: crossdesk-win-x64-portable-${{ env.VERSION_NUM }}
path: ${{ github.workspace }}/crossdesk-win-x64-portable-${{ env.VERSION_NUM }}.zip
release:
name: Publish Release
if: startsWith(github.ref, 'refs/tags/v')
needs:
[build-linux, build-macos, build-windows-x64]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Download all artifacts
uses: actions/download-artifact@v8
with:
path: artifacts
- name: Extract version number
id: version
run: |
VERSION="${GITHUB_REF##*/}"
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
BUILD_DATE=$(TZ=Asia/Shanghai date +%Y%m%d)
BUILD_DATE_ISO=$(TZ=Asia/Shanghai date +%Y-%m-%d)
VERSION_NUM="${VERSION#v}-${BUILD_DATE}-${SHORT_SHA}"
VERSION_WITH_V="v${VERSION_NUM}"
VERSION_ONLY="${VERSION#v}"
echo "VERSION_NUM=${VERSION_NUM}" >> $GITHUB_OUTPUT
echo "VERSION_WITH_V=${VERSION_WITH_V}" >> $GITHUB_OUTPUT
echo "VERSION_ONLY=${VERSION_ONLY}" >> $GITHUB_OUTPUT
echo "BUILD_DATE=${BUILD_DATE}" >> $GITHUB_OUTPUT
echo "BUILD_DATE_ISO=${BUILD_DATE_ISO}" >> $GITHUB_OUTPUT
- name: Rename artifacts
run: |
mkdir -p release
cp artifacts/crossdesk-macos-x64-${{ steps.version.outputs.VERSION_WITH_V }}/* release/crossdesk-macos-x64-${{ steps.version.outputs.VERSION_WITH_V }}.pkg
cp artifacts/crossdesk-macos-arm64-${{ steps.version.outputs.VERSION_WITH_V }}/* release/crossdesk-macos-arm64-${{ steps.version.outputs.VERSION_WITH_V }}.pkg
cp artifacts/crossdesk-linux-amd64-${{ steps.version.outputs.VERSION_WITH_V }}/* release/crossdesk-linux-amd64-${{ steps.version.outputs.VERSION_WITH_V }}.deb
cp artifacts/crossdesk-linux-arm64-${{ steps.version.outputs.VERSION_WITH_V }}/* release/crossdesk-linux-arm64-${{ steps.version.outputs.VERSION_WITH_V }}.deb
cp artifacts/crossdesk-win-x64-${{ steps.version.outputs.VERSION_WITH_V }}/* release/crossdesk-win-x64-${{ steps.version.outputs.VERSION_WITH_V }}.exe
cp artifacts/crossdesk-win-x64-portable-${{ steps.version.outputs.VERSION_WITH_V }}/* release/crossdesk-win-x64-portable-${{ steps.version.outputs.VERSION_WITH_V }}.zip
- name: List release files
run: ls -lh release/
- name: Upload to Versioned GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.version.outputs.VERSION_WITH_V }}
name: Release ${{ steps.version.outputs.VERSION_WITH_V }}
draft: false
prerelease: false
files: release/*
generate_release_notes: false
body: |
Binary release only. Source code is not included.
- name: Create or update 'latest' tag
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -f latest
git push origin latest --force
- name: Upload to GitHub Release (latest)
uses: softprops/action-gh-release@v2
with:
tag_name: latest
name: Latest Release
draft: false
prerelease: false
files: release/*
generate_release_notes: false
- name: Upload artifacts to server
uses: burnett01/rsync-deployments@5.2
with:
switches: -avzr --progress --delete
path: release/*
remote_path: /var/www/html/downloads/
remote_host: ${{ secrets.SERVER_HOST }}
remote_user: ${{ secrets.SERVER_USER }}
remote_key: ${{ secrets.SERVER_KEY }}
- name: Generate version.json
run: |
cat > version.json << EOF
{
"version": "${{ steps.version.outputs.VERSION_ONLY }}",
"releaseDate": "${{ steps.version.outputs.BUILD_DATE_ISO }}",
"releaseName": "",
"releaseNotes": "",
"tagName": "${{ steps.version.outputs.VERSION_WITH_V }}",
"downloads": {
"windows-x64": {
"url": "https://downloads.crossdesk.cn/crossdesk-win-x64-${{ steps.version.outputs.VERSION_WITH_V }}.exe",
"filename": "crossdesk-win-x64-${{ steps.version.outputs.VERSION_WITH_V }}.exe"
},
"windows-x64-portable": {
"url": "https://downloads.crossdesk.cn/crossdesk-win-x64-portable-${{ steps.version.outputs.VERSION_WITH_V }}.zip",
"filename": "crossdesk-win-x64-portable-${{ steps.version.outputs.VERSION_WITH_V }}.zip"
},
"macos-x64": {
"url": "https://downloads.crossdesk.cn/crossdesk-macos-x64-${{ steps.version.outputs.VERSION_WITH_V }}.pkg",
"filename": "crossdesk-macos-x64-${{ steps.version.outputs.VERSION_WITH_V }}.pkg"
},
"macos-arm64": {
"url": "https://downloads.crossdesk.cn/crossdesk-macos-arm64-${{ steps.version.outputs.VERSION_WITH_V }}.pkg",
"filename": "crossdesk-macos-arm64-${{ steps.version.outputs.VERSION_WITH_V }}.pkg"
},
"linux-amd64": {
"url": "https://downloads.crossdesk.cn/crossdesk-linux-amd64-${{ steps.version.outputs.VERSION_WITH_V }}.deb",
"filename": "crossdesk-linux-amd64-${{ steps.version.outputs.VERSION_WITH_V }}.deb"
},
"linux-arm64": {
"url": "https://downloads.crossdesk.cn/crossdesk-linux-arm64-${{ steps.version.outputs.VERSION_WITH_V }}.deb",
"filename": "crossdesk-linux-arm64-${{ steps.version.outputs.VERSION_WITH_V }}.deb"
}
}
}
EOF
cat version.json
- name: Upload version.json to server
uses: burnett01/rsync-deployments@5.2
with:
switches: -avzr --delete
path: version.json
remote_path: /var/www/html/version/
remote_host: ${{ secrets.SERVER_HOST }}
remote_user: ${{ secrets.SERVER_USER }}
remote_key: ${{ secrets.SERVER_KEY }}
+80
View File
@@ -0,0 +1,80 @@
name: Close Inactive Issues
on:
schedule:
# run every day at midnight
- cron: "0 0 * * *"
permissions:
issues: write
pull-requests: write
contents: read
jobs:
close_inactive_issues:
runs-on: ubuntu-latest
steps:
- name: Check inactive issues and close them
uses: actions/github-script@v6
with:
script: |
const { data: issues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 100,
});
const now = new Date().getTime();
const inactivePeriod = 7 * 24 * 60 * 60 * 1000; // 7 days
for (const issue of issues) {
// skip pull requests (they are also returned by listForRepo)
if (issue.pull_request) continue;
// skip labeled issues
if (issue.labels.length > 0) {
console.log(`Skipping issue #${issue.number} (Has labels).`);
continue;
}
// fetch comments for this issue
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
per_page: 100,
});
// determine the "last activity" time
let lastActivityTime;
if (comments.length > 0) {
const lastComment = comments[comments.length - 1];
lastActivityTime = new Date(lastComment.updated_at).getTime();
} else {
lastActivityTime = new Date(issue.created_at).getTime();
}
// check inactivity
if (now - lastActivityTime > inactivePeriod) {
console.log(`Closing inactive issue: #${issue.number} (No recent replies for 7 days)`);
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: "This issue has been automatically closed due to inactivity for 7 days."
});
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed',
});
} else {
console.log(`Skipping issue #${issue.number} (Active within 7 days).`);
}
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+144
View File
@@ -0,0 +1,144 @@
name: Update version.json from Release
on:
release:
types: [published, edited]
permissions:
contents: write
jobs:
update-version-json:
name: Update version.json with release information
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Extract version from tag
id: version
run: |
TAG_NAME="${{ github.event.release.tag_name }}"
VERSION_ONLY="${TAG_NAME#v}"
echo "TAG_NAME=${TAG_NAME}" >> $GITHUB_OUTPUT
echo "VERSION_ONLY=${VERSION_ONLY}" >> $GITHUB_OUTPUT
# Extract date from tag if available (format: v1.2.3-20251113-abc)
if [[ "${TAG_NAME}" =~ -([0-9]{8})- ]]; then
DATE_STR="${BASH_REMATCH[1]}"
BUILD_DATE_ISO="${DATE_STR:0:4}-${DATE_STR:4:2}-${DATE_STR:6:2}"
else
# Use release published date
BUILD_DATE_ISO=$(echo "${{ github.event.release.published_at }}" | cut -d'T' -f1)
fi
echo "BUILD_DATE_ISO=${BUILD_DATE_ISO}" >> $GITHUB_OUTPUT
- name: Install jq
run: sudo apt-get update && sudo apt-get install -y jq
- name: Get release information
id: release_info
run: |
# Use jq to properly escape JSON
RELEASE_BODY="${{ github.event.release.body }}"
RELEASE_NAME="${{ github.event.release.name }}"
# Handle empty values
if [ -z "$RELEASE_BODY" ]; then
RELEASE_BODY=""
fi
if [ -z "$RELEASE_NAME" ]; then
RELEASE_NAME=""
fi
# Save to temporary files for proper handling
echo -n "$RELEASE_BODY" > /tmp/release_body.txt
echo -n "$RELEASE_NAME" > /tmp/release_name.txt
# Use jq to escape JSON strings
RELEASE_BODY_JSON=$(jq -Rs . < /tmp/release_body.txt)
RELEASE_NAME_JSON=$(jq -Rs . < /tmp/release_name.txt)
echo "RELEASE_BODY=${RELEASE_BODY_JSON}" >> $GITHUB_OUTPUT
echo "RELEASE_NAME=${RELEASE_NAME_JSON}" >> $GITHUB_OUTPUT
- name: Download current version.json from server
id: download_version
continue-on-error: true
run: |
# Try to download current version.json from server
curl -f -s "https://version.crossdesk.cn/version.json" -o version.json || echo "Failed to download, will create new one"
- name: Generate or update version.json
run: |
# If version.json exists, try to preserve downloads section
if [ -f version.json ] && jq -e '.downloads' version.json > /dev/null 2>&1; then
EXISTING_DOWNLOADS=$(jq -c '.downloads' version.json)
if [ "$EXISTING_DOWNLOADS" != "null" ] && [ "$EXISTING_DOWNLOADS" != "{}" ]; then
DOWNLOADS_JSON="$EXISTING_DOWNLOADS"
else
DOWNLOADS_JSON=""
fi
else
DOWNLOADS_JSON=""
fi
# If downloads is empty, use default structure
if [ -z "$DOWNLOADS_JSON" ]; then
DOWNLOADS_JSON=$(cat << DOWNLOADS_EOF
{
"windows-x64": {
"url": "https://downloads.crossdesk.cn/crossdesk-win-x64-${{ steps.version.outputs.TAG_NAME }}.exe",
"filename": "crossdesk-win-x64-${{ steps.version.outputs.TAG_NAME }}.exe"
},
"windows-x64-portable": {
"url": "https://downloads.crossdesk.cn/crossdesk-win-x64-portable-${{ steps.version.outputs.TAG_NAME }}.zip",
"filename": "crossdesk-win-x64-portable-${{ steps.version.outputs.TAG_NAME }}.zip"
},
"macos-x64": {
"url": "https://downloads.crossdesk.cn/crossdesk-macos-x64-${{ steps.version.outputs.TAG_NAME }}.pkg",
"filename": "crossdesk-macos-x64-${{ steps.version.outputs.TAG_NAME }}.pkg"
},
"macos-arm64": {
"url": "https://downloads.crossdesk.cn/crossdesk-macos-arm64-${{ steps.version.outputs.TAG_NAME }}.pkg",
"filename": "crossdesk-macos-arm64-${{ steps.version.outputs.TAG_NAME }}.pkg"
},
"linux-amd64": {
"url": "https://downloads.crossdesk.cn/crossdesk-linux-amd64-${{ steps.version.outputs.TAG_NAME }}.deb",
"filename": "crossdesk-linux-amd64-${{ steps.version.outputs.TAG_NAME }}.deb"
},
"linux-arm64": {
"url": "https://downloads.crossdesk.cn/crossdesk-linux-arm64-${{ steps.version.outputs.TAG_NAME }}.deb",
"filename": "crossdesk-linux-arm64-${{ steps.version.outputs.TAG_NAME }}.deb"
}
}
DOWNLOADS_EOF
)
fi
# Generate version.json using cat and heredoc
cat > version.json << EOF
{
"version": "${{ steps.version.outputs.VERSION_ONLY }}",
"releaseDate": "${{ steps.version.outputs.BUILD_DATE_ISO }}",
"releaseName": ${{ steps.release_info.outputs.RELEASE_NAME }},
"releaseNotes": ${{ steps.release_info.outputs.RELEASE_BODY }},
"tagName": "${{ steps.version.outputs.TAG_NAME }}",
"downloads": ${DOWNLOADS_JSON}
}
EOF
cat version.json
- name: Upload version.json to server
uses: burnett01/rsync-deployments@5.2
with:
switches: -avzr --delete
path: version.json
remote_path: /var/www/html/version/
remote_host: ${{ secrets.SERVER_HOST }}
remote_user: ${{ secrets.SERVER_USER }}
remote_key: ${{ secrets.SERVER_KEY }}
-3
View File
@@ -1,12 +1,9 @@
# Xmake cache
.xmake/
build/
thirdparty/ffmpeg/lib/*
.VSCodeCounter/
# MacOS Cache
.DS_Store
# VSCode cache
.vscode
projectx.code-workspace
+3
View File
@@ -0,0 +1,3 @@
[submodule "submodules/minirtc"]
path = submodules/minirtc
url = https://github.com/kunkundi/minirtc.git
+165
View File
@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
+254 -24
View File
@@ -1,34 +1,264 @@
# projectx
# CrossDesk
vcpkg/buildtrees/versioning_/versions/pcre/69e232f12c4e3eab4115f0672466a6661978bea2$ vim portfile.cmake
<a href="https://hellogithub.com/repository/kunkundi/crossdesk" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=55d41367570345f1838e02fd12be7961&claim_uid=cb0OpZRrBuGVAfL&theme=small" alt="FeaturedHelloGitHub" /></a>
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-brightgreen.svg)]()
[![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0)
[![GitHub last commit](https://img.shields.io/github/last-commit/kunkundi/crossdesk)](https://github.com/kunkundi/crossdesk/commits/web-client)
[![Build Status](https://github.com/kunkundi/crossdesk/actions/workflows/build.yml/badge.svg)](https://github.com/kunkundi/crossdesk/actions)
[![Docker Pulls](https://img.shields.io/docker/pulls/crossdesk/crossdesk-server)](https://hub.docker.com/r/crossdesk/crossdesk-server/tags)
[![GitHub issues](https://img.shields.io/github/issues/kunkundi/crossdesk.svg)]()
[![GitHub stars](https://img.shields.io/github/stars/kunkundi/crossdesk.svg?style=social)]()
[![GitHub forks](https://img.shields.io/github/forks/kunkundi/crossdesk.svg?style=social)]()
- URLS "https://ftp.pcre.org/pub/pcre/pcre-${PCRE_VERSION}.zip"
+ URLS "https://sourceforge.net/projects/pcre/files/pcre/${PCRE_VERSION}/pcre-${PCRE_VERSION}.zip"
[ [English](README_EN.md) / 中文 ]
linux
PC 客户端
![sup_example](https://github.com/user-attachments/assets/eeb64fbe-1f07-4626-be1c-b77396beb905)
sudo apt-get install nvidia-cuda-toolkit
solve <cuda.h>
Web 客户端
<p align="center">
<img width="850" height="550" alt="6bddcbed47ffd4b9988a4037c7f4f524" src="https://github.com/user-attachments/assets/e44f73f9-24ac-46a3-a189-b7f8b6669881" />
</p>
sudo apt-get install libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-xfixes0-dev libxv-dev
solve x11
## 简介
sudo apt-get -y install libasound2-dev libsndio-dev libxcb-shm0-dev
solve asound sndio xcb-shm
CrossDesk 是一个轻量级的跨平台远程桌面软件,支持 Web 端控制远程设备。
sudo apt-get -y install libasound2-dev libpulse-dev && rebuild
solve error dsp no such audio device
CrossDesk 是 [MiniRTC](https://github.com/kunkundi/minirtc.git) 实时音视频传输库的实验性应用。MiniRTC 是一个轻量级的跨平台实时音视频传输库。它具有网络透传([RFC5245](https://datatracker.ietf.org/doc/html/rfc5245)),视频软硬编解码(H264/AV1),音频编解码([Opus](https://github.com/xiph/opus)),信令交互,网络拥塞控制,传输加密([SRTP](https://tools.ietf.org/html/rfc3711))等基础能力。
sudo apt-get install libavcodec-dev libavformat-dev libavutil-dev libavfilter-dev libavdevice-dev
## 系统要求
sudo apt remove libssl-dev libglib2.0-dev
| 平台 | 最低版本 |
|----------------|---------------------------|
| **Windows** | Windows 10 及以上 (64 位) |
| **macOS** | macOS Intel 15.0 及以上 ( 大于 14.0 小于 15.0 的版本可自行编译实现兼容 )<br> macOS Apple Silicon 14.0 及以上 |
| **Linux** | Ubuntu 22.04 及以上 ( 低版本可自行编译实现兼容 ) |
install:
@echo hello world
install -D build/linux/x86_64/release/remote_desk -t /usr/bin
install -D config/config.ini -t /usr/bin
install -D build/linux/x86_64/release/libprojectx.so -t /usr/lib
install -D thirdparty/nvcodec/Lib/x64/libnvidia-encode.so.1 -t /usr/lib
install -D thirdparty/nvcodec/Lib/x64/libnvidia-encode.so -t /usr/lib
install -D thirdparty/nvcodec/Lib/x64/libnvcuvid.so.1 -t /usr/lib
install -D thirdparty/nvcodec/Lib/x64/libnvcuvid.so -t /usr/lib
## 使用
在菜单栏“对端ID”处输入远端桌面的ID,点击“→”即可发起远程连接。
![usage1](https://github.com/user-attachments/assets/3a4bb59f-c84c-44d2-9a20-11790aac510e)
如果远端桌面设置了连接密码,则本端需填写正确的连接密码才能成功发起远程连接。
![password](https://github.com/user-attachments/assets/1beadcce-640d-4f5c-8e77-51917b5294d5)
发起连接前,可在设置中自定义配置项,如语言、视频编码格式等。
![settings](https://github.com/user-attachments/assets/8bc5468d-7bbb-4e30-95bd-da1f352ac08c)
### Web 客户端
浏览器访问 [CrossDesk Web Client](https://web.crossdesk.cn/)。
输入 **远程设备 ID****密码**,点击连接即可接入远程设备。如图,**iOS Safari 远程控制 Win11**
<img width="645" height="300" alt="_cgi-bin_mmwebwx-bin_webwxgetmsgimg__ MsgID=932911462648581698 skey=@crypt_1f5153b1_b550ca7462b5009ce03c991cca2a92a7 mmweb_appid=wx_webfilehelper" src="https://github.com/user-attachments/assets/a5109e6f-752c-4654-9f4e-7e161bddf43e" />
## 如何编译
依赖:
- [xmake](https://xmake.io/#/guide/installation)
- [cmake](https://cmake.org/download/)
Linux环境下需安装以下包:
```
sudo apt-get install -y software-properties-common git curl unzip build-essential libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-xfixes0-dev libxfixes-dev libxv-dev libxtst-dev libasound2-dev libsndio-dev libxcb-shm0-dev libasound2-dev libpulse-dev
```
编译
```
git clone https://github.com/kunkundi/crossdesk.git
cd crossdesk
git submodule init
git submodule update
xmake b -vy crossdesk
```
编译选项
```
--USE_CUDA=true/false: 启用 CUDA 硬件编解码,默认不启用
--CROSSDESK_VERSION=xxx: 指定 CrossDesk 的版本
# 示例
xmake f --CROSSDESK_VERSION=1.0.0 --USE_CUDA=true
```
运行
```
xmake r crossdesk
```
### 无 CUDA 环境下的开发支持
对于**未安装 CUDA 环境的 Linux 开发者,如果希望编译后的成果物拥有硬件编解码能力**,这里提供了预配置的 [Ubuntu 22.04 Docker 镜像](https://hub.docker.com/r/crossdesk/ubuntu22.04)。该镜像内置必要的构建依赖,可在容器中开箱即用,无需额外配置即可直接编译项目。
进入容器,下载工程后执行:
```
export CUDA_PATH=/usr/local/cuda
export XMAKE_GLOBALDIR=/data
xmake f --USE_CUDA=true
xmake b --root -vy crossdesk
```
对于**未安装 CUDA 环境的 Windows 开发者**,执行下面的命令安装 CUDA 编译环境:
```
xmake require -vy "cuda 12.6.3"
```
安装完成后执行:
```
xmake require --info "cuda 12.6.3"
```
输出如下:
<img width="860" height="226" alt="Image" src="https://github.com/user-attachments/assets/999ac365-581a-4b9a-806e-05eb3e4cf44d" />
根据上述输出获取到 CUDA 的安装目录,即 installdir 指向的位置。将 CUDA_PATH 加入系统环境变量,或在终端中输入:
```
set CUDA_PATH=path_to_cuda_installdir
```
重新执行:
```
xmake f --USE_CUDA=true
xmake b -vy crossdesk
```
#### 注意
运行时如果客户端状态栏显示 **未连接服务器**,请先在 [CrossDesk 官方网站](https://www.crossdesk.cn/) 安装客户端,以便在环境中安装所需的证书文件。
<img width="256" height="120" alt="image" src="https://github.com/user-attachments/assets/1812f7d6-516b-4b4f-8a3d-98bee505cc5a" />
## 关于 Xmake
#### 安装 Xmake
使用 curl
```
curl -fsSL https://xmake.io/shget.text | bash
```
使用 wget
```
wget https://xmake.io/shget.text -O - | bash
```
使用 powershell
```
irm https://xmake.io/psget.text | iex
```
#### 编译选项
```
# 切换编译模式
xmake f -m debug/release
# 可选编译参数
-r :重新构建目标
-v :显示详细的构建日志
-y :自动确认提示
# 示例
xmake b -vy crossdesk
```
#### 运行选项
```
# 使用调试模式运行
xmake r -d crossdesk
```
更多使用方法可参考 [Xmake官方文档](https://xmake.io/guide/quick-start.html) 。
## 自托管服务器
推荐使用Docker部署CrossDesk Server。
```bash
sudo docker run -d \
--name crossdesk_server \
--network host \
-e EXTERNAL_IP=xxx.xxx.xxx.xxx \
-e INTERNAL_IP=xxx.xxx.xxx.xxx \
-e CROSSDESK_SERVER_PORT=xxxx \
-e COTURN_PORT=xxxx \
-e MIN_PORT=xxxxx \
-e MAX_PORT=xxxxx \
-v /var/lib/crossdesk:/var/lib/crossdesk \
-v /var/log/crossdesk:/var/log/crossdesk \
crossdesk/crossdesk-server:v1.1.6
```
上述命令中,用户需注意的参数如下:
**参数**
- EXTERNAL_IP:服务器公网 IP , 对应 CrossDesk 客户端**自托管服务器配置**中填写的**服务器地址**
- INTERNAL_IP:服务器内网 IP
- CROSSDESK_SERVER_PORT:自托管服务使用的端口,对应 CrossDesk 客户端**自托管服务器配置**中填写的**服务器端口**
- COTURN_PORT: COTURN 服务使用的端口, 对应 CrossDesk 客户端**自托管服务器配置**中填写的**中继服务端口**
- MIN_PORT/MAX_PORTCOTURN 服务使用的端口范围,例如:MIN_PORT=50000, MAX_PORT=60000,范围可根据客户端数量调整。
- `-v /var/lib/crossdesk:/var/lib/crossdesk`:持久化数据库和证书文件到宿主机
- `-v /var/log/crossdesk:/var/log/crossdesk`:持久化日志文件到宿主机
**示例**
```bash
sudo docker run -d \
--name crossdesk_server \
--network host \
-e EXTERNAL_IP=114.114.114.114 \
-e INTERNAL_IP=10.0.0.1 \
-e CROSSDESK_SERVER_PORT=9099 \
-e COTURN_PORT=3478 \
-e MIN_PORT=50000 \
-e MAX_PORT=60000 \
-v /var/lib/crossdesk:/var/lib/crossdesk \
-v /var/log/crossdesk:/var/log/crossdesk \
crossdesk/crossdesk-server:v1.1.6
```
**注意**
- **服务器需开放端口:COTURN_PORT/udpCOTURN_PORT/tcpMIN_PORT-MAX_PORT/udpCROSSDESK_SERVER_PORT/tcp。**
- 如果不挂载 volume,容器删除后数据会丢失
- 证书文件会在首次启动时自动生成并持久化到宿主机的 `/var/lib/crossdesk/certs` 路径下。由于默认使用的是自签证书,无法保障安全性,建议在云服务商申请正式证书放到该目录下并重启服务。
- 数据库文件会自动创建并持久化到宿主机的 `/var/lib/crossdesk/db/crossdesk-server.db` 路径下
- 日志文件会自动创建并持久化到宿主机的 `/var/log/crossdesk/` 路径下
**权限注意**:如果 Docker 自动创建的目录权限不足(属于 root),容器内用户无法写入,会导致:
- 证书生成失败,容器启动脚本会报错退出
- 数据库目录创建失败,程序会抛出异常并崩溃
- 日志目录创建失败,日志文件无法写入(但程序可能继续运行)
**解决方案**:在启动容器前手动设置权限:
```bash
sudo mkdir -p /var/lib/crossdesk /var/log/crossdesk
sudo chown -R $(id -u):$(id -g) /var/lib/crossdesk /var/log/crossdesk
```
### 客户端
1. 点击右上角设置进入设置页面。<br><br>
<img width="600" height="210" alt="image" src="https://github.com/user-attachments/assets/6431131d-b32a-4726-8783-6788f47baa3b" /><br>
2. 点击`自托管服务器配置`按钮。<br><br>
<img width="600" height="160" alt="image" src="https://github.com/user-attachments/assets/24c761a3-1985-4d7e-84be-787383c2afb8" /><br>
3. 输入`服务器地址`(**EXTERNAL_IP**)、`信令服务端口`(**CROSSDESK_SERVER_PORT**)、`中继服务端口`(**COTURN_PORT**),点击确认按钮。
4. 勾选`自托管服务器配置`选项,点击确认按钮保存设置。如果服务端使用的是正式证书,则到此步骤为止,客户端即可显示已连接服务器。
5. 如果使用默认证书(正式证书忽略此步骤),则需要将服务端`/var/lib/crossdesk/certs/`目录下的`api.crossdesk.cn_root.crt`自签根证书下载到运行客户端的机器,并执行下述命令安装证书:
Windows 平台使用**管理员权限**打开 PowerShell 执行
```
certutil -addstore "Root" "C:\path\to\api.crossdesk.cn_root.crt"
```
Linux
```
sudo cp /path/to/api.crossdesk.cn_root.crt /usr/local/share/ca-certificates/api.crossdesk.cn_root.crt
sudo update-ca-certificates
```
macOS
```
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain path/to/api.crossdesk.cn_root.crt
```
### Web 客户端
详情见项目 [CrossDesk Web Client](https://github.com/kunkundi/crossdesk-web-client)。
# 常见问题
见 [常见问题](https://github.com/kunkundi/crossdesk/blob/self-hosted-server/docs/FAQ.md) 。
+276
View File
@@ -0,0 +1,276 @@
# CrossDesk
<a href="https://hellogithub.com/repository/kunkundi/crossdesk" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=55d41367570345f1838e02fd12be7961&claim_uid=cb0OpZRrBuGVAfL&theme=small" alt="FeaturedHelloGitHub" /></a>
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-brightgreen.svg)]()
[![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0)
[![GitHub last commit](https://img.shields.io/github/last-commit/kunkundi/crossdesk)](https://github.com/kunkundi/crossdesk/commits/web-client)
[![Build Status](https://github.com/kunkundi/crossdesk/actions/workflows/build.yml/badge.svg)](https://github.com/kunkundi/crossdesk/actions)
[![Docker Pulls](https://img.shields.io/docker/pulls/crossdesk/crossdesk-server)](https://hub.docker.com/r/crossdesk/crossdesk-server/tags)
[![GitHub issues](https://img.shields.io/github/issues/kunkundi/crossdesk.svg)]()
[![GitHub stars](https://img.shields.io/github/stars/kunkundi/crossdesk.svg?style=social)]()
[![GitHub forks](https://img.shields.io/github/forks/kunkundi/crossdesk.svg?style=social)]()
[ [中文](README.md) / English ]
PC Client
![sup_example](https://github.com/user-attachments/assets/3f17d8f3-7c4a-4b63-bae4-903363628687)
Web Client
<p align="center">
<img width="850" height="550" alt="6bddcbed47ffd4b9988a4037c7f4f524" src="https://github.com/user-attachments/assets/e44f73f9-24ac-46a3-a189-b7f8b6669881" />
</p>
# Intro
CrossDesk is a lightweight cross-platform remote desktop software.
CrossDesk is an experimental application of [MiniRTC](https://github.com/kunkundi/minirtc.git), a lightweight cross-platform real-time audio and video transmission library. MiniRTC provides fundamental capabilities including network traversal ([RFC5245](https://datatracker.ietf.org/doc/html/rfc5245)), video software/hardware encoding and decoding (H264/AV1), audio encoding/decoding ([Opus](https://github.com/xiph/opus)), signaling interaction, network congestion control, and transmission encryption ([SRTP](https://tools.ietf.org/html/rfc3711)).
## System Requirements
| Platform | Minimum Version |
|-----------|-----------------|
| **Windows** | Windows 10 or later (64-bit) |
| **macOS** | macOS Intel 15.0 or later *(versions between 14.0 and 15.0 can be built manually for compatibility)*<br>macOS Apple Silicon 14.0 or later |
| **Linux** | Ubuntu 22.04 or later *(older versions can be built manually for compatibility)* |
## Usage
Enter the remote desktop ID in the menu bars “Remote ID” field and click “→” to initiate a remote connection.
![usage1](https://github.com/user-attachments/assets/3a4bb59f-c84c-44d2-9a20-11790aac510e)
If the remote desktop requires a connection password, you must enter the correct password on your side to successfully establish the connection.
![password](https://github.com/user-attachments/assets/1beadcce-640d-4f5c-8e77-51917b5294d5)
Before connecting, you can customize configuration options in the settings, such as language and video encoding format.
![settings](https://github.com/user-attachments/assets/8bc5468d-7bbb-4e30-95bd-da1f352ac08c)
### Web Client
Visit [CrossDesk Web Client](https://web.crossdesk.cn/).
Enter the **Remote Device ID** and **Password**, then click Connect to access the remote device. As shown, **iOS Safari remotely controlling Windows 11**:
<img width="645" height="300" alt="_cgi-bin_mmwebwx-bin_webwxgetmsgimg__ MsgID=932911462648581698 skey=@crypt_1f5153b1_b550ca7462b5009ce03c991cca2a92a7 mmweb_appid=wx_webfilehelper" src="https://github.com/user-attachments/assets/a5109e6f-752c-4654-9f4e-7e161bddf43e" />
## How to build
Requirements:
- [xmake](https://xmake.io/#/guide/installation)
- [cmake](https://cmake.org/download/)
Following packages need to be installed on Linux:
```
sudo apt-get install -y software-properties-common git curl unzip build-essential libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-xfixes0-dev libxfixes-dev libxv-dev libxtst-dev libasound2-dev libsndio-dev libxcb-shm0-dev libasound2-dev libpulse-dev
```
Build:
```
git clone https://github.com/kunkundi/crossdesk.git
cd crossdesk
git submodule init
git submodule update
xmake b -vy crossdesk
```
Build options:
```
--USE_CUDA=true/false: enable CUDA acceleration codec, default: false
--CROSSDESK_VERSION=xxx: set the version number
# example:
xmake f --CROSSDESK_VERSION=1.0.0 --USE_CUDA=true
```
Run:
```
xmake r crossdesk
```
#### Development Without CUDA Environment
For **Linux developers who do not have a CUDA environment installed and want to enable hardware codec feature**, a preconfigured [Ubuntu 22.04 Docker image](https://hub.docker.com/r/crossdesk/ubuntu22.04) is provided.
This image comes with all required build dependencies and allows you to build the project directly inside the container without any additional setup.
After entering the container, download the project and run:
```
export CUDA_PATH=/usr/local/cuda
export XMAKE_GLOBALDIR=/data
xmake f --USE_CUDA=true
xmake b --root -vy crossdesk
```
For **Windows developers without a CUDA environment** installed, run the following command to install the CUDA build environment:
```
xmake require -vy "cuda 12.6.3"
```
After the installation is complete, execute:
```
xmake require --info "cuda 12.6.3"
```
The output will look like this:
<img width="860" height="226" alt="Image" src="https://github.com/user-attachments/assets/999ac365-581a-4b9a-806e-05eb3e4cf44d" />
From the output above, locate the CUDA installation directory — this is the path pointed to by installdir.
Add this path to your system environment variable CUDA_PATH, or set it in the terminal using:
```
set CUDA_PATH=path_to_cuda_installdir:
```
Then re-run:
```
xmake f --USE_CUDA=true
xmake b -vy crossdesk
```
#### Notice
If the client status bar shows **Disconnected** during runtime, please first install the client from the [CrossDesk official website](https://www.crossdesk.cn/) to ensure the required certificate files are available in the environment.
<img width="256" height="120" alt="image" src="https://github.com/user-attachments/assets/1812f7d6-516b-4b4f-8a3d-98bee505cc5a" />
## About Xmake
#### Installing Xmake
You can install Xmake using one of the following methods:
Using curl:
```
curl -fsSL https://xmake.io/shget.text | bash
```
Using wget:
```
wget https://xmake.io/shget.text -O - | bash
```
Using powershell:
```
irm https://xmake.io/psget.text | iex
```
#### Build Options
```
# Switch build mode
xmake f -m debug/release
# Optional build parameters
-r : Rebuild the target
-v : Show detailed build logs
-y : Automatically confirm prompts
# Example
xmake b -vy crossdesk
```
#### Run Options
```
# Run in debug mode
xmake r -d crossdesk
```
For more information, please refer to the [official Xmake documentation](https://xmake.io/guide/quick-start.html) .
## Self-Hosted Server
It is recommended to deploy CrossDesk Server using Docker.
```
sudo docker run -d \
--name crossdesk_server \
--network host \
-e EXTERNAL_IP=xxx.xxx.xxx.xxx \
-e INTERNAL_IP=xxx.xxx.xxx.xxx \
-e CROSSDESK_SERVER_PORT=xxxx \
-e COTURN_PORT=xxxx \
-e MIN_PORT=xxxxx \
-e MAX_PORT=xxxxx \
-v /var/lib/crossdesk:/var/lib/crossdesk \
-v /var/log/crossdesk:/var/log/crossdesk \
crossdesk/crossdesk-server:v1.1.6
```
The parameters you need to pay attention to are as follows:
**Parameters**
- **EXTERNAL_IP**: The servers public IP. This corresponds to **Server Address** in the CrossDesk clients **Self-Hosted Server Configuration**.
- **INTERNAL_IP**: The servers internal IP.
- **CROSSDESK_SERVER_PORT**: The port used by the self-hosted service. This corresponds to **Server Port** in the CrossDesk clients **Self-Hosted Server Configuration**.
- **COTURN_PORT**: The port used by the COTURN service. This corresponds to **Relay Service Port** in the CrossDesk clients **Self-Hosted Server Configuration**.
- **MIN_PORT / MAX_PORT**: The port range used by the COTURN service. Example: `MIN_PORT=50000`, `MAX_PORT=60000`. Adjust the range depending on the number of clients.
- `-v /var/lib/crossdesk:/var/lib/crossdesk`: Persists database and certificate files on the host machine.
- `-v /var/log/crossdesk:/var/log/crossdesk`: Persists log files on the host machine.
**Example**:
```bash
sudo docker run -d \
--name crossdesk_server \
--network host \
-e EXTERNAL_IP=114.114.114.114 \
-e INTERNAL_IP=10.0.0.1 \
-e CROSSDESK_SERVER_PORT=9099 \
-e COTURN_PORT=3478 \
-e MIN_PORT=50000 \
-e MAX_PORT=60000 \
-v /var/lib/crossdesk:/var/lib/crossdesk \
-v /var/log/crossdesk:/var/log/crossdesk \
crossdesk/crossdesk-server:v1.1.6
```
**Notes**
- **The server must open the following ports: COTURN_PORT/udp, COTURN_PORT/tcp, MIN_PORTMAX_PORT/udp, and CROSSDESK_SERVER_PORT/tcp.**
- If you dont mount volumes, all data will be lost when the container is removed.
- Certificate files will be automatically generated on first startup and persisted to the host at `/var/lib/crossdesk/certs`.As the default certificates are self-signed and cannot guarantee security, it is strongly recommended to apply for a trusted certificate from a cloud provider, deploy it to this directory, and restart the service.
- The database file will be automatically created and stored at `/var/lib/crossdesk/db/crossdesk-server.db`.
- Log files will be created and stored at `/var/log/crossdesk/`.
**Permission Notice**
If the directories automatically created by Docker belong to root and have insufficient write permissions, the container user may not be able to write to them. This can cause:
- Certificate generation failure, leading to startup script errors and container exit.
- Database directory creation failure, causing the program to throw exceptions and crash.
- Log directory creation failure, preventing logs from being written (though the program may continue running).
**Solution:** Manually set permissions before starting the container:
```bash
sudo mkdir -p /var/lib/crossdesk /var/log/crossdesk
sudo chown -R $(id -u):$(id -g) /var/lib/crossdesk /var/log/crossdesk
```
### Server Side
Place **crossdesk.cn.key** and **crossdesk.cn_bundle.crt** into the **/path/to/your/certs** directory.
### Client Side
1. Click the settings icon in the top-right corner to enter the settings page.<br><br>
<img width="600" height="210" alt="image" src="https://github.com/user-attachments/assets/6431131d-b32a-4726-8783-6788f47baa3b" /><br>
2. Click `Self-Hosted Server Configuration` button.<br><br>
<img width="600" height="160" alt="image" src="https://github.com/user-attachments/assets/24c761a3-1985-4d7e-84be-787383c2afb8" /><br>
3. Enter the `Server Address` (**EXTERNAL_IP**), `Signaling Service Port` (**CROSSDESK_SERVER_PORT**), and `Relay Service Port` (**COTURN_PORT**) and click OK button.
4. Check the `Self-hosted server configuration` option and click the OK button to save the settings. If the server is using a valid (official) certificate, the process ends here and the client will show that it is connected to the server.
5. If the default certificate is used (skip this step if an official certificate is used), download the self-signed root certificate `api.crossdesk.cn_root.crt` from the server directory /var/lib/crossdesk/certs/ to the machine running the client, and install the certificate by executing the following command:
On Windows, open PowerShell with **administrator privileges** and execute:
```
certutil -addstore "Root" "C:\path\to\api.crossdesk.cn_root.crt"
```
Linux
```
sudo cp /path/to/api.crossdesk.cn_root.crt /usr/local/share/ca-certificates/api.crossdesk.cn_root.crt
sudo update-ca-certificates
```
macOS
```
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain path/to/api.crossdesk.cn_root.crt
```
### Web Client
See [CrossDesk Web Client](https://github.com/kunkundi/crossdesk-web-client)。
# FAQ
See [FAQ](https://github.com/kunkundi/crosssesk/blob/self-hosted-server/docs/FAQ.md) .
-19
View File
@@ -1,19 +0,0 @@
[signal server]
ip = 150.158.81.30
port = 9099
[stun server]
ip = 150.158.81.30
port = 3478
[turn server]
ip = 150.158.81.30
port = 3478
username = dijunkun
password = dijunkunpw
[hardware acceleration]
turn_on = false
[av1 encoding]
turn_on = true
Binary file not shown.
+33
View File
@@ -0,0 +1,33 @@
# 常见问题(FAQ
欢迎来到 **CrossDesk 常见问题** 页面!
这里整理了用户和开发者最常见的一些疑问。如果你没有找到答案,欢迎在 [Issues](https://github.com/kunkundi/crossdesk/issues) 中反馈。
---
### Q1. 对等连接失败
**A:**
打开设置,勾选 **启用中继服务** 选项,尝试重新发起连接。
<img width="396" height="306" alt="Image" src="https://github.com/user-attachments/assets/fd8db148-c782-4f4d-b874-8f1b2a7ec7d6" />
由于公共中继服务器带宽较小,连接的清晰度流畅度可能会下降,建议自建服务器。 [Issue #8](https://github.com/kunkundi/crossdesk/issues/8)
### Q2. Windows 无 CUDA 环境下编译
**A:**
运行下面的命令安装 CUDA 编译环境。
```
xmake require -vy "cuda 12.6.3"
```
安装完成后执行
```
xmake require --info "cuda 12.6.3"
```
输出如下
<img width="860" height="226" alt="Image" src="https://github.com/user-attachments/assets/999ac365-581a-4b9a-806e-05eb3e4cf44d" />
根据上述输出获取到 CUDA 的安装目录,即 installdir 指向的位置。将 CUDA_PATH 加入系统环境变量,或在终端中输入 set CUDA_PATH=path_to_cuda_installdir,重新执行 xmake b -vy crossdesk 即可。
[Issue #6](https://github.com/kunkundi/crossdesk/issues/6)
---
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

+98
View File
@@ -0,0 +1,98 @@
#!/bin/bash
set -e
PKG_NAME="crossdesk"
APP_NAME="CrossDesk"
APP_VERSION="$1"
ARCHITECTURE="amd64"
MAINTAINER="Junkun Di <junkun.di@hotmail.com>"
DESCRIPTION="A simple cross-platform remote desktop client."
# Remove 'v' prefix from version for Debian package (Debian version must start with digit)
DEB_VERSION="${APP_VERSION#v}"
DEB_DIR="${PKG_NAME}-${DEB_VERSION}"
DEBIAN_DIR="$DEB_DIR/DEBIAN"
BIN_DIR="$DEB_DIR/usr/bin"
ICON_BASE_DIR="$DEB_DIR/usr/share/icons/hicolor"
DESKTOP_DIR="$DEB_DIR/usr/share/applications"
rm -rf "$DEB_DIR"
mkdir -p "$DEBIAN_DIR" "$BIN_DIR" "$DESKTOP_DIR"
cp build/linux/x86_64/release/crossdesk "$BIN_DIR/$PKG_NAME"
chmod +x "$BIN_DIR/$PKG_NAME"
ln -s "$PKG_NAME" "$BIN_DIR/$APP_NAME"
for size in 16 24 32 48 64 96 128 256; do
mkdir -p "$ICON_BASE_DIR/${size}x${size}/apps"
cp "icons/linux/crossdesk_${size}x${size}.png" \
"$ICON_BASE_DIR/${size}x${size}/apps/${PKG_NAME}.png"
done
cat > "$DEBIAN_DIR/control" << EOF
Package: $PKG_NAME
Version: $DEB_VERSION
Architecture: $ARCHITECTURE
Maintainer: $MAINTAINER
Description: $DESCRIPTION
Depends: libc6 (>= 2.29), libstdc++6 (>= 9), libx11-6, libxcb1,
libxcb-randr0, libxcb-xtest0, libxcb-xinerama0, libxcb-shape0,
libxcb-xkb1, libxcb-xfixes0, libxv1, libxtst6, libasound2,
libsndio7.0, libxcb-shm0, libpulse0, libdrm2, libdbus-1-3,
libpipewire-0.3-0, xdg-desktop-portal,
xdg-desktop-portal-gtk | xdg-desktop-portal-kde | xdg-desktop-portal-wlr
Recommends: nvidia-cuda-toolkit
Priority: optional
Section: utils
EOF
cat > "$DESKTOP_DIR/$PKG_NAME.desktop" << EOF
[Desktop Entry]
Version=$DEB_VERSION
Name=$APP_NAME
Comment=$DESCRIPTION
Exec=/usr/bin/$PKG_NAME
Icon=$PKG_NAME
Terminal=false
Type=Application
Categories=Utility;
EOF
cat > "$DEBIAN_DIR/postrm" << EOF
#!/bin/bash
set -e
if [ "\$1" = "remove" ] || [ "\$1" = "purge" ]; then
rm -f /usr/bin/$PKG_NAME || true
rm -f /usr/bin/$APP_NAME || true
rm -f /usr/share/applications/$PKG_NAME.desktop || true
for size in 16 24 32 48 64 96 128 256; do
rm -f /usr/share/icons/hicolor/\${size}x\${size}/apps/$PKG_NAME.png || true
done
fi
exit 0
EOF
chmod +x "$DEBIAN_DIR/postrm"
cat > "$DEBIAN_DIR/postinst" << 'EOF'
#!/bin/bash
set -e
exit 0
EOF
chmod +x "$DEBIAN_DIR/postinst"
dpkg-deb --build "$DEB_DIR"
OUTPUT_FILE="${PKG_NAME}-linux-${ARCHITECTURE}-${APP_VERSION}.deb"
mv "$DEB_DIR.deb" "$OUTPUT_FILE"
rm -rf "$DEB_DIR"
echo "✅ Deb package created: $OUTPUT_FILE"
+97
View File
@@ -0,0 +1,97 @@
#!/bin/bash
set -e
PKG_NAME="crossdesk"
APP_NAME="CrossDesk"
APP_VERSION="$1"
ARCHITECTURE="arm64"
MAINTAINER="Junkun Di <junkun.di@hotmail.com>"
DESCRIPTION="A simple cross-platform remote desktop client."
# Remove 'v' prefix from version for Debian package (Debian version must start with digit)
DEB_VERSION="${APP_VERSION#v}"
DEB_DIR="${PKG_NAME}-${DEB_VERSION}"
DEBIAN_DIR="$DEB_DIR/DEBIAN"
BIN_DIR="$DEB_DIR/usr/bin"
ICON_BASE_DIR="$DEB_DIR/usr/share/icons/hicolor"
DESKTOP_DIR="$DEB_DIR/usr/share/applications"
rm -rf "$DEB_DIR"
mkdir -p "$DEBIAN_DIR" "$BIN_DIR" "$DESKTOP_DIR"
cp build/linux/arm64/release/crossdesk "$BIN_DIR"
chmod +x "$BIN_DIR/$PKG_NAME"
ln -s "$PKG_NAME" "$BIN_DIR/$APP_NAME"
for size in 16 24 32 48 64 96 128 256; do
mkdir -p "$ICON_BASE_DIR/${size}x${size}/apps"
cp "icons/linux/crossdesk_${size}x${size}.png" \
"$ICON_BASE_DIR/${size}x${size}/apps/${PKG_NAME}.png"
done
cat > "$DEBIAN_DIR/control" << EOF
Package: $PKG_NAME
Version: $DEB_VERSION
Architecture: $ARCHITECTURE
Maintainer: $MAINTAINER
Description: $DESCRIPTION
Depends: libc6 (>= 2.29), libstdc++6 (>= 9), libx11-6, libxcb1,
libxcb-randr0, libxcb-xtest0, libxcb-xinerama0, libxcb-shape0,
libxcb-xkb1, libxcb-xfixes0, libxv1, libxtst6, libasound2,
libsndio7.0, libxcb-shm0, libpulse0, libdrm2, libdbus-1-3,
libpipewire-0.3-0, xdg-desktop-portal,
xdg-desktop-portal-gtk | xdg-desktop-portal-kde | xdg-desktop-portal-wlr
Priority: optional
Section: utils
EOF
cat > "$DESKTOP_DIR/$PKG_NAME.desktop" << EOF
[Desktop Entry]
Version=$DEB_VERSION
Name=$APP_NAME
Comment=$DESCRIPTION
Exec=/usr/bin/$PKG_NAME
Icon=$PKG_NAME
Terminal=false
Type=Application
Categories=Utility;
EOF
cat > "$DEBIAN_DIR/postrm" << EOF
#!/bin/bash
set -e
if [ "\$1" = "remove" ] || [ "\$1" = "purge" ]; then
rm -f /usr/bin/$PKG_NAME || true
rm -f /usr/bin/$APP_NAME || true
rm -f /usr/share/applications/$PKG_NAME.desktop || true
for size in 16 24 32 48 64 96 128 256; do
rm -f /usr/share/icons/hicolor/\${size}x\${size}/apps/$PKG_NAME.png || true
done
fi
exit 0
EOF
chmod +x "$DEBIAN_DIR/postrm"
cat > "$DEBIAN_DIR/postinst" << 'EOF'
#!/bin/bash
set -e
exit 0
EOF
chmod +x "$DEBIAN_DIR/postinst"
dpkg-deb --build "$DEB_DIR"
OUTPUT_FILE="crossdesk-linux-arm64-$APP_VERSION.deb"
mv "$DEB_DIR.deb" "$OUTPUT_FILE"
rm -rf "$DEB_DIR"
echo "✅ Deb package created: $OUTPUT_FILE"
+178
View File
@@ -0,0 +1,178 @@
#!/bin/bash
set -e
APP_NAME="crossdesk"
APP_NAME_UPPER="CrossDesk"
EXECUTABLE_PATH="./build/macosx/arm64/release/crossdesk"
APP_VERSION="$1"
PLATFORM="macos"
ARCH="arm64"
IDENTIFIER="cn.crossdesk.app"
ICON_PATH="icons/macos/crossdesk.icns"
MACOS_MIN_VERSION="10.12"
APP_BUNDLE="${APP_NAME_UPPER}.app"
CONTENTS_DIR="${APP_BUNDLE}/Contents"
MACOS_DIR="${CONTENTS_DIR}/MacOS"
RESOURCES_DIR="${CONTENTS_DIR}/Resources"
PKG_NAME="${APP_NAME}-${PLATFORM}-${ARCH}-${APP_VERSION}.pkg"
DMG_NAME="${APP_NAME}-${PLATFORM}-${ARCH}-${APP_VERSION}.dmg"
VOL_NAME="Install ${APP_NAME_UPPER}"
echo "delete old files"
rm -rf "${APP_BUNDLE}" "${PKG_NAME}" "${DMG_NAME}" build_pkg_temp CrossDesk_dmg_temp
mkdir -p build_pkg_temp
mkdir -p "${MACOS_DIR}" "${RESOURCES_DIR}"
cp "${EXECUTABLE_PATH}" "${MACOS_DIR}/${APP_NAME_UPPER}"
chmod +x "${MACOS_DIR}/${APP_NAME_UPPER}"
if [ -f "${ICON_PATH}" ]; then
cp "${ICON_PATH}" "${RESOURCES_DIR}/crossedesk.icns"
ICON_KEY="<key>CFBundleIconFile</key><string>crossedesk.icns</string>"
else
ICON_KEY=""
fi
echo "generate Info.plist"
cat > "${CONTENTS_DIR}/Info.plist" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>${APP_NAME_UPPER}</string>
<key>CFBundleDisplayName</key>
<string>${APP_NAME_UPPER}</string>
<key>CFBundleIdentifier</key>
<string>${IDENTIFIER}</string>
<key>CFBundleVersion</key>
<string>${APP_VERSION}</string>
<key>CFBundleShortVersionString</key>
<string>${APP_VERSION}</string>
<key>CFBundleExecutable</key>
<string>${APP_NAME_UPPER}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
${ICON_KEY}
<key>LSMinimumSystemVersion</key>
<string>${MACOS_MIN_VERSION}</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>应用需要访问摄像头</string>
<key>NSMicrophoneUsageDescription</key>
<string>应用需要访问麦克风</string>
<key>NSAppleEventsUsageDescription</key>
<string>应用需要发送 Apple 事件</string>
<key>NSScreenCaptureUsageDescription</key>
<string>应用需要录屏权限以捕获屏幕内容</string>
</dict>
</plist>
EOF
echo ".app created successfully."
echo "building pkg..."
pkgbuild \
--identifier "${IDENTIFIER}" \
--version "${APP_VERSION}" \
--install-location "/Applications" \
--component "${APP_BUNDLE}" \
build_pkg_temp/${APP_NAME}-component.pkg
mkdir -p build_pkg_scripts
cat > build_pkg_scripts/postinstall <<'EOF'
#!/bin/bash
set -e
IDENTIFIER="cn.crossdesk.app"
# 获取当前登录用户
USER_HOME=$( /usr/bin/stat -f "%Su" /dev/console )
HOME_DIR=$( /usr/bin/dscl . -read /Users/$USER_HOME NFSHomeDirectory | awk '{print $2}' )
# 清除应用的权限授权,以便重新授权
# 使用 tccutil 重置录屏权限和辅助功能权限
if command -v tccutil >/dev/null 2>&1; then
# 重置录屏权限
tccutil reset ScreenCapture "$IDENTIFIER" 2>/dev/null || true
# 重置辅助功能权限
tccutil reset Accessibility "$IDENTIFIER" 2>/dev/null || true
# 重置摄像头权限(如果需要)
tccutil reset Camera "$IDENTIFIER" 2>/dev/null || true
# 重置麦克风权限(如果需要)
tccutil reset Microphone "$IDENTIFIER" 2>/dev/null || true
fi
# 为所有用户清除权限(可选,如果需要)
# 遍历所有用户目录并清除权限
for USER_DIR in /Users/*; do
if [ -d "$USER_DIR" ] && [ "$USER_DIR" != "/Users/Shared" ]; then
USER_NAME=$(basename "$USER_DIR")
# 跳过系统用户
if [ "$USER_NAME" != "Shared" ] && [ -d "$USER_DIR/Library" ]; then
# 删除 TCC 数据库中的相关条目(需要管理员权限)
TCC_DB="$USER_DIR/Library/Application Support/com.apple.TCC/TCC.db"
if [ -f "$TCC_DB" ]; then
# 使用 sqlite3 删除相关权限记录(如果可用)
if command -v sqlite3 >/dev/null 2>&1; then
sqlite3 "$TCC_DB" "DELETE FROM access WHERE client='$IDENTIFIER' AND service IN ('kTCCServiceScreenCapture', 'kTCCServiceAccessibility');" 2>/dev/null || true
fi
fi
fi
fi
done
exit 0
EOF
chmod +x build_pkg_scripts/postinstall
productbuild \
--package build_pkg_temp/${APP_NAME}-component.pkg \
"${PKG_NAME}"
echo "PKG package created: ${PKG_NAME}"
# Set custom icon for PKG file
if [ -f "${ICON_PATH}" ]; then
echo "Setting custom icon for PKG file..."
# Create a temporary iconset from icns
TEMP_ICON_DIR=$(mktemp -d)
cp "${ICON_PATH}" "${TEMP_ICON_DIR}/icon.icns"
# Use sips to create a png from icns for the icon
sips -s format png "${TEMP_ICON_DIR}/icon.icns" --out "${TEMP_ICON_DIR}/icon.png" 2>/dev/null || true
# Method: Use osascript to set file icon (works on macOS)
osascript <<APPLESCRIPT
use framework "Foundation"
use framework "AppKit"
set iconPath to POSIX file "${TEMP_ICON_DIR}/icon.icns"
set targetPath to POSIX file "$(pwd)/${PKG_NAME}"
set iconImage to current application's NSImage's alloc()'s initWithContentsOfFile:(POSIX path of iconPath)
set workspace to current application's NSWorkspace's sharedWorkspace()
workspace's setIcon:iconImage forFile:(POSIX path of targetPath) options:0
APPLESCRIPT
if [ $? -eq 0 ]; then
echo "Custom icon set successfully for ${PKG_NAME}"
else
echo "Warning: Failed to set custom icon (this is optional)"
fi
rm -rf "${TEMP_ICON_DIR}"
fi
echo "Set icon finished"
rm -rf build_pkg_temp build_pkg_scripts ${APP_BUNDLE}
echo "PKG package created successfully."
echo "package ${APP_BUNDLE}"
echo "installer ${PKG_NAME}"
+178
View File
@@ -0,0 +1,178 @@
#!/bin/bash
set -e
APP_NAME="crossdesk"
APP_NAME_UPPER="CrossDesk"
EXECUTABLE_PATH="build/macosx/x86_64/release/crossdesk"
APP_VERSION="$1"
PLATFORM="macos"
ARCH="x64"
IDENTIFIER="cn.crossdesk.app"
ICON_PATH="icons/macos/crossdesk.icns"
MACOS_MIN_VERSION="10.12"
APP_BUNDLE="${APP_NAME_UPPER}.app"
CONTENTS_DIR="${APP_BUNDLE}/Contents"
MACOS_DIR="${CONTENTS_DIR}/MacOS"
RESOURCES_DIR="${CONTENTS_DIR}/Resources"
PKG_NAME="${APP_NAME}-${PLATFORM}-${ARCH}-${APP_VERSION}.pkg"
DMG_NAME="${APP_NAME}-${PLATFORM}-${ARCH}-${APP_VERSION}.dmg"
VOL_NAME="Install ${APP_NAME_UPPER}"
echo "delete old files"
rm -rf "${APP_BUNDLE}" "${PKG_NAME}" "${DMG_NAME}" build_pkg_temp CrossDesk_dmg_temp
mkdir -p build_pkg_temp
mkdir -p "${MACOS_DIR}" "${RESOURCES_DIR}"
cp "${EXECUTABLE_PATH}" "${MACOS_DIR}/${APP_NAME_UPPER}"
chmod +x "${MACOS_DIR}/${APP_NAME_UPPER}"
if [ -f "${ICON_PATH}" ]; then
cp "${ICON_PATH}" "${RESOURCES_DIR}/crossedesk.icns"
ICON_KEY="<key>CFBundleIconFile</key><string>crossedesk.icns</string>"
else
ICON_KEY=""
fi
echo "generate Info.plist"
cat > "${CONTENTS_DIR}/Info.plist" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>${APP_NAME_UPPER}</string>
<key>CFBundleDisplayName</key>
<string>${APP_NAME_UPPER}</string>
<key>CFBundleIdentifier</key>
<string>${IDENTIFIER}</string>
<key>CFBundleVersion</key>
<string>${APP_VERSION}</string>
<key>CFBundleShortVersionString</key>
<string>${APP_VERSION}</string>
<key>CFBundleExecutable</key>
<string>${APP_NAME_UPPER}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
${ICON_KEY}
<key>LSMinimumSystemVersion</key>
<string>${MACOS_MIN_VERSION}</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>应用需要访问摄像头</string>
<key>NSMicrophoneUsageDescription</key>
<string>应用需要访问麦克风</string>
<key>NSAppleEventsUsageDescription</key>
<string>应用需要发送 Apple 事件</string>
<key>NSScreenCaptureUsageDescription</key>
<string>应用需要录屏权限以捕获屏幕内容</string>
</dict>
</plist>
EOF
echo ".app created successfully."
echo "building pkg..."
pkgbuild \
--identifier "${IDENTIFIER}" \
--version "${APP_VERSION}" \
--install-location "/Applications" \
--component "${APP_BUNDLE}" \
build_pkg_temp/${APP_NAME}-component.pkg
mkdir -p build_pkg_scripts
cat > build_pkg_scripts/postinstall <<'EOF'
#!/bin/bash
set -e
IDENTIFIER="cn.crossdesk.app"
# 获取当前登录用户
USER_HOME=$( /usr/bin/stat -f "%Su" /dev/console )
HOME_DIR=$( /usr/bin/dscl . -read /Users/$USER_HOME NFSHomeDirectory | awk '{print $2}' )
# 清除应用的权限授权,以便重新授权
# 使用 tccutil 重置录屏权限和辅助功能权限
if command -v tccutil >/dev/null 2>&1; then
# 重置录屏权限
tccutil reset ScreenCapture "$IDENTIFIER" 2>/dev/null || true
# 重置辅助功能权限
tccutil reset Accessibility "$IDENTIFIER" 2>/dev/null || true
# 重置摄像头权限(如果需要)
tccutil reset Camera "$IDENTIFIER" 2>/dev/null || true
# 重置麦克风权限(如果需要)
tccutil reset Microphone "$IDENTIFIER" 2>/dev/null || true
fi
# 为所有用户清除权限(可选,如果需要)
# 遍历所有用户目录并清除权限
for USER_DIR in /Users/*; do
if [ -d "$USER_DIR" ] && [ "$USER_DIR" != "/Users/Shared" ]; then
USER_NAME=$(basename "$USER_DIR")
# 跳过系统用户
if [ "$USER_NAME" != "Shared" ] && [ -d "$USER_DIR/Library" ]; then
# 删除 TCC 数据库中的相关条目(需要管理员权限)
TCC_DB="$USER_DIR/Library/Application Support/com.apple.TCC/TCC.db"
if [ -f "$TCC_DB" ]; then
# 使用 sqlite3 删除相关权限记录(如果可用)
if command -v sqlite3 >/dev/null 2>&1; then
sqlite3 "$TCC_DB" "DELETE FROM access WHERE client='$IDENTIFIER' AND service IN ('kTCCServiceScreenCapture', 'kTCCServiceAccessibility');" 2>/dev/null || true
fi
fi
fi
fi
done
exit 0
EOF
chmod +x build_pkg_scripts/postinstall
productbuild \
--package build_pkg_temp/${APP_NAME}-component.pkg \
"${PKG_NAME}"
echo "PKG package created: ${PKG_NAME}"
# Set custom icon for PKG file
if [ -f "${ICON_PATH}" ]; then
echo "Setting custom icon for PKG file..."
# Create a temporary iconset from icns
TEMP_ICON_DIR=$(mktemp -d)
cp "${ICON_PATH}" "${TEMP_ICON_DIR}/icon.icns"
# Use sips to create a png from icns for the icon
sips -s format png "${TEMP_ICON_DIR}/icon.icns" --out "${TEMP_ICON_DIR}/icon.png" 2>/dev/null || true
# Method: Use osascript to set file icon (works on macOS)
osascript <<APPLESCRIPT
use framework "Foundation"
use framework "AppKit"
set iconPath to POSIX file "${TEMP_ICON_DIR}/icon.icns"
set targetPath to POSIX file "$(pwd)/${PKG_NAME}"
set iconImage to current application's NSImage's alloc()'s initWithContentsOfFile:(POSIX path of iconPath)
set workspace to current application's NSWorkspace's sharedWorkspace()
workspace's setIcon:iconImage forFile:(POSIX path of targetPath) options:0
APPLESCRIPT
if [ $? -eq 0 ]; then
echo "Custom icon set successfully for ${PKG_NAME}"
else
echo "Warning: Failed to set custom icon (this is optional)"
fi
rm -rf "${TEMP_ICON_DIR}"
fi
echo "Set icon finished"
rm -rf build_pkg_temp build_pkg_scripts ${APP_BUNDLE}
echo "PKG package created successfully."
echo "package ${APP_BUNDLE}"
echo "installer ${PKG_NAME}"
+43
View File
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<!-- 应用程序标识 -->
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="*"
name="CrossDesk"
type="win32" />
<!-- 描述信息 -->
<description>CrossDesk Application</description>
<!-- 权限:要求管理员运行 -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<!-- DPI 感知设置:支持高分屏 -->
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<!-- Windows Vista/7 风格 DPI 感知 -->
<dpiAware>true/pm</dpiAware>
<!-- Windows 10/11 高级 DPI 感知 -->
<dpiAwareness>PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
<!-- Windows 兼容性声明 -->
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- 支持 Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- 支持 Windows 11(向下兼容 Win10 GUID -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>
+2
View File
@@ -0,0 +1,2 @@
// Application icon resource; load by the resource name IDI_ICON1.
IDI_ICON1 ICON "..\\..\\icons\\windows\\crossdesk.ico"
Binary file not shown.
+150
View File
@@ -0,0 +1,150 @@
; Set search path
!addincludedir "${__FILEDIR__}"
; Installer initial constants
!define PRODUCT_NAME "CrossDesk"
!define PRODUCT_VERSION "${VERSION}"
!define PRODUCT_PUBLISHER "CrossDesk"
!define PRODUCT_WEB_SITE "https://www.crossdesk.cn/"
!define APP_NAME "CrossDesk"
!define UNINSTALL_REG_KEY "CrossDesk"
; Installer icon path
!define MUI_ICON "${__FILEDIR__}\..\..\icons\windows\crossdesk.ico"
; Compression settings
SetCompressor /FINAL lzma
; Request admin privileges (needed to write HKLM)
RequestExecutionLevel admin
; ------ MUI Modern UI Definition ------
!include "MUI.nsh"
!define MUI_ABORTWARNING
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
; Add run-after-install option
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_TEXT "Run ${PRODUCT_NAME}"
!define MUI_FINISHPAGE_RUN_FUNCTION LaunchApp
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_LANGUAGE "SimpChinese"
!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
; ------ End of MUI Definition ------
; Include LogicLib for process handling
!include "LogicLib.nsh"
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "crossdesk-win-x64-${PRODUCT_VERSION}.exe"
InstallDir "$PROGRAMFILES\CrossDesk"
InstallDirRegKey HKCU "Software\${PRODUCT_NAME}" "InstallDir"
ShowInstDetails show
Section "MainSection"
; Check if CrossDesk is running
StrCpy $1 "CrossDesk.exe"
nsProcess::_FindProcess "$1"
Pop $R0
${If} $R0 = 0 ;
MessageBox MB_ICONQUESTION|MB_YESNO "CrossDesk is running. Do you want to close it and continue the installation?" IDYES closeApp IDNO cancelInstall
${Else}
Goto installApp
${EndIf}
closeApp:
nsProcess::_KillProcess "$1"
Pop $R0
Sleep 500
Goto installApp
cancelInstall:
SetDetailsPrint both
MessageBox MB_ICONEXCLAMATION|MB_OK "Installation has been aborted."
Abort
installApp:
SetOutPath "$INSTDIR"
SetOverwrite ifnewer
; Main application executable path
File /oname=CrossDesk.exe "..\..\build\windows\x64\release\crossdesk.exe"
; Bundle runtime DLLs from the release output directory
File "..\..\build\windows\x64\release\*.dll"
; Write uninstall information
WriteUninstaller "$INSTDIR\uninstall.exe"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "DisplayName" "${PRODUCT_NAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "UninstallString" "$INSTDIR\uninstall.exe"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "DisplayIcon" "$INSTDIR\CrossDesk.exe"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "NoRepair" 1
WriteRegStr HKCU "Software\${PRODUCT_NAME}" "InstallDir" "$INSTDIR"
SectionEnd
Section -AdditionalIcons
; Desktop shortcut
CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\CrossDesk.exe" "" "$INSTDIR\CrossDesk.exe"
; Start menu shortcut
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}.lnk" "$INSTDIR\CrossDesk.exe" "" "$INSTDIR\CrossDesk.exe"
SectionEnd
Section "Uninstall"
; Check if CrossDesk is running
StrCpy $1 "CrossDesk.exe"
nsProcess::_FindProcess "$1"
Pop $R0
${If} $R0 = 0
MessageBox MB_ICONQUESTION|MB_YESNO "CrossDesk is running. Do you want to close it and uninstall?" IDYES closeApp IDNO cancelUninstall
${Else}
Goto uninstallApp
${EndIf}
closeApp:
nsProcess::_KillProcess "$1"
Pop $R0
Sleep 500
Goto uninstallApp
cancelUninstall:
SetDetailsPrint both
MessageBox MB_ICONEXCLAMATION|MB_OK "Uninstallation has been aborted."
Abort
uninstallApp:
; Delete main executable and uninstaller
Delete "$INSTDIR\CrossDesk.exe"
Delete "$INSTDIR\uninstall.exe"
; Recursively delete installation directory
RMDir /r "$INSTDIR"
; Delete desktop and start menu shortcuts
Delete "$DESKTOP\${PRODUCT_NAME}.lnk"
Delete "$SMPROGRAMS\${PRODUCT_NAME}.lnk"
; Delete registry uninstall entry
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}"
; Delete remembered install dir
DeleteRegKey HKCU "Software\${PRODUCT_NAME}"
; Recursively delete CrossDesk folder in user AppData
RMDir /r "$APPDATA\CrossDesk"
RMDir /r "$LOCALAPPDATA\CrossDesk"
SectionEnd
; ------ Functions ------
Function LaunchApp
Exec "$INSTDIR\CrossDesk.exe"
FunctionEnd
+338
View File
@@ -0,0 +1,338 @@
#include "daemon.h"
#include <atomic>
#include <chrono>
#include <cstring>
#include <iostream>
#include <thread>
#include <vector>
#ifdef _WIN32
#include <process.h>
#include <tchar.h>
#include <windows.h>
#elif __APPLE__
#include <fcntl.h>
#include <limits.h>
#include <mach-o/dyld.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#else
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cstring>
#endif
#ifndef _WIN32
volatile std::sig_atomic_t Daemon::stop_requested_ = 0;
#endif
namespace {
constexpr int kRestartDelayMs = 1000;
#ifndef _WIN32
constexpr int kWaitPollIntervalMs = 200;
#endif
} // namespace
// get executable file path
static std::string GetExecutablePath() {
#ifdef _WIN32
char path[32768];
DWORD length = GetModuleFileNameA(nullptr, path, sizeof(path));
if (length > 0 && length < sizeof(path)) {
return std::string(path);
}
#elif __APPLE__
char path[PATH_MAX];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0) {
char resolved_path[PATH_MAX];
if (realpath(path, resolved_path) != nullptr) {
return std::string(resolved_path);
}
return std::string(path);
}
#else
char path[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", path, sizeof(path) - 1);
if (count != -1) {
path[count] = '\0';
return std::string(path);
}
#endif
return "";
}
Daemon::Daemon(const std::string& name) : name_(name), running_(false) {}
void Daemon::stop() {
running_.store(false);
#ifndef _WIN32
stop_requested_ = 1;
#endif
}
bool Daemon::isRunning() const {
#ifndef _WIN32
return running_.load() && (stop_requested_ == 0);
#else
return running_.load();
#endif
}
bool Daemon::start(MainLoopFunc loop) {
#ifdef _WIN32
running_.store(true);
return runWithRestart(loop);
#elif __APPLE__
// macOS: Use child process monitoring (like Windows) to preserve GUI
stop_requested_ = 0;
running_.store(true);
return runWithRestart(loop);
#else
// linux: Daemonize first, then run with restart monitoring
stop_requested_ = 0;
// check if running from terminal before fork
bool from_terminal =
(isatty(STDIN_FILENO) != 0) || (isatty(STDOUT_FILENO) != 0);
// first fork: detach from terminal
pid_t pid = fork();
if (pid < 0) {
std::cerr << "Failed to fork daemon process" << std::endl;
return false;
}
if (pid > 0) _exit(0);
if (setsid() < 0) {
std::cerr << "Failed to create new session" << std::endl;
return false;
}
pid = fork();
if (pid < 0) {
std::cerr << "Failed to fork daemon process (second fork)" << std::endl;
return false;
}
if (pid > 0) _exit(0);
umask(0);
chdir("/");
// redirect file descriptors: keep stdout/stderr if from terminal, else
// redirect to /dev/null
int fd = open("/dev/null", O_RDWR);
if (fd >= 0) {
dup2(fd, STDIN_FILENO);
if (!from_terminal) {
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
}
if (fd > 2) close(fd);
}
// set up signal handlers
signal(SIGTERM, [](int) { stop_requested_ = 1; });
signal(SIGINT, [](int) { stop_requested_ = 1; });
// ignore SIGPIPE
signal(SIGPIPE, SIG_IGN);
running_.store(true);
return runWithRestart(loop);
#endif
}
#ifdef _WIN32
static int RunLoopCatchCpp(Daemon::MainLoopFunc& loop) {
try {
loop();
return 0; // normal exit
} catch (const std::exception& e) {
std::cerr << "Exception caught: " << e.what() << std::endl;
return 1; // c++ exception
} catch (...) {
std::cerr << "Unknown exception caught" << std::endl;
return 1; // other exception
}
}
static int RunLoopWithSEH(Daemon::MainLoopFunc& loop) {
__try {
return RunLoopCatchCpp(loop);
} __except (EXCEPTION_EXECUTE_HANDLER) {
// catch system-level crashes (access violation, divide by zero, etc.)
DWORD code = GetExceptionCode();
std::cerr << "System crash detected (SEH exception code: 0x" << std::hex
<< code << std::dec << ")" << std::endl;
return 2; // System crash
}
}
#endif
// run with restart logic: parent monitors child process and restarts on crash
bool Daemon::runWithRestart(MainLoopFunc loop) {
int restart_count = 0;
std::string exe_path = GetExecutablePath();
if (exe_path.empty()) {
std::cerr
<< "Failed to get executable path, falling back to direct execution"
<< std::endl;
while (isRunning()) {
try {
loop();
break;
} catch (...) {
restart_count++;
std::cerr << "Exception caught, restarting... (attempt "
<< restart_count << ")" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(kRestartDelayMs));
}
}
return true;
}
while (isRunning()) {
#ifdef _WIN32
// windows: use CreateProcess to create child process
STARTUPINFOA si = {sizeof(si)};
PROCESS_INFORMATION pi = {0};
std::string cmd_line = "\"" + exe_path + "\" --child";
std::vector<char> cmd_line_buf(cmd_line.begin(), cmd_line.end());
cmd_line_buf.push_back('\0');
BOOL success = CreateProcessA(
nullptr, // executable file path (specified in command line)
cmd_line_buf.data(), // command line arguments
nullptr, // process security attributes
nullptr, // thread security attributes
FALSE, // don't inherit handles
0, // creation flags
nullptr, // environment variables (inherit from parent)
nullptr, // current directory
&si, // startup info
&pi // process information
);
if (!success) {
std::cerr << "Failed to create child process, error: " << GetLastError()
<< std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(kRestartDelayMs));
restart_count++;
continue;
}
while (isRunning()) {
DWORD wait_result = WaitForSingleObject(pi.hProcess, 200);
if (wait_result == WAIT_OBJECT_0) {
break;
}
if (wait_result == WAIT_FAILED) {
std::cerr << "Failed waiting child process, error: " << GetLastError()
<< std::endl;
break;
}
}
if (!isRunning()) {
TerminateProcess(pi.hProcess, 1);
WaitForSingleObject(pi.hProcess, 3000);
}
DWORD exit_code = 0;
GetExitCodeProcess(pi.hProcess, &exit_code);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
if (!isRunning() || exit_code == 0) {
break; // normal exit
}
restart_count++;
std::cerr << "Child process exited with code " << exit_code
<< ", restarting... (attempt " << restart_count << ")"
<< std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(kRestartDelayMs));
#else
// linux: use fork + exec to create child process
pid_t pid = fork();
if (pid == 0) {
execl(exe_path.c_str(), exe_path.c_str(), "--child", nullptr);
_exit(1); // exec failed
} else if (pid > 0) {
int status = 0;
pid_t waited_pid = -1;
while (isRunning()) {
waited_pid = waitpid(pid, &status, WNOHANG);
if (waited_pid == pid) {
break;
}
if (waited_pid < 0 && errno != EINTR) {
break;
}
std::this_thread::sleep_for(
std::chrono::milliseconds(kWaitPollIntervalMs));
}
if (!isRunning() && waited_pid != pid) {
kill(pid, SIGTERM);
waited_pid = waitpid(pid, &status, 0);
}
if (waited_pid < 0) {
if (!isRunning()) {
break;
}
restart_count++;
std::cerr << "waitpid failed, errno: " << errno
<< ", restarting... (attempt " << restart_count << ")"
<< std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(kRestartDelayMs));
continue;
}
if (WIFEXITED(status)) {
int exit_code = WEXITSTATUS(status);
if (!isRunning() || exit_code == 0) {
break; // normal exit
}
restart_count++;
std::cerr << "Child process exited with code " << exit_code
<< ", restarting... (attempt " << restart_count << ")"
<< std::endl;
} else if (WIFSIGNALED(status)) {
if (!isRunning()) {
break;
}
restart_count++;
std::cerr << "Child process crashed with signal " << WTERMSIG(status)
<< ", restarting... (attempt " << restart_count << ")"
<< std::endl;
} else {
restart_count++;
std::cerr << "Child process exited with unknown status, restarting... "
"(attempt "
<< restart_count << ")" << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(kRestartDelayMs));
} else {
std::cerr << "Failed to fork child process" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(kRestartDelayMs));
restart_count++;
}
#endif
}
return true;
}
+37
View File
@@ -0,0 +1,37 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-11-19
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _DAEMON_H_
#define _DAEMON_H_
#include <atomic>
#include <csignal>
#include <functional>
#include <string>
class Daemon {
public:
using MainLoopFunc = std::function<void()>;
Daemon(const std::string& name);
bool start(MainLoopFunc loop);
void stop();
bool isRunning() const;
private:
std::string name_;
bool runWithRestart(MainLoopFunc loop);
#ifndef _WIN32
static volatile std::sig_atomic_t stop_requested_;
#endif
std::atomic<bool> running_;
};
#endif
+63
View File
@@ -0,0 +1,63 @@
#ifdef _WIN32
#ifdef CROSSDESK_DEBUG
#pragma comment(linker, "/subsystem:\"console\"")
#else
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#endif
#endif
#include <cstring>
#include <memory>
#include <string>
#include "config_center.h"
#include "daemon.h"
#include "path_manager.h"
#include "render.h"
int main(int argc, char* argv[]) {
// check if running as child process
bool is_child = false;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--child") == 0) {
is_child = true;
break;
}
}
if (is_child) {
// child process: run render directly
crossdesk::Render render;
render.Run();
return 0;
}
bool enable_daemon = false;
auto path_manager = std::make_unique<crossdesk::PathManager>("CrossDesk");
if (path_manager) {
std::string cache_path = path_manager->GetCachePath().string();
crossdesk::ConfigCenter config_center(cache_path + "/config.ini");
enable_daemon = config_center.IsEnableDaemon();
}
if (enable_daemon) {
// start daemon with restart monitoring
Daemon daemon("CrossDesk");
// define main loop function: run render and stop daemon on normal exit
Daemon::MainLoopFunc main_loop = [&daemon]() {
crossdesk::Render render;
render.Run();
daemon.stop();
};
// start daemon and return result
bool success = daemon.start(main_loop);
return success ? 0 : 1;
}
// run without daemon: direct execution
crossdesk::Render render;
render.Run();
return 0;
}
+302
View File
@@ -0,0 +1,302 @@
#include "autostart.h"
#include <cstdlib>
#include <filesystem>
#include <fstream>
#ifdef _WIN32
#include <windows.h>
#elif defined(__APPLE__)
#include <limits.h>
#include <mach-o/dyld.h>
#include <unistd.h>
#elif defined(__linux__)
#include <linux/limits.h>
#include <unistd.h>
#endif
namespace crossdesk {
static std::string get_home_dir() {
const char* home = std::getenv("HOME");
if (!home) {
return "";
}
return std::string(home);
}
static bool file_exists(const std::string& path) {
return std::filesystem::exists(path) &&
std::filesystem::is_regular_file(path);
}
static std::string GetExecutablePath() {
#ifdef _WIN32
char path[32768];
DWORD length = GetModuleFileNameA(nullptr, path, sizeof(path));
if (length > 0 && length < sizeof(path)) {
return std::string(path);
}
#elif defined(__APPLE__)
char path[1024];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0) {
char resolved_path[PATH_MAX];
if (realpath(path, resolved_path) != nullptr) {
return std::string(resolved_path);
}
return std::string(path);
}
#elif defined(__linux__)
char path[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", path, sizeof(path) - 1);
if (count != -1) {
path[count] = '\0';
return std::string(path);
}
#endif
return "";
}
// Windows
#ifdef _WIN32
static constexpr const char* WINDOWS_RUN_KEY =
"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
static bool windows_enable(const std::string& appName,
const std::string& exePath) {
if (exePath.empty() || !std::filesystem::exists(exePath)) {
return false;
}
HKEY hKey = nullptr;
// Use KEY_WRITE to ensure we have write permission
LONG result =
RegOpenKeyExA(HKEY_CURRENT_USER, WINDOWS_RUN_KEY, 0, KEY_WRITE, &hKey);
if (result != ERROR_SUCCESS) {
return false;
}
std::string regValue = exePath;
if (!exePath.empty() && exePath.find(' ') != std::string::npos) {
if (exePath.front() != '"' || exePath.back() != '"') {
regValue = "\"" + exePath + "\"";
}
}
// Ensure we close the key even if RegSetValueExA fails
result = RegSetValueExA(hKey, appName.c_str(), 0, REG_SZ,
reinterpret_cast<const BYTE*>(regValue.c_str()),
static_cast<DWORD>(regValue.size() + 1));
RegCloseKey(hKey);
return result == ERROR_SUCCESS;
}
static bool windows_disable(const std::string& appName) {
HKEY hKey = nullptr;
LONG result =
RegOpenKeyExA(HKEY_CURRENT_USER, WINDOWS_RUN_KEY, 0, KEY_WRITE, &hKey);
if (result != ERROR_SUCCESS) {
return false;
}
result = RegDeleteValueA(hKey, appName.c_str());
RegCloseKey(hKey);
// Return true even if the value doesn't exist (already disabled)
return result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND;
}
static bool windows_exists(const std::string& appName) {
HKEY hKey = nullptr;
LONG result =
RegOpenKeyExA(HKEY_CURRENT_USER, WINDOWS_RUN_KEY, 0, KEY_READ, &hKey);
if (result != ERROR_SUCCESS) {
return false;
}
result = RegQueryValueExA(hKey, appName.c_str(), nullptr, nullptr, nullptr,
nullptr);
RegCloseKey(hKey);
return result == ERROR_SUCCESS;
}
#endif
// Linux
#if defined(__linux__)
static std::string linux_desktop_path(const std::string& appName) {
std::string home = get_home_dir();
if (home.empty()) {
return "";
}
return home + "/.config/autostart/" + appName + ".desktop";
}
static bool linux_enable(const std::string& appName,
const std::string& exePath) {
std::string home = get_home_dir();
if (home.empty()) {
return false;
}
std::filesystem::path dir =
std::filesystem::path(home) / ".config" / "autostart";
// Create directory if it doesn't exist
std::error_code ec;
std::filesystem::create_directories(dir, ec);
if (ec) {
return false;
}
std::string path = linux_desktop_path(appName);
if (path.empty()) {
return false;
}
std::ofstream file(path);
if (!file.is_open()) {
return false;
}
file << "[Desktop Entry]\n";
file << "Type=Application\n";
file << "Exec=" << exePath << "\n";
file << "Hidden=false\n";
file << "NoDisplay=false\n";
file << "X-GNOME-Autostart-enabled=true\n";
file << "Terminal=false\n";
file << "StartupNotify=false\n";
file << "Name=" << appName << "\n";
file.close();
return file.good();
}
static bool linux_disable(const std::string& appName) {
std::string path = linux_desktop_path(appName);
if (path.empty()) {
return false;
}
std::error_code ec;
return std::filesystem::remove(path, ec) && !ec;
}
static bool linux_exists(const std::string& appName) {
std::string path = linux_desktop_path(appName);
if (path.empty()) {
return false;
}
return file_exists(path);
}
#endif
// macOS
#ifdef __APPLE__
static std::string mac_plist_path(const std::string& appName) {
std::string home = get_home_dir();
if (home.empty()) {
return "";
}
return home + "/Library/LaunchAgents/" + appName + ".plist";
}
static bool mac_enable(const std::string& appName, const std::string& exePath) {
std::string path = mac_plist_path(appName);
if (path.empty()) {
return false;
}
// Ensure LaunchAgents directory exists
std::filesystem::path dir =
std::filesystem::path(get_home_dir()) / "Library" / "LaunchAgents";
std::error_code ec;
std::filesystem::create_directories(dir, ec);
if (ec) {
return false;
}
std::ofstream file(path);
if (!file.is_open()) {
return false;
}
file << R"(<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>)"
<< appName << R"(</string>
<key>ProgramArguments</key>
<array>
<string>)"
<< exePath << R"(</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>)";
file.close();
return file.good();
}
static bool mac_disable(const std::string& appName) {
std::string path = mac_plist_path(appName);
if (path.empty()) {
return false;
}
std::error_code ec;
return std::filesystem::remove(path, ec) && !ec;
}
static bool mac_exists(const std::string& appName) {
std::string path = mac_plist_path(appName);
if (path.empty()) {
return false;
}
return file_exists(path);
}
#endif
bool EnableAutostart(const std::string& appName) {
std::string exePath = GetExecutablePath();
if (exePath.empty()) {
return false;
}
#ifdef _WIN32
return windows_enable(appName, exePath);
#elif __APPLE__
return mac_enable(appName, exePath);
#else
return linux_enable(appName, exePath);
#endif
}
bool DisableAutostart(const std::string& appName) {
#ifdef _WIN32
return windows_disable(appName);
#elif __APPLE__
return mac_disable(appName);
#else
return linux_disable(appName);
#endif
}
bool IsAutostartEnabled(const std::string& appName) {
#ifdef _WIN32
return windows_exists(appName);
#elif __APPLE__
return mac_exists(appName);
#else
return linux_exists(appName);
#endif
}
} // namespace crossdesk
+21
View File
@@ -0,0 +1,21 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-11-18
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _AUTOSTART_H_
#define _AUTOSTART_H_
#include <string>
namespace crossdesk {
bool EnableAutostart(const std::string& appName);
bool DisableAutostart(const std::string& appName);
bool IsAutostartEnabled(const std::string& appName);
} // namespace crossdesk
#endif
-87
View File
@@ -1,87 +0,0 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-03-14
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _ANY_INVOCABLE_H_
#define _ANY_INVOCABLE_H_
#include <functional>
#include <iostream>
#include <memory>
#include <type_traits>
// 简化版的 AnyInvocable
template <typename Signature>
class AnyInvocable;
template <typename R, typename... Args>
class AnyInvocable<R(Args...)> {
public:
// 默认构造函数
AnyInvocable() = default;
AnyInvocable(std::nullptr_t) noexcept : callable_(nullptr) {}
// 构造函数:接受一个可以调用的对象(排除 nullptr)
template <typename Callable, typename = std::enable_if_t<!std::is_same_v<
std::decay_t<Callable>, std::nullptr_t>>>
AnyInvocable(Callable&& callable)
: callable_(std::make_unique<CallableWrapper<Callable>>(
std::forward<Callable>(callable))) {}
// 调用运算符(支持 void 和非 void 返回类型)
R operator()(Args... args) {
if (!callable_) {
throw std::bad_function_call();
}
if constexpr (std::is_void_v<R>) {
callable_->Invoke(std::forward<Args>(args)...);
} else {
return callable_->Invoke(std::forward<Args>(args)...);
}
}
// 移动构造函数
AnyInvocable(AnyInvocable&&) = default;
// 移动赋值运算符
AnyInvocable& operator=(AnyInvocable&&) = default;
// 判断是否有效
explicit operator bool() const { return static_cast<bool>(callable_); }
private:
// 抽象基类,允许不同类型的可调用对象
struct CallableBase {
virtual ~CallableBase() = default;
virtual R Invoke(Args&&... args) = 0;
};
// 模板派生类:实际存储 callable 对象
template <typename Callable>
struct CallableWrapper : public CallableBase {
CallableWrapper(Callable&& callable)
: callable_(std::forward<Callable>(callable)) {}
R Invoke(Args&&... args) override {
if constexpr (std::is_void_v<R>) {
callable_(std::forward<Args>(args)...);
} else {
return callable_(std::forward<Args>(args)...);
}
}
Callable callable_;
};
std::unique_ptr<CallableBase> callable_;
};
// 简单的包装函数
template <typename R, typename... Args>
AnyInvocable<R(Args...)> MakeMoveOnlyFunction(std::function<R(Args...)>&& f) {
return AnyInvocable<R(Args...)>(std::move(f));
}
#endif // _ANY_INVOCABLE_H_
-319
View File
@@ -1,319 +0,0 @@
/*
* Copyright 2015 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_ARRAY_VIEW_H_
#define API_ARRAY_VIEW_H_
#include <algorithm>
#include <array>
#include <cstddef>
#include <iterator>
#include <type_traits>
#include "rtc_base/type_traits.h"
namespace rtc {
// tl;dr: rtc::ArrayView is the same thing as gsl::span from the Guideline
// Support Library.
//
// Many functions read from or write to arrays. The obvious way to do this is
// to use two arguments, a pointer to the first element and an element count:
//
// bool Contains17(const int* arr, size_t size) {
// for (size_t i = 0; i < size; ++i) {
// if (arr[i] == 17)
// return true;
// }
// return false;
// }
//
// This is flexible, since it doesn't matter how the array is stored (C array,
// std::vector, rtc::Buffer, ...), but it's error-prone because the caller has
// to correctly specify the array length:
//
// Contains17(arr, arraysize(arr)); // C array
// Contains17(arr.data(), arr.size()); // std::vector
// Contains17(arr, size); // pointer + size
// ...
//
// It's also kind of messy to have two separate arguments for what is
// conceptually a single thing.
//
// Enter rtc::ArrayView<T>. It contains a T pointer (to an array it doesn't
// own) and a count, and supports the basic things you'd expect, such as
// indexing and iteration. It allows us to write our function like this:
//
// bool Contains17(rtc::ArrayView<const int> arr) {
// for (auto e : arr) {
// if (e == 17)
// return true;
// }
// return false;
// }
//
// And even better, because a bunch of things will implicitly convert to
// ArrayView, we can call it like this:
//
// Contains17(arr); // C array
// Contains17(arr); // std::vector
// Contains17(rtc::ArrayView<int>(arr, size)); // pointer + size
// Contains17(nullptr); // nullptr -> empty ArrayView
// ...
//
// ArrayView<T> stores both a pointer and a size, but you may also use
// ArrayView<T, N>, which has a size that's fixed at compile time (which means
// it only has to store the pointer).
//
// One important point is that ArrayView<T> and ArrayView<const T> are
// different types, which allow and don't allow mutation of the array elements,
// respectively. The implicit conversions work just like you'd hope, so that
// e.g. vector<int> will convert to either ArrayView<int> or ArrayView<const
// int>, but const vector<int> will convert only to ArrayView<const int>.
// (ArrayView itself can be the source type in such conversions, so
// ArrayView<int> will convert to ArrayView<const int>.)
//
// Note: ArrayView is tiny (just a pointer and a count if variable-sized, just
// a pointer if fix-sized) and trivially copyable, so it's probably cheaper to
// pass it by value than by const reference.
namespace array_view_internal {
// Magic constant for indicating that the size of an ArrayView is variable
// instead of fixed.
enum : std::ptrdiff_t { kArrayViewVarSize = -4711 };
// Base class for ArrayViews of fixed nonzero size.
template <typename T, std::ptrdiff_t Size>
class ArrayViewBase {
static_assert(Size > 0, "ArrayView size must be variable or non-negative");
public:
ArrayViewBase(T* data, size_t /* size */) : data_(data) {}
static constexpr size_t size() { return Size; }
static constexpr bool empty() { return false; }
T* data() const { return data_; }
protected:
static constexpr bool fixed_size() { return true; }
private:
T* data_;
};
// Specialized base class for ArrayViews of fixed zero size.
template <typename T>
class ArrayViewBase<T, 0> {
public:
explicit ArrayViewBase(T* /* data */, size_t /* size */) {}
static constexpr size_t size() { return 0; }
static constexpr bool empty() { return true; }
T* data() const { return nullptr; }
protected:
static constexpr bool fixed_size() { return true; }
};
// Specialized base class for ArrayViews of variable size.
template <typename T>
class ArrayViewBase<T, array_view_internal::kArrayViewVarSize> {
public:
ArrayViewBase(T* data, size_t size)
: data_(size == 0 ? nullptr : data), size_(size) {}
size_t size() const { return size_; }
bool empty() const { return size_ == 0; }
T* data() const { return data_; }
protected:
static constexpr bool fixed_size() { return false; }
private:
T* data_;
size_t size_;
};
} // namespace array_view_internal
template <typename T,
std::ptrdiff_t Size = array_view_internal::kArrayViewVarSize>
class ArrayView final : public array_view_internal::ArrayViewBase<T, Size> {
public:
using value_type = T;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using const_iterator = const T*;
// Construct an ArrayView from a pointer and a length.
template <typename U>
ArrayView(U* data, size_t size)
: array_view_internal::ArrayViewBase<T, Size>::ArrayViewBase(data, size) {
}
// Construct an empty ArrayView. Note that fixed-size ArrayViews of size > 0
// cannot be empty.
ArrayView() : ArrayView(nullptr, 0) {}
ArrayView(std::nullptr_t) // NOLINT
: ArrayView() {}
ArrayView(std::nullptr_t, size_t size)
: ArrayView(static_cast<T*>(nullptr), size) {
static_assert(Size == 0 || Size == array_view_internal::kArrayViewVarSize,
"");
}
// Construct an ArrayView from a C-style array.
template <typename U, size_t N>
ArrayView(U (&array)[N]) // NOLINT
: ArrayView(array, N) {
static_assert(Size == N || Size == array_view_internal::kArrayViewVarSize,
"Array size must match ArrayView size");
}
// (Only if size is fixed.) Construct a fixed size ArrayView<T, N> from a
// non-const std::array instance. For an ArrayView with variable size, the
// used ctor is ArrayView(U& u) instead.
template <typename U, size_t N,
typename std::enable_if<
Size == static_cast<std::ptrdiff_t>(N)>::type* = nullptr>
ArrayView(std::array<U, N>& u) // NOLINT
: ArrayView(u.data(), u.size()) {}
// (Only if size is fixed.) Construct a fixed size ArrayView<T, N> where T is
// const from a const(expr) std::array instance. For an ArrayView with
// variable size, the used ctor is ArrayView(U& u) instead.
template <typename U, size_t N,
typename std::enable_if<
Size == static_cast<std::ptrdiff_t>(N)>::type* = nullptr>
ArrayView(const std::array<U, N>& u) // NOLINT
: ArrayView(u.data(), u.size()) {}
// (Only if size is fixed.) Construct an ArrayView from any type U that has a
// static constexpr size() method whose return value is equal to Size, and a
// data() method whose return value converts implicitly to T*. In particular,
// this means we allow conversion from ArrayView<T, N> to ArrayView<const T,
// N>, but not the other way around. We also don't allow conversion from
// ArrayView<T> to ArrayView<T, N>, or from ArrayView<T, M> to ArrayView<T,
// N> when M != N.
template <typename U, typename std::enable_if<
Size != array_view_internal::kArrayViewVarSize &&
HasDataAndSize<U, T>::value>::type* = nullptr>
ArrayView(U& u) // NOLINT
: ArrayView(u.data(), u.size()) {
static_assert(U::size() == Size, "Sizes must match exactly");
}
template <typename U, typename std::enable_if<
Size != array_view_internal::kArrayViewVarSize &&
HasDataAndSize<U, T>::value>::type* = nullptr>
ArrayView(const U& u) // NOLINT(runtime/explicit)
: ArrayView(u.data(), u.size()) {
static_assert(U::size() == Size, "Sizes must match exactly");
}
// (Only if size is variable.) Construct an ArrayView from any type U that
// has a size() method whose return value converts implicitly to size_t, and
// a data() method whose return value converts implicitly to T*. In
// particular, this means we allow conversion from ArrayView<T> to
// ArrayView<const T>, but not the other way around. Other allowed
// conversions include
// ArrayView<T, N> to ArrayView<T> or ArrayView<const T>,
// std::vector<T> to ArrayView<T> or ArrayView<const T>,
// const std::vector<T> to ArrayView<const T>,
// rtc::Buffer to ArrayView<uint8_t> or ArrayView<const uint8_t>, and
// const rtc::Buffer to ArrayView<const uint8_t>.
template <typename U, typename std::enable_if<
Size == array_view_internal::kArrayViewVarSize &&
HasDataAndSize<U, T>::value>::type* = nullptr>
ArrayView(U& u) // NOLINT
: ArrayView(u.data(), u.size()) {}
template <typename U, typename std::enable_if<
Size == array_view_internal::kArrayViewVarSize &&
HasDataAndSize<U, T>::value>::type* = nullptr>
ArrayView(const U& u) // NOLINT(runtime/explicit)
: ArrayView(u.data(), u.size()) {}
// Indexing and iteration. These allow mutation even if the ArrayView is
// const, because the ArrayView doesn't own the array. (To prevent mutation,
// use a const element type.)
T& operator[](size_t idx) const { return this->data()[idx]; }
T* begin() const { return this->data(); }
T* end() const { return this->data() + this->size(); }
const T* cbegin() const { return this->data(); }
const T* cend() const { return this->data() + this->size(); }
std::reverse_iterator<T*> rbegin() const {
return std::make_reverse_iterator(end());
}
std::reverse_iterator<T*> rend() const {
return std::make_reverse_iterator(begin());
}
std::reverse_iterator<const T*> crbegin() const {
return std::make_reverse_iterator(cend());
}
std::reverse_iterator<const T*> crend() const {
return std::make_reverse_iterator(cbegin());
}
ArrayView<T> subview(size_t offset, size_t size) const {
return offset < this->size()
? ArrayView<T>(this->data() + offset,
std::min(size, this->size() - offset))
: ArrayView<T>();
}
ArrayView<T> subview(size_t offset) const {
return subview(offset, this->size());
}
};
// Comparing two ArrayViews compares their (pointer,size) pairs; it does *not*
// dereference the pointers.
template <typename T, std::ptrdiff_t Size1, std::ptrdiff_t Size2>
bool operator==(const ArrayView<T, Size1>& a, const ArrayView<T, Size2>& b) {
return a.data() == b.data() && a.size() == b.size();
}
template <typename T, std::ptrdiff_t Size1, std::ptrdiff_t Size2>
bool operator!=(const ArrayView<T, Size1>& a, const ArrayView<T, Size2>& b) {
return !(a == b);
}
// Variable-size ArrayViews are the size of two pointers; fixed-size ArrayViews
// are the size of one pointer. (And as a special case, fixed-size ArrayViews
// of size 0 require no storage.)
static_assert(sizeof(ArrayView<int>) == 2 * sizeof(int*), "");
static_assert(sizeof(ArrayView<int, 17>) == sizeof(int*), "");
static_assert(std::is_empty<ArrayView<int, 0>>::value, "");
template <typename T>
inline ArrayView<T> MakeArrayView(T* data, size_t size) {
return ArrayView<T>(data, size);
}
// Only for primitive types that have the same size and aligment.
// Allow reinterpret cast of the array view to another primitive type of the
// same size.
// Template arguments order is (U, T, Size) to allow deduction of the template
// arguments in client calls: reinterpret_array_view<target_type>(array_view).
template <typename U, typename T, std::ptrdiff_t Size>
inline ArrayView<U, Size> reinterpret_array_view(ArrayView<T, Size> view) {
static_assert(sizeof(U) == sizeof(T) && alignof(U) == alignof(T),
"ArrayView reinterpret_cast is only supported for casting "
"between views that represent the same chunk of memory.");
static_assert(
std::is_fundamental<T>::value && std::is_fundamental<U>::value,
"ArrayView reinterpret_cast is only supported for casting between "
"fundamental types.");
return ArrayView<U, Size>(reinterpret_cast<U*>(view.data()), view.size());
}
} // namespace rtc
#endif // API_ARRAY_VIEW_H_
-93
View File
@@ -1,93 +0,0 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/clock/clock.h"
#include "rtc_base/time_utils.h"
namespace webrtc {
namespace {
int64_t NtpOffsetUsCalledOnce() {
constexpr int64_t kNtpJan1970Sec = 2208988800;
int64_t clock_time = rtc::TimeMicros();
int64_t utc_time = rtc::TimeUTCMicros();
return utc_time - clock_time + kNtpJan1970Sec * rtc::kNumMicrosecsPerSec;
}
NtpTime TimeMicrosToNtp(int64_t time_us) {
static int64_t ntp_offset_us = NtpOffsetUsCalledOnce();
int64_t time_ntp_us = time_us + ntp_offset_us;
// Convert seconds to uint32 through uint64 for a well-defined cast.
// A wrap around, which will happen in 2036, is expected for NTP time.
uint32_t ntp_seconds =
static_cast<uint64_t>(time_ntp_us / rtc::kNumMicrosecsPerSec);
// Scale fractions of the second to NTP resolution.
constexpr int64_t kNtpFractionsInSecond = 1LL << 32;
int64_t us_fractions = time_ntp_us % rtc::kNumMicrosecsPerSec;
uint32_t ntp_fractions =
us_fractions * kNtpFractionsInSecond / rtc::kNumMicrosecsPerSec;
return NtpTime(ntp_seconds, ntp_fractions);
}
} // namespace
class WebrtcClock : public Clock {
public:
WebrtcClock(std::shared_ptr<SystemClock> system_clock)
: system_clock_(system_clock) {}
WebrtcClock() = delete;
Timestamp CurrentTime() override {
return Timestamp::Micros(system_clock_->CurrentTimeUs());
}
NtpTime ConvertTimestampToNtpTime(Timestamp timestamp) override {
int64_t time_us = timestamp.us();
constexpr int64_t kNtpJan1970Sec = 2208988800;
int64_t clock_time = system_clock_->CurrentTimeUs();
int64_t utc_time = system_clock_->CurrentUtcTimeUs();
static int64_t ntp_offset_us =
utc_time - clock_time + kNtpJan1970Sec * rtc::kNumMicrosecsPerSec;
int64_t time_ntp_us = time_us + ntp_offset_us;
// Convert seconds to uint32 through uint64 for a well-defined cast.
// A wrap around, which will happen in 2036, is expected for NTP time.
uint32_t ntp_seconds =
static_cast<uint64_t>(time_ntp_us / rtc::kNumMicrosecsPerSec);
// Scale fractions of the second to NTP resolution.
constexpr int64_t kNtpFractionsInSecond = 1LL << 32;
int64_t us_fractions = time_ntp_us % rtc::kNumMicrosecsPerSec;
uint32_t ntp_fractions =
us_fractions * kNtpFractionsInSecond / rtc::kNumMicrosecsPerSec;
return NtpTime(ntp_seconds, ntp_fractions);
}
private:
std::shared_ptr<SystemClock> system_clock_;
};
Clock* Clock::GetWebrtcClock(std::shared_ptr<SystemClock> system_clock) {
static Clock* const clock = new WebrtcClock(system_clock);
return clock;
}
std::shared_ptr<Clock> Clock::GetWebrtcClockShared(
std::shared_ptr<SystemClock> system_clock) {
return std::make_shared<WebrtcClock>(system_clock);
}
} // namespace webrtc
-76
View File
@@ -1,76 +0,0 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef SYSTEM_WRAPPERS_INCLUDE_CLOCK_H_
#define SYSTEM_WRAPPERS_INCLUDE_CLOCK_H_
#include <stdint.h>
#include <atomic>
#include <memory>
#include "api/ntp/ntp_time.h"
#include "api/units/timestamp.h"
#include "clock/system_clock.h"
namespace webrtc {
// January 1970, in NTP seconds.
const uint32_t kNtpJan1970 = 2208988800UL;
// Magic NTP fractional unit.
const double kMagicNtpFractionalUnit = 4.294967296E+9;
// A clock interface that allows reading of absolute and relative timestamps.
class Clock {
public:
virtual ~Clock() {}
// Return a timestamp relative to an unspecified epoch.
virtual Timestamp CurrentTime() = 0;
int64_t TimeInMilliseconds() { return CurrentTime().ms(); }
int64_t TimeInMicroseconds() { return CurrentTime().us(); }
// Retrieve an NTP absolute timestamp (with an epoch of Jan 1, 1900).
NtpTime CurrentNtpTime() { return ConvertTimestampToNtpTime(CurrentTime()); }
int64_t CurrentNtpInMilliseconds() { return CurrentNtpTime().ToMs(); }
// Converts between a relative timestamp returned by this clock, to NTP time.
virtual NtpTime ConvertTimestampToNtpTime(Timestamp timestamp) = 0;
int64_t ConvertTimestampToNtpTimeInMilliseconds(int64_t timestamp_ms) {
return ConvertTimestampToNtpTime(Timestamp::Millis(timestamp_ms)).ToMs();
}
// Converts NtpTime to a Timestamp with UTC epoch.
// A `Minus Infinity` Timestamp is returned if the NtpTime is invalid.
static Timestamp NtpToUtc(NtpTime ntp_time) {
if (!ntp_time.Valid()) {
return Timestamp::MinusInfinity();
}
// Seconds since UTC epoch.
int64_t time = ntp_time.seconds() - kNtpJan1970;
// Microseconds since UTC epoch (not including NTP fraction)
time = time * 1'000'000;
// Fractions part of the NTP time, in microseconds.
int64_t time_fraction =
DivideRoundToNearest(int64_t{ntp_time.fractions()} * 1'000'000,
NtpTime::kFractionsPerSecond);
return Timestamp::Micros(time + time_fraction);
}
// Returns an instance of the real-time system clock implementation.
static Clock* GetWebrtcClock(std::shared_ptr<SystemClock> system_clock);
static std::shared_ptr<Clock> GetWebrtcClockShared(
std::shared_ptr<SystemClock> system_clock);
};
} // namespace webrtc
#endif // SYSTEM_WRAPPERS_INCLUDE_CLOCK_H_
-127
View File
@@ -1,127 +0,0 @@
/*
* Copyright 2016 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_FUNCTION_VIEW_H_
#define API_FUNCTION_VIEW_H_
#include <cstddef>
#include <type_traits>
#include <utility>
// Just like std::function, FunctionView will wrap any callable and hide its
// actual type, exposing only its signature. But unlike std::function,
// FunctionView doesn't own its callable---it just points to it. Thus, it's a
// good choice mainly as a function argument when the callable argument will
// not be called again once the function has returned.
//
// Its constructors are implicit, so that callers won't have to convert lambdas
// and other callables to FunctionView<Blah(Blah, Blah)> explicitly. This is
// safe because FunctionView is only a reference to the real callable.
//
// Example use:
//
// void SomeFunction(rtc::FunctionView<int(int)> index_transform);
// ...
// SomeFunction([](int i) { return 2 * i + 1; });
//
// Note: FunctionView is tiny (essentially just two pointers) and trivially
// copyable, so it's probably cheaper to pass it by value than by const
// reference.
namespace rtc {
template <typename T>
class FunctionView; // Undefined.
template <typename RetT, typename... ArgT>
class FunctionView<RetT(ArgT...)> final {
public:
// Constructor for lambdas and other callables; it accepts every type of
// argument except those noted in its enable_if call.
template <
typename F,
typename std::enable_if<
// Not for function pointers; we have another constructor for that
// below.
!std::is_function<typename std::remove_pointer<
typename std::remove_reference<F>::type>::type>::value &&
// Not for nullptr; we have another constructor for that below.
!std::is_same<std::nullptr_t,
typename std::remove_cv<F>::type>::value &&
// Not for FunctionView objects; we have another constructor for that
// (the implicitly declared copy constructor).
!std::is_same<FunctionView,
typename std::remove_cv<typename std::remove_reference<
F>::type>::type>::value>::type* = nullptr>
FunctionView(F&& f)
: call_(CallVoidPtr<typename std::remove_reference<F>::type>) {
f_.void_ptr = &f;
}
// Constructor that accepts function pointers. If the argument is null, the
// result is an empty FunctionView.
template <
typename F,
typename std::enable_if<std::is_function<typename std::remove_pointer<
typename std::remove_reference<F>::type>::type>::value>::type* =
nullptr>
FunctionView(F&& f)
: call_(f ? CallFunPtr<typename std::remove_pointer<F>::type> : nullptr) {
f_.fun_ptr = reinterpret_cast<void (*)()>(f);
}
// Constructor that accepts nullptr. It creates an empty FunctionView.
template <typename F, typename std::enable_if<std::is_same<
std::nullptr_t, typename std::remove_cv<F>::type>::
value>::type* = nullptr>
FunctionView(F&& /* f */) : call_(nullptr) {}
// Default constructor. Creates an empty FunctionView.
FunctionView() : call_(nullptr) {}
RetT operator()(ArgT... args) const {
return call_(f_, std::forward<ArgT>(args)...);
}
// Returns true if we have a function, false if we don't (i.e., we're null).
explicit operator bool() const { return !!call_; }
private:
union VoidUnion {
void* void_ptr;
void (*fun_ptr)();
};
template <typename F>
static RetT CallVoidPtr(VoidUnion vu, ArgT... args) {
return (*static_cast<F*>(vu.void_ptr))(std::forward<ArgT>(args)...);
}
template <typename F>
static RetT CallFunPtr(VoidUnion vu, ArgT... args) {
return (reinterpret_cast<typename std::add_pointer<F>::type>(vu.fun_ptr))(
std::forward<ArgT>(args)...);
}
// A pointer to the callable thing, with type information erased. It's a
// union because we have to use separate types depending on if the callable
// thing is a function pointer or something else.
VoidUnion f_;
// Pointer to a dispatch function that knows the type of the callable thing
// that's stored in f_, and how to call it. A FunctionView object is empty
// (null) iff call_ is null.
RetT (*call_)(VoidUnion, ArgT...);
};
} // namespace rtc
#endif // API_FUNCTION_VIEW_H_
-42
View File
@@ -1,42 +0,0 @@
/*
* Copyright 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_MEDIA_TYPES_H_
#define API_MEDIA_TYPES_H_
#include <string>
// The cricket and webrtc have separate definitions for what a media type is.
// They're not compatible. Watch out for this.
namespace cricket {
enum MediaType {
MEDIA_TYPE_AUDIO,
MEDIA_TYPE_VIDEO,
MEDIA_TYPE_DATA,
MEDIA_TYPE_UNSUPPORTED
};
extern const char kMediaTypeAudio[];
extern const char kMediaTypeVideo[];
extern const char kMediaTypeData[];
std::string MediaTypeToString(MediaType type);
} // namespace cricket
namespace webrtc {
enum class MediaType { ANY, AUDIO, VIDEO, DATA };
} // namespace webrtc
#endif // API_MEDIA_TYPES_H_
-51
View File
@@ -1,51 +0,0 @@
/*
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_NETWORK_STATE_PREDICTOR_H_
#define API_NETWORK_STATE_PREDICTOR_H_
#include <cstdint>
#include <memory>
#include "api/transport/bandwidth_usage.h"
namespace webrtc {
// TODO(yinwa): work in progress. API in class NetworkStatePredictor should not
// be used by other users until this comment is removed.
// NetworkStatePredictor predict network state based on current network metrics.
// Usage:
// Setup by calling Initialize.
// For each update, call Update. Update returns network state
// prediction.
class NetworkStatePredictor {
public:
virtual ~NetworkStatePredictor() {}
// Returns current network state prediction.
// Inputs: send_time_ms - packet send time.
// arrival_time_ms - packet arrival time.
// network_state - computed network state.
virtual BandwidthUsage Update(int64_t send_time_ms,
int64_t arrival_time_ms,
BandwidthUsage network_state) = 0;
};
class NetworkStatePredictorFactoryInterface {
public:
virtual std::unique_ptr<NetworkStatePredictor>
CreateNetworkStatePredictor() = 0;
virtual ~NetworkStatePredictorFactoryInterface() = default;
};
} // namespace webrtc
#endif // API_NETWORK_STATE_PREDICTOR_H_
-136
View File
@@ -1,136 +0,0 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef SYSTEM_WRAPPERS_INCLUDE_NTP_TIME_H_
#define SYSTEM_WRAPPERS_INCLUDE_NTP_TIME_H_
#include <cmath>
#include <cstdint>
#include <limits>
#include "rtc_base/numerics/safe_conversions.h"
namespace webrtc {
class NtpTime {
public:
static constexpr uint64_t kFractionsPerSecond = 0x100000000;
NtpTime() : value_(0) {}
explicit NtpTime(uint64_t value) : value_(value) {}
NtpTime(uint32_t seconds, uint32_t fractions)
: value_(seconds * kFractionsPerSecond + fractions) {}
NtpTime(const NtpTime&) = default;
NtpTime& operator=(const NtpTime&) = default;
explicit operator uint64_t() const { return value_; }
void Set(uint32_t seconds, uint32_t fractions) {
value_ = seconds * kFractionsPerSecond + fractions;
}
void Reset() { value_ = 0; }
int64_t ToMs() const {
static constexpr double kNtpFracPerMs = 4.294967296E6; // 2^32 / 1000.
const double frac_ms = static_cast<double>(fractions()) / kNtpFracPerMs;
return 1000 * static_cast<int64_t>(seconds()) +
static_cast<int64_t>(frac_ms + 0.5);
}
// NTP standard (RFC1305, section 3.1) explicitly state value 0 is invalid.
bool Valid() const { return value_ != 0; }
uint32_t seconds() const {
return rtc::dchecked_cast<uint32_t>(value_ / kFractionsPerSecond);
}
uint32_t fractions() const {
return rtc::dchecked_cast<uint32_t>(value_ % kFractionsPerSecond);
}
private:
uint64_t value_;
};
inline bool operator==(const NtpTime& n1, const NtpTime& n2) {
return static_cast<uint64_t>(n1) == static_cast<uint64_t>(n2);
}
inline bool operator!=(const NtpTime& n1, const NtpTime& n2) {
return !(n1 == n2);
}
// Converts `int64_t` milliseconds to Q32.32-formatted fixed-point seconds.
// Performs clamping if the result overflows or underflows.
inline int64_t Int64MsToQ32x32(int64_t milliseconds) {
// TODO(bugs.webrtc.org/10893): Change to use `rtc::saturated_cast` once the
// bug has been fixed.
double result =
std::round(milliseconds * (NtpTime::kFractionsPerSecond / 1000.0));
// Explicitly cast values to double to avoid implicit conversion warnings
// The conversion of the std::numeric_limits<int64_t>::max() triggers
// -Wimplicit-int-float-conversion warning in clang 10.0.0 without explicit
// cast
if (result <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
return std::numeric_limits<int64_t>::min();
}
if (result >= static_cast<double>(std::numeric_limits<int64_t>::max())) {
return std::numeric_limits<int64_t>::max();
}
return rtc::dchecked_cast<int64_t>(result);
}
// Converts `int64_t` milliseconds to UQ32.32-formatted fixed-point seconds.
// Performs clamping if the result overflows or underflows.
inline uint64_t Int64MsToUQ32x32(int64_t milliseconds) {
// TODO(bugs.webrtc.org/10893): Change to use `rtc::saturated_cast` once the
// bug has been fixed.
double result =
std::round(milliseconds * (NtpTime::kFractionsPerSecond / 1000.0));
// Explicitly cast values to double to avoid implicit conversion warnings
// The conversion of the std::numeric_limits<int64_t>::max() triggers
// -Wimplicit-int-float-conversion warning in clang 10.0.0 without explicit
// cast
if (result <= static_cast<double>(std::numeric_limits<uint64_t>::min())) {
return std::numeric_limits<uint64_t>::min();
}
if (result >= static_cast<double>(std::numeric_limits<uint64_t>::max())) {
return std::numeric_limits<uint64_t>::max();
}
return rtc::dchecked_cast<uint64_t>(result);
}
// Converts Q32.32-formatted fixed-point seconds to `int64_t` milliseconds.
inline int64_t Q32x32ToInt64Ms(int64_t q32x32) {
return rtc::dchecked_cast<int64_t>(
std::round(q32x32 * (1000.0 / NtpTime::kFractionsPerSecond)));
}
// Converts UQ32.32-formatted fixed-point seconds to `int64_t` milliseconds.
inline int64_t UQ32x32ToInt64Ms(uint64_t q32x32) {
return rtc::dchecked_cast<int64_t>(
std::round(q32x32 * (1000.0 / NtpTime::kFractionsPerSecond)));
}
// Converts UQ32.32-formatted fixed-point seconds to `int64_t` microseconds.
inline int64_t UQ32x32ToInt64Us(uint64_t q32x32) {
return rtc::dchecked_cast<int64_t>(
std::round(q32x32 * (1'000'000.0 / NtpTime::kFractionsPerSecond)));
}
// Converts Q32.32-formatted fixed-point seconds to `int64_t` microseconds.
inline int64_t Q32x32ToInt64Us(int64_t q32x32) {
return rtc::dchecked_cast<int64_t>(
std::round(q32x32 * (1'000'000.0 / NtpTime::kFractionsPerSecond)));
}
} // namespace webrtc
#endif // SYSTEM_WRAPPERS_INCLUDE_NTP_TIME_H_
-59
View File
@@ -1,59 +0,0 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/ntp/ntp_time_util.h"
#include <algorithm>
#include <cstdint>
#include "api/units/time_delta.h"
#include "rtc_base/numerics/divide_round.h"
#include "rtc_base/time_utils.h"
namespace webrtc {
uint32_t SaturatedToCompactNtp(TimeDelta delta) {
constexpr uint32_t kMaxCompactNtp = 0xFFFFFFFF;
constexpr int kCompactNtpInSecond = 0x10000;
if (delta <= TimeDelta::Zero()) return 0;
if (delta.us() >=
kMaxCompactNtp * rtc::kNumMicrosecsPerSec / kCompactNtpInSecond)
return kMaxCompactNtp;
// To convert to compact ntp need to divide by 1e6 to get seconds,
// then multiply by 0x10000 to get the final result.
// To avoid float operations, multiplication and division swapped.
return DivideRoundToNearest(delta.us() * kCompactNtpInSecond,
rtc::kNumMicrosecsPerSec);
}
TimeDelta CompactNtpIntervalToTimeDelta(uint32_t compact_ntp_interval) {
// Convert to 64bit value to avoid multiplication overflow.
int64_t value = int64_t{compact_ntp_interval};
if (compact_ntp_interval > 0x8000'0000) {
value -= (int64_t{1} << 32);
}
// To convert to TimeDelta need to divide by 2^16 to get seconds,
// then multiply by 1'000'000 to get microseconds. To avoid float operations,
// multiplication and division are swapped.
int64_t us = DivideRoundToNearest(value * rtc::kNumMicrosecsPerSec, 1 << 16);
return TimeDelta::Micros(us);
}
TimeDelta CompactNtpRttToTimeDelta(uint32_t compact_ntp_interval) {
static constexpr TimeDelta kMinRtt = TimeDelta::Millis(1);
// Interval to convert expected to be positive, e.g. RTT or delay.
// Because interval can be derived from non-monotonic ntp clock,
// it might become negative that is indistinguishable from very large values.
// Since very large RTT/delay is less likely than non-monotonic ntp clock,
// such value is considered negative and converted to minimum value of 1ms.
// Small RTT value is considered too good to be true and increased to 1ms.
return std::max(CompactNtpIntervalToTimeDelta(compact_ntp_interval), kMinRtt);
}
} // namespace webrtc
-61
View File
@@ -1,61 +0,0 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef MODULES_RTP_RTCP_SOURCE_NTP_TIME_UTIL_H_
#define MODULES_RTP_RTCP_SOURCE_NTP_TIME_UTIL_H_
#include <stdint.h>
#include "api/ntp/ntp_time.h"
#include "api/units/time_delta.h"
#include "rtc_base/numerics/safe_conversions.h"
namespace webrtc {
// Helper function for compact ntp representation:
// RFC 3550, Section 4. Time Format.
// Wallclock time is represented using the timestamp format of
// the Network Time Protocol (NTP).
// ...
// In some fields where a more compact representation is
// appropriate, only the middle 32 bits are used; that is, the low 16
// bits of the integer part and the high 16 bits of the fractional part.
inline uint32_t CompactNtp(NtpTime ntp) {
return (ntp.seconds() << 16) | (ntp.fractions() >> 16);
}
// Converts interval to compact ntp (1/2^16 seconds) resolution.
// Negative values converted to 0, Overlarge values converted to max uint32_t.
uint32_t SaturatedToCompactNtp(TimeDelta delta);
// Convert interval to the NTP time resolution (1/2^32 seconds ~= 0.2 ns).
// For deltas with absolute value larger than 35 minutes result is unspecified.
inline constexpr int64_t ToNtpUnits(TimeDelta delta) {
// For better precision `delta` is taken with best TimeDelta precision (us),
// then multiplaction and conversion to seconds are swapped to avoid float
// arithmetic.
// 2^31 us ~= 35.8 minutes.
return (rtc::saturated_cast<int32_t>(delta.us()) * (int64_t{1} << 32)) /
1'000'000;
}
// Converts interval from compact ntp (1/2^16 seconds) resolution to TimeDelta.
// This interval can be up to ~9.1 hours (2^15 seconds).
// Values close to 2^16 seconds are considered negative.
TimeDelta CompactNtpIntervalToTimeDelta(uint32_t compact_ntp_interval);
// Converts interval from compact ntp (1/2^16 seconds) resolution to TimeDelta.
// This interval can be up to ~9.1 hours (2^15 seconds).
// Values close to 2^16 seconds are considered negative and are converted to
// minimum value of 1ms.
TimeDelta CompactNtpRttToTimeDelta(uint32_t compact_ntp_interval);
} // namespace webrtc
#endif // MODULES_RTP_RTCP_SOURCE_NTP_TIME_UTIL_H_
-67
View File
@@ -1,67 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_REF_COUNT_H_
#define API_REF_COUNT_H_
namespace webrtc {
// Refcounted objects should implement the following informal interface:
//
// void AddRef() const ;
// RefCountReleaseStatus Release() const;
//
// You may access members of a reference-counted object, including the AddRef()
// and Release() methods, only if you already own a reference to it, or if
// you're borrowing someone else's reference. (A newly created object is a
// special case: the reference count is zero on construction, and the code that
// creates the object should immediately call AddRef(), bringing the reference
// count from zero to one, e.g., by constructing an rtc::scoped_refptr).
//
// AddRef() creates a new reference to the object.
//
// Release() releases a reference to the object; the caller now has one less
// reference than before the call. Returns kDroppedLastRef if the number of
// references dropped to zero because of this (in which case the object destroys
// itself). Otherwise, returns kOtherRefsRemained, to signal that at the precise
// time the caller's reference was dropped, other references still remained (but
// if other threads own references, this may of course have changed by the time
// Release() returns).
//
// The caller of Release() must treat it in the same way as a delete operation:
// Regardless of the return value from Release(), the caller mustn't access the
// object. The object might still be alive, due to references held by other
// users of the object, but the object can go away at any time, e.g., as the
// result of another thread calling Release().
//
// Calling AddRef() and Release() manually is discouraged. It's recommended to
// use rtc::scoped_refptr to manage all pointers to reference counted objects.
// Note that rtc::scoped_refptr depends on compile-time duck-typing; formally
// implementing the below RefCountInterface is not required.
enum class RefCountReleaseStatus { kDroppedLastRef, kOtherRefsRemained };
// Interfaces where refcounting is part of the public api should
// inherit this abstract interface. The implementation of these
// methods is usually provided by the RefCountedObject template class,
// applied as a leaf in the inheritance tree.
class RefCountInterface {
public:
virtual void AddRef() const = 0;
virtual RefCountReleaseStatus Release() const = 0;
// Non-public destructor, because Release() has exclusive responsibility for
// destroying the object.
protected:
virtual ~RefCountInterface() {}
};
} // namespace webrtc
#endif // API_REF_COUNT_H_
-107
View File
@@ -1,107 +0,0 @@
/*
* Copyright 2017 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_REF_COUNTED_BASE_H_
#define API_REF_COUNTED_BASE_H_
#include <type_traits>
#include "api/ref_count.h"
#include "rtc_base/ref_counter.h"
namespace webrtc {
class RefCountedBase {
public:
RefCountedBase() = default;
RefCountedBase(const RefCountedBase&) = delete;
RefCountedBase& operator=(const RefCountedBase&) = delete;
void AddRef() const { ref_count_.IncRef(); }
RefCountReleaseStatus Release() const {
const auto status = ref_count_.DecRef();
if (status == RefCountReleaseStatus::kDroppedLastRef) {
delete this;
}
return status;
}
protected:
// Provided for internal webrtc subclasses for corner cases where it's
// necessary to know whether or not a reference is exclusively held.
bool HasOneRef() const { return ref_count_.HasOneRef(); }
virtual ~RefCountedBase() = default;
private:
mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
};
// Template based version of `RefCountedBase` for simple implementations that do
// not need (or want) destruction via virtual destructor or the overhead of a
// vtable.
//
// To use:
// struct MyInt : public rtc::RefCountedNonVirtual<MyInt> {
// int foo_ = 0;
// };
//
// rtc::scoped_refptr<MyInt> my_int(new MyInt());
//
// sizeof(MyInt) on a 32 bit system would then be 8, int + refcount and no
// vtable generated.
template <typename T>
class RefCountedNonVirtual {
public:
RefCountedNonVirtual() = default;
RefCountedNonVirtual(const RefCountedNonVirtual&) = delete;
RefCountedNonVirtual& operator=(const RefCountedNonVirtual&) = delete;
void AddRef() const { ref_count_.IncRef(); }
RefCountReleaseStatus Release() const {
// If you run into this assert, T has virtual methods. There are two
// options:
// 1) The class doesn't actually need virtual methods, the type is complete
// so the virtual attribute(s) can be removed.
// 2) The virtual methods are a part of the design of the class. In this
// case you can consider using `RefCountedBase` instead or alternatively
// use `rtc::RefCountedObject`.
static_assert(!std::is_polymorphic<T>::value,
"T has virtual methods. RefCountedBase is a better fit.");
const auto status = ref_count_.DecRef();
if (status == RefCountReleaseStatus::kDroppedLastRef) {
delete static_cast<const T*>(this);
}
return status;
}
protected:
// Provided for internal webrtc subclasses for corner cases where it's
// necessary to know whether or not a reference is exclusively held.
bool HasOneRef() const { return ref_count_.HasOneRef(); }
~RefCountedNonVirtual() = default;
private:
mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
};
} // namespace webrtc
// Backwards compatibe aliases.
// TODO: https://issues.webrtc.org/42225969 - deprecate and remove.
namespace rtc {
using RefCountedBase = webrtc::RefCountedBase;
template <typename T>
using RefCountedNonVirtual = webrtc::RefCountedNonVirtual<T>;
} // namespace rtc
#endif // API_REF_COUNTED_BASE_H_
-129
View File
@@ -1,129 +0,0 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef _RTP_RTCP_TYPEDEF_H_
#define _RTP_RTCP_TYPEDEF_H_
#include <stddef.h>
#include <array>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <numeric>
#include <optional>
#include <utility>
#include <vector>
#include "api/array_view.h"
#include "api/transport/network_types.h"
#include "api/units/data_rate.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#define RTCP_CNAME_SIZE 256 // RFC 3550 page 44, including null termination
#define IP_PACKET_SIZE 1500 // we assume ethernet
namespace webrtc {
const int kVideoPayloadTypeFrequency = 90000;
// TODO(bugs.webrtc.org/6458): Remove this when all the depending projects are
// updated to correctly set rtp rate for RtcpSender.
const int kBogusRtpRateForAudioRtcp = 8000;
// Minimum RTP header size in bytes.
const uint8_t kRtpHeaderSize = 12;
// This enum must not have any gaps, i.e., all integers between
// kRtpExtensionNone and kRtpExtensionNumberOfExtensions must be valid enum
// entries.
enum RTPExtensionType : int {
kRtpExtensionNone,
kRtpExtensionTransmissionTimeOffset,
kRtpExtensionAudioLevel,
kRtpExtensionCsrcAudioLevel,
kRtpExtensionInbandComfortNoise,
kRtpExtensionAbsoluteSendTime,
kRtpExtensionAbsoluteCaptureTime,
kRtpExtensionVideoRotation,
kRtpExtensionTransportSequenceNumber,
kRtpExtensionTransportSequenceNumber02,
kRtpExtensionPlayoutDelay,
kRtpExtensionVideoContentType,
kRtpExtensionVideoLayersAllocation,
kRtpExtensionVideoTiming,
kRtpExtensionRtpStreamId,
kRtpExtensionRepairedRtpStreamId,
kRtpExtensionMid,
kRtpExtensionGenericFrameDescriptor,
kRtpExtensionGenericFrameDescriptor00 [[deprecated]] =
kRtpExtensionGenericFrameDescriptor,
kRtpExtensionDependencyDescriptor,
kRtpExtensionGenericFrameDescriptor02 [[deprecated]] =
kRtpExtensionDependencyDescriptor,
kRtpExtensionColorSpace,
kRtpExtensionVideoFrameTrackingId,
kRtpExtensionCorruptionDetection,
kRtpExtensionNumberOfExtensions // Must be the last entity in the enum.
};
enum RTCPAppSubTypes { kAppSubtypeBwe = 0x00 };
// TODO(sprang): Make this an enum class once rtcp_receiver has been cleaned up.
enum RTCPPacketType : uint32_t {
kRtcpReport = 0x0001,
kRtcpSr = 0x0002,
kRtcpRr = 0x0004,
kRtcpSdes = 0x0008,
kRtcpBye = 0x0010,
kRtcpPli = 0x0020,
kRtcpNack = 0x0040,
kRtcpFir = 0x0080,
kRtcpTmmbr = 0x0100,
kRtcpTmmbn = 0x0200,
kRtcpSrReq = 0x0400,
kRtcpLossNotification = 0x2000,
kRtcpRemb = 0x10000,
kRtcpTransmissionTimeOffset = 0x20000,
kRtcpXrReceiverReferenceTime = 0x40000,
kRtcpXrDlrrReportBlock = 0x80000,
kRtcpTransportFeedback = 0x100000,
kRtcpXrTargetBitrate = 0x200000,
};
enum class KeyFrameReqMethod : uint8_t {
kNone, // Don't request keyframes.
kPliRtcp, // Request keyframes through Picture Loss Indication.
kFirRtcp // Request keyframes through Full Intra-frame Request.
};
enum RtxMode {
kRtxOff = 0x0,
kRtxRetransmitted = 0x1, // Only send retransmissions over RTX.
kRtxRedundantPayloads = 0x2 // Preventively send redundant payloads
// instead of padding.
};
const size_t kRtxHeaderSize = 2;
// NOTE! `kNumMediaTypes` must be kept in sync with RtpPacketMediaType!
static constexpr size_t kNumMediaTypes = 5;
enum class RtpPacketMediaType : size_t {
kAudio, // Audio media packets.
kVideo, // Video media packets.
kRetransmission, // Retransmisions, sent as response to NACK.
kForwardErrorCorrection, // FEC packets.
kPadding = kNumMediaTypes - 1, // RTX or plain padding sent to maintain BWE.
// Again, don't forget to update `kNumMediaTypes` if you add another value!
};
} // namespace webrtc
#endif // _RTP_RTCP_TYPEDEF_H_
-203
View File
@@ -1,203 +0,0 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Originally these classes are from Chromium.
// http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/ref_counted.h?view=markup
//
// A smart pointer class for reference counted objects. Use this class instead
// of calling AddRef and Release manually on a reference counted object to
// avoid common memory leaks caused by forgetting to Release an object
// reference. Sample usage:
//
// class MyFoo : public RefCounted<MyFoo> {
// ...
// };
//
// void some_function() {
// scoped_refptr<MyFoo> foo = make_ref_counted<MyFoo>();
// foo->Method(param);
// // `foo` is released when this function returns
// }
//
// void some_other_function() {
// scoped_refptr<MyFoo> foo = make_ref_counted<MyFoo>();
// ...
// foo = nullptr; // explicitly releases `foo`
// ...
// if (foo)
// foo->Method(param);
// }
//
// The above examples show how scoped_refptr<T> acts like a pointer to T.
// Given two scoped_refptr<T> classes, it is also possible to exchange
// references between the two objects, like so:
//
// {
// scoped_refptr<MyFoo> a = make_ref_counted<MyFoo>();
// scoped_refptr<MyFoo> b;
//
// b.swap(a);
// // now, `b` references the MyFoo object, and `a` references null.
// }
//
// To make both `a` and `b` in the above example reference the same MyFoo
// object, simply use the assignment operator:
//
// {
// scoped_refptr<MyFoo> a = make_ref_counted<MyFoo>();
// scoped_refptr<MyFoo> b;
//
// b = a;
// // now, `a` and `b` each own a reference to the same MyFoo object.
// }
//
#ifndef API_SCOPED_REFPTR_H_
#define API_SCOPED_REFPTR_H_
#include <cstddef>
#include <memory>
#include <utility>
namespace webrtc {
template <class T>
class scoped_refptr {
public:
using element_type = T;
scoped_refptr() : ptr_(nullptr) {}
scoped_refptr(std::nullptr_t) : ptr_(nullptr) {} // NOLINT(runtime/explicit)
explicit scoped_refptr(T* p) : ptr_(p) {}
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {}
template <typename U>
scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {}
// Move constructors.
scoped_refptr(scoped_refptr<T>&& r) noexcept : ptr_(std::move(r.ptr_)) {}
template <typename U>
scoped_refptr(scoped_refptr<U>&& r) noexcept : ptr_(std::move(r.ptr_)) {}
~scoped_refptr() = default;
T* get() const { return ptr_.get(); }
explicit operator bool() const { return ptr_ != nullptr; }
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_.get(); }
T* release() {
T* retVal = ptr_.get();
ptr_.reset();
return retVal;
}
scoped_refptr<T>& operator=(T* p) {
ptr_.reset(p);
return *this;
}
scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
ptr_ = r.ptr_;
return *this;
}
template <typename U>
scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
ptr_ = r.ptr_;
return *this;
}
scoped_refptr<T>& operator=(scoped_refptr<T>&& r) noexcept {
ptr_ = std::move(r.ptr_);
return *this;
}
template <typename U>
scoped_refptr<T>& operator=(scoped_refptr<U>&& r) noexcept {
ptr_ = std::move(r.ptr_);
return *this;
}
void swap(T** pp) noexcept { std::swap(ptr_, *pp); }
void swap(scoped_refptr<T>& r) noexcept { std::swap(ptr_, r.ptr_); }
protected:
std::shared_ptr<T> ptr_;
};
template <typename T, typename U>
bool operator==(const scoped_refptr<T>& a, const scoped_refptr<U>& b) {
return a.get() == b.get();
}
template <typename T, typename U>
bool operator!=(const scoped_refptr<T>& a, const scoped_refptr<U>& b) {
return !(a == b);
}
template <typename T>
bool operator==(const scoped_refptr<T>& a, std::nullptr_t) {
return a.get() == nullptr;
}
template <typename T>
bool operator!=(const scoped_refptr<T>& a, std::nullptr_t) {
return !(a == nullptr);
}
template <typename T>
bool operator==(std::nullptr_t, const scoped_refptr<T>& a) {
return a.get() == nullptr;
}
template <typename T>
bool operator!=(std::nullptr_t, const scoped_refptr<T>& a) {
return !(a == nullptr);
}
// Comparison with raw pointer.
template <typename T, typename U>
bool operator==(const scoped_refptr<T>& a, const U* b) {
return a.get() == b;
}
template <typename T, typename U>
bool operator!=(const scoped_refptr<T>& a, const U* b) {
return !(a == b);
}
template <typename T, typename U>
bool operator==(const T* a, const scoped_refptr<U>& b) {
return a == b.get();
}
template <typename T, typename U>
bool operator!=(const T* a, const scoped_refptr<U>& b) {
return !(a == b);
}
// Ordered comparison, needed for use as a std::map key.
template <typename T, typename U>
bool operator<(const scoped_refptr<T>& a, const scoped_refptr<U>& b) {
return a.get() < b.get();
}
} // namespace webrtc
namespace rtc {
// Backwards compatible alias.
// TODO: bugs.webrtc.org/42225969 - Deprecate and remove.
using ::webrtc::scoped_refptr;
} // namespace rtc
#endif // API_SCOPED_REFPTR_H_
@@ -1,17 +0,0 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-01-15
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _BANDWIDTH_USAGE_H_
#define _BANDWIDTH_USAGE_H_
enum class BandwidthUsage {
kBwNormal = 0,
kBwUnderusing = 1,
kBwOverusing = 2,
kLast
};
#endif
-42
View File
@@ -1,42 +0,0 @@
/*
* Copyright 2024 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_TRANSPORT_ECN_MARKING_H_
#define API_TRANSPORT_ECN_MARKING_H_
namespace webrtc {
// TODO: bugs.webrtc.org/42225697 - L4S support is slowly being developed.
// Help is appreciated.
// L4S Explicit Congestion Notification (ECN) .
// https://www.rfc-editor.org/rfc/rfc9331.html ECT stands for ECN-Capable
// Transport and CE stands for Congestion Experienced.
// RFC-3168, Section 5
// +-----+-----+
// | ECN FIELD |
// +-----+-----+
// ECT CE [Obsolete] RFC 2481 names for the ECN bits.
// 0 0 Not-ECT
// 0 1 ECT(1)
// 1 0 ECT(0)
// 1 1 CE
enum class EcnMarking {
kNotEct = 0, // Not ECN-Capable Transport
kEct1 = 1, // ECN-Capable Transport
kEct0 = 2, // Not used by L4s (or webrtc.)
kCe = 3, // Congestion experienced
};
} // namespace webrtc
#endif // API_TRANSPORT_ECN_MARKING_H_
-124
View File
@@ -1,124 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_TRANSPORT_NETWORK_CONTROL_H_
#define API_TRANSPORT_NETWORK_CONTROL_H_
#include <memory>
#include <optional>
#include "api/transport/network_types.h"
#include "api/units/data_rate.h"
#include "api/units/time_delta.h"
namespace webrtc {
class TargetTransferRateObserver {
public:
virtual ~TargetTransferRateObserver() = default;
// Called to indicate target transfer rate as well as giving information about
// the current estimate of network parameters.
virtual void OnTargetTransferRate(TargetTransferRate) = 0;
// Called to provide updates to the expected target rate in case it changes
// before the first call to OnTargetTransferRate.
virtual void OnStartRateUpdate(DataRate) {}
};
// Configuration sent to factory create function. The parameters here are
// optional to use for a network controller implementation.
struct NetworkControllerConfig {
explicit NetworkControllerConfig() {}
// The initial constraints to start with, these can be changed at any later
// time by calls to OnTargetRateConstraints. Note that the starting rate
// has to be set initially to provide a starting state for the network
// controller, even though the field is marked as optional.
TargetRateConstraints constraints;
// Initial stream specific configuration, these are changed at any later time
// by calls to OnStreamsConfig.
StreamsConfig stream_based_config;
};
// NetworkControllerInterface is implemented by network controllers. A network
// controller is a class that uses information about network state and traffic
// to estimate network parameters such as round trip time and bandwidth. Network
// controllers does not guarantee thread safety, the interface must be used in a
// non-concurrent fashion.
class NetworkControllerInterface {
public:
virtual ~NetworkControllerInterface() = default;
// Called when network availabilty changes.
virtual NetworkControlUpdate OnNetworkAvailability(NetworkAvailability) = 0;
// Called when the receiving or sending endpoint changes address.
virtual NetworkControlUpdate OnNetworkRouteChange(NetworkRouteChange) = 0;
// Called periodically with a periodicy as specified by
// NetworkControllerFactoryInterface::GetProcessInterval.
virtual NetworkControlUpdate OnProcessInterval(ProcessInterval) = 0;
// Called when remotely calculated bitrate is received.
virtual NetworkControlUpdate OnRemoteBitrateReport(RemoteBitrateReport) = 0;
// Called round trip time has been calculated by protocol specific mechanisms.
virtual NetworkControlUpdate OnRoundTripTimeUpdate(RoundTripTimeUpdate) = 0;
// Called when a packet is sent on the network.
virtual NetworkControlUpdate OnSentPacket(SentPacket) = 0;
// Called when a packet is received from the remote client.
virtual NetworkControlUpdate OnReceivedPacket(ReceivedPacket) = 0;
// Called when the stream specific configuration has been updated.
virtual NetworkControlUpdate OnStreamsConfig(StreamsConfig) = 0;
// Called when target transfer rate constraints has been changed.
virtual NetworkControlUpdate OnTargetRateConstraints(
TargetRateConstraints) = 0;
// Called when a protocol specific calculation of packet loss has been made.
virtual NetworkControlUpdate OnTransportLossReport(TransportLossReport) = 0;
// Called with per packet feedback regarding receive time.
virtual NetworkControlUpdate OnTransportPacketsFeedback(
TransportPacketsFeedback) = 0;
// Called with network state estimate updates.
virtual NetworkControlUpdate OnNetworkStateEstimate(NetworkStateEstimate) = 0;
};
// NetworkControllerFactoryInterface is an interface for creating a network
// controller.
class NetworkControllerFactoryInterface {
public:
virtual ~NetworkControllerFactoryInterface() = default;
// Used to create a new network controller, requires an observer to be
// provided to handle callbacks.
virtual std::unique_ptr<NetworkControllerInterface> Create(
NetworkControllerConfig config) = 0;
// Returns the interval by which the network controller expects
// OnProcessInterval calls.
virtual TimeDelta GetProcessInterval() const = 0;
};
// Under development, subject to change without notice.
class NetworkStateEstimator {
public:
// Gets the current best estimate according to the estimator.
virtual std::optional<NetworkStateEstimate> GetCurrentEstimate() = 0;
// Called with per packet feedback regarding receive time.
// Used when the NetworkStateEstimator runs in the sending endpoint.
virtual void OnTransportPacketsFeedback(const TransportPacketsFeedback&) = 0;
// Called with per packet feedback regarding receive time.
// Used when the NetworkStateEstimator runs in the receiving endpoint.
virtual void OnReceivedPacket(const PacketResult&) {}
// Called when the receiving or sending endpoint changes address.
virtual void OnRouteChange(const NetworkRouteChange&) = 0;
virtual ~NetworkStateEstimator() = default;
};
class NetworkStateEstimatorFactory {
public:
virtual std::unique_ptr<NetworkStateEstimator> Create() = 0;
virtual ~NetworkStateEstimatorFactory() = default;
};
} // namespace webrtc
#endif // API_TRANSPORT_NETWORK_CONTROL_H_
-107
View File
@@ -1,107 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/transport/network_types.h"
#include <algorithm>
#include <vector>
namespace webrtc {
StreamsConfig::StreamsConfig() = default;
StreamsConfig::StreamsConfig(const StreamsConfig&) = default;
StreamsConfig::~StreamsConfig() = default;
TargetRateConstraints::TargetRateConstraints() = default;
TargetRateConstraints::TargetRateConstraints(const TargetRateConstraints&) =
default;
TargetRateConstraints::~TargetRateConstraints() = default;
NetworkRouteChange::NetworkRouteChange() = default;
NetworkRouteChange::NetworkRouteChange(const NetworkRouteChange&) = default;
NetworkRouteChange::~NetworkRouteChange() = default;
PacketResult::PacketResult() = default;
PacketResult::PacketResult(const PacketResult& other) = default;
PacketResult::~PacketResult() = default;
bool PacketResult::ReceiveTimeOrder::operator()(const PacketResult& lhs,
const PacketResult& rhs) {
if (lhs.receive_time != rhs.receive_time)
return lhs.receive_time < rhs.receive_time;
if (lhs.sent_packet.send_time != rhs.sent_packet.send_time)
return lhs.sent_packet.send_time < rhs.sent_packet.send_time;
return lhs.sent_packet.sequence_number < rhs.sent_packet.sequence_number;
}
TransportPacketsFeedback::TransportPacketsFeedback() = default;
TransportPacketsFeedback::TransportPacketsFeedback(
const TransportPacketsFeedback& other) = default;
TransportPacketsFeedback::~TransportPacketsFeedback() = default;
std::vector<PacketResult> TransportPacketsFeedback::ReceivedWithSendInfo()
const {
std::vector<PacketResult> res;
for (const PacketResult& fb : packet_feedbacks) {
if (fb.IsReceived()) {
res.push_back(fb);
}
}
return res;
}
std::vector<PacketResult> TransportPacketsFeedback::LostWithSendInfo() const {
std::vector<PacketResult> res;
for (const PacketResult& fb : packet_feedbacks) {
if (!fb.IsReceived()) {
res.push_back(fb);
}
}
return res;
}
std::vector<PacketResult> TransportPacketsFeedback::PacketsWithFeedback()
const {
return packet_feedbacks;
}
std::vector<PacketResult> TransportPacketsFeedback::SortedByReceiveTime()
const {
std::vector<PacketResult> res;
for (const PacketResult& fb : packet_feedbacks) {
if (fb.IsReceived()) {
res.push_back(fb);
}
}
std::sort(res.begin(), res.end(), PacketResult::ReceiveTimeOrder());
return res;
}
NetworkControlUpdate::NetworkControlUpdate() = default;
NetworkControlUpdate::NetworkControlUpdate(const NetworkControlUpdate&) =
default;
NetworkControlUpdate::~NetworkControlUpdate() = default;
PacedPacketInfo::PacedPacketInfo() = default;
PacedPacketInfo::PacedPacketInfo(int probe_cluster_id,
int probe_cluster_min_probes,
int probe_cluster_min_bytes)
: probe_cluster_id(probe_cluster_id),
probe_cluster_min_probes(probe_cluster_min_probes),
probe_cluster_min_bytes(probe_cluster_min_bytes) {}
bool PacedPacketInfo::operator==(const PacedPacketInfo& rhs) const {
return send_bitrate == rhs.send_bitrate &&
probe_cluster_id == rhs.probe_cluster_id &&
probe_cluster_min_probes == rhs.probe_cluster_min_probes &&
probe_cluster_min_bytes == rhs.probe_cluster_min_bytes;
}
} // namespace webrtc
-292
View File
@@ -1,292 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_TRANSPORT_NETWORK_TYPES_H_
#define API_TRANSPORT_NETWORK_TYPES_H_
#include <stdint.h>
#include <cmath>
#include <optional>
#include <vector>
#include "api/transport/ecn_marking.h"
#include "api/units/data_rate.h"
#include "api/units/data_size.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
namespace webrtc {
// Configuration
// Represents constraints and rates related to the currently enabled streams.
// This is used as input to the congestion controller via the StreamsConfig
// struct.
struct BitrateAllocationLimits {
// The total minimum send bitrate required by all sending streams.
DataRate min_allocatable_rate = DataRate::Zero();
// The total maximum allocatable bitrate for all currently available streams.
DataRate max_allocatable_rate = DataRate::Zero();
// The max bitrate to use for padding. The sum of the per-stream max padding
// rate.
DataRate max_padding_rate = DataRate::Zero();
};
// Use StreamsConfig for information about streams that is required for specific
// adjustments to the algorithms in network controllers. Especially useful
// for experiments.
struct StreamsConfig {
StreamsConfig();
StreamsConfig(const StreamsConfig&);
~StreamsConfig();
Timestamp at_time = Timestamp::PlusInfinity();
std::optional<bool> requests_alr_probing;
// If `enable_repeated_initial_probing` is set to true, Probes are sent
// periodically every 1s during the first 5s after the network becomes
// available. The probes ignores max_total_allocated_bitrate.
std::optional<bool> enable_repeated_initial_probing;
std::optional<double> pacing_factor;
// TODO(srte): Use BitrateAllocationLimits here.
std::optional<DataRate> min_total_allocated_bitrate;
std::optional<DataRate> max_padding_rate;
std::optional<DataRate> max_total_allocated_bitrate;
};
struct TargetRateConstraints {
TargetRateConstraints();
TargetRateConstraints(const TargetRateConstraints&);
~TargetRateConstraints();
Timestamp at_time = Timestamp::PlusInfinity();
std::optional<DataRate> min_data_rate;
std::optional<DataRate> max_data_rate;
// The initial bandwidth estimate to base target rate on. This should be used
// as the basis for initial OnTargetTransferRate and OnPacerConfig callbacks.
std::optional<DataRate> starting_rate;
};
// Send side information
struct NetworkAvailability {
Timestamp at_time = Timestamp::PlusInfinity();
bool network_available = false;
};
struct NetworkRouteChange {
NetworkRouteChange();
NetworkRouteChange(const NetworkRouteChange&);
~NetworkRouteChange();
Timestamp at_time = Timestamp::PlusInfinity();
// The TargetRateConstraints are set here so they can be changed synchronously
// when network route changes.
TargetRateConstraints constraints;
};
struct PacedPacketInfo {
PacedPacketInfo();
PacedPacketInfo(int probe_cluster_id, int probe_cluster_min_probes,
int probe_cluster_min_bytes);
bool operator==(const PacedPacketInfo& rhs) const;
// TODO(srte): Move probing info to a separate, optional struct.
static constexpr int kNotAProbe = -1;
DataRate send_bitrate = DataRate::BitsPerSec(0);
int probe_cluster_id = kNotAProbe;
int probe_cluster_min_probes = -1;
int probe_cluster_min_bytes = -1;
int probe_cluster_bytes_sent = 0;
};
struct SentPacket {
Timestamp send_time = Timestamp::PlusInfinity();
// Size of packet with overhead up to IP layer.
DataSize size = DataSize::Zero();
// Size of preceeding packets that are not part of feedback.
DataSize prior_unacked_data = DataSize::Zero();
// Probe cluster id and parameters including bitrate, number of packets and
// number of bytes.
PacedPacketInfo pacing_info;
// True if the packet is an audio packet, false for video, padding, RTX etc.
bool audio = false;
// Transport independent sequence number, any tracked packet should have a
// sequence number that is unique over the whole call and increasing by 1 for
// each packet.
int64_t sequence_number;
// Tracked data in flight when the packet was sent, excluding unacked data.
DataSize data_in_flight = DataSize::Zero();
};
struct ReceivedPacket {
Timestamp send_time = Timestamp::MinusInfinity();
Timestamp receive_time = Timestamp::PlusInfinity();
DataSize size = DataSize::Zero();
};
// Transport level feedback
struct RemoteBitrateReport {
Timestamp receive_time = Timestamp::PlusInfinity();
DataRate bandwidth = DataRate::Infinity();
};
struct RoundTripTimeUpdate {
Timestamp receive_time = Timestamp::PlusInfinity();
TimeDelta round_trip_time = TimeDelta::PlusInfinity();
bool smoothed = false;
};
struct TransportLossReport {
Timestamp receive_time = Timestamp::PlusInfinity();
Timestamp start_time = Timestamp::PlusInfinity();
Timestamp end_time = Timestamp::PlusInfinity();
uint64_t packets_lost_delta = 0;
uint64_t packets_received_delta = 0;
};
// Packet level feedback
struct PacketResult {
class ReceiveTimeOrder {
public:
bool operator()(const PacketResult& lhs, const PacketResult& rhs);
};
PacketResult();
PacketResult(const PacketResult&);
~PacketResult();
inline bool IsReceived() const { return !receive_time.IsPlusInfinity(); }
SentPacket sent_packet;
Timestamp receive_time = Timestamp::PlusInfinity();
EcnMarking ecn = EcnMarking::kNotEct;
};
struct TransportPacketsFeedback {
TransportPacketsFeedback();
TransportPacketsFeedback(const TransportPacketsFeedback& other);
~TransportPacketsFeedback();
Timestamp feedback_time = Timestamp::PlusInfinity();
DataSize data_in_flight = DataSize::Zero();
bool transport_supports_ecn = false;
std::vector<PacketResult> packet_feedbacks;
// Arrival times for messages without send time information.
std::vector<Timestamp> sendless_arrival_times;
std::vector<PacketResult> ReceivedWithSendInfo() const;
std::vector<PacketResult> LostWithSendInfo() const;
std::vector<PacketResult> PacketsWithFeedback() const;
std::vector<PacketResult> SortedByReceiveTime() const;
};
// Network estimation
struct NetworkEstimate {
Timestamp at_time = Timestamp::PlusInfinity();
// Deprecated, use TargetTransferRate::target_rate instead.
DataRate bandwidth = DataRate::Infinity();
TimeDelta round_trip_time = TimeDelta::PlusInfinity();
TimeDelta bwe_period = TimeDelta::PlusInfinity();
float loss_rate_ratio = 0;
};
// Network control
struct PacerConfig {
Timestamp at_time = Timestamp::PlusInfinity();
// Pacer should send at most data_window data over time_window duration.
DataSize data_window = DataSize::Infinity();
TimeDelta time_window = TimeDelta::PlusInfinity();
// Pacer should send at least pad_window data over time_window duration.
DataSize pad_window = DataSize::Zero();
DataRate data_rate() const { return data_window / time_window; }
DataRate pad_rate() const { return pad_window / time_window; }
};
struct ProbeClusterConfig {
Timestamp at_time = Timestamp::PlusInfinity();
DataRate target_data_rate = DataRate::Zero();
// Duration of a probe.
TimeDelta target_duration = TimeDelta::Zero();
// Delta time between sent bursts of packets during probe.
TimeDelta min_probe_delta = TimeDelta::Millis(2);
int32_t target_probe_count = 0;
int32_t id = 0;
};
struct TargetTransferRate {
Timestamp at_time = Timestamp::PlusInfinity();
// The estimate on which the target rate is based on.
NetworkEstimate network_estimate;
DataRate target_rate = DataRate::Zero();
DataRate stable_target_rate = DataRate::Zero();
double cwnd_reduce_ratio = 0;
};
// Contains updates of network controller comand state. Using optionals to
// indicate whether a member has been updated. The array of probe clusters
// should be used to send out probes if not empty.
struct NetworkControlUpdate {
NetworkControlUpdate();
NetworkControlUpdate(const NetworkControlUpdate&);
~NetworkControlUpdate();
bool has_updates() const {
return congestion_window.has_value() || pacer_config.has_value() ||
!probe_cluster_configs.empty() || target_rate.has_value();
}
std::optional<DataSize> congestion_window;
std::optional<PacerConfig> pacer_config;
std::vector<ProbeClusterConfig> probe_cluster_configs;
std::optional<TargetTransferRate> target_rate;
};
// Process control
struct ProcessInterval {
Timestamp at_time = Timestamp::PlusInfinity();
std::optional<DataSize> pacer_queue;
};
// Under development, subject to change without notice.
struct NetworkStateEstimate {
double confidence = NAN;
// The time the estimate was received/calculated.
Timestamp update_time = Timestamp::MinusInfinity();
Timestamp last_receive_time = Timestamp::MinusInfinity();
Timestamp last_send_time = Timestamp::MinusInfinity();
// Total estimated link capacity.
DataRate link_capacity = DataRate::MinusInfinity();
// Used as a safe measure of available capacity.
DataRate link_capacity_lower = DataRate::MinusInfinity();
// Used as limit for increasing bitrate.
DataRate link_capacity_upper = DataRate::MinusInfinity();
TimeDelta pre_link_buffer_delay = TimeDelta::MinusInfinity();
TimeDelta post_link_buffer_delay = TimeDelta::MinusInfinity();
TimeDelta propagation_delay = TimeDelta::MinusInfinity();
// Only for debugging
TimeDelta time_delta = TimeDelta::MinusInfinity();
Timestamp last_feed_time = Timestamp::MinusInfinity();
double cross_delay_rate = NAN;
double spike_delay_rate = NAN;
DataRate link_capacity_std_dev = DataRate::MinusInfinity();
DataRate link_capacity_min = DataRate::MinusInfinity();
double cross_traffic_ratio = NAN;
};
} // namespace webrtc
#endif // API_TRANSPORT_NETWORK_TYPES_H_
-30
View File
@@ -1,30 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/units/data_rate.h"
#include <string>
namespace webrtc {
std::string ToString(DataRate value) {
if (value.IsPlusInfinity()) {
return "+inf bps";
} else if (value.IsMinusInfinity()) {
return "-inf bps";
} else {
if (value.bps() == 0 || value.bps() % 1000 != 0) {
return std::to_string(value.bps()) + " bps";
} else {
return std::to_string(value.kbps()) + " kbps";
}
}
}
} // namespace webrtc
-141
View File
@@ -1,141 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_UNITS_DATA_RATE_H_
#define API_UNITS_DATA_RATE_H_
#include <cstdint>
#include <limits>
#include <string>
#include <type_traits>
#include "api/units/data_size.h"
#include "api/units/frequency.h"
#include "api/units/time_delta.h"
#include "unit_base.h"
namespace webrtc {
// DataRate is a class that represents a given data rate. This can be used to
// represent bandwidth, encoding bitrate, etc. The internal storage is bits per
// second (bps).
class DataRate final : public rtc_units_impl::RelativeUnit<DataRate> {
public:
template <typename T>
static constexpr DataRate BitsPerSec(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromValue(value);
}
template <typename T>
static constexpr DataRate BytesPerSec(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(8, value);
}
template <typename T>
static constexpr DataRate KilobitsPerSec(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(1000, value);
}
static constexpr DataRate Infinity() { return PlusInfinity(); }
constexpr DataRate() = default;
template <typename Sink>
friend void AbslStringify(Sink& sink, DataRate value);
template <typename T = int64_t>
constexpr T bps() const {
return ToValue<T>();
}
template <typename T = int64_t>
constexpr T bytes_per_sec() const {
return ToFraction<8, T>();
}
template <typename T = int64_t>
constexpr T kbps() const {
return ToFraction<1000, T>();
}
constexpr int64_t bps_or(int64_t fallback_value) const {
return ToValueOr(fallback_value);
}
constexpr int64_t kbps_or(int64_t fallback_value) const {
return ToFractionOr<1000>(fallback_value);
}
private:
// Bits per second used internally to simplify debugging by making the value
// more recognizable.
friend class rtc_units_impl::UnitBase<DataRate>;
using RelativeUnit::RelativeUnit;
static constexpr bool one_sided = true;
};
namespace data_rate_impl {
inline constexpr int64_t Microbits(const DataSize& size) {
constexpr int64_t kMaxBeforeConversion =
std::numeric_limits<int64_t>::max() / 8000000;
return size.bytes() * 8000000;
}
inline constexpr int64_t MillibytePerSec(const DataRate& size) {
constexpr int64_t kMaxBeforeConversion =
std::numeric_limits<int64_t>::max() / (1000 / 8);
return size.bps() * (1000 / 8);
}
} // namespace data_rate_impl
inline constexpr DataRate operator/(const DataSize size,
const TimeDelta duration) {
return DataRate::BitsPerSec(data_rate_impl::Microbits(size) / duration.us());
}
inline constexpr TimeDelta operator/(const DataSize size, const DataRate rate) {
return TimeDelta::Micros(data_rate_impl::Microbits(size) / rate.bps());
}
inline constexpr DataSize operator*(const DataRate rate,
const TimeDelta duration) {
int64_t microbits = rate.bps() * duration.us();
return DataSize::Bytes((microbits + 4000000) / 8000000);
}
inline constexpr DataSize operator*(const TimeDelta duration,
const DataRate rate) {
return rate * duration;
}
inline constexpr DataSize operator/(const DataRate rate,
const Frequency frequency) {
int64_t millihertz = frequency.millihertz<int64_t>();
// Note that the value is truncated here reather than rounded, potentially
// introducing an error of .5 bytes if rounding were expected.
return DataSize::Bytes(data_rate_impl::MillibytePerSec(rate) / millihertz);
}
inline constexpr Frequency operator/(const DataRate rate, const DataSize size) {
return Frequency::MilliHertz(data_rate_impl::MillibytePerSec(rate) /
size.bytes());
}
inline constexpr DataRate operator*(const DataSize size,
const Frequency frequency) {
int64_t millibits_per_second =
size.bytes() * 8 * frequency.millihertz<int64_t>();
return DataRate::BitsPerSec((millibits_per_second + 500) / 1000);
}
inline constexpr DataRate operator*(const Frequency frequency,
const DataSize size) {
return size * frequency;
}
std::string ToString(DataRate value);
template <typename Sink>
void AbslStringify(Sink& sink, DataRate value) {
sink.Append(ToString(value));
}
} // namespace webrtc
#endif // API_UNITS_DATA_RATE_H_
-26
View File
@@ -1,26 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/units/data_size.h"
#include <string>
namespace webrtc {
std::string ToString(DataSize value) {
if (value.IsPlusInfinity()) {
return "+inf bytes";
} else if (value.IsMinusInfinity()) {
return "-inf bytes";
} else {
return std::to_string(value.bytes()) + " bytes";
}
}
} // namespace webrtc
-60
View File
@@ -1,60 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_UNITS_DATA_SIZE_H_
#define API_UNITS_DATA_SIZE_H_
#include <cstdint>
#include <string>
#include <type_traits>
#include "unit_base.h" // IWYU pragma: export
namespace webrtc {
// DataSize is a class represeting a count of bytes.
class DataSize final : public rtc_units_impl::RelativeUnit<DataSize> {
public:
template <typename T>
static constexpr DataSize Bytes(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromValue(value);
}
static constexpr DataSize Infinity() { return PlusInfinity(); }
constexpr DataSize() = default;
template <typename Sink>
friend void AbslStringify(Sink& sink, DataSize value);
template <typename T = int64_t>
constexpr T bytes() const {
return ToValue<T>();
}
constexpr int64_t bytes_or(int64_t fallback_value) const {
return ToValueOr(fallback_value);
}
private:
friend class rtc_units_impl::UnitBase<DataSize>;
using RelativeUnit::RelativeUnit;
static constexpr bool one_sided = true;
};
std::string ToString(DataSize value);
template <typename Sink>
void AbslStringify(Sink& sink, DataSize value) {
sink.Append(ToString(value));
}
} // namespace webrtc
#endif // API_UNITS_DATA_SIZE_H_
-27
View File
@@ -1,27 +0,0 @@
/*
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "frequency.h"
#include <cstdint>
#include <string>
namespace webrtc {
std::string ToString(Frequency value) {
if (value.IsPlusInfinity()) {
return "+inf Hz";
} else if (value.IsMinusInfinity()) {
return "-inf Hz";
} else if (value.millihertz<int64_t>() % 1000 != 0) {
return std::to_string(value.hertz<double>()) + " Hz";
} else {
return std::to_string(value.hertz<int64_t>()) + " Hz";
}
}
} // namespace webrtc
-89
View File
@@ -1,89 +0,0 @@
/*
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_UNITS_FREQUENCY_H_
#define API_UNITS_FREQUENCY_H_
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <string>
#include <type_traits>
#include "api/units/time_delta.h"
#include "unit_base.h" // IWYU pragma: export
namespace webrtc {
class Frequency final : public rtc_units_impl::RelativeUnit<Frequency> {
public:
template <typename T>
static constexpr Frequency MilliHertz(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromValue(value);
}
template <typename T>
static constexpr Frequency Hertz(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(1'000, value);
}
template <typename T>
static constexpr Frequency KiloHertz(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(1'000'000, value);
}
constexpr Frequency() = default;
template <typename Sink>
friend void AbslStringify(Sink& sink, Frequency value);
template <typename T = int64_t>
constexpr T hertz() const {
return ToFraction<1000, T>();
}
template <typename T = int64_t>
constexpr T millihertz() const {
return ToValue<T>();
}
private:
friend class rtc_units_impl::UnitBase<Frequency>;
using RelativeUnit::RelativeUnit;
static constexpr bool one_sided = true;
};
inline constexpr Frequency operator/(int64_t nominator,
const TimeDelta& interval) {
constexpr int64_t kKiloPerMicro = 1000 * 1000000;
return Frequency::MilliHertz(nominator * kKiloPerMicro / interval.us());
}
inline constexpr TimeDelta operator/(int64_t nominator,
const Frequency& frequency) {
constexpr int64_t kMegaPerMilli = 1000000 * 1000;
return TimeDelta::Micros(nominator * kMegaPerMilli / frequency.millihertz());
}
inline constexpr double operator*(Frequency frequency, TimeDelta time_delta) {
return frequency.hertz<double>() * time_delta.seconds<double>();
}
inline constexpr double operator*(TimeDelta time_delta, Frequency frequency) {
return frequency * time_delta;
}
std::string ToString(Frequency value);
template <typename Sink>
void AbslStringify(Sink& sink, Frequency value) {
sink.Append(ToString(value));
}
} // namespace webrtc
#endif // API_UNITS_FREQUENCY_H_
-32
View File
@@ -1,32 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/units/time_delta.h"
#include <string>
namespace webrtc {
std::string ToString(TimeDelta value) {
if (value.IsPlusInfinity()) {
return "+inf ms";
} else if (value.IsMinusInfinity()) {
return "-inf ms";
} else {
if (value.us() == 0 || (value.us() % 1000) != 0)
return std::to_string(value.us()) + " us";
else if (value.ms() % 1000 != 0)
return std::to_string(value.ms()) + " ms";
else
return std::to_string(value.seconds()) + " s";
}
}
} // namespace webrtc
-104
View File
@@ -1,104 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_UNITS_TIME_DELTA_H_
#define API_UNITS_TIME_DELTA_H_
#include <cstdint>
#include <cstdlib>
#include <string>
#include <type_traits>
#include "unit_base.h" // IWYU pragma: export
namespace webrtc {
// TimeDelta represents the difference between two timestamps. Commonly this can
// be a duration. However since two Timestamps are not guaranteed to have the
// same epoch (they might come from different computers, making exact
// synchronisation infeasible), the duration covered by a TimeDelta can be
// undefined. To simplify usage, it can be constructed and converted to
// different units, specifically seconds (s), milliseconds (ms) and
// microseconds (us).
class TimeDelta final : public rtc_units_impl::RelativeUnit<TimeDelta> {
public:
template <typename T>
static constexpr TimeDelta Minutes(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return Seconds(value * 60);
}
template <typename T>
static constexpr TimeDelta Seconds(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(1'000'000, value);
}
template <typename T>
static constexpr TimeDelta Millis(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(1'000, value);
}
template <typename T>
static constexpr TimeDelta Micros(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromValue(value);
}
constexpr TimeDelta() = default;
template <typename Sink>
friend void AbslStringify(Sink& sink, TimeDelta value);
template <typename T = int64_t>
constexpr T seconds() const {
return ToFraction<1000000, T>();
}
template <typename T = int64_t>
constexpr T ms() const {
return ToFraction<1000, T>();
}
template <typename T = int64_t>
constexpr T us() const {
return ToValue<T>();
}
template <typename T = int64_t>
constexpr T ns() const {
return ToMultiple<1000, T>();
}
constexpr int64_t seconds_or(int64_t fallback_value) const {
return ToFractionOr<1000000>(fallback_value);
}
constexpr int64_t ms_or(int64_t fallback_value) const {
return ToFractionOr<1000>(fallback_value);
}
constexpr int64_t us_or(int64_t fallback_value) const {
return ToValueOr(fallback_value);
}
constexpr TimeDelta Abs() const {
return us() < 0 ? TimeDelta::Micros(-us()) : *this;
}
private:
friend class rtc_units_impl::UnitBase<TimeDelta>;
using RelativeUnit::RelativeUnit;
static constexpr bool one_sided = false;
};
std::string ToString(TimeDelta value);
template <typename Sink>
void AbslStringify(Sink& sink, TimeDelta value) {
sink.Append(ToString(value));
}
} // namespace webrtc
#endif // API_UNITS_TIME_DELTA_H_
-30
View File
@@ -1,30 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/units/timestamp.h"
#include <string>
namespace webrtc {
std::string ToString(Timestamp value) {
if (value.IsPlusInfinity()) {
return "+inf ms";
} else if (value.IsMinusInfinity()) {
return "-inf ms";
} else {
if (value.us() == 0 || (value.us() % 1000) != 0)
return std::to_string(value.us()) + " us";
else if (value.ms() % 1000 != 0)
return std::to_string(value.ms()) + " ms";
else
return std::to_string(value.seconds()) + " s";
}
}
} // namespace webrtc
-120
View File
@@ -1,120 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_UNITS_TIMESTAMP_H_
#define API_UNITS_TIMESTAMP_H_
#include <cstdint>
#include <string>
#include <type_traits>
#include "time_delta.h"
#include "unit_base.h" // IWYU pragma: export
namespace webrtc {
// Timestamp represents the time that has passed since some unspecified epoch.
// The epoch is assumed to be before any represented timestamps, this means that
// negative values are not valid. The most notable feature is that the
// difference of two Timestamps results in a TimeDelta.
class Timestamp final : public rtc_units_impl::UnitBase<Timestamp> {
public:
template <typename T>
static constexpr Timestamp Seconds(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(1'000'000, value);
}
template <typename T>
static constexpr Timestamp Millis(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(1'000, value);
}
template <typename T>
static constexpr Timestamp Micros(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromValue(value);
}
Timestamp() = delete;
template <typename Sink>
friend void AbslStringify(Sink& sink, Timestamp value);
template <typename T = int64_t>
constexpr T seconds() const {
return ToFraction<1000000, T>();
}
template <typename T = int64_t>
constexpr T ms() const {
return ToFraction<1000, T>();
}
template <typename T = int64_t>
constexpr T us() const {
return ToValue<T>();
}
constexpr int64_t seconds_or(int64_t fallback_value) const {
return ToFractionOr<1000000>(fallback_value);
}
constexpr int64_t ms_or(int64_t fallback_value) const {
return ToFractionOr<1000>(fallback_value);
}
constexpr int64_t us_or(int64_t fallback_value) const {
return ToValueOr(fallback_value);
}
constexpr Timestamp operator+(const TimeDelta delta) const {
if (IsPlusInfinity() || delta.IsPlusInfinity()) {
return PlusInfinity();
} else if (IsMinusInfinity() || delta.IsMinusInfinity()) {
return MinusInfinity();
}
return Timestamp::Micros(us() + delta.us());
}
constexpr Timestamp operator-(const TimeDelta delta) const {
if (IsPlusInfinity() || delta.IsMinusInfinity()) {
return PlusInfinity();
} else if (IsMinusInfinity() || delta.IsPlusInfinity()) {
return MinusInfinity();
}
return Timestamp::Micros(us() - delta.us());
}
constexpr TimeDelta operator-(const Timestamp other) const {
if (IsPlusInfinity() || other.IsMinusInfinity()) {
return TimeDelta::PlusInfinity();
} else if (IsMinusInfinity() || other.IsPlusInfinity()) {
return TimeDelta::MinusInfinity();
}
return TimeDelta::Micros(us() - other.us());
}
constexpr Timestamp& operator-=(const TimeDelta delta) {
*this = *this - delta;
return *this;
}
constexpr Timestamp& operator+=(const TimeDelta delta) {
*this = *this + delta;
return *this;
}
private:
friend class rtc_units_impl::UnitBase<Timestamp>;
using UnitBase::UnitBase;
static constexpr bool one_sided = true;
};
std::string ToString(Timestamp value);
template <typename Sink>
void AbslStringify(Sink& sink, Timestamp value) {
sink.Append(ToString(value));
}
} // namespace webrtc
#endif // API_UNITS_TIMESTAMP_H_
-275
View File
@@ -1,275 +0,0 @@
/*
* Copyright 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_UNITS_UNIT_BASE_H_
#define RTC_BASE_UNITS_UNIT_BASE_H_
#include <stdint.h>
#include <algorithm>
#include <cmath>
#include <limits>
#include <type_traits>
#include "rtc_base/numerics/divide_round.h"
#include "rtc_base/numerics/safe_conversions.h"
namespace webrtc {
namespace rtc_units_impl {
// UnitBase is a base class for implementing custom value types with a specific
// unit. It provides type safety and commonly useful operations. The underlying
// storage is always an int64_t, it's up to the unit implementation to choose
// what scale it represents.
//
// It's used like:
// class MyUnit: public UnitBase<MyUnit> {...};
//
// Unit_T is the subclass representing the specific unit.
template <class Unit_T>
class UnitBase {
public:
UnitBase() = delete;
static constexpr Unit_T Zero() { return Unit_T(0); }
static constexpr Unit_T PlusInfinity() { return Unit_T(PlusInfinityVal()); }
static constexpr Unit_T MinusInfinity() { return Unit_T(MinusInfinityVal()); }
constexpr bool IsZero() const { return value_ == 0; }
constexpr bool IsFinite() const { return !IsInfinite(); }
constexpr bool IsInfinite() const {
return value_ == PlusInfinityVal() || value_ == MinusInfinityVal();
}
constexpr bool IsPlusInfinity() const { return value_ == PlusInfinityVal(); }
constexpr bool IsMinusInfinity() const {
return value_ == MinusInfinityVal();
}
constexpr bool operator==(const UnitBase<Unit_T>& other) const {
return value_ == other.value_;
}
constexpr bool operator!=(const UnitBase<Unit_T>& other) const {
return value_ != other.value_;
}
constexpr bool operator<=(const UnitBase<Unit_T>& other) const {
return value_ <= other.value_;
}
constexpr bool operator>=(const UnitBase<Unit_T>& other) const {
return value_ >= other.value_;
}
constexpr bool operator>(const UnitBase<Unit_T>& other) const {
return value_ > other.value_;
}
constexpr bool operator<(const UnitBase<Unit_T>& other) const {
return value_ < other.value_;
}
constexpr Unit_T RoundTo(const Unit_T& resolution) const {
return Unit_T((value_ + resolution.value_ / 2) / resolution.value_) *
resolution.value_;
}
constexpr Unit_T RoundUpTo(const Unit_T& resolution) const {
return Unit_T((value_ + resolution.value_ - 1) / resolution.value_) *
resolution.value_;
}
constexpr Unit_T RoundDownTo(const Unit_T& resolution) const {
return Unit_T(value_ / resolution.value_) * resolution.value_;
}
protected:
template <typename T, typename std::enable_if<
std::is_integral<T>::value>::type* = nullptr>
static constexpr Unit_T FromValue(T value) {
return Unit_T(rtc::dchecked_cast<int64_t>(value));
}
template <typename T, typename std::enable_if<
std::is_floating_point<T>::value>::type* = nullptr>
static constexpr Unit_T FromValue(T value) {
if (value == std::numeric_limits<T>::infinity()) {
return PlusInfinity();
} else if (value == -std::numeric_limits<T>::infinity()) {
return MinusInfinity();
} else {
return FromValue(rtc::dchecked_cast<int64_t>(value));
}
}
template <typename T, typename std::enable_if<
std::is_integral<T>::value>::type* = nullptr>
static constexpr Unit_T FromFraction(int64_t denominator, T value) {
return Unit_T(rtc::dchecked_cast<int64_t>(value * denominator));
}
template <typename T, typename std::enable_if<
std::is_floating_point<T>::value>::type* = nullptr>
static constexpr Unit_T FromFraction(int64_t denominator, T value) {
return FromValue(value * denominator);
}
template <typename T = int64_t>
constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
ToValue() const {
return rtc::dchecked_cast<T>(value_);
}
template <typename T>
constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
ToValue() const {
return IsPlusInfinity() ? std::numeric_limits<T>::infinity()
: IsMinusInfinity() ? -std::numeric_limits<T>::infinity()
: value_;
}
template <typename T>
constexpr T ToValueOr(T fallback_value) const {
return IsFinite() ? value_ : fallback_value;
}
template <int64_t Denominator, typename T = int64_t>
constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
ToFraction() const {
return rtc::dchecked_cast<T>(DivideRoundToNearest(value_, Denominator));
}
template <int64_t Denominator, typename T>
constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
ToFraction() const {
return ToValue<T>() * (1 / static_cast<T>(Denominator));
}
template <int64_t Denominator>
constexpr int64_t ToFractionOr(int64_t fallback_value) const {
return IsFinite() ? DivideRoundToNearest(value_, Denominator)
: fallback_value;
}
template <int64_t Factor, typename T = int64_t>
constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
ToMultiple() const {
return rtc::dchecked_cast<T>(ToValue() * Factor);
}
template <int64_t Factor, typename T>
constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
ToMultiple() const {
return ToValue<T>() * Factor;
}
explicit constexpr UnitBase(int64_t value) : value_(value) {}
private:
template <class RelativeUnit_T>
friend class RelativeUnit;
static inline constexpr int64_t PlusInfinityVal() {
return std::numeric_limits<int64_t>::max();
}
static inline constexpr int64_t MinusInfinityVal() {
return std::numeric_limits<int64_t>::min();
}
constexpr Unit_T& AsSubClassRef() { return static_cast<Unit_T&>(*this); }
constexpr const Unit_T& AsSubClassRef() const {
return static_cast<const Unit_T&>(*this);
}
int64_t value_;
};
// Extends UnitBase to provide operations for relative units, that is, units
// that have a meaningful relation between values such that a += b is a
// sensible thing to do. For a,b <- same unit.
template <class Unit_T>
class RelativeUnit : public UnitBase<Unit_T> {
public:
constexpr Unit_T Clamped(Unit_T min_value, Unit_T max_value) const {
return std::max(min_value,
std::min(UnitBase<Unit_T>::AsSubClassRef(), max_value));
}
constexpr void Clamp(Unit_T min_value, Unit_T max_value) {
*this = Clamped(min_value, max_value);
}
constexpr Unit_T operator+(const Unit_T other) const {
if (this->IsPlusInfinity() || other.IsPlusInfinity()) {
return this->PlusInfinity();
} else if (this->IsMinusInfinity() || other.IsMinusInfinity()) {
return this->MinusInfinity();
}
return UnitBase<Unit_T>::FromValue(this->ToValue() + other.ToValue());
}
constexpr Unit_T operator-(const Unit_T other) const {
if (this->IsPlusInfinity() || other.IsMinusInfinity()) {
return this->PlusInfinity();
} else if (this->IsMinusInfinity() || other.IsPlusInfinity()) {
return this->MinusInfinity();
}
return UnitBase<Unit_T>::FromValue(this->ToValue() - other.ToValue());
}
constexpr Unit_T& operator+=(const Unit_T other) {
*this = *this + other;
return this->AsSubClassRef();
}
constexpr Unit_T& operator-=(const Unit_T other) {
*this = *this - other;
return this->AsSubClassRef();
}
constexpr double operator/(const Unit_T other) const {
return UnitBase<Unit_T>::template ToValue<double>() /
other.template ToValue<double>();
}
template <typename T,
typename std::enable_if_t<std::is_floating_point_v<T>>* = nullptr>
constexpr Unit_T operator/(T scalar) const {
return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() / scalar));
}
template <typename T,
typename std::enable_if_t<std::is_integral_v<T>>* = nullptr>
constexpr Unit_T operator/(T scalar) const {
return UnitBase<Unit_T>::FromValue(this->ToValue() / scalar);
}
constexpr Unit_T operator*(double scalar) const {
return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() * scalar));
}
constexpr Unit_T operator*(int64_t scalar) const {
return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
}
constexpr Unit_T operator*(int32_t scalar) const {
return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
}
constexpr Unit_T operator*(size_t scalar) const {
return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
}
protected:
using UnitBase<Unit_T>::UnitBase;
constexpr RelativeUnit() : UnitBase<Unit_T>(0) {}
};
template <class Unit_T>
inline constexpr Unit_T operator*(double scalar, RelativeUnit<Unit_T> other) {
return other * scalar;
}
template <class Unit_T>
inline constexpr Unit_T operator*(int64_t scalar, RelativeUnit<Unit_T> other) {
return other * scalar;
}
template <class Unit_T>
inline constexpr Unit_T operator*(int32_t scalar, RelativeUnit<Unit_T> other) {
return other * scalar;
}
template <class Unit_T>
inline constexpr Unit_T operator*(size_t scalar, RelativeUnit<Unit_T> other) {
return other * scalar;
}
template <class Unit_T>
inline constexpr Unit_T operator-(RelativeUnit<Unit_T> other) {
if (other.IsPlusInfinity()) return UnitBase<Unit_T>::MinusInfinity();
if (other.IsMinusInfinity()) return UnitBase<Unit_T>::PlusInfinity();
return -1 * other;
}
} // namespace rtc_units_impl
} // namespace webrtc
#endif // RTC_BASE_UNITS_UNIT_BASE_H_
-118
View File
@@ -1,118 +0,0 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/video/video_timing.h"
#include <algorithm>
#include <cstdint>
#include <string>
#include "api/array_view.h"
#include "api/units/time_delta.h"
#include "log.h"
#include "rtc_base/numerics/safe_conversions.h"
namespace webrtc {
uint16_t VideoSendTiming::GetDeltaCappedMs(int64_t base_ms, int64_t time_ms) {
if (time_ms < base_ms) {
LOG_ERROR("Delta {} ms expected to be positive", (time_ms - base_ms));
}
return rtc::saturated_cast<uint16_t>(time_ms - base_ms);
}
uint16_t VideoSendTiming::GetDeltaCappedMs(TimeDelta delta) {
if (delta < TimeDelta::Zero()) {
LOG_ERROR("Delta {} ms expected to be positive", delta.ms());
}
return rtc::saturated_cast<uint16_t>(delta.ms());
}
TimingFrameInfo::TimingFrameInfo()
: rtp_timestamp(0),
capture_time_ms(-1),
encode_start_ms(-1),
encode_finish_ms(-1),
packetization_finish_ms(-1),
pacer_exit_ms(-1),
network_timestamp_ms(-1),
network2_timestamp_ms(-1),
receive_start_ms(-1),
receive_finish_ms(-1),
decode_start_ms(-1),
decode_finish_ms(-1),
render_time_ms(-1),
flags(VideoSendTiming::kNotTriggered) {}
int64_t TimingFrameInfo::EndToEndDelay() const {
return capture_time_ms >= 0 ? decode_finish_ms - capture_time_ms : -1;
}
bool TimingFrameInfo::IsLongerThan(const TimingFrameInfo& other) const {
int64_t other_delay = other.EndToEndDelay();
return other_delay == -1 || EndToEndDelay() > other_delay;
}
bool TimingFrameInfo::operator<(const TimingFrameInfo& other) const {
return other.IsLongerThan(*this);
}
bool TimingFrameInfo::operator<=(const TimingFrameInfo& other) const {
return !IsLongerThan(other);
}
bool TimingFrameInfo::IsOutlier() const {
return !IsInvalid() && (flags & VideoSendTiming::kTriggeredBySize);
}
bool TimingFrameInfo::IsTimerTriggered() const {
return !IsInvalid() && (flags & VideoSendTiming::kTriggeredByTimer);
}
bool TimingFrameInfo::IsInvalid() const {
return flags == VideoSendTiming::kInvalid;
}
std::string TimingFrameInfo::ToString() const {
if (IsInvalid()) {
return "";
}
std::ostringstream oss;
oss << rtp_timestamp << ',' << capture_time_ms << ',' << encode_start_ms
<< ',' << encode_finish_ms << ',' << packetization_finish_ms << ','
<< pacer_exit_ms << ',' << network_timestamp_ms << ','
<< network2_timestamp_ms << ',' << receive_start_ms << ','
<< receive_finish_ms << ',' << decode_start_ms << ',' << decode_finish_ms
<< ',' << render_time_ms << ',' << IsOutlier() << ','
<< IsTimerTriggered();
return oss.str();
}
VideoPlayoutDelay::VideoPlayoutDelay(TimeDelta min, TimeDelta max)
: min_(std::clamp(min, TimeDelta::Zero(), kMax)),
max_(std::clamp(max, min_, kMax)) {
if (!(TimeDelta::Zero() <= min && min <= max && max <= kMax)) {
LOG_ERROR("Invalid video playout delay: [{},{}]. Clamped to [{},{}]", min,
max, this->min(), this->max());
}
}
bool VideoPlayoutDelay::Set(TimeDelta min, TimeDelta max) {
if (TimeDelta::Zero() <= min && min <= max && max <= kMax) {
min_ = min;
max_ = max;
return true;
}
return false;
}
} // namespace webrtc
-149
View File
@@ -1,149 +0,0 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_VIDEO_VIDEO_TIMING_H_
#define API_VIDEO_VIDEO_TIMING_H_
#include <stdint.h>
#include <limits>
#include <string>
#include "api/units/time_delta.h"
namespace webrtc {
// Video timing timestamps in ms counted from capture_time_ms of a frame.
// This structure represents data sent in video-timing RTP header extension.
struct VideoSendTiming {
enum TimingFrameFlags : uint8_t {
kNotTriggered = 0, // Timing info valid, but not to be transmitted.
// Used on send-side only.
kTriggeredByTimer = 1 << 0, // Frame marked for tracing by periodic timer.
kTriggeredBySize = 1 << 1, // Frame marked for tracing due to size.
kInvalid = std::numeric_limits<uint8_t>::max() // Invalid, ignore!
};
// Returns |time_ms - base_ms| capped at max 16-bit value.
// Used to fill this data structure as per
// https://webrtc.org/experiments/rtp-hdrext/video-timing/ extension stores
// 16-bit deltas of timestamps from packet capture time.
static uint16_t GetDeltaCappedMs(int64_t base_ms, int64_t time_ms);
static uint16_t GetDeltaCappedMs(TimeDelta delta);
uint16_t encode_start_delta_ms;
uint16_t encode_finish_delta_ms;
uint16_t packetization_finish_delta_ms;
uint16_t pacer_exit_delta_ms;
uint16_t network_timestamp_delta_ms;
uint16_t network2_timestamp_delta_ms;
uint8_t flags = TimingFrameFlags::kInvalid;
};
// Used to report precise timings of a 'timing frames'. Contains all important
// timestamps for a lifetime of that specific frame. Reported as a string via
// GetStats(). Only frame which took the longest between two GetStats calls is
// reported.
struct TimingFrameInfo {
TimingFrameInfo();
// Returns end-to-end delay of a frame, if sender and receiver timestamps are
// synchronized, -1 otherwise.
int64_t EndToEndDelay() const;
// Returns true if current frame took longer to process than `other` frame.
// If other frame's clocks are not synchronized, current frame is always
// preferred.
bool IsLongerThan(const TimingFrameInfo& other) const;
// Returns true if flags are set to indicate this frame was marked for tracing
// due to the size being outside some limit.
bool IsOutlier() const;
// Returns true if flags are set to indicate this frame was marked fro tracing
// due to cyclic timer.
bool IsTimerTriggered() const;
// Returns true if the timing data is marked as invalid, in which case it
// should be ignored.
bool IsInvalid() const;
std::string ToString() const;
bool operator<(const TimingFrameInfo& other) const;
bool operator<=(const TimingFrameInfo& other) const;
uint32_t rtp_timestamp; // Identifier of a frame.
// All timestamps below are in local monotonous clock of a receiver.
// If sender clock is not yet estimated, sender timestamps
// (capture_time_ms ... pacer_exit_ms) are negative values, still
// relatively correct.
int64_t capture_time_ms; // Captrue time of a frame.
int64_t encode_start_ms; // Encode start time.
int64_t encode_finish_ms; // Encode completion time.
int64_t packetization_finish_ms; // Time when frame was passed to pacer.
int64_t pacer_exit_ms; // Time when last packet was pushed out of pacer.
// Two in-network RTP processor timestamps: meaning is application specific.
int64_t network_timestamp_ms;
int64_t network2_timestamp_ms;
int64_t receive_start_ms; // First received packet time.
int64_t receive_finish_ms; // Last received packet time.
int64_t decode_start_ms; // Decode start time.
int64_t decode_finish_ms; // Decode completion time.
int64_t render_time_ms; // Proposed render time to insure smooth playback.
uint8_t flags; // Flags indicating validity and/or why tracing was triggered.
};
// Minimum and maximum playout delay values from capture to render.
// These are best effort values.
//
// min = max = 0 indicates that the receiver should try and render
// frame as soon as possible.
//
// min = x, max = y indicates that the receiver is free to adapt
// in the range (x, y) based on network jitter.
// This class ensures invariant 0 <= min <= max <= kMax.
class VideoPlayoutDelay {
public:
// Maximum supported value for the delay limit.
static constexpr TimeDelta kMax = TimeDelta::Millis(10) * 0xFFF;
// Creates delay limits that indicates receiver should try to render frame
// as soon as possible.
static VideoPlayoutDelay Minimal() {
return VideoPlayoutDelay(TimeDelta::Zero(), TimeDelta::Zero());
}
// Creates valid, but unspecified limits.
VideoPlayoutDelay() = default;
VideoPlayoutDelay(const VideoPlayoutDelay&) = default;
VideoPlayoutDelay& operator=(const VideoPlayoutDelay&) = default;
VideoPlayoutDelay(TimeDelta min, TimeDelta max);
bool Set(TimeDelta min, TimeDelta max);
TimeDelta min() const { return min_; }
TimeDelta max() const { return max_; }
friend bool operator==(const VideoPlayoutDelay& lhs,
const VideoPlayoutDelay& rhs) {
return lhs.min_ == rhs.min_ && lhs.max_ == rhs.max_;
}
private:
TimeDelta min_ = TimeDelta::Zero();
TimeDelta max_ = kMax;
};
} // namespace webrtc
#endif // API_VIDEO_VIDEO_TIMING_H_
-390
View File
@@ -1,390 +0,0 @@
/*
* @Author: DI JUNKUN
* @Date: 2024-12-18
* Copyright 2018 The WebRTC project authors. All Rights Reserved.
*/
#ifndef _BYTE_IO_H_
#define _BYTE_IO_H_
// This file contains classes for reading and writing integer types from/to
// byte array representations. Signed/unsigned, partial (whole byte) sizes,
// and big/little endian byte order is all supported.
//
// Usage examples:
//
// uint8_t* buffer = ...;
//
// // Read an unsigned 4 byte integer in big endian format
// uint32_t val = ByteReader<uint32_t>::ReadBigEndian(buffer);
//
// // Read a signed 24-bit (3 byte) integer in little endian format
// int32_t val = ByteReader<int32_t, 3>::ReadLittle(buffer);
//
// // Write an unsigned 8 byte integer in little endian format
// ByteWriter<uint64_t>::WriteLittleEndian(buffer, val);
//
// Write an unsigned 40-bit (5 byte) integer in big endian format
// ByteWriter<uint64_t, 5>::WriteBigEndian(buffer, val);
//
// These classes are implemented as recursive templetizations, intended to make
// it easy for the compiler to completely inline the reading/writing.
#include <stdint.h>
#include <limits>
// According to ISO C standard ISO/IEC 9899, section 6.2.6.2 (2), the three
// representations of signed integers allowed are two's complement, one's
// complement and sign/magnitude. We can detect which is used by looking at
// the two last bits of -1, which will be 11 in two's complement, 10 in one's
// complement and 01 in sign/magnitude.
// TODO(sprang): In the unlikely event that we actually need to support a
// platform that doesn't use two's complement, implement conversion to/from
// wire format.
// Assume the if any one signed integer type is two's complement, then all
// other will be too.
static_assert(
(-1 & 0x03) == 0x03,
"Only two's complement representation of signed integers supported.");
// Plain const char* won't work for static_assert, use #define instead.
#define kSizeErrorMsg "Byte size must be less than or equal to data type size."
// Utility class for getting the unsigned equivalent of a signed type.
template <typename T>
struct UnsignedOf;
// Class for reading integers from a sequence of bytes.
// T = type of integer, B = bytes to read, is_signed = true if signed integer.
// If is_signed is true and B < sizeof(T), sign extension might be needed.
template <typename T, unsigned int B = sizeof(T),
bool is_signed = std::numeric_limits<T>::is_signed>
class ByteReader;
// Specialization of ByteReader for unsigned types.
template <typename T, unsigned int B>
class ByteReader<T, B, false> {
public:
static T ReadBigEndian(const uint8_t* data) {
static_assert(B <= sizeof(T), kSizeErrorMsg);
return InternalReadBigEndian(data);
}
static T ReadLittleEndian(const uint8_t* data) {
static_assert(B <= sizeof(T), kSizeErrorMsg);
return InternalReadLittleEndian(data);
}
private:
static T InternalReadBigEndian(const uint8_t* data) {
T val(0);
for (unsigned int i = 0; i < B; ++i)
val |= static_cast<T>(data[i]) << ((B - 1 - i) * 8);
return val;
}
static T InternalReadLittleEndian(const uint8_t* data) {
T val(0);
for (unsigned int i = 0; i < B; ++i)
val |= static_cast<T>(data[i]) << (i * 8);
return val;
}
};
// Specialization of ByteReader for signed types.
template <typename T, unsigned int B>
class ByteReader<T, B, true> {
public:
typedef typename UnsignedOf<T>::Type U;
static T ReadBigEndian(const uint8_t* data) {
U unsigned_val = ByteReader<T, B, false>::ReadBigEndian(data);
if (B < sizeof(T)) unsigned_val = SignExtend(unsigned_val);
return ReinterpretAsSigned(unsigned_val);
}
static T ReadLittleEndian(const uint8_t* data) {
U unsigned_val = ByteReader<T, B, false>::ReadLittleEndian(data);
if (B < sizeof(T)) unsigned_val = SignExtend(unsigned_val);
return ReinterpretAsSigned(unsigned_val);
}
private:
// As a hack to avoid implementation-specific or undefined behavior when
// bit-shifting or casting signed integers, read as a signed equivalent
// instead and convert to signed. This is safe since we have asserted that
// two's complement for is used.
static T ReinterpretAsSigned(U unsigned_val) {
// An unsigned value with only the highest order bit set (ex 0x80).
const U kUnsignedHighestBitMask = static_cast<U>(1)
<< ((sizeof(U) * 8) - 1);
// A signed value with only the highest bit set. Since this is two's
// complement form, we can use the min value from std::numeric_limits.
const T kSignedHighestBitMask = std::numeric_limits<T>::min();
T val;
if ((unsigned_val & kUnsignedHighestBitMask) != 0) {
// Casting is only safe when unsigned value can be represented in the
// signed target type, so mask out highest bit and mask it back manually.
val = static_cast<T>(unsigned_val & ~kUnsignedHighestBitMask);
val |= kSignedHighestBitMask;
} else {
val = static_cast<T>(unsigned_val);
}
return val;
}
// If number of bytes is less than native data type (eg 24 bit, in int32_t),
// and the most significant bit of the actual data is set, we must sign
// extend the remaining byte(s) with ones so that the correct negative
// number is retained.
// Ex: 0x810A0B -> 0xFF810A0B, but 0x710A0B -> 0x00710A0B
static U SignExtend(const U val) {
const uint8_t kMsb = static_cast<uint8_t>(val >> ((B - 1) * 8));
if ((kMsb & 0x80) != 0) {
// Create a mask where all bits used by the B bytes are set to one,
// for instance 0x00FFFFFF for B = 3. Bit-wise invert that mask (to
// (0xFF000000 in the example above) and add it to the input value.
// The "B % sizeof(T)" is a workaround to undefined values warnings for
// B == sizeof(T), in which case this code won't be called anyway.
const U kUsedBitsMask = (1 << ((B % sizeof(T)) * 8)) - 1;
return ~kUsedBitsMask | val;
}
return val;
}
};
// Class for writing integers to a sequence of bytes
// T = type of integer, B = bytes to write
template <typename T, unsigned int B = sizeof(T),
bool is_signed = std::numeric_limits<T>::is_signed>
class ByteWriter;
// Specialization of ByteWriter for unsigned types.
template <typename T, unsigned int B>
class ByteWriter<T, B, false> {
public:
static void WriteBigEndian(uint8_t* data, T val) {
static_assert(B <= sizeof(T), kSizeErrorMsg);
for (unsigned int i = 0; i < B; ++i) {
data[i] = val >> ((B - 1 - i) * 8);
}
}
static void WriteLittleEndian(uint8_t* data, T val) {
static_assert(B <= sizeof(T), kSizeErrorMsg);
for (unsigned int i = 0; i < B; ++i) {
data[i] = val >> (i * 8);
}
}
};
// Specialization of ByteWriter for signed types.
template <typename T, unsigned int B>
class ByteWriter<T, B, true> {
public:
typedef typename UnsignedOf<T>::Type U;
static void WriteBigEndian(uint8_t* data, T val) {
ByteWriter<U, B, false>::WriteBigEndian(data, ReinterpretAsUnsigned(val));
}
static void WriteLittleEndian(uint8_t* data, T val) {
ByteWriter<U, B, false>::WriteLittleEndian(data,
ReinterpretAsUnsigned(val));
}
private:
static U ReinterpretAsUnsigned(T val) {
// According to ISO C standard ISO/IEC 9899, section 6.3.1.3 (1, 2) a
// conversion from signed to unsigned keeps the value if the new type can
// represent it, and otherwise adds one more than the max value of T until
// the value is in range. For two's complement, this fortunately means
// that the bit-wise value will be intact. Thus, since we have asserted that
// two's complement form is actually used, a simple cast is sufficient.
return static_cast<U>(val);
}
};
// ----- Below follows specializations of UnsignedOf utility class -----
template <>
struct UnsignedOf<int8_t> {
typedef uint8_t Type;
};
template <>
struct UnsignedOf<int16_t> {
typedef uint16_t Type;
};
template <>
struct UnsignedOf<int32_t> {
typedef uint32_t Type;
};
template <>
struct UnsignedOf<int64_t> {
typedef uint64_t Type;
};
// ----- Below follows specializations for unsigned, B in { 1, 2, 4, 8 } -----
// TODO(sprang): Check if these actually help or if generic cases will be
// unrolled to and optimized to similar performance.
// Specializations for single bytes
template <typename T>
class ByteReader<T, 1, false> {
public:
static T ReadBigEndian(const uint8_t* data) {
static_assert(sizeof(T) == 1, kSizeErrorMsg);
return data[0];
}
static T ReadLittleEndian(const uint8_t* data) {
static_assert(sizeof(T) == 1, kSizeErrorMsg);
return data[0];
}
};
template <typename T>
class ByteWriter<T, 1, false> {
public:
static void WriteBigEndian(uint8_t* data, T val) {
static_assert(sizeof(T) == 1, kSizeErrorMsg);
data[0] = val;
}
static void WriteLittleEndian(uint8_t* data, T val) {
static_assert(sizeof(T) == 1, kSizeErrorMsg);
data[0] = val;
}
};
// Specializations for two byte words
template <typename T>
class ByteReader<T, 2, false> {
public:
static T ReadBigEndian(const uint8_t* data) {
static_assert(sizeof(T) >= 2, kSizeErrorMsg);
return (data[0] << 8) | data[1];
}
static T ReadLittleEndian(const uint8_t* data) {
static_assert(sizeof(T) >= 2, kSizeErrorMsg);
return data[0] | (data[1] << 8);
}
};
template <typename T>
class ByteWriter<T, 2, false> {
public:
static void WriteBigEndian(uint8_t* data, T val) {
static_assert(sizeof(T) >= 2, kSizeErrorMsg);
data[0] = val >> 8;
data[1] = val;
}
static void WriteLittleEndian(uint8_t* data, T val) {
static_assert(sizeof(T) >= 2, kSizeErrorMsg);
data[0] = val;
data[1] = val >> 8;
}
};
// Specializations for four byte words.
template <typename T>
class ByteReader<T, 4, false> {
public:
static T ReadBigEndian(const uint8_t* data) {
static_assert(sizeof(T) >= 4, kSizeErrorMsg);
return (Get(data, 0) << 24) | (Get(data, 1) << 16) | (Get(data, 2) << 8) |
Get(data, 3);
}
static T ReadLittleEndian(const uint8_t* data) {
static_assert(sizeof(T) >= 4, kSizeErrorMsg);
return Get(data, 0) | (Get(data, 1) << 8) | (Get(data, 2) << 16) |
(Get(data, 3) << 24);
}
private:
inline static T Get(const uint8_t* data, unsigned int index) {
return static_cast<T>(data[index]);
}
};
// Specializations for four byte words.
template <typename T>
class ByteWriter<T, 4, false> {
public:
static void WriteBigEndian(uint8_t* data, T val) {
static_assert(sizeof(T) >= 4, kSizeErrorMsg);
data[0] = val >> 24;
data[1] = val >> 16;
data[2] = val >> 8;
data[3] = val;
}
static void WriteLittleEndian(uint8_t* data, T val) {
static_assert(sizeof(T) >= 4, kSizeErrorMsg);
data[0] = val;
data[1] = val >> 8;
data[2] = val >> 16;
data[3] = val >> 24;
}
};
// Specializations for eight byte words.
template <typename T>
class ByteReader<T, 8, false> {
public:
static T ReadBigEndian(const uint8_t* data) {
static_assert(sizeof(T) >= 8, kSizeErrorMsg);
return (Get(data, 0) << 56) | (Get(data, 1) << 48) | (Get(data, 2) << 40) |
(Get(data, 3) << 32) | (Get(data, 4) << 24) | (Get(data, 5) << 16) |
(Get(data, 6) << 8) | Get(data, 7);
}
static T ReadLittleEndian(const uint8_t* data) {
static_assert(sizeof(T) >= 8, kSizeErrorMsg);
return Get(data, 0) | (Get(data, 1) << 8) | (Get(data, 2) << 16) |
(Get(data, 3) << 24) | (Get(data, 4) << 32) | (Get(data, 5) << 40) |
(Get(data, 6) << 48) | (Get(data, 7) << 56);
}
private:
inline static T Get(const uint8_t* data, unsigned int index) {
return static_cast<T>(data[index]);
}
};
template <typename T>
class ByteWriter<T, 8, false> {
public:
static void WriteBigEndian(uint8_t* data, T val) {
static_assert(sizeof(T) >= 8, kSizeErrorMsg);
data[0] = val >> 56;
data[1] = val >> 48;
data[2] = val >> 40;
data[3] = val >> 32;
data[4] = val >> 24;
data[5] = val >> 16;
data[6] = val >> 8;
data[7] = val;
}
static void WriteLittleEndian(uint8_t* data, T val) {
static_assert(sizeof(T) >= 8, kSizeErrorMsg);
data[0] = val;
data[1] = val >> 8;
data[2] = val >> 16;
data[3] = val >> 24;
data[4] = val >> 32;
data[5] = val >> 40;
data[6] = val >> 48;
data[7] = val >> 56;
}
};
#endif
-140
View File
@@ -1,140 +0,0 @@
#include "system_clock.h"
#include <time.h>
#include <cstdint>
#include <limits>
#if defined(__POSIX__)
#include <sys/time.h>
#endif
#if defined(__APPLE__)
#include <mach/mach_time.h>
#endif
#if defined(_WIN32)
#include <windows.h>
#endif
int64_t SystemClock::ConvertToNtpTime(int64_t time_us) {
constexpr int64_t kMicrosecondsPerSecond = 1000000;
constexpr uint64_t kNtpFractionalUnit = 0x100000000; // 2^32
uint32_t seconds = static_cast<uint32_t>(time_us / kMicrosecondsPerSecond);
uint32_t fractions =
static_cast<uint32_t>((time_us % kMicrosecondsPerSecond) *
kNtpFractionalUnit / kMicrosecondsPerSecond);
return seconds * kNtpFractionalUnit + fractions;
}
int64_t SystemClock::CurrentTimeNs() {
int64_t ticks = -1; // Default to error case
#if defined(__APPLE__)
static mach_timebase_info_data_t timebase;
if (timebase.denom == 0 && mach_timebase_info(&timebase) != KERN_SUCCESS) {
return -1; // Error case for macOS timebase info retrieval
}
ticks = static_cast<int64_t>(mach_absolute_time() * timebase.numer) /
timebase.denom;
#elif defined(__POSIX__)
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
return -1; // Error case for POSIX clock retrieval
}
ticks = static_cast<int64_t>(ts.tv_sec) * kNumNanosecsPerSec +
static_cast<int64_t>(ts.tv_nsec);
#elif defined(_WIN32)
static volatile LONG last_timegettime = 0;
static volatile int64_t num_wrap_timegettime = 0;
volatile LONG* last_timegettime_ptr = &last_timegettime;
DWORD now = timeGetTime();
DWORD old = InterlockedExchange(last_timegettime_ptr, now);
if (now < old) {
// Handle wraparound (when timeGetTime() wraps around after ~49.7 days)
if (old > 0xf0000000 && now < 0x0fffffff) {
num_wrap_timegettime++;
}
}
// Convert milliseconds to nanoseconds and add wraparound offset
ticks = static_cast<int64_t>(now) + (num_wrap_timegettime << 32);
ticks *= 1000000;
#endif
return ticks;
}
int64_t SystemClock::CurrentTime() { return CurrentTimeNs() / 1000LL; }
int64_t SystemClock::CurrentTimeUs() { return CurrentTimeNs() / 1000LL; }
int64_t SystemClock::CurrentTimeMs() { return CurrentTimeNs() / 1000000LL; }
int64_t SystemClock::CurrentNtpTime() {
return ConvertToNtpTime(CurrentTimeNs());
}
int64_t SystemClock::CurrentNtpTimeMs() {
int64_t ntp_ts = ConvertToNtpTime(CurrentTimeNs());
uint32_t seconds = static_cast<uint32_t>(ntp_ts / 1000000000);
uint32_t fractions = static_cast<uint32_t>(ntp_ts % 1000000000);
static constexpr double kNtpFracPerMs = 4.294967296E6; // 2^32 / 1000.
const double frac_ms = static_cast<double>(fractions) / kNtpFracPerMs;
return 1000 * static_cast<int64_t>(seconds) +
static_cast<int64_t>(frac_ms + 0.5);
}
int64_t SystemClock::CurrentUtcTimeNs() {
#if defined(__POSIX__)
struct timeval time;
gettimeofday(&time, nullptr);
return (static_cast<int64_t>(time.tv_sec) * 1000000000 + time.tv_usec * 1000);
#elif defined(_WIN32)
FILETIME file_time;
GetSystemTimeAsFileTime(&file_time);
int64_t file_time_100ns =
((int64_t)file_time.dwHighDateTime << 32) | file_time.dwLowDateTime;
constexpr int64_t kUnixEpochFileTimeOffsetIn100ns = 116444736000000000LL;
return (file_time_100ns - kUnixEpochFileTimeOffsetIn100ns) * 100;
#elif defined(__APPLE__)
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
return -1; // Error case for macOS clock retrieval
}
return static_cast<int64_t>(ts.tv_sec) * 1000000000LL + ts.tv_nsec;
#endif
return 0;
}
int64_t SystemClock::CurrentUtcTimeUs() { return CurrentUtcTimeNs() / 1000LL; }
int64_t SystemClock::CurrentUtcTimeMs() {
return CurrentUtcTimeNs() / 1000000LL;
}
int64_t SystemClock::CurrentUtcTime() {
return CurrentUtcTimeNs() / 1000000000LL;
}
int64_t SystemClock::NtpToUtc(int64_t ntp_time) {
constexpr int64_t kNtpEpochOffset =
2208988800LL; // NTP epoch starts at 1900-01-01, Unix epoch starts at
// 1970-01-01
constexpr int64_t kMicrosecondsPerSecond = 1000000;
constexpr uint64_t kNtpFractionalUnit = 0x100000000; // 2^32
uint32_t seconds = static_cast<uint32_t>(ntp_time / kNtpFractionalUnit);
uint32_t fractions = static_cast<uint32_t>(ntp_time % kNtpFractionalUnit);
int64_t unix_seconds = static_cast<int64_t>(seconds) - kNtpEpochOffset;
int64_t microseconds =
(static_cast<int64_t>(fractions) * kMicrosecondsPerSecond) /
kNtpFractionalUnit;
return unix_seconds * kMicrosecondsPerSecond + microseconds;
}
-40
View File
@@ -1,40 +0,0 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-02-19
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _SYSTEM_CLOCK_H_
#define _SYSTEM_CLOCK_H_
#include <cstdint>
#include <memory>
static const int64_t kNtpEpochOffset = 2208988800LL;
class SystemClock {
public:
SystemClock() = default;
~SystemClock() = default;
int64_t CurrentTime();
int64_t CurrentTimeUs();
int64_t CurrentTimeMs();
int64_t CurrentTimeNs();
int64_t CurrentNtpTime();
int64_t CurrentNtpTimeMs();
int64_t CurrentUtcTime();
int64_t CurrentUtcTimeMs();
int64_t CurrentUtcTimeUs();
int64_t CurrentUtcTimeNs();
int64_t ConvertToNtpTime(int64_t time_us);
int64_t NtpToUtc(int64_t ntp_time);
int64_t CurrentNtpInMilliseconds() { return CurrentNtpTimeMs(); }
};
#endif
-6
View File
@@ -1,6 +0,0 @@
#include "common.h"
int CommonDummy()
{
return 0;
}
-88
View File
@@ -1,88 +0,0 @@
#ifndef _COMMON_H_
#define _COMMON_H_
#include <iostream>
#include <mutex>
#include <random>
#include <unordered_set>
int CommonDummy();
constexpr size_t HASH_STRING_PIECE(const char *string_piece) {
std::size_t result = 0;
while (*string_piece) {
result = (result * 131) + *string_piece++;
}
return result;
}
constexpr size_t operator"" _H(const char *string_piece, size_t) {
return HASH_STRING_PIECE(string_piece);
}
inline const std::string GetIceUsername(const std::string &sdp) {
std::string result = "";
std::string start = "ice-ufrag:";
std::string end = "\r\n";
size_t startPos = sdp.find(start);
size_t endPos = sdp.find(end);
if (startPos != std::string::npos && endPos != std::string::npos) {
result = sdp.substr(startPos + start.length(),
endPos - startPos - start.length());
}
return result;
}
// SSRCManager is used to manage the SSRCs that have been used.
class SSRCManager {
public:
static SSRCManager &Instance() {
static SSRCManager instance;
return instance;
}
void AddSsrc(uint32_t ssrc) {
std::lock_guard<std::mutex> lock(mutex_);
ssrcs_.insert(ssrc);
}
void DeleteSsrc(uint32_t ssrc) {
std::lock_guard<std::mutex> lock(mutex_);
ssrcs_.erase(ssrc);
}
bool Contains(uint32_t ssrc) {
std::lock_guard<std::mutex> lock(mutex_);
return ssrcs_.count(ssrc) > 0;
}
private:
SSRCManager() = default;
~SSRCManager() = default;
SSRCManager(const SSRCManager &) = delete;
SSRCManager &operator=(const SSRCManager &) = delete;
std::unordered_set<uint32_t> ssrcs_;
std::mutex mutex_;
};
inline uint32_t GenerateRandomSSRC() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<uint32_t> dis(1, 0xFFFFFFFF);
return dis(gen);
}
inline uint32_t GenerateUniqueSsrc() {
uint32_t new_ssrc;
do {
new_ssrc = GenerateRandomSSRC();
} while (SSRCManager::Instance().Contains(new_ssrc));
SSRCManager::Instance().AddSsrc(new_ssrc);
return new_ssrc;
}
#endif
-58
View File
@@ -1,58 +0,0 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-01-22
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _COPY_ON_WRITE_BUFFER_H_
#define _COPY_ON_WRITE_BUFFER_H_
#include <memory>
#include <vector>
class CopyOnWriteBuffer {
public:
CopyOnWriteBuffer() = default;
CopyOnWriteBuffer(size_t size) {
buffer_ = std::make_shared<std::vector<uint8_t>>(size);
}
CopyOnWriteBuffer(const uint8_t* data, size_t size) {
buffer_ = std::make_shared<std::vector<uint8_t>>(data, data + size);
}
CopyOnWriteBuffer(const CopyOnWriteBuffer& other) = default;
CopyOnWriteBuffer(CopyOnWriteBuffer&& other) noexcept = default;
CopyOnWriteBuffer& operator=(const CopyOnWriteBuffer& other) = default;
CopyOnWriteBuffer& operator=(CopyOnWriteBuffer&& other) noexcept = default;
void SetData(const uint8_t* data, size_t size) {
buffer_ = std::make_shared<std::vector<uint8_t>>(data, data + size);
}
void InsertDataAt(size_t offset, const uint8_t* data, size_t size) {
EnsureUnique();
buffer_->insert(buffer_->begin() + offset, data, data + size);
}
const uint8_t* data() const { return buffer_ ? buffer_->data() : nullptr; }
size_t size() const { return buffer_ ? buffer_->size() : 0; }
uint8_t& operator[](size_t index) {
EnsureUnique();
return (*buffer_)[index];
}
const uint8_t& operator[](size_t index) const { return (*buffer_)[index]; }
private:
void EnsureUnique() {
if (buffer_.use_count() != 1) {
buffer_ = std::make_shared<std::vector<uint8_t>>(*buffer_);
}
}
std::shared_ptr<std::vector<uint8_t>> buffer_;
};
#endif
+46
View File
@@ -0,0 +1,46 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-05-15
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _DISPLAY_INFO_H_
#define _DISPLAY_INFO_H_
#include <string>
namespace crossdesk {
class DisplayInfo {
public:
DisplayInfo(std::string name, int left, int top, int right, int bottom)
: name(name), left(left), top(top), right(right), bottom(bottom) {
width = right - left;
height = bottom - top;
}
DisplayInfo(void* handle, std::string name, bool is_primary, int left,
int top, int right, int bottom)
: handle(handle),
name(name),
is_primary(is_primary),
left(left),
top(top),
right(right),
bottom(bottom) {
width = right - left;
height = bottom - top;
}
~DisplayInfo() {}
void* handle = nullptr;
std::string name = "";
bool is_primary = false;
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
int width = 0;
int height = 0;
};
} // namespace crossdesk
#endif
-65
View File
@@ -1,65 +0,0 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-03-12
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _INLINED_VECTOR_H_
#define _INLINED_VECTOR_H_
#include <array>
#include <initializer_list>
#include <iostream>
#include <vector>
template <typename T, size_t N>
class InlinedVector {
public:
InlinedVector() : size_(0), use_heap_(false) {}
void push_back(const T& value) {
if (!use_heap_ && size_ < N) {
stack_data_[size_] = value;
} else {
if (!use_heap_) {
heap_data_.reserve(N * 2);
for (size_t i = 0; i < size_; ++i) {
heap_data_.push_back(stack_data_[i]);
}
use_heap_ = true;
}
heap_data_.push_back(value);
}
++size_;
}
void assign(size_t n, const T& value) {
clear();
for (size_t i = 0; i < n; ++i) {
push_back(value);
}
}
size_t size() const { return size_; }
T& operator[](size_t index) {
return use_heap_ ? heap_data_[index] : stack_data_[index];
}
const T& operator[](size_t index) const {
return use_heap_ ? heap_data_[index] : stack_data_[index];
}
private:
void clear() {
size_ = 0;
use_heap_ = false;
heap_data_.clear();
}
size_t size_;
bool use_heap_;
std::array<T, N> stack_data_;
std::vector<T> heap_data_;
};
#endif // _INLINED_VECTOR_H_
-36
View File
@@ -1,36 +0,0 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-01-14
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _LIMITS_BASE_H_
#define _LIMITS_BASE_H_
#include <limits>
template <typename T>
bool IsInfinite(const T& value) {
return value == std::numeric_limits<T>::min() ||
value == std::numeric_limits<T>::max();
}
template <typename T>
bool IsFinite(const T& value) {
return !IsInfinite(value);
}
template <typename T>
bool IsPlusFinite(const T& value) {
return value == std::numeric_limits<T>::max();
}
template <typename T>
bool IsMinusFinite(const T& value) {
return value == std::numeric_limits<T>::min();
}
#define INT64_T_MAX std::numeric_limits<int64_t>::max()
#define INT64_T_MIN std::numeric_limits<int64_t>::min()
#endif
-130
View File
@@ -1,130 +0,0 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-01-08
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _MOD_OPS_H_
#define _MOD_OPS_H_
#include <algorithm>
#include <type_traits>
template <unsigned long M> // NOLINT
inline unsigned long Add(unsigned long a, unsigned long b) { // NOLINT
// RTC_DCHECK_LT(a, M);
unsigned long t = M - b % M; // NOLINT
unsigned long res = a - t; // NOLINT
if (t > a) return res + M;
return res;
}
template <unsigned long M> // NOLINT
inline unsigned long Subtract(unsigned long a, unsigned long b) { // NOLINT
// RTC_DCHECK_LT(a, M);
unsigned long sub = b % M; // NOLINT
if (a < sub) return M - (sub - a);
return a - sub;
}
// Calculates the forward difference between two wrapping numbers.
//
// Example:
// uint8_t x = 253;
// uint8_t y = 2;
//
// ForwardDiff(x, y) == 5
//
// 252 253 254 255 0 1 2 3
// #################################################
// | | x | | | | | y | |
// #################################################
// |----->----->----->----->----->
//
// ForwardDiff(y, x) == 251
//
// 252 253 254 255 0 1 2 3
// #################################################
// | | x | | | | | y | |
// #################################################
// -->-----> |----->---
//
// If M > 0 then wrapping occurs at M, if M == 0 then wrapping occurs at the
// largest value representable by T.
template <typename T, T M>
inline typename std::enable_if<(M > 0), T>::type ForwardDiff(T a, T b) {
static_assert(std::is_unsigned<T>::value,
"Type must be an unsigned integer.");
// RTC_DCHECK_LT(a, M);
// RTC_DCHECK_LT(b, M);
return a <= b ? b - a : M - (a - b);
}
template <typename T, T M>
inline typename std::enable_if<(M == 0), T>::type ForwardDiff(T a, T b) {
static_assert(std::is_unsigned<T>::value,
"Type must be an unsigned integer.");
return b - a;
}
template <typename T>
inline T ForwardDiff(T a, T b) {
return ForwardDiff<T, 0>(a, b);
}
// Calculates the reverse difference between two wrapping numbers.
//
// Example:
// uint8_t x = 253;
// uint8_t y = 2;
//
// ReverseDiff(y, x) == 5
//
// 252 253 254 255 0 1 2 3
// #################################################
// | | x | | | | | y | |
// #################################################
// <-----<-----<-----<-----<-----|
//
// ReverseDiff(x, y) == 251
//
// 252 253 254 255 0 1 2 3
// #################################################
// | | x | | | | | y | |
// #################################################
// ---<-----| |<-----<--
//
// If M > 0 then wrapping occurs at M, if M == 0 then wrapping occurs at the
// largest value representable by T.
template <typename T, T M>
inline typename std::enable_if<(M > 0), T>::type ReverseDiff(T a, T b) {
static_assert(std::is_unsigned<T>::value,
"Type must be an unsigned integer.");
// RTC_DCHECK_LT(a, M);
// RTC_DCHECK_LT(b, M);
return b <= a ? a - b : M - (b - a);
}
template <typename T, T M>
inline typename std::enable_if<(M == 0), T>::type ReverseDiff(T a, T b) {
static_assert(std::is_unsigned<T>::value,
"Type must be an unsigned integer.");
return a - b;
}
template <typename T>
inline T ReverseDiff(T a, T b) {
return ReverseDiff<T, 0>(a, b);
}
// Calculates the minimum distance between to wrapping numbers.
//
// The minimum distance is defined as min(ForwardDiff(a, b), ReverseDiff(a, b))
template <typename T, T M = 0>
inline T MinDiff(T a, T b) {
static_assert(std::is_unsigned<T>::value,
"Type must be an unsigned integer.");
return (std::min)(ForwardDiff<T, M>(a, b), ReverseDiff<T, M>(a, b));
}
#endif
-61
View File
@@ -1,61 +0,0 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
#define MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
#include <limits>
#include <optional>
namespace webrtc {
template <typename U>
inline bool IsNewer(U value, U prev_value) {
static_assert(!std::numeric_limits<U>::is_signed, "U must be unsigned");
// kBreakpoint is the half-way mark for the type U. For instance, for a
// uint16_t it will be 0x8000, and for a uint32_t, it will be 0x8000000.
constexpr U kBreakpoint = (std::numeric_limits<U>::max() >> 1) + 1;
// Distinguish between elements that are exactly kBreakpoint apart.
// If t1>t2 and |t1-t2| = kBreakpoint: IsNewer(t1,t2)=true,
// IsNewer(t2,t1)=false
// rather than having IsNewer(t1,t2) = IsNewer(t2,t1) = false.
if (value - prev_value == kBreakpoint) {
return value > prev_value;
}
return value != prev_value &&
static_cast<U>(value - prev_value) < kBreakpoint;
}
// NB: Doesn't fulfill strict weak ordering requirements.
// Mustn't be used as std::map Compare function.
inline bool IsNewerSequenceNumber(uint16_t sequence_number,
uint16_t prev_sequence_number) {
return IsNewer(sequence_number, prev_sequence_number);
}
// NB: Doesn't fulfill strict weak ordering requirements.
// Mustn't be used as std::map Compare function.
inline bool IsNewerTimestamp(uint32_t timestamp, uint32_t prev_timestamp) {
return IsNewer(timestamp, prev_timestamp);
}
inline uint16_t LatestSequenceNumber(uint16_t sequence_number1,
uint16_t sequence_number2) {
return IsNewerSequenceNumber(sequence_number1, sequence_number2)
? sequence_number1
: sequence_number2;
}
inline uint32_t LatestTimestamp(uint32_t timestamp1, uint32_t timestamp2) {
return IsNewerTimestamp(timestamp1, timestamp2) ? timestamp1 : timestamp2;
}
} // namespace webrtc
#endif // MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
+152
View File
@@ -0,0 +1,152 @@
#include "platform.h"
#include <cstdlib>
#include <cstring>
#include "rd_log.h"
#ifdef _WIN32
#include <Winsock2.h>
#include <iphlpapi.h>
#elif __APPLE__
#include <ifaddrs.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <sys/socket.h>
#include <sys/types.h>
#elif __linux__
#include <fcntl.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
namespace crossdesk {
std::string GetMac() {
char mac_addr[16];
int len = 0;
#ifdef _WIN32
IP_ADAPTER_INFO adapterInfo[16];
DWORD bufferSize = sizeof(adapterInfo);
DWORD result = GetAdaptersInfo(adapterInfo, &bufferSize);
if (result == ERROR_SUCCESS) {
PIP_ADAPTER_INFO adapter = adapterInfo;
while (adapter) {
for (UINT i = 0; i < adapter->AddressLength; i++) {
len += sprintf_s(mac_addr + len, sizeof(mac_addr) - len, "%.2X",
adapter->Address[i]);
}
break;
}
}
#elif __APPLE__
std::string if_name = "en0";
struct ifaddrs* addrs;
struct ifaddrs* cursor;
const struct sockaddr_dl* dlAddr;
if (!getifaddrs(&addrs)) {
cursor = addrs;
while (cursor != 0) {
const struct sockaddr_dl* socAddr =
(const struct sockaddr_dl*)cursor->ifa_addr;
if ((cursor->ifa_addr->sa_family == AF_LINK) &&
(socAddr->sdl_type == IFT_ETHER) &&
strcmp(if_name.c_str(), cursor->ifa_name) == 0) {
dlAddr = (const struct sockaddr_dl*)cursor->ifa_addr;
const unsigned char* base =
(const unsigned char*)&dlAddr->sdl_data[dlAddr->sdl_nlen];
for (int i = 0; i < dlAddr->sdl_alen; i++) {
len +=
snprintf(mac_addr + len, sizeof(mac_addr) - len, "%.2X", base[i]);
}
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
#elif __linux__
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
return "";
}
struct ifreq ifr;
struct ifconf ifc;
char buf[1024];
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
close(sock);
return "";
}
struct ifreq* it = ifc.ifc_req;
const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
for (; it != end; ++it) {
std::strcpy(ifr.ifr_name, it->ifr_name);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
continue;
}
if (ifr.ifr_flags & IFF_LOOPBACK) {
continue;
}
if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
continue;
}
std::string mac_address;
for (int i = 0; i < 6; ++i) {
len += sprintf(mac_addr + len, "%.2X", ifr.ifr_hwaddr.sa_data[i] & 0xff);
}
break;
}
close(sock);
#endif
return mac_addr;
}
std::string GetHostName() {
char hostname[256];
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
LOG_ERROR("WSAStartup failed");
return "";
}
if (gethostname(hostname, sizeof(hostname)) == SOCKET_ERROR) {
LOG_ERROR("gethostname failed: {}", WSAGetLastError());
WSACleanup();
return "";
}
WSACleanup();
#else
if (gethostname(hostname, sizeof(hostname)) == -1) {
LOG_ERROR("gethostname failed");
return "";
}
#endif
return hostname;
}
bool IsWaylandSession() {
#if defined(__linux__) && !defined(__APPLE__)
const char* session_type = std::getenv("XDG_SESSION_TYPE");
if (session_type) {
if (std::strcmp(session_type, "wayland") == 0 ||
std::strcmp(session_type, "Wayland") == 0) {
return true;
}
if (std::strcmp(session_type, "x11") == 0 ||
std::strcmp(session_type, "X11") == 0) {
return false;
}
}
const char* wayland_display = std::getenv("WAYLAND_DISPLAY");
return wayland_display && wayland_display[0] != '\0';
#else
return false;
#endif
}
} // namespace crossdesk
+19
View File
@@ -0,0 +1,19 @@
/*
* @Author: DI JUNKUN
* @Date: 2023-12-18
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _PLATFORM_H_
#define _PLATFORM_H_
#include <iostream>
namespace crossdesk {
std::string GetMac();
std::string GetHostName();
bool IsWaylandSession();
} // namespace crossdesk
#endif
+63
View File
@@ -0,0 +1,63 @@
#include "rounded_corner_button.h"
namespace crossdesk {
bool RoundedCornerButton(const char* label, const ImVec2& size, float rounding,
ImDrawFlags round_flags, bool enabled,
ImU32 normal_col, ImU32 hover_col, ImU32 active_col,
ImU32 border_col) {
ImGuiWindow* current_window = ImGui::GetCurrentWindow();
if (current_window->SkipItems) return false;
const ImGuiStyle& style = ImGui::GetStyle();
ImGuiID button_id = current_window->GetID(label);
ImVec2 cursor_pos = current_window->DC.CursorPos;
ImVec2 button_size = ImGui::CalcItemSize(size, 0.0f, 0.0f);
ImRect button_rect(cursor_pos, ImVec2(cursor_pos.x + button_size.x,
cursor_pos.y + button_size.y));
ImGui::ItemSize(button_rect);
if (!ImGui::ItemAdd(button_rect, button_id)) return false;
bool is_hovered = false, is_held = false;
bool is_pressed = false;
if (enabled) {
is_pressed =
ImGui::ButtonBehavior(button_rect, button_id, &is_hovered, &is_held);
}
if (normal_col == 0) normal_col = ImGui::GetColorU32(ImGuiCol_Button);
if (hover_col == 0) hover_col = ImGui::GetColorU32(ImGuiCol_ButtonHovered);
if (active_col == 0) active_col = ImGui::GetColorU32(ImGuiCol_ButtonActive);
if (border_col == 0) border_col = ImGui::GetColorU32(ImGuiCol_Border);
ImU32 fill_color = normal_col;
if (is_held && is_hovered)
fill_color = active_col;
else if (is_hovered)
fill_color = hover_col;
if (!enabled) fill_color = IM_COL32(120, 120, 120, 180);
ImDrawList* window_draw_list = ImGui::GetWindowDrawList();
window_draw_list->AddRectFilled(button_rect.Min, button_rect.Max, fill_color,
rounding, round_flags);
if (style.FrameBorderSize > 0.0f) {
window_draw_list->AddRect(button_rect.Min, button_rect.Max, border_col,
rounding, round_flags, style.FrameBorderSize);
}
ImU32 text_color =
ImGui::GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled);
const char* label_end = ImGui::FindRenderedTextEnd(label);
ImGui::PushStyleColor(ImGuiCol_Text,
ImGui::ColorConvertU32ToFloat4(text_color));
ImGui::RenderTextClipped(button_rect.Min, button_rect.Max, label, label_end,
nullptr, ImVec2(0.5f, 0.5f), &button_rect);
ImGui::PopStyleColor();
return is_pressed;
}
} // namespace crossdesk
+20
View File
@@ -0,0 +1,20 @@
/*
* @Author: DI JUNKUN
* @Date: 2026-02-26
* Copyright (c) 2026 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _ROUNDED_CORNER_BUTTON_H_
#define _ROUNDED_CORNER_BUTTON_H_
#include "imgui.h"
#include "imgui_internal.h"
namespace crossdesk {
bool RoundedCornerButton(const char* label, const ImVec2& size, float rounding,
ImDrawFlags round_flags, bool enabled = true,
ImU32 normal_col = 0, ImU32 hover_col = 0,
ImU32 active_col = 0, ImU32 border_col = 0);
} // namespace crossdesk
#endif
-32
View File
@@ -1,32 +0,0 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_ARRAYSIZE_H_
#define RTC_BASE_ARRAYSIZE_H_
#include <stddef.h>
// This file defines the arraysize() macro and is derived from Chromium's
// base/macros.h.
// The arraysize(arr) macro returns the # of elements in an array arr.
// The expression is a compile-time constant, and therefore can be
// used in defining new arrays, for example. If you use arraysize on
// a pointer by mistake, you will get a compile-time error.
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
template <typename T, size_t N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
#endif // RTC_BASE_ARRAYSIZE_H_
-39
View File
@@ -1,39 +0,0 @@
/*
* Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/bitrate_tracker.h"
#include <optional>
#include "api/units/data_rate.h"
#include "api/units/timestamp.h"
#include "rtc_base/rate_statistics.h"
namespace webrtc {
BitrateTracker::BitrateTracker(TimeDelta max_window_size)
: impl_(max_window_size.ms(), RateStatistics::kBpsScale) {}
std::optional<DataRate> BitrateTracker::Rate(Timestamp now) const {
if (std::optional<int64_t> rate = impl_.Rate(now.ms())) {
return DataRate::BitsPerSec(*rate);
}
return std::nullopt;
}
bool BitrateTracker::SetWindowSize(TimeDelta window_size, Timestamp now) {
return impl_.SetWindowSize(window_size.ms(), now.ms());
}
void BitrateTracker::Update(int64_t bytes, Timestamp now) {
impl_.Update(bytes, now.ms());
}
} // namespace webrtc
-64
View File
@@ -1,64 +0,0 @@
/*
* Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_BITRATE_TRACKER_H_
#define RTC_BASE_BITRATE_TRACKER_H_
#include <stddef.h>
#include <stdint.h>
#include <optional>
#include "api/units/data_rate.h"
#include "api/units/data_size.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "rtc_base/rate_statistics.h"
namespace webrtc {
// Class to estimate bitrates over running window.
// Timestamps used in Update(), Rate() and SetWindowSize() must never
// decrease for two consecutive calls.
// This class is thread unsafe.
class BitrateTracker {
public:
// max_window_sizes = Maximum window size for the rate estimation.
// Initial window size is set to this, but may be changed
// to something lower by calling SetWindowSize().
explicit BitrateTracker(TimeDelta max_window_size);
BitrateTracker(const BitrateTracker&) = default;
BitrateTracker(BitrateTracker&&) = default;
BitrateTracker& operator=(const BitrateTracker&) = delete;
BitrateTracker& operator=(BitrateTracker&&) = delete;
~BitrateTracker() = default;
// Resets instance to original state.
void Reset() { impl_.Reset(); }
// Updates bitrate with a new data point, moving averaging window as needed.
void Update(int64_t bytes, Timestamp now);
void Update(DataSize size, Timestamp now) { Update(size.bytes(), now); }
// Returns bitrate, moving averaging window as needed.
// Returns nullopt when bitrate can't be measured.
std::optional<DataRate> Rate(Timestamp now) const;
// Update the size of the averaging window. The maximum allowed value for
// `window_size` is `max_window_size` as supplied in the constructor.
bool SetWindowSize(TimeDelta window_size, Timestamp now);
private:
RateStatistics impl_;
};
} // namespace webrtc
#endif // RTC_BASE_BITRATE_TRACKER_H_
-199
View File
@@ -1,199 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_BYTE_ORDER_H_
#define RTC_BASE_BYTE_ORDER_H_
#include <stdint.h>
#include <cstring>
#if defined(__POSIX__) && !defined(__native_client__)
#include <arpa/inet.h>
#endif
#include "rtc_base/system/arch.h"
#if defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define htobe16(v) OSSwapHostToBigInt16(v)
#define htobe32(v) OSSwapHostToBigInt32(v)
#define htobe64(v) OSSwapHostToBigInt64(v)
#define be16toh(v) OSSwapBigToHostInt16(v)
#define be32toh(v) OSSwapBigToHostInt32(v)
#define be64toh(v) OSSwapBigToHostInt64(v)
#define htole16(v) OSSwapHostToLittleInt16(v)
#define htole32(v) OSSwapHostToLittleInt32(v)
#define htole64(v) OSSwapHostToLittleInt64(v)
#define le16toh(v) OSSwapLittleToHostInt16(v)
#define le32toh(v) OSSwapLittleToHostInt32(v)
#define le64toh(v) OSSwapLittleToHostInt64(v)
#elif defined(_WIN32) || defined(__native_client__)
#if defined(_WIN32)
#include <stdlib.h>
#include <winsock2.h>
#else
#include <netinet/in.h> // no-presubmit-check
#endif // defined(_WIN32)
#if defined(WEBRTC_ARCH_LITTLE_ENDIAN)
#define htobe16(v) htons(v)
#define htobe32(v) htonl(v)
#define be16toh(v) ntohs(v)
#define be32toh(v) ntohl(v)
#define htole16(v) (v)
#define htole32(v) (v)
#define htole64(v) (v)
#define le16toh(v) (v)
#define le32toh(v) (v)
#define le64toh(v) (v)
#if defined(_WIN32)
#define htobe64(v) _byteswap_uint64(v)
#define be64toh(v) _byteswap_uint64(v)
#endif // defined(_WIN32)
#if defined(__native_client__)
#define htobe64(v) __builtin_bswap64(v)
#define be64toh(v) __builtin_bswap64(v)
#endif // defined(__native_client__)
#elif defined(WEBRTC_ARCH_BIG_ENDIAN)
#define htobe16(v) (v)
#define htobe32(v) (v)
#define be16toh(v) (v)
#define be32toh(v) (v)
#define htole16(v) __builtin_bswap16(v)
#define htole32(v) __builtin_bswap32(v)
#define htole64(v) __builtin_bswap64(v)
#define le16toh(v) __builtin_bswap16(v)
#define le32toh(v) __builtin_bswap32(v)
#define le64toh(v) __builtin_bswap64(v)
#if defined(_WIN32)
#define htobe64(v) (v)
#define be64toh(v) (v)
#endif // defined(_WIN32)
#if defined(__native_client__)
#define htobe64(v) (v)
#define be64toh(v) (v)
#endif // defined(__native_client__)
#else
#error WEBRTC_ARCH_BIG_ENDIAN or WEBRTC_ARCH_LITTLE_ENDIAN must be defined.
#endif // defined(WEBRTC_ARCH_LITTLE_ENDIAN)
#elif defined(__POSIX__)
#include <endian.h>
#else
#error "Missing byte order functions for this arch."
#endif // defined(__APPLE__)
namespace rtc {
// Reading and writing of little and big-endian numbers from memory
inline void Set8(void* memory, size_t offset, uint8_t v) {
static_cast<uint8_t*>(memory)[offset] = v;
}
inline uint8_t Get8(const void* memory, size_t offset) {
return static_cast<const uint8_t*>(memory)[offset];
}
inline void SetBE16(void* memory, uint16_t v) {
uint16_t val = htobe16(v);
memcpy(memory, &val, sizeof(val));
}
inline void SetBE32(void* memory, uint32_t v) {
uint32_t val = htobe32(v);
memcpy(memory, &val, sizeof(val));
}
inline void SetBE64(void* memory, uint64_t v) {
uint64_t val = htobe64(v);
memcpy(memory, &val, sizeof(val));
}
inline uint16_t GetBE16(const void* memory) {
uint16_t val;
memcpy(&val, memory, sizeof(val));
return be16toh(val);
}
inline uint32_t GetBE32(const void* memory) {
uint32_t val;
memcpy(&val, memory, sizeof(val));
return be32toh(val);
}
inline uint64_t GetBE64(const void* memory) {
uint64_t val;
memcpy(&val, memory, sizeof(val));
return be64toh(val);
}
inline void SetLE16(void* memory, uint16_t v) {
uint16_t val = htole16(v);
memcpy(memory, &val, sizeof(val));
}
inline void SetLE32(void* memory, uint32_t v) {
uint32_t val = htole32(v);
memcpy(memory, &val, sizeof(val));
}
inline void SetLE64(void* memory, uint64_t v) {
uint64_t val = htole64(v);
memcpy(memory, &val, sizeof(val));
}
inline uint16_t GetLE16(const void* memory) {
uint16_t val;
memcpy(&val, memory, sizeof(val));
return le16toh(val);
}
inline uint32_t GetLE32(const void* memory) {
uint32_t val;
memcpy(&val, memory, sizeof(val));
return le32toh(val);
}
inline uint64_t GetLE64(const void* memory) {
uint64_t val;
memcpy(&val, memory, sizeof(val));
return le64toh(val);
}
// Check if the current host is big endian.
inline bool IsHostBigEndian() {
#if defined(WEBRTC_ARCH_BIG_ENDIAN)
return true;
#else
return false;
#endif
}
inline uint16_t HostToNetwork16(uint16_t n) { return htobe16(n); }
inline uint32_t HostToNetwork32(uint32_t n) { return htobe32(n); }
inline uint64_t HostToNetwork64(uint64_t n) { return htobe64(n); }
inline uint16_t NetworkToHost16(uint16_t n) { return be16toh(n); }
inline uint32_t NetworkToHost32(uint32_t n) { return be32toh(n); }
inline uint64_t NetworkToHost64(uint64_t n) { return be64toh(n); }
} // namespace rtc
#endif // RTC_BASE_BYTE_ORDER_H_
@@ -1,61 +0,0 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
#define MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
#include <limits>
#include <optional>
namespace webrtc {
template <typename U>
inline bool IsNewer(U value, U prev_value) {
static_assert(!std::numeric_limits<U>::is_signed, "U must be unsigned");
// kBreakpoint is the half-way mark for the type U. For instance, for a
// uint16_t it will be 0x8000, and for a uint32_t, it will be 0x8000000.
constexpr U kBreakpoint = (std::numeric_limits<U>::max() >> 1) + 1;
// Distinguish between elements that are exactly kBreakpoint apart.
// If t1>t2 and |t1-t2| = kBreakpoint: IsNewer(t1,t2)=true,
// IsNewer(t2,t1)=false
// rather than having IsNewer(t1,t2) = IsNewer(t2,t1) = false.
if (value - prev_value == kBreakpoint) {
return value > prev_value;
}
return value != prev_value &&
static_cast<U>(value - prev_value) < kBreakpoint;
}
// NB: Doesn't fulfill strict weak ordering requirements.
// Mustn't be used as std::map Compare function.
inline bool IsNewerSequenceNumber(uint16_t sequence_number,
uint16_t prev_sequence_number) {
return IsNewer(sequence_number, prev_sequence_number);
}
// NB: Doesn't fulfill strict weak ordering requirements.
// Mustn't be used as std::map Compare function.
inline bool IsNewerTimestamp(uint32_t timestamp, uint32_t prev_timestamp) {
return IsNewer(timestamp, prev_timestamp);
}
inline uint16_t LatestSequenceNumber(uint16_t sequence_number1,
uint16_t sequence_number2) {
return IsNewerSequenceNumber(sequence_number1, sequence_number2)
? sequence_number1
: sequence_number2;
}
inline uint32_t LatestTimestamp(uint32_t timestamp1, uint32_t timestamp2) {
return IsNewerTimestamp(timestamp1, timestamp2) ? timestamp1 : timestamp2;
}
} // namespace webrtc
#endif // MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
@@ -1,27 +0,0 @@
/*
* Copyright 2018 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/network/sent_packet.h"
namespace rtc {
PacketInfo::PacketInfo() = default;
PacketInfo::PacketInfo(const PacketInfo& info) = default;
PacketInfo::~PacketInfo() = default;
SentPacket::SentPacket() = default;
SentPacket::SentPacket(int64_t packet_id, int64_t send_time_ms)
: packet_id(packet_id), send_time_ms(send_time_ms) {}
SentPacket::SentPacket(int64_t packet_id,
int64_t send_time_ms,
const rtc::PacketInfo& info)
: packet_id(packet_id), send_time_ms(send_time_ms), info(info) {}
} // namespace rtc
-70
View File
@@ -1,70 +0,0 @@
/*
* Copyright 2018 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_NETWORK_SENT_PACKET_H_
#define RTC_BASE_NETWORK_SENT_PACKET_H_
#include <stddef.h>
#include <stdint.h>
#include <optional>
namespace rtc {
enum class PacketType {
kUnknown,
kData,
kIceConnectivityCheck,
kIceConnectivityCheckResponse,
kStunMessage,
kTurnMessage,
};
enum class PacketInfoProtocolType {
kUnknown,
kUdp,
kTcp,
kSsltcp,
kTls,
};
struct PacketInfo {
PacketInfo();
PacketInfo(const PacketInfo& info);
~PacketInfo();
bool included_in_feedback = false;
bool included_in_allocation = false;
// `is_media` is true if this is an audio or video packet, excluding
// retransmissions.
bool is_media = false;
PacketType packet_type = PacketType::kUnknown;
PacketInfoProtocolType protocol = PacketInfoProtocolType::kUnknown;
// A unique id assigned by the network manager, and std::nullopt if not set.
std::optional<uint16_t> network_id;
size_t packet_size_bytes = 0;
size_t turn_overhead_bytes = 0;
size_t ip_overhead_bytes = 0;
};
struct SentPacket {
SentPacket();
SentPacket(int64_t packet_id, int64_t send_time_ms);
SentPacket(int64_t packet_id, int64_t send_time_ms,
const rtc::PacketInfo& info);
int64_t packet_id = -1;
int64_t send_time_ms = -1;
rtc::PacketInfo info;
};
} // namespace rtc
#endif // RTC_BASE_NETWORK_SENT_PACKET_H_
-44
View File
@@ -1,44 +0,0 @@
/*
* Copyright 2020 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/network_constants.h"
namespace rtc {
std::string AdapterTypeToString(AdapterType type) {
switch (type) {
case ADAPTER_TYPE_ANY:
return "Wildcard";
case ADAPTER_TYPE_UNKNOWN:
return "Unknown";
case ADAPTER_TYPE_ETHERNET:
return "Ethernet";
case ADAPTER_TYPE_WIFI:
return "Wifi";
case ADAPTER_TYPE_CELLULAR:
return "Cellular";
case ADAPTER_TYPE_CELLULAR_2G:
return "Cellular2G";
case ADAPTER_TYPE_CELLULAR_3G:
return "Cellular3G";
case ADAPTER_TYPE_CELLULAR_4G:
return "Cellular4G";
case ADAPTER_TYPE_CELLULAR_5G:
return "Cellular5G";
case ADAPTER_TYPE_VPN:
return "VPN";
case ADAPTER_TYPE_LOOPBACK:
return "Loopback";
default:
return std::string();
}
}
} // namespace rtc
-72
View File
@@ -1,72 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_NETWORK_CONSTANTS_H_
#define RTC_BASE_NETWORK_CONSTANTS_H_
#include <stdint.h>
#include <string>
namespace rtc {
constexpr uint16_t kNetworkCostMax = 999;
constexpr uint16_t kNetworkCostCellular2G = 980;
constexpr uint16_t kNetworkCostCellular3G = 910;
constexpr uint16_t kNetworkCostCellular = 900;
constexpr uint16_t kNetworkCostCellular4G = 500;
constexpr uint16_t kNetworkCostCellular5G = 250;
constexpr uint16_t kNetworkCostUnknown = 50;
constexpr uint16_t kNetworkCostLow = 10;
constexpr uint16_t kNetworkCostMin = 0;
// Add 1 to network cost of underlying network type
// so that e.g a "plain" WIFI is prefered over a VPN over WIFI
// everything else being equal.
constexpr uint16_t kNetworkCostVpn = 1;
// alias
constexpr uint16_t kNetworkCostHigh = kNetworkCostCellular;
enum AdapterType {
// This enum resembles the one in Chromium net::ConnectionType.
ADAPTER_TYPE_UNKNOWN = 0,
ADAPTER_TYPE_ETHERNET = 1 << 0,
ADAPTER_TYPE_WIFI = 1 << 1,
ADAPTER_TYPE_CELLULAR = 1 << 2, // This is CELLULAR of unknown type.
ADAPTER_TYPE_VPN = 1 << 3,
ADAPTER_TYPE_LOOPBACK = 1 << 4,
// ADAPTER_TYPE_ANY is used for a network, which only contains a single "any
// address" IP address (INADDR_ANY for IPv4 or in6addr_any for IPv6), and can
// use any/all network interfaces. Whereas ADAPTER_TYPE_UNKNOWN is used
// when the network uses a specific interface/IP, but its interface type can
// not be determined or not fit in this enum.
ADAPTER_TYPE_ANY = 1 << 5,
ADAPTER_TYPE_CELLULAR_2G = 1 << 6,
ADAPTER_TYPE_CELLULAR_3G = 1 << 7,
ADAPTER_TYPE_CELLULAR_4G = 1 << 8,
ADAPTER_TYPE_CELLULAR_5G = 1 << 9
};
std::string AdapterTypeToString(AdapterType type);
// Useful for testing!
constexpr AdapterType kAllAdapterTypes[] = {
ADAPTER_TYPE_UNKNOWN, ADAPTER_TYPE_ETHERNET,
ADAPTER_TYPE_WIFI, ADAPTER_TYPE_CELLULAR,
ADAPTER_TYPE_VPN, ADAPTER_TYPE_LOOPBACK,
ADAPTER_TYPE_ANY, ADAPTER_TYPE_CELLULAR_2G,
ADAPTER_TYPE_CELLULAR_3G, ADAPTER_TYPE_CELLULAR_4G,
ADAPTER_TYPE_CELLULAR_5G,
};
} // namespace rtc
#endif // RTC_BASE_NETWORK_CONSTANTS_H_
-27
View File
@@ -1,27 +0,0 @@
/*
* Copyright 2020 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/network_route.h"
namespace rtc {
bool RouteEndpoint::operator==(const RouteEndpoint& other) const {
return adapter_type_ == other.adapter_type_ &&
adapter_id_ == other.adapter_id_ && network_id_ == other.network_id_ &&
uses_turn_ == other.uses_turn_;
}
bool NetworkRoute::operator==(const NetworkRoute& other) const {
return connected == other.connected && local == other.local &&
remote == other.remote && packet_overhead == other.packet_overhead &&
last_sent_packet_id == other.last_sent_packet_id;
}
} // namespace rtc
-93
View File
@@ -1,93 +0,0 @@
/*
* Copyright 2016 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_NETWORK_ROUTE_H_
#define RTC_BASE_NETWORK_ROUTE_H_
#include <stdint.h>
#include <sstream>
#include <string>
#include "rtc_base/network_constants.h"
// TODO(honghaiz): Make a directory that describes the interfaces and structs
// the media code can rely on and the network code can implement, and both can
// depend on that, but not depend on each other. Then, move this file to that
// directory.
namespace rtc {
class RouteEndpoint {
public:
RouteEndpoint() {} // Used by tests.
RouteEndpoint(AdapterType adapter_type, uint16_t adapter_id,
uint16_t network_id, bool uses_turn)
: adapter_type_(adapter_type),
adapter_id_(adapter_id),
network_id_(network_id),
uses_turn_(uses_turn) {}
RouteEndpoint(const RouteEndpoint&) = default;
RouteEndpoint& operator=(const RouteEndpoint&) = default;
// Used by tests.
static RouteEndpoint CreateWithNetworkId(uint16_t network_id) {
return RouteEndpoint(ADAPTER_TYPE_UNKNOWN,
/* adapter_id = */ 0, network_id,
/* uses_turn = */ false);
}
RouteEndpoint CreateWithTurn(bool uses_turn) const {
return RouteEndpoint(adapter_type_, adapter_id_, network_id_, uses_turn);
}
AdapterType adapter_type() const { return adapter_type_; }
uint16_t adapter_id() const { return adapter_id_; }
uint16_t network_id() const { return network_id_; }
bool uses_turn() const { return uses_turn_; }
bool operator==(const RouteEndpoint& other) const;
private:
AdapterType adapter_type_ = ADAPTER_TYPE_UNKNOWN;
uint16_t adapter_id_ = 0;
uint16_t network_id_ = 0;
bool uses_turn_ = false;
};
struct NetworkRoute {
bool connected = false;
RouteEndpoint local;
RouteEndpoint remote;
// Last packet id sent on the PREVIOUS route.
int last_sent_packet_id = -1;
// The overhead in bytes from IP layer and above.
// This is the maximum of any part of the route.
int packet_overhead = 0;
std::string DebugString() const {
std::ostringstream oss;
oss << "[ connected: " << connected << " local: [ " << local.adapter_id()
<< "/" << local.network_id() << " "
<< AdapterTypeToString(local.adapter_type())
<< " turn: " << local.uses_turn() << " ] remote: [ "
<< remote.adapter_id() << "/" << remote.network_id() << " "
<< AdapterTypeToString(remote.adapter_type())
<< " turn: " << remote.uses_turn()
<< " ] packet_overhead_bytes: " << packet_overhead << " ]";
return oss.str();
}
bool operator==(const NetworkRoute& other) const;
bool operator!=(const NetworkRoute& other) { return !operator==(other); }
};
} // namespace rtc
#endif // RTC_BASE_NETWORK_ROUTE_H_
@@ -1,56 +0,0 @@
/*
* Copyright 2019 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_NUMERICS_DIVIDE_ROUND_H_
#define RTC_BASE_NUMERICS_DIVIDE_ROUND_H_
#include <type_traits>
#include "safe_compare.h"
namespace webrtc {
template <typename Dividend, typename Divisor>
inline auto constexpr DivideRoundUp(Dividend dividend, Divisor divisor) {
static_assert(std::is_integral<Dividend>(), "");
static_assert(std::is_integral<Divisor>(), "");
auto quotient = dividend / divisor;
auto remainder = dividend % divisor;
return quotient + (remainder > 0 ? 1 : 0);
}
template <typename Dividend, typename Divisor>
inline auto constexpr DivideRoundToNearest(Dividend dividend, Divisor divisor) {
static_assert(std::is_integral<Dividend>(), "");
static_assert(std::is_integral<Divisor>(), "");
if (dividend < Dividend{0}) {
auto half_of_divisor = divisor / 2;
auto quotient = dividend / divisor;
auto remainder = dividend % divisor;
if (rtc::SafeGt(-remainder, half_of_divisor)) {
--quotient;
}
return quotient;
}
auto half_of_divisor = (divisor - 1) / 2;
auto quotient = dividend / divisor;
auto remainder = dividend % divisor;
if (rtc::SafeGt(remainder, half_of_divisor)) {
++quotient;
}
return quotient;
}
} // namespace webrtc
#endif // RTC_BASE_NUMERICS_DIVIDE_ROUND_H_
@@ -1,81 +0,0 @@
/*
* Copyright 2019 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "event_based_exponential_moving_average.h"
#include <cmath>
#include <cstdint>
#include <limits>
namespace {
// For a normal distributed value, the 95% double sided confidence interval is
// is 1.96 * stddev.
constexpr double ninetyfive_percent_confidence = 1.96;
} // namespace
namespace rtc {
// `half_time` specifies how much weight will be given to old samples,
// a sample gets exponentially less weight so that it's 50%
// after `half_time` time units has passed.
EventBasedExponentialMovingAverage::EventBasedExponentialMovingAverage(
int half_time) {
SetHalfTime(half_time);
}
void EventBasedExponentialMovingAverage::SetHalfTime(int half_time) {
tau_ = static_cast<double>(half_time) / log(2);
Reset();
}
void EventBasedExponentialMovingAverage::Reset() {
value_ = std::nan("uninit");
sample_variance_ = std::numeric_limits<double>::infinity();
estimator_variance_ = 1;
last_observation_timestamp_.reset();
}
void EventBasedExponentialMovingAverage::AddSample(int64_t now, int sample) {
if (!last_observation_timestamp_.has_value()) {
value_ = sample;
} else {
// TODO(webrtc:11140): This should really be > (e.g not >=)
// but some pesky tests run with simulated clock and let
// samples arrive simultaneously!
// Variance gets computed after second sample.
int64_t age = now - *last_observation_timestamp_;
double e = exp(-age / tau_);
double alpha = e / (1 + e);
double one_minus_alpha = 1 - alpha;
double sample_diff = sample - value_;
value_ = one_minus_alpha * value_ + alpha * sample;
estimator_variance_ =
(one_minus_alpha * one_minus_alpha) * estimator_variance_ +
(alpha * alpha);
if (sample_variance_ == std::numeric_limits<double>::infinity()) {
// First variance.
sample_variance_ = sample_diff * sample_diff;
} else {
double new_variance = one_minus_alpha * sample_variance_ +
alpha * sample_diff * sample_diff;
sample_variance_ = new_variance;
}
}
last_observation_timestamp_ = now;
}
double EventBasedExponentialMovingAverage::GetConfidenceInterval() const {
return ninetyfive_percent_confidence *
sqrt(sample_variance_ * estimator_variance_);
}
} // namespace rtc
@@ -1,70 +0,0 @@
/*
* Copyright 2019 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_NUMERICS_EVENT_BASED_EXPONENTIAL_MOVING_AVERAGE_H_
#define RTC_BASE_NUMERICS_EVENT_BASED_EXPONENTIAL_MOVING_AVERAGE_H_
#include <cmath>
#include <cstdint>
#include <limits>
#include <optional>
namespace rtc {
/**
* This class implements exponential moving average for time series
* estimating both value, variance and variance of estimator based on
* https://en.wikipedia.org/w/index.php?title=Moving_average&section=9#Application_to_measuring_computer_performance
* with the additions from nisse@ added to
* https://en.wikipedia.org/wiki/Talk:Moving_average.
*
* A sample gets exponentially less weight so that it's 50%
* after `half_time` time units.
*/
class EventBasedExponentialMovingAverage {
public:
// `half_time` specifies how much weight will be given to old samples,
// see example above.
explicit EventBasedExponentialMovingAverage(int half_time);
void AddSample(int64_t now, int value);
double GetAverage() const { return value_; }
double GetVariance() const { return sample_variance_; }
// Compute 95% confidence interval assuming that
// - variance of samples are normal distributed.
// - variance of estimator is normal distributed.
//
// The returned values specifies the distance from the average,
// i.e if X = GetAverage(), m = GetConfidenceInterval()
// then a there is 95% likelihood that the observed variables is inside
// [ X +/- m ].
double GetConfidenceInterval() const;
// Reset
void Reset();
// Update the half_time.
// NOTE: resets estimate too.
void SetHalfTime(int half_time);
private:
double tau_;
double value_ = std::nan("uninit");
double sample_variance_ = std::numeric_limits<double>::infinity();
// This is the ratio between variance of the estimate and variance of samples.
double estimator_variance_ = 1;
std::optional<int64_t> last_observation_timestamp_;
};
} // namespace rtc
#endif // RTC_BASE_NUMERICS_EVENT_BASED_EXPONENTIAL_MOVING_AVERAGE_H_
@@ -1,41 +0,0 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "exp_filter.h"
#include <cmath>
namespace rtc {
const float ExpFilter::kValueUndefined = -1.0f;
void ExpFilter::Reset(float alpha) {
alpha_ = alpha;
filtered_ = kValueUndefined;
}
float ExpFilter::Apply(float exp, float sample) {
if (filtered_ == kValueUndefined) {
// Initialize filtered value.
filtered_ = sample;
} else if (exp == 1.0) {
filtered_ = alpha_ * filtered_ + (1 - alpha_) * sample;
} else {
float alpha = std::pow(alpha_, exp);
filtered_ = alpha * filtered_ + (1 - alpha) * sample;
}
if (max_ != kValueUndefined && filtered_ > max_) {
filtered_ = max_;
}
return filtered_;
}
void ExpFilter::UpdateBase(float alpha) { alpha_ = alpha; }
} // namespace rtc

Some files were not shown because too many files have changed in this diff Show More