私有化部署WebRTC:基于aiortc实现Web浏览器直接预览远程摄像头

私有化部署WebRTC:基于aiortc实现Web浏览器直接预览远程摄像头

私有化部署WebRTC:基于aiortc实现Web浏览器直接预览远程摄像头

引言:为什么需要这个方案?

在现代物联网和安防监控领域,远程查看摄像头视频流是一个常见需求。传统的解决方案通常采用RTSP协议,但这种方案存在一个致命缺陷:现代Web浏览器(如Chrome、Firefox)无法直接播放RTSP流

之前我尝试了以下方案:

  • 第三方P2P穿透方案:仅支持Windows/Linux Qt客户端,不支持Web浏览器
  • EasyRTC等现成方案:无法私有化部署,稳定性欠佳
  • 直接使用libwebrtc:编译复杂,依赖庞大

今天,我介绍一个基于aiortc的简化方案,它能够:

  1. ✅ 在Web浏览器中直接预览远程摄像头
  2. ✅ 完全私有化部署,数据不经过第三方
  3. ✅ 支持P2P直连、STUN穿透和TURN中转多种连接方式
  4. ✅ 跨平台支持(Windows、Linux、Mac)
  5. ✅ 代码简洁,易于理解和定制

一、WebRTC与aiortc:技术基础

什么是WebRTC?

WebRTC(Web实时通信)是一个开源项目,允许Web浏览器和移动应用进行实时音视频通信和数据传输,而无需安装任何插件。它的核心优势在于:

  1. 点对点通信:数据直接在两个客户端之间传输
  2. 低延迟:专为实时通信设计
  3. 浏览器原生支持:现代浏览器都内置WebRTC API
  4. 自动NAT穿透:通过STUN/TURN技术解决网络障碍

为什么选择aiortc?

aiortc是一个基于Python asyncio的WebRTC实现库,相比原生libwebrtc,它有如下优势:

特性aiortclibwebrtc
安装复杂度pip一键安装需要复杂编译
语言友好性Python,易于集成C++,集成复杂
代码简洁性高级API,代码简洁低级API,代码冗长
灵活性易于自定义和扩展修改困难

二、系统架构设计

我们的解决方案包含四个核心组件:

视频流

信令交换

ICE协商

SDP/ICE转发

SDP/ICE转发

远程设备

WebRTC PeerConnection

Web浏览器

信令服务器

STUN/TURN服务器

组件说明:

  1. STUN/TURN服务器(coturn)
    • STUN:帮助设备发现自己的公网IP和端口
    • TURN:当P2P无法建立时,作为数据中转服务器
  2. 信令服务器(Python WebSocket)
    • 交换WebRTC连接所需的SDP(会话描述协议)和ICE候选地址
    • 管理设备注册和发现
  3. Web服务器(Python HTTP)
    • 提供Web页面给用户访问
    • 集成WebRTC JavaScript客户端
  4. 设备端(Python aiortc)
    • 捕获视频流(摄像头、文件、虚拟视频)
    • 通过WebRTC传输视频到Web端

三、详细部署步骤

步骤1:环境准备

在开始之前,请确保你有一台具有公网IP的云服务器(如阿里云ECS)。我们将在这台服务器上部署所有服务。

首先设置环境变量(这些变量将在后续脚本中使用):

exportECS_IP_ADDR=替换为你的云服务器实际IP地址 exportSTUN_SRV=$ECS_IP_ADDRexportSTUN_PORT=3478exportSIGNALING_SRV=$ECS_IP_ADDR#信令服务器,用来交换WebRTC连接需要的信息exportSIGNALING_PORT=9901exportWEB_SRV=$ECS_IP_ADDR# Web服务器exportWEB_PORT=9900

重要提示:将这些变量添加到你的~/.bashrc文件中,以便每次登录时自动加载。

步骤2:部署STUN/TURN服务器

STUN/TURN服务器是WebRTC的"网络向导",帮助两个设备找到彼此并建立连接。

2.1 安装coturn
# 在CentOS/RHEL系统上安装 yum install coturn -y # 配置coturncat> /etc/coturn/turnserver.conf <<EOF listening-ip=0.0.0.0 listening-port=$STUN_PORT relay-ip=$(ifconfig eth0 |grep -w inet |awk'{print $2}') external-ip=$ECS_IP_ADDR log-file=/var/tmp/turn.log min-port=40000 max-port=65535 EOF systemctl restart coturn systemctl status coturn 
2.2 配置防火墙

云服务器需要开放以下端口:

  • 3478:STUN/TURN服务端口
  • 9900:Web服务端口
  • 9901:信令服务器端口
  • 40000-65535:TURN中继端口范围

在阿里云控制台的安全组中,添加入站规则允许这些端口的TCP和UDP流量。

请添加图片描述
2.3 测试STUN/TURN服务

