本篇不详细介绍websocket,只针对websocket整合rtc。

一、简单说下webrtc的流程

webrtc是P2P通信,也就是实际交流的只有两个人,而要建立通信,这两个人需要交换一些信息来保证通信安全。而且,webrtc必须通过ssh加密,也就是使用https协议、wss协议。

借用一幅图

1.1 创建端点的解析

以下解析不包括websockt,只针对stun做解析。与上图略有不同

  1. 首先,Client A创建端点(Create PeerConnection),并添加音视频流(Add Streams)。接下来通知Client B,让Client B也创建一个端点。

  2. Client B收到通知后,Client B创建端点(Create PeerConnection),并添加音视频流(Add Streams),

  3. 接下来,Client B创建一个用于answer的SDP对象(Create Answer),保存并发送给Client A。

  4. Client A收到用于answer的SDP后,保存下来。

  5. 然后, Client A创建一个用于offer的SDP对象(Create Office),保存并发送给Client B。

  6. 最后,Client B保存收到的用于offer的SDP对象

以上步骤完成之后:

1、rtc会自动收集Candidate信息,并通过回调函数通知你,用于交换Candidate信息。

2、交换完Candidate信息后,P2P连接就建立好了。并通过回调函数,将远程视频流给你

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

1.2 交换Candidate信息

