Kurento Java Tutorial - Hello World

2023-05-16

Kurento Java Tutorial - Hello World

这个web应用程序是为Java开发人员介绍用Kurento编程的原则而设计的。它包含一个WebRTC镜像视频通信(环回)。本教程假设您具备Java、JavaScript、HTML和WebRTC的基本知识。在开始本教程之前,我们还建议阅读关于Kurento和WebRTC的部分。

注释

此应用程序使用HTTPS。如果您在本地主机中运行它并在浏览器中接受安全异常,它将正常工作,但是如果远程运行,您应该保护您的应用程序。有关更多信息,请选中“配置Java服务器以使用HTTPS”。

快速开始

跟着下面的步骤运行演示程序:
1、安装Kurento Media Server: 安装向导链接
2、运行这些命令:

git clone https://github.com/Kurento/kurento-tutorial-java.git
cd kurento-tutorial-java/kurento-hello-world
git checkout 6.13.0
mvn -U clean spring-boot:run -Dkms.url=ws://localhost:8888/kurento

3、使用WebRTC兼容浏览器(Chrome、Firefox)打开演示页:https://localhost:8443/
4、单击“开始”开始演示。
5、允许访问您的网络摄像头。
6、一旦协商并建立环回连接,您就应该在本地和远程占位符中看到您的网络摄像机视频。
7、单击“停止”完成演示。

理解这个例子

Kurento为开发人员提供了一个Kurento Java客户端来控制Kurento媒体服务器。这个客户端库可以用于任何类型的Java应用程序:服务器端Web、桌面、Android等。它与任何框架都兼容,如JavaEE、Spring、Play、Vert.x、Swing和JavaFX。

这个Hello World演示是使用Kurento可以创建的最简单的web应用程序之一。下图显示了此演示运行的屏幕截图:

在这里插入图片描述
Kurento Hello World Screenshot: WebRTC in loopback

应用程序的界面(一个HTML网页)由两个HTML5标记组成:一个显示本地流(由设备网络摄像头捕获),另一个显示媒体服务器发送回客户端的远程流。

应用程序的逻辑非常简单:本地流被发送到Kurento媒体服务器,该服务器将其发送回客户端,而无需修改。要实现此行为,我们需要创建一个由单个媒体元素(即WebRtcEndpoint)组成的媒体管道,该管道具有交换全双工(双向)WebRTC媒体流的能力。此媒体元素连接到自身,以便将它从浏览器接收到的媒体发送回浏览器。此媒体管道如下图所示:

在这里插入图片描述
这是一个web应用程序,因此它遵循客户机-服务器体系结构。在客户端,逻辑是用JavaScript实现的。在服务器端,我们使用基于Spring引导的应用服务器,使用Kurento Java客户机API来控制Kurento媒体服务器的功能。总之,这个演示的顶层架构是三层的。为了与这些实体通信,使用了两个websocket:
1.在客户端和应用服务器之间创建一个WebSocket来实现一个自定义的信令协议。
2、另一个WebSocket用于执行Kurento Java客户端和Kurento媒体服务器之间的通信。
此通信使用Kurento协议进行。有关详细说明,请阅读本节:Kurento协议。

下图显示了与应用程序接口交互的完整序列图:
i)JavaScript逻辑;
ii)应用服务器逻辑(使用Kurento Java客户端);
iii)Kurento媒体服务器。在这里插入图片描述
Kurento Hello World(loopbak中的WebRTC)演示的完整序列图

应用服务逻辑

这个演示是在服务器端使用Java开发的,基于Spring Boot框架,它在生成的maven工件中嵌入了Tomcat web服务器,从而简化了开发和部署过程。

注释
您可以使用您喜欢的任何Java服务器端技术来使用Kurento构建web应用程序。例如,一个纯Java EE应用程序、SIP Servlets、Play、Vert.x等等。为了方便起见,我们选择了Spring Boot。

在下图中,您可以看到服务器端代码的类图:

在这里插入图片描述
HelloWorld应用程序的服务器端类图

这个演示的main class是HelloWorldApp。

