WebRTC(Web Real-Time Communication,网页即时通信),是一个支持网页浏览器进行实时语音对话或视频对话的技术,目的是无插件实现web端的实时通信的能力。WebRTC提供了视频会议的核心技术,包括音视频的采集、编解码、网络传输、展示等功能,并且还支持跨平台,包括linux、windows、mac、android等。
WebRTC
2010 年 Google 以 6820 万美元收购 VoIP 软件开发商 Global IP Solutions 的 GIPS 引擎,在经过收购之后没多久,Google 将该引擎改名为“WebRTC”,并宣布向开发者们开源了源代码。
2012 年,Google 将 WebRTC 集成到 Chrome 浏览器中。随后, Mozilla、Opera、Ericsson 等 PC 浏览器以及手机浏览器均开始支持 WebRTC 技术。
2017 年,苹果在 WWDC17 上正式宣布其浏览器内核 WebKit 也正式支持 WebRTC。
基于 Chromium 的新版 Edge 现在可在预览版中使用。新版本的 Edge 提供了 WebRTC 开发者常用的许多功能,如支持数据通道、RTCPeerConnection 中的 Strem、VP9 编解码器和 MediaStream Recording。
在 Discord、Google Hangouts 和 Facebook Messenger 等一些国内的多媒体网络应用中,也都需要 WebRTC 才能实现。
但是,WebRTC 的发展还面临着诸多的挑战:
浏览器面临的主要挑战是完成 WebRTC 1.0 API 的实现,以及消除实现差异。WebRTC API 在其历史中经历了三次主要迭代,需要实现互操作性、改进测试覆盖率等方面的标准。W3C 在实现这一目标方面一直在稳步前进,但还未成熟。
前实时音视频通信领域,也并不只有 WebRTC 一种可供选择的技术,专有的自研协议和 WebRTC 的互操作性通常使用网关实现。
WebRTC协议介绍:https://www.cnblogs.com/SingleCat/p/11315349.html
基于Webrtc、Kurento的一种低延迟架构实现:https://www.jianshu.com/p/ac307371def4
WebRTC的开源实现:
1、Jitsi Videobridge
Jitsi是一个SFU开源框架,由Atlassian维护,被集成到HipChat中。
Jitsi是一个处理XMPP信号流的SFU,适用于SIP/XMPP视频通话,会议,聊天,桌面共享,文件传输。如果你不需要SFU或者使用其他信号协议,最好还是使用其他项目。但由于Jitsi项目的简单明了,很多外包供应商很喜欢使用Jitsi,将它集成到自己的项目案例当中。
Github项目地址:https://github.com/jitsi/jitsi
2、Kurento
Kurento 是一个 WebRTC 流媒体服务器以及一些客户端API,可以实现webrtc mcu、sfu等功能。2016年被Twilio收购,Kurento目前推进到6.13版本。nubomedia 开源框架是基于kurento开发的官方paas 平台,提高了稳定性,但是并不推荐学习使用。它可以实现的功能包括
Kurento服务器实现的功能
官网地址:http://www.kurento.org
2019年12月发布的最新的6.13版本的文档:https://doc-kurento.readthedocs.io/en/6.13.0/project/relnotes/v6_13_0.html
由于Kurento开源服务只有Ubuntu的版本,所以在WSL的UBUNTU上安装Kurento服务器是再适合不过了。建议安装Kurento的6.11版本,因为最新的版本并不支持kms-datachannelexample等组件,无法运行显示字幕等实例,如果只是学习WebRTC,可以无视。
6.11版本的文档https://doc-kurento.readthedocs.io/en/6.11.0/user/about.html
WSL上的安装:
1、 在Ubuntu子系统内确认安装GnuPG
sudo apt-get update && sudo apt-get install --no-install-recommends --yes \
gnupg
在Ubuntu子系统内确认安装GnuPG
2、 在16.04的Ubuntu子系统,执行:
DISTRO="xenial" # KMS for Ubuntu 16.04 (Xenial)
DISTRO="bionic" # KMS for Ubuntu 18.04 (Bionic)
在18.04的Ubuntu子系统,执行
DISTRO="bionic" # KMS for Ubuntu 18.04 (Bionic)
3、下面两条指令指令增加Kurento仓库到系统配置中:
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 5AFA7A83
sudo tee "/etc/apt/sources.list.d/kurento.list" >/dev/null <<EOF
# Kurento Media Server - Release packages
deb [arch=amd64] http://ubuntu.openvidu.io/6.13.0 $DISTRO kms6
EOF
增加Kurento仓库到系统配置
4、 安装Kurento服务KMS
sudo apt-get update && sudo apt-get install --yes kurento-media-server
安装过程中下载较慢,特别是下载GStream组件的时候,如果下载速度降到很低,可以中断重新下载,具备断点重传。
5、安装完成后,可以用下面的指令启动服务,或者停止服务
sudo service kurento-media-server start
sudo service kurento-media-server stop
启动KMS服务
KMS会在Ubuntu子系统本地生成一个端口在8888的服务,可以通过/etc/kurento/kurento.conf.json进行KMS的详细配置。
KMS服务的配置
6、可以在/var/log /kurento-media-server/下查看KMS的日志信息
KMS的日志信息
7、如果需要在远程服务器上部署KMS服务,则需要继续安装STUN或者TURN服务器,来穿透NAT墙。可以参照该网文来安装Docker设置,https://blog.csdn.net/XRRRICK/article/details/85010829
8、之后可以继续下载Kurento的示例代码来安装运行,有SpringBoot、NodeJS等版本的程序供选择。我这里用SpringBoot就是Java的例程:Kurento Java Tutorial - Hello World
(1) 运行以下命令来下载Java实例代码、设置6.11分支,打包运行SpringBoot项目:
git clone https://github.com/Kurento/kurento-tutorial-java.git
cd kurento-tutorial-java/kurento-hello-world
git checkout 6.11.0
mvn -U clean spring-boot:run -Dkms.url=ws://localhost:8888/kurento
启动Hello World的SpringBoot项目
这里的-Dkms.url=ws://localhost:8888/kurento是本地KMS服务提供的路径,如果端口没有什么变化,可以省略不写。
(2) 如果启动没有什么错误的话,就可以在WebRTC兼容的浏览器(Chrome、Edge、360浏览器等)输入以下地址(注意是https协议):https://localhost:8443/,这个Helloworld实例是将本地摄像头采集到的音视频流发送到KMS服务器后,又回送到浏览器,左边的Video组件是显示本地的视频,右边的Video组件是显示回送的视频。
可以看到界面:
Helloworld示例
在界面的console里你可以看到整个浏览器客户端与应用服务器(SpringBoot创建的8433端口的Web服务)的消息协商过程。
如果在Chrome浏览器中,可以在浏览器的另一个标签里打开:chrome://webrtc-internals/,可以看到Google浏览器提供的对WebRTC数据的统计。
Chrome浏览器里的WebRTC统计信息
有兴趣的同学可以摘取其中的静态JS文件和库文件,组合到自己的应用里。
可以在我的网站rtc目录下访问这个helloworld示例,rtc/hello.html
PyQt5中,可以使用PyQtWebEngine模块快速定制专属浏览器,缺省的PyQt5包中并不包含这个模块,请使用命令:
pip install PyQtWebEngine
安装这个模块。
QWebEngineView类提供了一个用于查看和编辑Web文档部件,web view是Qt WebEngine网页浏览模块的主要部件的组件。可以在各种应用程序中使用它来实时显示Internet上的Web内容。
和其他Qt部件一样,必须show()函数才可以显示Web视图,简单的示例代码如下:
webView = QWebEegineView(self)
view.load(QUrl('http://qt-project.org/'))
view.show()
QWebEegineView 常用函数:
QWebEegineView 常用信号:
代码演示如何定制一个简单的浏览器,备注(QWebEngine 模块的内核使用的Chorme, 测试程序在win10下运行正常,在Ubutun下需要加开关 --no-sandbox)。完整代码如下:
资源文件:resource.qrc
<RCC>
<qresource>
<file>images/back.png</file>
<file>images/next.png</file>
<file>images/close.png</file>
<file>images/reload.png</file>
</qresource>
</RCC>
代码文件:
import sys
from PyQt5.QtCore import Qt, QUrl, QSize
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (QApplication, QMainWindow, QLineEdit,
QMenuBar, QToolBar, QMenu, QAction)
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings
import resource_rc
default_url = 'https://www.toutiao.com/i6856673250190033415/'
class WebEngineView(QWebEngineView):
windowList = []
class DemoBrowser(QMainWindow):
def __init__(self, parent=None):
super(DemoBrowser, self).__init__(parent)
# 设置窗口标题
self.setWindowTitle('实战Qt for Python: QWeEngineView演示')
# 设置窗口大小
self.resize(640, 480)
webSettings = QWebEngineSettings.globalSettings()
webSettings.setAttribute(QWebEngineSettings.JavascriptEnabled, True)
webSettings.setAttribute(QWebEngineSettings.PluginsEnabled, True)
webSettings.setAttribute(QWebEngineSettings.JavascriptCanOpenWindows, True)
self.browser = QWebEngineView(self)
self.setCentralWidget(self.browser)
self.initBar()
self.browser.load(QUrl(default_url))
def initBar(self):
#菜单条
menuBar = self.menuBar()
menuFile = menuBar.addMenu('文件(&F)')
actionExit = QAction('退出(&X)', self)
actionExit.triggered.connect(QApplication.instance().quit)
menuFile.addAction(actionExit)
#浏览器工具条
navBar = QToolBar('Navigation')
navBar.setIconSize(QSize(16, 16))
self.addToolBar(navBar)
self.editUrl = QLineEdit()
#地址栏能响应回车按键信号
self.editUrl.returnPressed.connect(self.navigateToUrl)
navBar.addAction(QAction(QIcon(':/images/back.png'), 'Back', self, triggered=self.browser.back))
navBar.addAction(QAction(QIcon(':/images/next.png'), 'Forward', self, triggered=self.browser.forward))
navBar.addAction(QAction(QIcon(':/images/close.png'), 'Stop', self, triggered=self.browser.stop))
navBar.addAction(QAction(QIcon(':/images/reload.png'), 'Reload', self, triggered=self.browser.reload))
navBar.addSeparator()
navBar.addWidget(self.editUrl)
#浏览器相应url地址的变化
self.browser.urlChanged.connect(self.renewUrl)
def navigateToUrl(self):
url = QUrl(self.editUrl.text())
if url.scheme() == '':
url.setScheme('http')
self.browser.setUrl(url)
def renewUrl(self, url):
# 将当前网页的链接更新到地址栏
self.editUrl.setText(url.toString())
self.editUrl.setCursorPosition(0)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = DemoBrowser()
window.show()
sys.exit(app.exec())
运行效果如下图:
使用QWebEngineView实现一个简单的浏览器
前一篇: 实战PyQt5: 132-一个轻量级的地图应用
请多多关注,评论,收藏,点赞,和转发。
文主要以 HackerScreenSaver 新功能的开发经历介绍 webBrowser中网页如何调用.NET方法的过程。
之前开源了一款名为 HackerScreenSaver 的 Windows 屏保程序。该程序具有模拟黑客炫酷界面的特点,用户可以将自定义的网页作为锁屏界面。不久前,有网友提出一个有趣的需求:能否在退出屏保时需要输入密码?虽然我不太清楚他的用意,但这个其实可以安排,不过需要变通一下。
之前做这个程序的时候我就发现,屏幕保护程序需要自己处理退出,如果屏保程序设计得不够合理,可能会导致用户在无法正常退出屏保时遇到困扰。所以在设计之初,我添加了 MouseKeyHook
用来监听全局的键鼠事件。
那么设计新的功能来实现网友的需求也很简单,当然不是直接的设计什么密码输入,然后判断退出的功能。这里只需将屏保退出的功能提供给网页控制就可以了。
之前介绍到为了程序简易软件采用了 webBrowser,那么为了让网页可以决定什么时候退出屏保,就需要让 webBrowser 中的网页可以调用 .NET 的方法。
在网页中,我们需要在屏保退出的逻辑部分添加一段 JavaScript 代码,用于调用 .NET 方法。这段代码的核心是 window.external
对象,它允许 JavaScript 访问 .NET 对象。我们在用户输入正确密码或者游戏胜利等条件下执行下面的 JavaScript 代码即可:
window.external.ExecuteExitSrc();
对于 .NET 代码,可以创建一个和单独的类以供 web 调用:
[ComVisible(true)]
public class JavaScriptInteraction
{
public void ExecuteExitSrc()
{
Application.Exit();
}
}
需要注意的是,我们需要在该类上添加一个 [ComVisible(true)]
特性。这个特性使得该类的公共成员可以被 COM 组件访问,从而实现 JavaScript 与 .NET 方法之间的互操作,否则你会收到下面的错误信息:
System.ArgumentException:“ObjectForScripting 的类必须对 COM 可见。请确认该对象是公共的,或考虑向您的类添加 ComVisible 特性。”
最后,需要在 webBrowser
控件的 ObjectForScripting
属性中设置一个 .NET 对象,这个对象将用于被 JavaScript 调用:
webB.ObjectForScripting = new JavaScriptInteraction();
为了演示新功能的使用,在 html 目录中,提供了一个演示用的 exit.html
直接提供了网页退出屏保的演示按钮。
新的功能提供了更多的可玩性,用户可以根据自己的喜好设计各种有意思的屏保,这样也是满足了输入密码退出这个功能的实现基础。当然我们可以有许多有意思的功能可以自行设计,比如:
1.解谜屏保:设计一个带有简单谜题的屏保,用户需要在网页上回答正确才能退出屏保。谜题可以是数学题、逻辑题或者常识题等,每次屏保激活时,可以随机从题库中抽取一道题目。既然是题库,甚至可以利用屏保学习各种知识,比如英语单词,各种考试题等等。2.拼图屏保:制作一个拼图游戏,用户需要在网页上完成拼图才能退出屏保。可以使用用户自己的照片作为拼图素材,或者从网上随机抓取图片。拼图难度可以根据用户的喜好进行调整。3.计时屏保:设置一个倒计时屏保,用户需要在网页上等待一段时间(例如,1分钟)后才能退出屏保。在等待期间,可以展示一些有趣的事物,如名言警句、美丽的图片或者实时新闻等。
通过这些有趣的屏保设计方案,用户在退出屏保时可以享受到更多互动和趣味性。此外,这些方案还可以根据用户的喜好和需求进行定制和扩展,为用户带来更丰富的屏保体验。
同时,我还在更新中提供了一个经典的 2048 小游戏,要求玩家在赢得游戏后才能退出屏保。
这个游戏改的逻辑其实是没有改好的,也懒得调整了,更新一下游戏介绍也是可以的。
当玩家在游戏中努力拼搏,最终赢得游戏时,他们可能会发现,游戏并没有因此结束,屏保依然继续运行。这时,他们可能会意识到,即使付出了努力,结果也不一定如人意。而当玩家选择投降并重新开始游戏10次后,他们将发现这个看似无用的操作竟然让屏保退出,让电脑恢复正常使用。
也许只有努力过才会发现,游戏还是投降躺平舒服些,只需要重开十次,就会被比你努力凑齐 2048 赢得游戏来退出屏保更快。人生有时就是这样,在现实生活中,我们往往会面临两种选择:努力拼搏还是躺平投降。有时候,努力拼搏的结果并不一定能让我们达到预期的目标,反而可能让我们陷入更深困境,带来更多的困扰。而在某些情况下,选择躺平投降,反而能让我们以更轻松的心态面对问题,从而找到解决问题的更快方法。当然,该拼搏的时候,还是需要努力一把,万一就成功了呢?
本文向大家介绍了如何在 webBrowser 中的网页调用 .NET 方法,以及如何在屏保程序中加入游戏元素。通过这些技巧,我们可以为用户带来更有趣的屏保体验。希望本文能对大家有所帮助,最后项目地址是:https://github.com/sangyuxiaowu/HackerScreenSaver?wt.mc_id=DT-MVP-5005195 感兴趣的话,可以下载体验一下。
*请认真填写需求信息,我们会在24小时内与您取得联系。