WebRTC音视频通话(二)简单音视频通话

这篇具有很好参考价值的文章主要介绍了WebRTC音视频通话(二)简单音视频通话。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

一、简单说下webrtc的流程

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

借用一幅图

WebRTC音视频通话(二)简单音视频通话

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↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓文章来源地址https://www.toymoban.com/news/detail-408518.html

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的文件

WebRTC音视频通话(二)简单音视频通话 

2.2 配置ssh信息

webrtc.keystore文件放在resource目录下

WebRTC音视频通话(二)简单音视频通话

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;

    @OnMessage
    public 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;
            }
        }
    }

    @OnClose
    public 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));
    }


    @SneakyThrows
    private 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音视频通话(二)简单音视频通话的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • WebRTC音视频通话-RTC直播本地视频及相册视频文件

    WebRTC音视频通话-RTC直播本地视频及相册视频文件 WebRTC音视频通话-RTC直播本地视频文件效果图如下 WebRTC音视频通话-RTC直播本地视频文件时候,用到了AVPlayer、CADisplayLink。 AVPlayer是什么? AVPlayer是基于AVFoundation框架的一个类,很接近底层,灵活性强,可以自定义视频播放样式

    2024年02月13日
    浏览(31)
  • WebRTC音视频通话-实现GPUImage视频美颜滤镜效果iOS

    WebRTC音视频通话-实现GPUImage视频美颜滤镜效果 在WebRTC音视频通话的GPUImage美颜效果图如下 可以看下 之前搭建ossrs服务,可以查看:https://blog.csdn.net/gloryFlow/article/details/132257196 之前实现iOS端调用ossrs音视频通话,可以查看:https://blog.csdn.net/gloryFlow/article/details/132262724 之前WebR

    2024年02月12日
    浏览(39)
  • WebRTC音视频通话-WebRTC推拉流过程中日志log输出

    WebRTC音视频通话-WebRTC推拉流过程中日志log输出 之前实现iOS端调用ossrs服务实现推拉流流程。 推流:https://blog.csdn.net/gloryFlow/article/details/132262724 拉流:https://blog.csdn.net/gloryFlow/article/details/132417602 在推拉流过程中的WebRTC的相关日志log输出可以看到一些相关描述信息。在WebRTC日志

    2024年02月10日
    浏览(37)
  • 【音视频流媒体】2、WebRTC 直播超详细介绍

    一对一直播框架: WebRTC终端: 音视频采集, 编解码, NAT穿越, 音视频数据传输 Signal服务器: 信令处理(如加入房间, 离开房间, 传递媒体协商消息) STUN/TURN服务器: 获取WebRTC终端在公网的IP地址, NAT穿越失败后的数据中转. js中 var promise = navigator.mediaDevices.getUserMedia(constraints); 可访问摄

    2023年04月18日
    浏览(33)
  • WebRTC音视频通话-iOS端调用ossrs直播拉流

    WebRTC音视频通话-iOS端调用ossrs直播拉流 之前实现iOS端调用ossrs服务,文中提到了推流。没有写拉流流程,所以会用到文中的WebRTCClient。请详细查看:https://blog.csdn.net/gloryFlow/article/details/132262724 最近有朋友问过,我发现之前少了一块拉流流程,这里补充一下。 2.1、拉流实现时

    2024年02月11日
    浏览(40)
  • WebRTC音视频通话-新增或修改SDP中的码率Bitrate限制

    WebRTC音视频通话-新增或修改SDP中的码率Bitrate限制参数 之前搭建ossrs服务,可以查看:https://blog.csdn.net/gloryFlow/article/details/132257196 之前实现iOS端调用ossrs音视频通话,可以查看:https://blog.csdn.net/gloryFlow/article/details/132262724 之前WebRTC音视频通话高分辨率不显示画面问题,可以查

    2024年02月13日
    浏览(31)
  • 基于webrtc的音视频通话,实现相机流识别人脸的功能

    这几天研究了一下webRTC的基础能力,在此基础之上能实现的视频通话,互动等更多实用功能。项目中使用的是阿里的rtc,我研究的是声网的是否符合功能,后续会总结和记录一下应用到的几个功能实现方法。 今天要记录的功能是项目流识别人脸的功能,其实类似功能很常见了

    2024年04月28日
    浏览(32)
  • Android平台一对一音视频通话方案对比:WebRTC VS RTMP VS RTSP

    一对一音视频通话使用场景 一对一音视频通话都需要稳定、清晰和流畅,以确保良好的用户体验,常用的使用场景如下: 社交应用 :社交应用是一种常见的使用场景,用户可以通过音视频通话进行面对面的交流; 在线教育: 老师和学生可以通过音视频通话功能进行实时互

    2024年02月13日
    浏览(31)
  • springboot+websocket+webrtc 仿微信、仿QQ 音视频通话聊天 飞鱼chat IM即时通讯

    仿微信、QQ音视频聊天,文字表情、收发文件图片等功能。本项目使用springboot+websocket+webrtc-bootstrap5+H5+JQuery3.3+mysql实现,可自适应PC端和移动端 git地址在最后 pc端效果图 WebSocket是一种在单个TCP连接上进行全双工通信的协议,这使得客户端和服务器之间的数据交换变得更加简单

    2024年02月04日
    浏览(38)
  • Hololens2远程音视频通话与AR远程空间标注,基于OpenXR+MRTK3+WebRTC实现

    下面展示一些 内联代码片 。

    2024年04月10日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包