如您所见,KurentoClient在这个类中被实例化为一个Spring Bean。此bean用于创建Kurento媒体管道,用于向应用程序添加媒体功能。在这个实例中,我们看到需要向客户机库指定Kurento媒体服务器的位置。在这个例子中,我们假设它位于localhost,监听端口8888。如果复制此示例,则需要在其中插入Kurento媒体服务器实例的特定位置。
一旦Kurento客户端被实例化,就可以与Kurento媒体服务器通信并控制其多媒体功能。

@SpringBootApplication
@EnableWebSocket
public class HelloWorldApp implements WebSocketConfigurer {
  @Bean
  public HelloWorldHandler handler() {
    return new HelloWorldHandler();
  }

  @Bean
  public KurentoClient kurentoClient() {
    return KurentoClient.create();
  }

  @Override
  public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(handler(), "/helloworld");
  }

  public static void main(String[] args) throws Exception {
    SpringApplication.run(HelloWorldApp.class, args);
  }
}

此web应用程序遵循单页应用程序体系结构(SPA),并使用WebSocket通过请求和响应与应用服务器通信。具体来说,main app类实现接口WebSocketConfigurer以注册一个WebSocketHandler,该WebSocketHandler处理 /helloworld 的WebSocket请求。

类HelloWorldHandler实现TextWebSocketHandler来处理文本WebSocket请求。这个类的中心部分是handleTextMessage方法。此方法实现请求的操作,通过WebSocket返回响应。换句话说,它实现了前面序列图中描述的信令协议的服务器部分。

public void handleTextMessage(WebSocketSession session, TextMessage message)
    throws Exception {
  [...]
  switch (messageId) {
    case "start":
      start(session, jsonMessage);
      break;
    case "stop": {
      stop(session);
      break;
    }
    case "onIceCandidate":
      onRemoteIceCandidate(session, jsonMessage);
      break;
    default:
      sendError(session, "Invalid message, ID: " + messageId);
      break;
  }
  [...]
}

The start() method performs the following actions:

  • 配置媒体处理逻辑。这是应用程序配置Kurento如何处理媒体的部分。换句话说,媒体管道就是在这里创建的。为此,对象KurentoClient用于创建mediapipline对象。使用它,我们需要的媒体元素被创建和连接。在本例中,我们只实例化一个WebRtcEndpoint,用于接收WebRTC流并将其发送回客户端。
final MediaPipeline pipeline = kurento.createMediaPipeline();

final WebRtcEndpoint webRtcEp =
    new WebRtcEndpoint.Builder(pipeline).build();

webRtcEp.connect(webRtcEp);
  • 创建事件侦听器。由Kurento管理的所有对象都能够发出几种类型的事件,如端点事件中所述。应用服务器可以监听它们,以便对媒体服务器的处理逻辑内部的情况有更多的了解。监听所有可能的事件是一个很好的实践,因此客户机应用程序拥有尽可能多的信息。
// Common events for all objects that inherit from BaseRtpEndpoint
addErrorListener(
    new EventListener<ErrorEvent>() { ... });
addMediaFlowInStateChangeListener(
    new EventListener<MediaFlowInStateChangeEvent>() { ... });
addMediaFlowOutStateChangeListener(
    new EventListener<MediaFlowOutStateChangeEvent>() { ... });
addConnectionStateChangedListener(
    new EventListener<ConnectionStateChangedEvent>() { ... });
addMediaStateChangedListener(
    new EventListener<MediaStateChangedEvent>() { ... });
addMediaTranscodingStateChangeListener(
    new EventListener<MediaTranscodingStateChangeEvent>() { ... });

// Events specific to objects of class WebRtcEndpoint
addIceCandidateFoundListener(
    new EventListener<IceCandidateFoundEvent>() { ... });
addIceComponentStateChangeListener(
    new EventListener<IceComponentStateChangeEvent>() { ... });
addIceGatheringDoneListener(
    new EventListener<IceGatheringDoneEvent>() { ... });
