引言

    在三年前,写智能小车的时候,当时小车上有一个摄像头需要采集,实现推拉流的操作,技术选型当时第一版用的是nginx的rtmp的推拉流,服务器的配置环境是centos,2H4G3M的一个配置,nginx的rtmp的延迟是20秒,超慢,后来研究了SRS以及ZLMediaKit这两个开源的推拉流服务器,没记错的话,两个都是基于c++开发的,性能都很棒,后来更换了推拉流服务器,小汽车的延迟在一秒不到,性能大幅度提升,当时研究了一下,然后没有记录,这次使用SRS实现了音视频通话,以及共享桌面的功能,特此记录以及分享给大家。

技术概览

    本demo总共涉及到三个服务,部署环境是腾讯云的轻量服务器,配置是2H2G3M的服务器,CENTOS系统,nginx部署前端,docker部署后端以及SRS服务。

    SRS 

      SRS是一个开源的(MIT协议)简单高效的实时视频服务器,支持RTMP、WebRTC、HLS、HTTP-FLV、SRT、MPEG-DASH和GB28181等协议。 SRS媒体服务器和FFmpeg、OBS、VLC、 WebRTC等客户端配合使用,提供流的接收和分发的能力,是一个典型的发布 (推流)和订阅(播放)服务器模型。 SRS支持互联网广泛应用的音视频协议转换,比如可以将RTMP或SRT, 转成HLS或HTTP-FLV或WebRTC等协议。

      后端

      后端是一个基于net8.0基础框架开发的一个webapi的接口,前后端通讯使用的是signalr,用来实现不同用户之间的一个消息更改通知,本项目没有涉及到任何数据库方面的。

    前端

      前端是基于node20.16.0,vue3。其中,推拉流的地址和后端服务器的地址配置在configjs.json中配置,pushUrl是推流的地址,pullUrl是拉流的地址,apiUrl是后端接口的地址,signalrUrl是用来做前后端websocket通讯的一个地址。在apiUrl和signalrUrl中的端口需要和上方的后端运行的端口保持一致才可以互相访问通讯,具体配置文档查看下方图例。

功能概览

    总体功能分为一下几个:

    设备检测/参数设置 

      这个页码主要是用来配置摄像头,并且检测摄像头是否可用,音频检测音频是否可用,并且配置音频设备,后续的音视频通话都是根据此处选择的设备进行推拉流,用户名称,由于本项目是一个demo,所以都是基于内存,用户是自己设置之后,在demo中与人通讯的一个标识;在这个页面配置好视频设备,音频设备,以及用户名称,就可以去后续的页面进行群聊或者单聊,或者桌面共享的功能。    

    群聊  

      群聊进入到页面,就可以看到已经存在的群聊信息,以及在线人数,可以进行加入或者删除群聊的操作,如果有新增的群组,此处也会使用Signalr进行同步更新获取最新的群组列表数据,此demo没有判断删除的时候权限问题以及如果有人正在群聊删除群组的问题,在设备检测页面没有选择音视频设备,也可以进入群组,可以查看有音视频的在线人员的一个音视频,如图所示,在上方输入要创建的群组名称,点击添加群组即可到如下页面,进入视频页面,会先去推流到服务器,以便下一个进入的人可以看到你的视频流,同时如果没有选择音视频设备,点击加入也是如下页面,并且该页面不会展示群组的在线人,可以从视频的摄像头上方可以查看是哪个用户的音视频。

    单聊

      单聊就是只有两个人进行音视频通话,同时也支持没有选择设备可以进行通话,没有添加文字聊天的支持,单聊列表,也会使用signalr进行同步更新,在用户设置了用户名称之后,在这里就可以看到列表数据的更新。点击通话就可以和在线的人员进行音视频通话,同时不能和自己通话,且选择的人如果在处于单聊状态中,也无法进行音视频通话,在选择了要进行通话的用户后,会进入到聊天页面,同时对方用户会收到一个提醒,是否接受音视频通话,可以拒绝,也可以接受,拒绝之后,请求方会退出到在线列表的页面,点击接受会进入到双方的一个音视频通话的页面,可以进行语音聊天,可以看对方的摄像头推送的视频流。同时接受之后,任意一方离开聊天,另外一方也会直接退出聊天页面。返回到用户在线列表页面中。

    共享桌面

      共享桌面的操作和群组的一样,在上方输入共享桌面的名称,点击按钮,即可进入到共享桌面的页面中去。进入到页面,会提示需要共享的屏幕内容,可选整个屏幕,浏览器或者窗口都可以,同时也可以选择是否要共享此页面的音频,点击分享之后,即可看到共享的视频内容,右侧显示了参与人列表,并且如果选择了音频设备,也会采集语音推送,多个参与人进行语音聊天,语音会显示谁在发言,收到了谁的语音流。同时当共享的人,点击了停止共享,其他参与人也可以共享自己的桌面,点击了共享桌面按钮,其他参与人的共享桌面按钮会隐藏,并且他们会看到采集的你的屏幕的视频信息。