Candidate信息是交换完SDP对象之后自动收集的信息。在创建端点(PeerConnection)的时候,添加回调函数(onIceCandidate

创建回调函数(onIceCandidate)

将Candidate信息发送给另一端(a发给b,b发给a)

保存发过来的 Candidate信息(addIceCandidate)。注意是保存发过来的,不是保存自己的!!!

交换完Candidate信息后,P2P连接就建立好了。

二、新建springboot项目,并开启ssh

因为rtc必须使用ssh,所以springboot需要使用https协议才可以

2.1 生成ssh自签名文件

在终端中执行

keytool -genkey -alias webrtc -dname "CN=Andy,OU=kfit,O=kfit,L=HaiDian,ST=BeiJing,C=CN" -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore webrtc.keystore -validity 36500

执行时,会要求输入密码;
执行后,会在根目录下生成一个webrtc.keystore的文件

2.2 配置ssh信息

webrtc.keystore文件放在resource目录下

application.yaml中填写配置信息

server:ssl:#证书的路径key-store: classpath:webrtc.keystore#证书密码key-store-password: 123456#秘钥库类型key-store-type: JKS

2.3 检测一下能不能跑起来

运行就行,能跑起来就OK。

三、编写websocket服务类

这个简单的demo只考虑一个房间,没有房间控制,所以websocket代码很少,主要代码都在js里面。

3.1 先放一下Message实体类

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Message
{private String operation;private Object msg;public Message setOperation(String operation){this.operation = operation;return this;}public Message setMsg(Object msg){this.msg = msg;return this;}public String getMsgStr(){return msg == null ? "" : msg.toString();}
}

3.2 服务类

主要有以下信息:

  • 加入房间(into)
  • 发送 sdp 对象(send-sdp)
  • 交换 candidate 信息(send-candidate)
package com.websocket.controller;import com.alibaba.fastjson.JSONObject;
import com.websocket.pojo.Message;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Controller;import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;@Log4j2
@Controller
@ServerEndpoint("/webrtc")
public class WebrtcController
{/*** 这里只做一个最简单的, 只有一个房间, 后面有需要自己可以改*/private static Session offer;private static Session answer;@OnMessagepublic void onMessage(Session session, String message){final Message data = JSONObject.parseObject(message, Message.class);final Message response = Message.builder().operation(data.getOperation()).build();switch (data.getOperation()) {//加入房间case "into": {if (offer == null) {offer = session;response.setMsg("offer");}else if (answer == null) {answer = session;response.setMsg("answer");}else {response.setMsg("none");}sendMessage(session, response);break;}case "start":sendMessage(offer, response);break;//发送 offer 的 SDP 对象case "send-offer"://发送 answer 的 SDP 对象case "send-answer"://交换 candidate 信息case "send-candidate": {sendOther(session, response.setMsg(data.getMsg()));break;}}}@OnClosepublic void onClose(Session session, CloseReason closeReason){if (offer != null && session.getId().equals(offer.getId())) {offer = null;}else if (answer != null && session.getId().equals(answer.getId())) {answer = null;}}public static void sendOther(Session session, Object msg){if (offer != null && session.getId().equals(offer.getId())) {sendMessage(answer, msg);}else if (answer != null && session.getId().equals(answer.getId())) {sendMessage(offer, msg);}}public static void sendMessage(Session session, Object msg){sendMessage(session, JSONObject.toJSONString(msg));}@SneakyThrowsprivate static void sendMessage(Session session, String msg){final RemoteEndpoint.Basic basic = session.getBasicRemote();basic.sendText(msg);}
}

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

四、页面

4.1 html

这部分不太重要,就直接放上来了

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head><meta charset="UTF-8"><title>websocket-demo</title><link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.2.1/css/bootstrap.min.css">
</head>
<body><div class="container py-3"><div class="row"><div class="col-12"><div id="addRoom" class="btn btn-primary">加入房间</div></div><div class="col-12 col-lg-6"><p>本地视频:</p><video id="localVideo" width="500px" height="300px" autoplay style="border: 1px solid black;"></video></div><div class="col-12 col-lg-6"><p>远程视频:</p><video id="remoteVideo" width="500px" height="300px" autoplay style="border: 1px solid black;"></video></div></div></div><script src="https://s3.pstatp.com/cdn/expire-1-M/jquery/3.3.1/jquery.min.js" type="text/javascript"></script></body>
</html>

4.2 webrtc工具类 webrtc-util.js

包括以下方法:

打开本地音视频流

创建PeerConnection对象

创建用于office的SDP对象

创建用于answer的SDP对象

保存SDP对象

保存Candidate信息

收集 candidate 的回调

获得远程视频流的回调

需要注意的是:最后的两个回调,需要在创建PeerConnection对象之后,打开本地音视频流之前执行。

4.2.1 本地变量

其中的 ice对象,根据上一篇测试通过的stun服务器信息填写。

//端点对象
let rtcPeerConnection;//本地视频流
let localMediaStream = null;//ice服务器信息, 用于创建 SDP 对象
let iceServers = {"iceServers": [// {"url": "stun:stun.l.google.com:19302"},{"urls": ["stun:159.75.239.36:3478"]},{"urls": ["turn:159.75.239.36:3478"], "username": "chr", "credential": "123456"},]
};// 本地音视频信息, 用于 打开本地音视频流
const mediaConstraints = {video: {width: 500, height: 300},audio: true //由于没有麦克风,所有如果请求音频,会报错,不过不会影响视频流播放
};// 创建 offer 的信息
const offerOptions = {iceRestart: true,offerToReceiveAudio: true, //由于没有麦克风,所有如果请求音频,会报错,不过不会影响视频流播放
};

4.2.2 打开本地音视频流 

// 1、打开本地音视频流
const openLocalMedia = (callback) => {console.log('打开本地视频流');navigator.mediaDevices.getUserMedia(mediaConstraints).then(stream => {localMediaStream = stream;//将 音视频流 添加到 端点 中for (const track of localMediaStream.getTracks()) {rtcPeerConnection.addTrack(track, localMediaStream);}callback(localMediaStream);})
}

4.2.3 创建 PeerConnection 对象 

// 2、创建 PeerConnection 对象
const createPeerConnection = () => {rtcPeerConnection = new RTCPeerConnection(iceServers);
}

4.2.4 创建用于 offer 的 SDP 对象 

// 3、创建用于 offer 的 SDP 对象
const createOffer = (callback) => {// 调用PeerConnection的 CreateOffer 方法创建一个用于 offer的SDP对象,SDP对象中保存当前音视频的相关参数。rtcPeerConnection.createOffer(offerOptions).then(sdp => {// 保存自己的 SDP 对象rtcPeerConnection.setLocalDescription(sdp).then(() => callback(sdp));}).catch(() => console.log('createOffer 失败'));
}

 4.2.5 创建用于 answer 的 SDP 对象

// 4、创建用于 answer 的 SDP 对象
const createAnswer = (callback) => {// 调用PeerConnection的 CreateAnswer 方法创建一个 answer的SDP对象rtcPeerConnection.createAnswer(offerOptions).then(sdp => {// 保存自己的 SDP 对象rtcPeerConnection.setLocalDescription(sdp).then(() => callback(sdp));}).catch(() => console.log('createAnswer 失败'))
}

4.2.6 保存远程的 SDP 对象 

// 5、保存远程的 SDP 对象
const saveSdp = (answerSdp, callback) => {rtcPeerConnection.setRemoteDescription(new RTCSessionDescription(answerSdp)).then(callback);
}

4.2.7 保存 candidate 信息 

// 6、保存 candidate 信息
const saveIceCandidate = (candidate) => {let iceCandidate = new RTCIceCandidate(candidate);rtcPeerConnection.addIceCandidate(iceCandidate).then(() => console.log('addIceCandidate 成功'));
}

4.2.8 收集 candidate 的回调

// 7、收集 candidate 的回调
const bindOnIceCandidate = (callback) => {// 绑定 收集 candidate 的回调rtcPeerConnection.onicecandidate = (event) => {if (event.candidate) {callback(event.candidate);}};
};

4.2.9 获得 远程视频流 的回调 

// 8、获得 远程视频流 的回调
const bindOnTrack = (callback) => {rtcPeerConnection.ontrack = (event) => callback(event.streams[0]);
};

以上代码都写在 webrtc-util.js 中,是可以复用滴

接下来,就是在html中引入这个js,然后和websocket整合一下,把通知、candidate 信息等等,通过websocket发送给另一端

End

如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

WebRTC音视频通话(二)简单音视频通话相关推荐

  1. WebRTC 实现P2P音视频通话——实现一对一音视频通话

    WebRTC 实现P2P音视频通话 WebRTC 实现P2P音视频通话--搭建信令服务器 WebRTC 实现P2P音视频通话--搭建stun/trun P2P穿透和转发服务器 WebRTC 实现P2P ...

  2. 一文学会 QQ视频通话、抖音的视频回显实现方案

    QQ视频通话.抖音的视频回显 是如何实现的 先说为什么会有这一篇文章: 2014年联想曾经做过一款 短视频软件,叫"魔力秀".可以说和现在的抖音基本是一样的,但因为"魔力 ...

  3. webrtc 入门第五章 一对一视频通话实现

    webrtc 入门第五章 一对一视频通话实现 一.介绍 ​ 在前面的章节我们学习了如何操作本地的设备摄像头,麦克风等,学会了如何进行本地的流媒体操作如录制,下载,同步等.在第三第四章节学习了webrt ...

  4. 入门启发:音视频的简单理解

    算机技术领域中,『音视频技术』应该说算是较复杂的小门类.较复杂的东西有个简单的入门指引,或者有前辈带路是很重要的. 前阵子,因为项目中急需音视频技术,虽然网上资料看似很丰富,但对初学者来说,很多资料都 ...

  5. 音视频开发二:音视频知识总结

    文章目录 简介 简单理解,音视频原理 音视频理论基础 音频 声音介绍 **为什么要存在数字音频 ?** **什么是数字音频?** 从"模拟信号"到"数字化"的过 ...

  6. JavaWeb-SpringBoot(抖音)_二、服务器间通讯

    JavaWeb-SpringBoot(抖音)_一.抖音项目制作 传送门 JavaWeb-SpringBoot(抖音)_二.服务器间通讯 传送门 JavaWeb-SpringBoot(抖音)_三.抖音项 ...

  7. 不若与众:说说抖音的二创激励计划

    七月份抖音与爱奇艺宣布达成合作,如今,抖音二创激励计划落地.9月5日,抖音公布二创激励计划,相当于为这场燎原之火又添了一大把柴. 此次计划是抖音与爱奇艺双方围绕长视频的二创与推广展开的探索,面向影视综 ...

  8. 音视频开发成长之路—进阶之路3个重要知识点丨WebRTC丨FFmpeg丨SRS流媒体服务器丨C++音视频丨嵌入式音视频

    音视频开发成长之路-进阶之路3个重要知识点 视频讲解如下,点击观看: 音视频开发成长之路-进阶之路3个重要知识点丨WebRTC丨FFmpeg丨SRS流媒体服务器丨C++音视频丨嵌入式音视频 音视频高级 ...

  9. (二)音视频:MediaCodec编码桌面信息 完整Demo 进一步理解H264

    (一)音视频:解码H264文件流程 渲染和拿到解码后源数据YUV 完整Demo] (二)音视频:MediaCodec编码桌面信息 完整Demo 进一步理解H264 (三)音视频:解析H264 SPS ...

  10. WebRTC系列<二> 案例与工具

     阅读关于webRTC的其他文章: WebRTC系列<一> 什么是WebRTC? WebRTC系列<二> 案例与工具 ----------------------------- ...

最新文章

  1. Linux教程 网络管理命令Netstat的使用
  2. Mycat简单实现读写分离与分库分表
  3. python3.5和pip3安装路径不匹配问题
  4. mvc php session,PHP Session入门教程
  5. bootstrap之排版类
  6. JMX和Spring –第1部分
  7. 微信小程序和vue双向绑定哪里不一样_浅析Vue 和微信小程序的区别、比较
  8. P2158 [SDOI2008]仪仗队 欧拉函数
  9. python 新式类和旧式类
  10. Android SDK下载网址
  11. c语言画bode图程序,根据上位机测得的Bode图的幅频特性,就能确定系统(或环节)的相频特性,试问这在什么系统时才能实现?...
  12. [BZOJ 5339] 教科书般的亵渎
  13. 《微电子概论》2.1 理论基础
  14. 【C#】委托,方法回调,匿名函数,拉姆达表达式
  15. 介绍一个使用go写的TUI性能监测工具gotop
  16. Linux下使用 ./ 来运行可执行文件
  17. uva 10158 War
  18. 使用selenium自动爬取斗鱼直播平台的所有房间信息
  19. 性能测试指南 | 一些实用的排查命令(未完待续)
  20. Linux下的硬盘信息查看

热门文章

  1. [开源]Qt宝马车标
  2. sunpinyin uint.h
  3. 解决vue项目404 nginx url转发
  4. 动动嘴就可以解锁?来看下华为最新的技术专利
  5. 5000配置一台游戏型计算机,开学装机:2020年如何配一台5000元主流配置的游戏主机?...
  6. (摘录)英语学习方法
  7. 新华网:软件工程师职业前景、薪水报酬及地位分析
  8. 分享2个VMware等虚拟机用的Macos系统镜像11.5、12.3.1
  9. 魅蓝e android版本,魅蓝E的安卓7.0来了!魅蓝E2却看哭了
  10. 软件项目经理的职责和技能有哪些