addNewCandidatePairSelectedListener(
    new EventListener<NewCandidatePairSelectedEvent>() { ... });
  • WebRTC SDP协商。在WebRTC中,SDP提供/应答模型用于协商将在对等方之间交换的音频或视频轨迹,以及它们支持的公共特性的子集。此协商通过在一个对等方中生成SDP提议,将其发送给另一个对等方,并返回将生成的SDP响应来完成。
    在这种特殊情况下,SDP提议由浏览器生成并发送给Kurento,Kurento随后生成SDP应答,该应答必须作为响应发送回浏览器。
// 'webrtcSdpOffer' is the SDP Offer generated by the browser;
// send the SDP Offer to KMS, and get back its SDP Answer
String webrtcSdpAnswer = webRtcEp.processOffer(webrtcSdpOffer);
sendMessage(session, webrtcSdpAnswer);
  • Gather ICE candidates。当SDP提供/应答协商正在进行时,每个对等方都可以开始收集将用于ICE协议的连接候选。此过程的工作方式与浏览器通过发出事件RTCPeerConnection.onicecandidate通知其客户机代码的方式非常相似;同样,Kurento的WebRtcEndpoint将通过事件IceCandidateFound通知其客户机应用程序。
webRtcEp.gatherCandidates();

Client-Side Logic

现在让我们转到应用程序的客户端。要在服务器端调用先前创建的WebSocket服务,我们使用JavaScript类WebSocket。我们使用一个名为Kurento-utils.js的特定Kurento JavaScript库来简化WebRTC与服务器的交互。这个库依赖于adapter.js,这是一个由Google维护的JavaScript WebRTC实用程序,它可以消除浏览器之间的差异。
这些库作为Maven依赖项引入到项目中,Maven依赖项从WebJars.org下载所有必需的文件;它们加载在index.html页面中,并在index.js文件中使用。
在下面的代码片段中,我们可以看到在path/helloworld中创建的WebSocket。然后,使用WebSocket的onmessage监听器在客户端实现JSON信令协议。请注意,有三条传入客户端的消息:startResponse、error和iceCandidate。为实现通信中的每一步都采取了方便的措施。例如,在函数start中,kurento-utils.js的函数webrtcpeeer.WebRtcPeerSendrecv用于启动WebRTC通信。

var ws = new WebSocket('ws://' + location.host + '/helloworld');

ws.onmessage = function(message) {
   var parsedMessage = JSON.parse(message.data);
   console.info('Received message: ' + message.data);

   switch (parsedMessage.id) {
   case 'startResponse':
      startResponse(parsedMessage);
      break;
   case 'error':
      if (state == I_AM_STARTING) {
         setState(I_CAN_START);
      }
      onError('Error message from server: ' + parsedMessage.message);
      break;
   case 'iceCandidate':
      webRtcPeer.addIceCandidate(parsedMessage.candidate, function(error) {
         if (error)
            return console.error('Error adding candidate: ' + error);
      });
      break;
   default:
      if (state == I_AM_STARTING) {
         setState(I_CAN_START);
      }
      onError('Unrecognized message', parsedMessage);
   }
}

function start() {
   console.log('Starting video call ...');

   // Disable start button
   setState(I_AM_STARTING);
   showSpinner(videoInput, videoOutput);

   console.log('Creating WebRtcPeer and generating local sdp offer ...');

   var options = {
      localVideo : videoInput,
      remoteVideo : videoOutput,
      onicecandidate : onIceCandidate
   }
   webRtcPeer = new kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv(options,
         function(error) {
            if (error)
               return console.error(error);
            webRtcPeer.generateOffer(onOffer);
         });
}

function onOffer(error, offerSdp) {
   if (error)
      return console.error('Error generating the offer');
   console.info('Invoking SDP offer callback function ' + location.host);
   var message = {
      id : 'start',
      sdpOffer : offerSdp
   }
   sendMessage(message);
}

function onIceCandidate(candidate) {
   console.log('Local candidate' + JSON.stringify(candidate));

   var message = {
      id : 'onIceCandidate',
      candidate : candidate
   };
   sendMessage(message);
}

function startResponse(message) {
   setState(I_CAN_STOP);
   console.log('SDP answer received from server. Processing ...');

   webRtcPeer.processAnswer(message.sdpAnswer, function(error) {
      if (error)
         return console.error(error);
   });
}