程序配置

    关于配置方面,主要是前端的配置以及SRS的配置,前端方面的配置,在刚开始已经阐述过,主要是SRS的推拉流的配置,以及API和Signalr的地址配置,如果服务器是外网, 地址必须是外网服务器的地址,关于SRS的配置,在下载好SRS之后,SRS提供了默认的配置文件夹,文件夹名字是叫conf文件夹,里面提供了各种不同功能的conf配置文件,此处我们基于console.conf进行改造,下面的是console.conf的配置信息,第一行是listen,默认是1935,代表SRS启动的时候的RMP的直播服务端口。max_connection代表最大连接数量,默认是1000,srs_log_tank是日志的打印方式,默认是console,即控制台,可选配置有file和console,file是文件的输出形式,如果是file的形式,必须通过配置srs_log_file参数配置日志的打印文件的路径,默认是.objs/srs.log的文件。daemon,代表的是是否以后台的形式运行,on代表开启,off代表关闭。http_api,SRS提供了一些api,这个配置代表是否开启http_api,并且端口是8080。下方,展示了SRS官网提供的API导航。rtc_server启用webrtc的功能,端口是udp的8000,默认是8000,其中最后一个配置是candidata,如果是本机部署,这个可以不需要配置,如果是需要部署在外网服务器,那这个就需要设置成外网的服务器地址。

    SRS的视频推拉流,有虚拟主机的概念,默认提供了一个defaultVhost的虚拟主机在配置文件里,虚拟主机内有单独的关于主机的配置,hls代表开启hls的视频协议功能,http_remux,是否为http开启直播流服务,mout代表的是挂载的http流,可以是不同的格式,默认是flv,可选有ts,即后缀是.ts,有mp3,aac等协议。rtc代表是否给虚拟主机开启webrtc的功能,并且是否开启rtmp转rtc,以及rtc转rtmp的功能。http_hooks是SRS在有客户端推流或者拉流的时候配置的一个接口回调,这个回调可以是我们自己写的后端服务,这里的配置是我配置的我实际的后端服务的接口地址,可以根据自己的实际情况进行调整,enable代表是开启HOOK,publish是推流的回调,unpublish是停止推流的时候,play和stop是拉流的播放和停止回调。play是针对拉流的配置,gop_cache是否缓存最后一帧,如果开启,客户端能够快速播放,如果关闭,客户端拉取的一直都是最新的,queue_length是缓存的帧一秒缓存的队列长度,如果超过这个,会移除之前的帧,mw_latency,关于流的合并写入的延迟,毫秒级单位。Publish是推流的一个配置,mr是合并读取的延迟,毫米级单位。

    关于上面说了那么多的配置,主要的配置还是http_hooks的配置,这个配置,是SRS在接收到推流请求,或者停止推流,以及拉流,停止拉流的时候对我们后端服务的一个回调,enabled代表是否开启回调,publish是开始推流的回调,unpublish是停止推流,play和stop是客户端在播放流或者停止流的时候的一个回调,这里如果部署在外网,且srs和后端服务在一个服务器,此处的地址可以使用局域网的地址,与前端配置不同的是,前端的配置必须是外网的地址。

    以上关于所有的全面配置可以参考以下网址:

    http_api:http://ossrs.net/lts/zh-cn/docs/v6/doc/http-api

    http_server:http://ossrs.net/lts/zh-cn/docs/v6/doc/http-server

    rtc_server/rtc:http://ossrs.net/lts/zh-cn/docs/v6/doc/webrtc

    hls:http://ossrs.net/lts/zh-cn/docs/v6/doc/hls

部署

    上面说到,我们的发布环境是centos,nginx和docker,所以在安装好了nginx之后 需要对nginx进行一个端口反向代理的配置,这里我用的是443端口,在网上生成了一个ssl证书,因为如果是使用http开头的网址,浏览器的机制,会不让使用摄像头,需要更改浏览器的配置才可以使得http的网址可以访问摄像头,如果是在本地部署和调试此服务,建议使用127.0.0.1或者localhost等方式来获取摄像头的信息,因为浏览器的安全机制,非https并且url地址是IP非127.0.0.1或者localhost的方式获取摄像头是有限制,接触限制的方式是在浏览器地址输入chrome://flags,回车之后,在弹出的页面中搜索Insecure origins treated as secure,如图,回车之后,需要将服务的IP地址输入在下方输入框中,并且将disabled更改为enabled,在更改完成后,浏览器下方会出现图3的面板,点击Relauch重启浏览器即可通过IP地址访问服务,并且加载摄像头,如果是中文disable是禁用,enable是启用,Relauch是重启。

    所以基于上面http的问题,需要生成一个ssl证书,让web使用https进行访问。下面我放一份我的nginx的配置,在下面的443的配置中,指定了servicename,以及root指向的是我们发布的之后的web前端的地址。指定了index.html,以及ssl证书相关的配置地址,配置根路径访问的是web前端的index.html,然后将路由中包括api,pull,push的指向对应的端口,如上图的端口配置情况,1985,使用webrtc进行推流,8080,进行拉流的端口,video是signalr的反向代理地址。

    以上是我服务器自己部署的nginx的一个配置。

    

  

# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/ user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid; # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf; events {
worker_connections 1024;
} http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
include /etc/nginx/mime.types;
default_type application/octet-stream; # Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf; server {
listen 80;
listen [::]:80;
server_name _;
root /video/dist/;
index index.html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
try_files $uri $uri/ /index.html;
}
error_page 404 /404.html;
location = /404.html {
} error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
server {
listen 443 ssl;
listen [::]:443;
server_name 49.233.22.57;
root /video/dist/;
index index.html;
ssl_certificate /sslfile/49.233.22.57.crt; # ssl证书存储路径
ssl_certificate_key /sslfile/49.233.22.57.private; # 秘钥存储路径 # ssl的一些配置
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #开启TLS协议 location / {
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://10.2.20.12:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
location /rtc {
proxy_pass http://10.2.20.12:1985;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
location /pull {
rewrite ^/pull/(.*)$ /$1 break;
proxy_pass http://10.2.20.12:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
location /video {
proxy_pass http://10.2.20.12:5000;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_cache_bypass $http_upgrade != '';
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
} # Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2;
# listen [::]:443 ssl http2;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# } }

    后端部署在docker中, 环境是net8的开发环境,dockerfile配置如下,将发布后的文件和dockerfile放在一起,执行docker build -t videoimg .指令,打包docker镜像。记得后面有一个点.,回车之后,生成了videoimg的docker镜像,生成镜像后,需要启动容器,docker run --name videoc --security-opt seccomp=unconfined  -d -p 5000:8080 videoimg 回车之后即可启动了后端服务的容器,本机的端口是5000,需要防火墙或者云服务器开启5000端口,

#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
COPY . . FROM base AS final
WORKDIR /app
ENTRYPOINT ["dotnet", "WebApplication1.dll"]

    docker启动SRS,如果SRS部署在外网服务器,需要在启动SRS容器之前,配置一个环境变量CANDIDATE="外网服务器IP地址",将外网的IP地址写入环境变量中,SRS启动会从中读取配置,也可以直接修改conf中关于CANDIDATE的配置直接更改为你的外网服务器的地址。配置好之后,启动SRS,docker run --rm  --name srs  -it -d -p 1935:1935 -p 1985:1985 -p 8080:8080 -p 1990:1990 -p 8088:8088 -p 8000:8000/udp -v /video/conf:/conf --env CANDIDATE=$CANDIDATE     registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5 ./objs/srs -c /conf/console.conf  上面的指令,-v是将容器内部的conf文件夹挂载出来,然后在后面指定使用了console.conf作为启动的配置文件,并且将端口信息暴露出来,推拉流,以及web服务器需要使用这些端口。

    SRS提供了一个web管理系统,防火墙等配置好之后,在浏览器输入IP:8080即可打开如下页面,在控制台可以看到视频的推拉流信息,以及流量的流入和流出。

端口配置

    服务器需要开启一下端口

    1:后端服务的端口,例如本例子的5000端口

    2:SRS相关端口:1935,1985,8080,1990,8088,8000/udp

代码和详细Windows文档地址

    关于更多的详细解读,可以查看写好的windows的文档部署地址,除了部署方式的差异,其余都一样。

    git地址:https://gitee.com/cxd199645/audio-video.git

总结

    关于做一个音视频通话的技术分享就到这里了,如果又不懂的,可以添加QQ/WX:934550201.

1. SRS

SRS是一个开源的(MIT协议)简单高效的实时视频服务器,支持RTMP、WebRTC、HLS、HTTP-FLV、SRT、MPEG-DASH和GB28181等协议。 SRS媒体服务器和FFmpegOBSVLC、 WebRTC等客户端配合使用,提供流的接收和分发的能力,是一个典型的发布 (推流)和订阅(播放)服务器模型。 SRS支持互联网广泛应用的音视频协议转换,比如可以将RTMPSRT, 转成HLSHTTP-FLVWebRTC等协议。

【音视频通话】使用asp.net core 8+vue3 实现高效音视频通话的更多相关文章

  1. asp.net core 中配合响应 html5 的音视频播放流,以及文件下载

    一.asp.net core 中配合响应 html5 的音视频播放流,以及文件下载 问题描述: 目前测试了在 Windows(谷歌浏览器).Android(系统浏览器.QQ.微信).iOS 三个系统不 ...

  2. 【asp.net core mvc + angular6实战】 - 1. 环境搭建

    为什么打算写这些文章? 没有为什么,只是为了学习Angular和更了解.Net Core等技术 需要用到的技术? 后端使用.Net Core 2.1 + EF Core 2.1 + Mysql 5.7 ...

  3. 【原创】Asp.NET Core Web API与Vue 3.0搭建前后分离项目

    特地记录一下,网上的教程写的稀里糊涂的,整得我都心塞塞的,其实实现的过程蛮简单的 问题是这样的:我将Vue构建生成好的文件,放在后端wwwroot文件里面,并开启静态文件访问功能,结果总是无法显示相应 ...

  4. ASP.NET Core 之 Identity 入门(一)

    前言 在 ASP.NET Core 中,仍然沿用了 ASP.NET里面的 Identity 组件库,负责对用户的身份进行认证,总体来说的话,没有MVC 5 里面那么复杂,因为在MVC 5里面引入了OW ...

  5. ASP.NET Core 中的那些认证中间件及一些重要知识点

    前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...

  6. ASP.NET Core应用的错误处理[3]:ExceptionHandlerMiddleware中间件如何呈现“定制化错误页面”

    DeveloperExceptionPageMiddleware中间件利用呈现出来的错误页面实现抛出异常和当前请求的详细信息以辅助开发人员更好地进行纠错诊断工作,而ExceptionHandlerMi ...

  7. ASP.NET Core MVC/WebAPi 模型绑定探索

    前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...

  8. ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”

    在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式>中,我们通过几个简单的实例演示了如何呈现一个错误页面,这些错误页面的呈现分别由三个对应的中间件来完成,接下来我们将 ...

  9. Asp.net Core中使用Session

    前言 2017年就这么悄无声息的开始了,2017年对我来说又是特别重要的一年. 元旦放假在家写了个Asp.net Core验证码登录, 做demo的过程中遇到两个小问题,第一是在Asp.net Cor ...

  10. ASP.NET Core 中文文档 第四章 MVC(3.8)视图中的依赖注入

    原文:Dependency injection into views 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:孟帅洋(书缘) ASP.NET Core 支持在视图中使用 依赖 ...

随机推荐

  1. vol2以及mimikatz插件安装教程

    volatility2安装 https://github.com/volatilityfoundation/volatility git clone https://github.com/volati ...

  2. Eureka 客户端依赖管理模块

    <dependencies> <!--Eureka客户端依赖--> <dependency> <groupId>org.springframework. ...

  3. Apache Kyuubi 在B站大数据场景下的应用实践

    01 背景介绍 近几年随着B站业务高速发展,数据量不断增加,离线计算集群规模从最初的两百台发展到目前近万台,从单机房发展到多机房架构.在离线计算引擎上目前我们主要使用Spark.Presto.Hive ...

  4. Javascript克隆数据

    JS 复制数据 1 浅复制 具体方法 // 数组 Array.prototype.slice // 普通对象 Object.assign 思考 2 深复制 1) function deepClone( ...

  5. 基于Java“花鸣”B2C电子商务平台设计实现(源码+lw+部署文档+讲解等)

    \n文末获取源码联系 感兴趣的可以先收藏起来,大家在毕设选题,项目以及论文编写等相关问题都可以给我加好友咨询 系统介绍: 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件 ...

  6. 蓝图中如何存储树结构: NPC对话的打开方式

    BFS来扩展成数组, 然后每一个node节点的child存储为索引.

  7. 2023/4/22 SCRUM个人博客

    1.我昨天的任务 学习如何使用QTdesign,并完善UI 2.遇到了什么困难 在QTable上无法理解前后端互通·的问题 3.我今天的任务 学习Qt知识QTableWidgetItem完善Pyqt5 ...

  8. python解决urllib发送请求报错:urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:xxxx)>

    在使用urllib.request.Request(url)前,添加代码放到最前面 import ssl ssl._create_default_https_context = ssl._create ...

  9. 一款基于Fluent设计风格、现代化的WPF UI控件库

    前言 今天大姚给大家分享一款基于Fluent设计风格.开源(MIT License).现代化的WPF UI控件库,它提供直观的设计.主题.导航和全新的沉浸式控件,全部都是原生且无缝地集成在一起:WPF ...

  10. 【PostgreSQL】下载安装PgSQL

    官网下载地址: https://www.enterprisedb.com/downloads/postgres-postgresql-downloads Windows平台 官网直接提供exe安装包, ...