访问Trickle ICE

请添加图片描述
stun:你的服务器IP:3478 turn:你的服务器IP:3478 

使用用户名webrtc,密码webrtc。如果测试成功,你会看到类似以下结果:

  • srflx:STUN穿透成功
  • relay:TURN中转可用

步骤3:部署信令服务器

信令服务器是WebRTC连接的"媒人",负责交换连接信息。它使用WebSocket协议进行实时通信。

3.1 创建信令服务器脚本
cat > signaling_server.py << EOF import asyncio import json import logging from aiohttp import web import aiohttp_cors logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__)classSignalingServer:def__init__(self): self.app = web.Application() self.clients ={ }# 存储连接的用户 self.setup_routes()defsetup_routes(self): cors = aiohttp_cors.setup(self.app, defaults={ "*": aiohttp_cors.ResourceOptions( allow_credentials=True, expose_headers="*", allow_headers="*",)})# 添加WebSocket路由 resource = cors.add(self.app.router.add_resource('/ws')) cors.add(resource.add_route("GET", self.websocket_handler))# 健康检查路由 self.app.router.add_get('/health', self.health_check)# 获取在线设备列表 self.app.router.add_get('/devices', self.get_devices)asyncdefhealth_check(self, request):return web.Response(text='OK')asyncdefget_devices(self, request):"""获取所有在线的设备""" devices =[]for client_id, client_info in self.clients.items():if client_info['type']=='device': devices.append({ 'id': client_id,'type': client_info['type']})return web.json_response({ 'devices': devices})asyncdefwebsocket_handler(self, request): ws = web.WebSocketResponse()await ws.prepare(request) client_id =None client_type =Nonetry:asyncfor msg in ws:if msg.type== web.WSMsgType.TEXT:try: data = json.loads(msg.data) message_type = data.get('type')if message_type =='register':# 客户端注册 client_id = data.get('client_id') client_type = data.get('client_type')# 'web' 或 'device'if client_id in self.clients:try:await self.clients[client_id]['ws'].close()except:pass self.clients[client_id]={ 'ws': ws,'type': client_type,'client_id': client_id } logger.info(f"Client registered: { client_id} ({ client_type})")await ws.send_str(json.dumps({ 'type':'registered','status':'success'}))elif message_type =='offer':# 转发 offer 到对应的设备端 target_device = data.get('target_device') offer_data = data.get('offer')if target_device in self.clients:await self.clients[target_device]['ws'].send_str(json.dumps({ 'type':'offer','offer': offer_data,'from_client': client_id })) logger.info(f"Offer forwarded from { client_id} to { target_device}")else: logger.warning(f"Target device not found: { target_device}")await ws.send_str(json.dumps({ 'type':'error','message':f'Device { target_device} not found'}))elif message_type =='answer':# 转发 answer 到对应的网页端 target_web = data.get('target_web') answer_data = data.get('answer')if target_web in self.clients:await self.clients[target_web]['ws'].send_str(json.dumps({ 'type':'answer','answer': answer_data,'from_client': client_id })) logger.info(f"Answer forwarded from { client_id} to { target_web}")elif message_type =='ice_candidate':# 转发 ICE candidate target = data.get('target') candidate = data.get('candidate')if target in self.clients:await self.clients[target]['ws'].send_str(json.dumps({ 'type':'ice_candidate','candidate': candidate,'from_client': client_id }))elif message_type =='ping':# 心跳检测await ws.send_str(json.dumps({ 'type':'pong'}))except json.JSONDecodeError as e: logger.error(f"JSON解析错误: { e}")elif msg.type== web.WSMsgType.ERROR: logger.error(f'WebSocket error: { ws.exception()}')except Exception as e: logger.error(f"WebSocket error: { e}")finally:# 清理客户端if client_id and client_id in self.clients:del self.clients[client_id] logger.info(f"Client disconnected: { client_id}")return ws defmain(): server = SignalingServer() logger.info("Starting signaling server on http://0.0.0.0:$SIGNALING_PORT") web.run_app(server.app, host='0.0.0.0', port=$SIGNALING_PORT)if __name__ =='__main__': main() EOF 
3.2 安装依赖并运行
# 安装Python环境(如果使用conda) yum install conda -y conda create -n myenv python=3.12source ~/.bashrc conda activate myenv # 安装Python依赖 pip install aiohttp pip install aiohttp_cors # 注意:脚本中的环境变量需要替换为实际值# 运行信令服务器 python signaling_server.py 

步骤4:部署Web服务器

Web服务器提供用户访问的界面,包含WebRTC JavaScript客户端。