function stop() {
   console.log('Stopping video call ...');
   setState(I_CAN_START);
   if (webRtcPeer) {
      webRtcPeer.dispose();
      webRtcPeer = null;

      var message = {
         id : 'stop'
      }
      sendMessage(message);
   }
   hideSpinner(videoInput, videoOutput);
}

function sendMessage(message) {
   var jsonMessage = JSON.stringify(message);
   console.log('Sending message: ' + jsonMessage);
   ws.send(jsonMessage);
}

依赖项

这个Java Spring应用程序是使用Maven实现的。pom.xml的相关部分是声明Kurento依赖项的地方。如下面的代码片段所示,我们需要两个依赖项:客户端的Kurento客户机Java依赖项(Kurento客户机)和JavaScript Kurento实用程序库(Kurento实用程序库)。其他客户端库由WebJars管理。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Kurento Java Tutorial - Hello World 的相关文章

  • 使用 Eclipse 将具有外部依赖项的 Java 项目导出到 jar

    有没有一种简单的方法可以将 Java 项目 包括其所有外部依赖项 导出到标准 jar 文件 我开发了一个使用多个 Apache 库的 SDK 我希望能够将该项目作为单个 jar 发布 到目前为止我找到的这个问题的答案要求将项目打包为 Run
  • Android CursorAdapter、ListView 和后台线程

    我一直在开发的这个应用程序有包含数兆字节数据的数据库可供筛选 许多活动只是列表视图 通过数据库中的各个级别的数据下降 直到到达 文档 即从数据库中提取并显示在手机上的 HTML 我遇到的问题是 其中一些活动需要能够通过捕获击键并重新运行带有
  • 按位运算符简单地翻转整数中的所有位?

    我必须翻转整数的二进制表示形式中的所有位 鉴于 10101 输出应该是 01010 当与整数一起使用时 完成此操作的按位运算符是什么 例如 如果我正在编写类似的方法int flipBits int n 什么会进入身体 我只需要翻转数字中已经
  • 想要从java中的char数组创建字符流

    我想从 char 数组构造一个流以使用 java 8 功能 例如过滤器和映射 char list a c e Stream
  • AWS SDK 2 承担角色

    Bean public DynamoDbClient amazonDynamoDB final AssumeRoleRequest assumeRoleRequest AssumeRoleRequest builder roleSessio
  • 限制 JPQL 中的结果数量

    如何限制从数据库检索结果的数量 select e from Entity e I need only 10 results for instance 您可以尝试像这样给出 10 个要显式获取的结果 entityManager createQ
  • 外部实体更改后索引不更新

    我目前正在开发一个项目 使用 JPA 2 1 保存数据并使用 hibernate search 4 5 0 final 搜索实体 映射类和索引后 搜索工作正常 但是 当我更改值时描述B 类从 someStr 到 anotherStr 数据库
  • 如何从 Java 中“double”类型的值中删除小数值

    我正在调用一个名为 calculateStampDuty 的方法 它将返回 财产需缴纳的印花税金额 百分比计算有效 很好 并返回正确的值 15000 0 但是 我想显示该值 前端用户只是 15000 所以只想删除小数点和任何前面的值 此后
  • java 中的 Try-with-resources 和 return 语句

    我想知道是否放一个return里面的声明尝试资源block 防止资源自动关闭 try Connection conn return conn createStatement execute 如果我写这样的东西将会联系被关闭 Oracle 文
  • 在 Java 中的 JFrame/JPanel/JComponent 中添加 Web 浏览器

    我正在开发一个 Java 应用程序 需要在应用程序中使用 Web 浏览器 我见过一些应用程序这样做 例如在同一应用程序中单击左侧面板中的提要并打开右侧面板中的链接时的 RSS 阅读器 我想实现类似的功能 在java中可以做到这一点吗 Jav
  • 使用 equals 方法比较两个对象,Java

    我有一个对象数组 我想将它们与目标对象进行比较 我想返回与目标对象完全匹配的对象的数量 这是我的计数方法 public int countMatchingGhosts Ghost target int count 0 for int i 0
  • Java:不使用 Arrays.sort() 对整数数组进行排序

    这是我们 Java 课程的练习之一中的说明 首先 我想说我 做了我的功课 我不仅仅是懒惰地请 Stack Overflow 上的人帮我回答这个问题 在所有其他练习中 这个特定项目一直是我的问题 因为我一直在努力寻找 完美的算法 编写JAVA
  • 如何构建和使用 TimeSeriesCollections

    我想在图表的 X 轴上显示一些日期 并且here https stackoverflow com questions 5118684 jfreechart histogram with dates据说我必须使用 TimeSeriesColl
  • JPA 的 Hibernate 查询提示

    我一直在尝试为所有可以通过设置的提示找到一个明确的资源Query setHint String Object JPA 中的方法调用 但我一无所获 有人知道一个好的参考吗 See 3 4 1 7 查询提示 http docs jboss or
  • Java 常量枚举[重复]

    这个问题在这里已经有答案了 可能的重复 理解 Java 中的枚举 https stackoverflow com questions 1419835 understanding enums in java 为什么我们应该使用枚举而不是 Ja
  • Java 中通用方法参数的 getClass()

    以下 Java 方法无法编译
  • 在java中创建一个XML树并将其转换为json对象

    我尝试创建也能够转换为 json 的树 但对于只有一个xpath 当我尝试实现多个 xpath 时 我无法获得所需的输出 这里我分享一下我的实现 private static Document addElemtbypath List
  • 尝试使用 Spring 和扩展 Hibernate JpaRepository 的自定义 GenericDao 接口来使用 EhCache

    背景 这是我的工作 简化 GenericDao接口 由任何实现DomainDao 通用Dao java NoRepositoryBean public interface GenericDao
  • 通过向上转换将 Java.sql.date 转换为 Java.util.date 安全吗?

    java sql date 扩展了 java util date 那么通过将 java sql date 转换为 java util date 是否可以在两者之间进行转换 或者有其他方法可以转换它们吗 您不一定需要强制转换 您可以将 SQL
  • 在 for 循环比较中使用集合大小

    Java 中 Collections 的 size 方法是否有编译器优化 考虑以下代码 for int i 0 i