4.1 创建Web服务器
cat > web_server.py << EOF from aiohttp import web import aiohttp_cors import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__)classWebServer:def__init__(self): self.app = web.Application() self.setup_routes()defsetup_routes(self): cors = aiohttp_cors.setup(self.app, defaults={ "*": aiohttp_cors.ResourceOptions( allow_credentials=True, expose_headers="*", allow_headers="*",)})# 主页面 self.app.router.add_get('/', self.index_handler) self.app.router.add_get('/index.html', self.index_handler)# 设备端页面 self.app.router.add_get

Read more

【愚公系列】《AI短视频创作一本通》011-AI 短视频分镜头设计(AI绘画工具的选择)

【愚公系列】《AI短视频创作一本通》011-AI 短视频分镜头设计(AI绘画工具的选择)

💎【行业认证·权威头衔】 ✔ 华为云天团核心成员:特约编辑/云享专家/开发者专家/产品云测专家 ✔ 开发者社区全满贯:ZEEKLOG博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主 ✔ 技术生态共建先锋:横跨鸿蒙、云计算、AI等前沿领域的技术布道者 🏆【荣誉殿堂】 🎖 连续三年蝉联"华为云十佳博主"(2022-2024) 🎖 双冠加冕ZEEKLOG"年度博客之星TOP2"(2022&2023) 🎖 十余个技术社区年度杰出贡献奖得主 📚【知识宝库】 覆盖全栈技术矩阵: ◾ 编程语言:.NET/Java/Python/Go/Node… ◾ 移动生态:HarmonyOS/iOS/Android/小程序 ◾ 前沿领域:

2026权威评测:毕业论文AIGC降重盘点,附免费试用

2026权威评测:毕业论文AIGC降重盘点,附免费试用

ZEEKLOG摘要: 2026年高校全面启用AIGC检测,传统同义词替换的降重方式已彻底失效!毕业论文“AIGC痕迹”究竟怎么破?本文基于真实学术场景,深度盘点5款主流AI学术工具,从原创性、降痕能力、服务保障等维度的实测数据出发,为你提供一份最靠谱的选型避坑指南。 一、 引言:“查重”退潮,“查痕”当道,你的论文还安全吗? 作为在ZEEKLOG深耕“AI效率工具”与“学术科研”板块多年的老博主,最近收到了大量本硕博同学的私信求助。来到2026年,学术圈的游戏规则已经发生巨变。 据最新发布的虚拟数据《2026中国高校学术诚信白皮书》显示:今年因“AIGC生成痕迹过高”被退回重写的毕业论文比例高达37.2%。知网、万方、格子达等主流平台已经完成了第三代AI检测大模型的迭代。 这就导致了一个绝对的核心痛点:过去市面上的传统降重工具,只是在玩“同义词替换”的文字游戏,不仅语法生硬,且在最新的查测系统中AIGC疑似度往往直接飙升至60%以上。学生们花了钱降重,反而因为“AI味太重”面临学术不端的指控,返工率极高。

双标通关指南:Paperzz 降重 / 降 AIGC 功能,精准适配知网维普 2026 最新检测体系

双标通关指南:Paperzz 降重 / 降 AIGC 功能,精准适配知网维普 2026 最新检测体系

Paperzz-AI官网免费论文查重复率AIGC检测/开题报告/文献综述/论文初稿paperzz - 降重/降AIGChttps://www.paperzz.cc/weight 在 2026 年本科、研究生论文审核季,学术检测迎来了 “双重严管” 时代 —— 知网、维普相继更新 AIGC 检测算法(知网 2.13 严审版、维普 2.6 严审版),重复率与 AIGC 率双指标成为论文通过的 “生死线”。不少同学陷入两难:AI 辅助写作提高了效率,却留下明显生成痕迹;手动降重耗时耗力,还容易破坏学术逻辑。 针对这一核心痛点,Paperzz 全新升级的降重 / 降 AIGC 功能,以 “精准适配最新检测算法” 为核心,打造了智能降重、

如何用ChatGPT降低毕业论文的AIGC重复率?(最新版详细攻略)

毕业季又到了,论文人的生存法则:“降重、降重、再降重!” 📚 尤其是今年,AIGC检测全面升级,以前的小技巧不太好用了,必须用更细致的方法应对。 这篇文章,一步步带你搞定AIGC率,让论文自然过检。 记得点赞➕收藏,不然到时候又得哭着翻笔记了😭。 一、为什么今年降AIGC变得这么难? 去年,用ChatGPT简单润色一下,AIGC率能从64.9%降到17.2%,谁用谁知道!👍 但,今年不一样了。 👉 2025年2月13日起,知网、维普、万方等系统,全面升级了AIGC检测。 👉 老方法直接被秒破,一测就爆表100%,而且检测报告显示:全文都疑似AI生成! 有没有很恐怖?就像你问老师考试重点,他告诉你:整本书都是!😱 所以,降AIGC不再是选修,是必修! (🔎 想提前规划论文选题?推荐参考👉 https://zhuanlan.zhihu.com/p/26493133188)