随机推荐

  • win10 安装debian,安装docker

    参考文章 xff1a https docs microsoft com zh cn windows wsl install win10 https docs docker com engine install debian https do
  • Jenkins结合SVN报错E230001: Server SSL certificate verification failed的解决方法

    最近公司搬家 xff0c 之前用来做一些自动化工作的Jenkins服务器 罢工 了 在最后SVN提交时报了一个之前没有的错误 xff1a svn E230001 Commit failed details follow svn E23000
  • 为WSL的ubuntu子系统安装图形化界面

    WSL只提供黑窗口登录功能 xff0c 为了使用gui xff0c 需要安装gui并且使用远程连接的方式登录 更新源 sudo apt get update 安装xorg sudo apt get install xorg 安装xfce4
  • Json 转sqlserver创建表脚本 JSONtoSQLGenerator

    This code takes a JSON input string and automatically generates SQL Server CREATE TABLE statements to make it easier to
  • 如何远程登陆Linux图形界面

    可以使用xrdp软件 xff0c 下面是具体的操作步骤 xff1a 1 给Linux系统安装xrdp工具 xff0c 在命令行中输入 xff1a sudo apt get install xrdp 2 在windows中点击开始 gt 运行
  • 信息学奥赛一本通-1049:晶晶赴约会

    题目描述 晶晶的朋友贝贝约晶晶下周一起去看展览 xff0c 但晶晶每周的1 3 5有课必须上课 xff0c 请帮晶晶判断她能否接受贝贝的邀请 xff0c 如果能输出YES xff1b 如果不能则输出NO 注意YES和NO都是大写字母 xff
  • 洛谷P1553 数字反转(升级版)

    洛谷P1553 数字反转 xff08 升级版 xff09 题目描述输入格式输出格式输入输出样例说明 提示个人理解整数百分数分数小数 AC代码写在最后 题目描述 给定一个数 xff0c 请将该数各个位上数字反转得到一个新数 这次与NOIp20
  • Windows10 WSL2 安装Ubuntu并使用图形化界面

    有了WSL2后 xff0c 又有可以折腾的东西了 可以使用WSL2的Linux环境编译 LaTeX LaTeX L A T E X 文档 xff0c 要比Windows端快很多 xff0c 也可以用vscode的Remote WSL插件来编
  • VMware创建虚拟机并分配地址

    修改虚拟机设置 修改网卡配置 vi etc sysconfig network scripts ifcfg ens33 TYPE 61 Ethernet PROXY METHOD 61 none BROWSER ONLY 61 no BOO
  • 蓝桥杯单片机开发板-定时器中断实现数码管0-99+摇摆灯(详解)

    本博文程序实现的功能是蓝桥杯51单片机通过定时器功能来实现数码管的计数与8个LED小灯的交替闪烁 首先是程序初始化函数 xff1a span class token keyword void span span class token fu
  • 鸿蒙OS2.0添加加密门禁卡进入卡包

    鸿蒙OS2 0添加加密门禁卡进入卡包 该功能需要手机支持NFC功能 xff0c 畅享 Nova 等系列不具备NFC功能 xff0c 如找不到添加小区门禁卡的功能 xff0c 可能需要将系统升级至最新版本 打开 钱包 在 钱包 gt 钥匙 g
  • 数据结构(一)——顺序表(C语言实现)

    定义实现 定义结构定义操作 创建顺序表初始化顺序表插入元素删除元素销毁顺序表 定义 数据结构是相互之间存在一种或多种特定关系的数据元素的集合 根据数据元素之间关系的不同特性 xff0c 通常有如下4类基本结构 集合 xff1a 结构中的数据
  • Latex引用参考文献,要作者名、章节、页码等详细信息

    Latex引用参考文献时 xff0c 在正文部分既想要出现文献号 xff0c 又想要作者名 章节 页码等详细信息时 xff0c 可以如下操作 xff1a 图1 xff0c 只需要在文中相应位置写入 xff1a citet ash 即可 图2
  • (一)OpenStack---M版---双节点搭建---基础环境配置

    视频已上线B站 传送门 配置如下 本次搭建采用2台4核4G的虚拟机 也可以用2台2核4G 主机名配置网络Controller4核4GInterface1 192 168 100 10 24Interface2 192 168 200 10
  • 亚马逊AWS-EC2云服务器部署代理服务

    首先 xff0c 在此阿里云 腾讯云 华为云购买一个云服务器推荐使用阿里云的 首先链接你的VPS xff0c 可以使用X shell Putty SecureCRTPortable 等SSH链接工具 注意 xff1a 如果不知道怎么使用工具
  • QT程序崩溃闪退问题

    1 查看程序是否产生dump文件 2 通过WINDBG启动运行软件 xff0c 抓取应用CRASH原因 3 监控应用的CPU 内存 句柄和线程是否有溢出 常见异常的原因有 xff1a 1 在线程执行中使用qDebug 2 在线程中使用 QD
  • Hi3559AV100开发调试日志

    2019 09 05 主板原生系统状态 1 串口正常 2 网络不工作 ifconfig 命令没有显示出网络设备列表 xff0c 不能对网络进行配置 运行 ip link set up dev eth0 命令解决问题 3 插入TF card
  • 关于Kurento 和 WebRTC-Kurento学习(一)

    关于Kurento 和 WebRTC 关于Kurento 和 WebRTC Kurento是一个WebRTC媒体服务器和一组客户端API xff0c 简化了针对web和智能手机平台的高级视频应用程序的开发 它的特点包括通信组 转码 录音 混
  • NAT穿越(p2p打洞)免费STUN服务器列表

    什么是STUN STUN xff08 Simple Traversal of UDP over NATs xff0c NAT 的UDP简单穿越 xff09 是一种网络协议 xff0c 它允许位于NAT xff08 或多重NAT xff09
  • Kurento Java Tutorial - Hello World

    Kurento Java Tutorial Hello World 这个web应用程序是为Java开发人员介绍用Kurento编程的原则而设计的 它包含一个WebRTC镜像视频通信 xff08 环回 xff09 本教程假设您具备Java J