1、gulp任务管理

app官方文档

npm start启动app,执行脚本:

"start": "gulp live"

该命令用启动gulp顺序任务组合live,位于gulpfile.js中,关于gulp相关点击这里

gulp.task('live', gulp.series(
'clean',
'lint',
'bundle:watch',
'html',
'css',
'resources',
'watch',
'browser'
));

分别执行以下任务:

  1. clean:清空OUTPUT_DIR目录;
  2. lint:将lib目录下的js文件读取到流并进行一些格式化等操作;
  3. bundle:watch:开启文件改变监控与绑定,该任务调用了gulpfile.js里面的bundle()函数,而bundle()函数里面主要是将上一步流中的js文件合并生成了mediasoup-demo-app.js文件,合并后的js文件有13.3M,这是一个大包的过程,便于一次性加载整个应用。
  4. html:复制index.html至OUTPUT_DIR目录下;
  5. css:读取stylus/index.styl文件,转化,重命名为mediasoup-demo-app.css输出到OUTPUT_DIR目录下;
  6. 在OUTPUT_DIR下创建resources目录;
  7. watch:监控html, styl, resources...等一系列文件变化
  8. browser:静态文件更新多端同步刷新配置
 总结一下,app目录下执行npm start命令后其实就是将相关静态资源复制到server/public目录下,并且开启了文件刷新监控,多端同步,并自动打开浏览器访问访问配置的路径。然后所有的请求处理是由server来处理的,app是个静态资源服务器。

关于app启动时报的这4个参数错误:

Possible race condition: `window.SHOW_INFO` might be reassigned based on an outdated value of `window.SHOW_INFO` 

该错误来源在app/lib/index.jsx中的run( )函数

if (info)
window.SHOW_INFO = true; if (throttleSecret)
window.NETWORK_THROTTLE_SECRET = throttleSecret;

然后自己加了几行代码,再启动发现错误越来越多,原来是Eslint代码风格检查的问题,并不会影响程序运行,代码风格规则配置在.eslintrc.js文件中,所以解决方法有3:

  1. 按配置的规则修改代码,参考这里,提交代码前先自己用 eslint 命令行检查修复一下对应的文件,例如 eslint file.js --fix(推荐)
  2. 干掉引起错误的规则,参考这里
  3. 选择忽略这个错误,比RoomClient.js文件报错了,那就在这个文件头部加上一行 /* eslint-disable */ ,表示此文件禁用代码检查警告,参考这里

2、RoomClient类

关于客户端房间的定义在app/lib/RoomClient.js模块中,该模块中引用了 mediasoup-client 模块,定义了RoomClient类,房间的相关属性,websocket事件,以及麦克风,摄像头,共享,聊天等交互操作。

加入房间后建立websocket连接客户端,用的是protoo-client 模块,这是一个专为群聊,会议设计的websocket模块,与一般的websocket client略有不同,除了websocket的open,close等事件之外还有request,response,notifaction事件,相关说明参考官方文档。

而server中用了与之对应的 protoo-server 模块,

3、Redux状态容器

除了上面的 gulp 外,RoomClient使用 Redux状态容器来记录 room 页面的状态参数,参见 Redux中文文档

Redux的唯一数据源store作为一个全局变量,定义在RoomClient.js中,并且对外暴露了

static init(data)
{
store = data.store;
}

init 函数,作为类的静态成员来初始化store,该函数在app/lib/index.jsx中被调用,将store赋给当前window对象并初始化,这些js文件最后合而为一被用于房间页面的js依赖。

导致store状态改变的action 事件描述定义在 app/lib/redux下,而与之对应的改变store的reducer纯函数定义在 app/lib/reducers目录下,STATE.md正是当前所有状态的展示。

然后在RoomClient中用store.dispatch()函数调用相关action改变store状态树,例如:

store.dispatch(
stateActions.setRoomState('closed'));

4、WebRTC

官网例子

webrtc才是核心,路漫漫其修远兮

5、屏幕共享的限制

mediasoup-demo client的屏幕捕捉是通过调用浏览器API实现的,只在Chrome和Firefox浏览器中可用。

6、动态页面-React部分

客户端页面涉及到React使用,简单了解一下,React官方文档.

index.jsx中使用:

import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux'; render(
<Provider store={store}>
<RoomContext.Provider value={roomClient}>
<Room />
</RoomContext.Provider>
</Provider>,
document.getElementById('mediasoup-demo-app-container')
);

Room.jsx,这是一个自定义的React的class组件,所有页面元素最后都被组合进这个组件中。

class Room extends React.Component
{
render()
{
const {
roomClient,
room,
me,
amActiveSpeaker,
onRoomLinkCopy
} = this.props; return (
<Appear duration={300}>
<div data-component='Room'>
<Notifications />
...............
............... componentDidMount()
{
const { roomClient } = this.props; roomClient.join();
}
}

componentDidMount() 方法会在组件已经被渲染到 DOM 中后运行,类似于wondow.load(),此处在Room组件渲染完成后执行join()加入Room方法。

7、页面样式-Stylus

Room页面样式用 Stylus语法指定,静态文件位于 app/stylus/ 目录下,Room.styl中定义了自己的样式,Peers.styl中定义了参会者的样式,了解一下stylus语法后可按需求修改。

8、app启动失败解决方案

app在启动时可能出现如下错误,原因是watch文件超过系统允许配置导致的

Error: ENOSPC:System limit for number of file watchers reached

解决方案 这里

9、协商应答的SDP信息

通过浏览器端输出日志可以发现,协商应答的sdp信息是在该函数中打印的

app/node_modules/mediasoup-client/lib/handlers/Chrome70.js/class SendHandler/stopSending()
async stopSending({ localId })
{
logger.debug('stopSending() [localId:%s]', localId); const transceiver = this._mapMidTransceiver.get(localId); if (!transceiver)
throw new Error('associated RTCRtpTransceiver not found'); transceiver.sender.replaceTrack(null);
this._pc.removeTrack(transceiver.sender);
this._remoteSdp.closeMediaSection(transceiver.mid); const offer = await this._pc.createOffer(); logger.debug(
'stopSending() | calling pc.setLocalDescription() [offer:%o]', offer); await this._pc.setLocalDescription(offer); const answer = { type: 'answer', sdp: this._remoteSdp.getSdp() }; logger.debug(
'stopSending() | calling pc.setRemoteDescription() [answer:%o]', answer); await this._pc.setRemoteDescription(answer);
}

这个sdp信息很关键,offer的太长了,应答sdp内容如下:

v=0
o=mediasoup-client 10000 4 IN IP4 0.0.0.0
s=-
t=0 0
a=ice-lite
a=fingerprint:sha-512 AA:99:03:C0:4E:DB:D6:BC:03:51:37:EF:40:00:09:34:99:43:71:CB:76:E8:CC:9E:3E:22:6F:BF:1E:44:0A:31:90:EE:ED:0F:E7:33:42:EF:0D:1E:F4:A4:04:67:4D:22:49:45:6C:8E:3D:FF:EA:6D:5C:07:D3:F4:E5:DF:BE:08
a=msid-semantic: WMS *
a=group:BUNDLE 0 1
m=audio 7 UDP/TLS/RTP/SAVPF 111
c=IN IP4 127.0.0.1
a=rtpmap:111 opus/48000/2
a=fmtp:111 stereo=1;usedtx=1
a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=setup:active
a=mid:0
a=recvonly
a=ice-ufrag:i5dt0ipouvpj58p6
a=ice-pwd:nqqq5j2hn4e4mtif07ffa4fiox7pby7g
a=candidate:udpcandidate 1 udp 1076302079 192.168.189.128 41774 typ host
a=end-of-candidates
a=ice-options:renomination
a=rtcp-mux
a=rtcp-rsize
m=application 7 DTLS/SCTP 5000
c=IN IP4 127.0.0.1
a=setup:active
a=mid:1
a=ice-ufrag:i5dt0ipouvpj58p6
a=ice-pwd:nqqq5j2hn4e4mtif07ffa4fiox7pby7g
a=candidate:udpcandidate 1 udp 1076302079 192.168.189.128 41774 typ host
a=end-of-candidates
a=ice-options:renomination
a=sctpmap:5000 webrtc-datachannel 262144
m=video 0 UDP/TLS/RTP/SAVPF 96 97
c=IN IP4 127.0.0.1
a=rtpmap:96 VP8/90000
a=rtpmap:97 rtx/90000
a=fmtp:96 x-google-start-bitrate=1000
a=fmtp:97 apt=96
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=setup:active
a=mid:2
a=inactive
a=ice-ufrag:i5dt0ipouvpj58p6
a=ice-pwd:nqqq5j2hn4e4mtif07ffa4fiox7pby7g
a=candidate:udpcandidate 1 udp 1076302079 192.168.189.128 41774 typ host
a=end-of-candidates
a=ice-options:renomination
a=rtcp-mux
a=rtcp-rsize

具体内容说明参见这里

mediasoup-demo解析-客户端的更多相关文章

  1. IOS CoreData 多表查询demo解析

    在IOS CoreData中,多表查询上相对来说,没有SQL直观,但CoreData的功能还是可以完成相关操作的. 下面使用CoreData进行关系数据库的表与表之间的关系演示.生成CoreData和 ...

  2. Ionic Demo 解析

    Ionic Demo 解析 index.html 解析 1.引入所需要的类库 <link rel="manifest" href="manifest.json&qu ...

  3. Netty源码解析—客户端启动

    Netty源码解析-客户端启动 Bootstrap示例 public final class EchoClient { static final boolean SSL = System.getPro ...

  4. 转:RealThinClient LinkedObjects Demo解析

    这个Demo源码实现比较怪,有点拗脑,原因估是作者想把控件的使用做得简单,而封装太多. 这里说是解析,其实是粗析,俺没有耐心每个实现点都查实清楚,看源码一般也就连读带猜的. 这个Demo表达出的意义, ...

  5. Android蓝牙联机Demo解析

    写在前面: 手游的双人对战实现方式有很多,比如: 联网对战(需要一个服务器负责转发客户端请求,各种大型手游的做法) 分屏对战(手机上下分屏,典型的例子就是切水果的双人对战) 蓝牙联机对战(通过蓝牙联机 ...

  6. android报表图形引擎(AChartEngine)demo解析与源码

    AchartEngine支持多种图表样式,本文介绍两种:线状表和柱状表. AchartEngine有两种启动的方式:一种是通过ChartFactory.get***View()方式来直接获取到view ...

  7. Android客户端OkHttp的使用以及tomcat服务器的解析客户端发过来的数据

    2020-02-15 21:25:42 ### android客户端客户向服务器发送json字符串或者以参数请求的方式发送数据 其中又分为post请求和get请求 1.activity.xml < ...

  8. 人脸识别Demo解析C#

    概述 不管你注意到没有,人脸识别已经走进了生活的角角落落,钉钉已经支持人脸打卡,火车站实名认证已经增加了人脸自助验证通道,更别提各个城市建设的『智能城市』和智慧大脑了.在人脸识别业界,通常由人脸识别提 ...

  9. SpringBoot使用activiti自定义流程demo解析

    环境搭建[这里直接讲解自定义流程] 集成 Activiti Modeler 下载源码 我这里选用的是 Activiti 5.23.0 版本的页面,下载 zip,解压 Activiti 5.23.0 源 ...

  10. zookeeper原理解析-客户端与服务器端交互

    Zookeeper集群中server数量总是确定的,所以集群中的server交互采用比较可靠的bio长连接模型:不同于集群中sever间交互zookeeper客户端其实数量是未知的,为了提高zooke ...

随机推荐

  1. 深入理解 C/C++ sizeof() 运算符

    过去有一段时间一直以为带个括号的 \(sizeof()\) 是 \(C/C++\) 的原生函数QAQ. 其实不然,\(sizeof\) 同位运算符(^|&~!)一样是一种单目运算符,作用于变量 ...

  2. Wireshark下载地址

    官方下载地址: https://www.wireshark.org/download.html

  3. 安装Gitlab到CentOS(YUM)

    运行环境 系统版本:CentOS Linux release 7.3.1611 (Core) 软件版本:Gitlab-ce-11.10.1 硬件要求:最低2核4GB,建议4核8GB 安装过程 1.安装 ...

  4. ubuntu--- tracker/libdeepsort.so 找不到cv报错

    一.刚开始解决尝试:因为“删掉lib下的libdeepsort.so报错”,原先以为是 libdeepsort.so 需要拷贝到 /lib路径下的问题,可是因为后来的工程有的好使,又的不好使了.''' ...

  5. 电脑和手机上常用apk或Pc软件的重要目录或文件或文件夹路径

    常用apk或Pc软件的重要目录或文件或文件夹路径 01.hosts文件位置在哪里 C:\Windows\System32\drivers\etc 02.Windows7的锁屏壁纸目录在哪 C:\Win ...

  6. PHP中根据二维数组中某个字段实现排序

    想要实现二维数组中根据某个字段排序,一般可以通过数组循环对比的方式实现.这里介绍一种更简单的方法,直接通过PHP函数实现.array_multisort() :可以用来一次对多个数组进行排序,或者根据 ...

  7. javascript当中arguments用法

    8)arguments 例 3.8.1<head>    <meta http-equiv="content-type" content="text/h ...

  8. hdu 1025 Constructing Roads In JGShining's Kingdom(最长上升子序列)

    题意:贫穷和富有的城市都按顺序1-n排列,需要在中间建造尽可能多的道路,最多可以建造多少条? 解:如果条件这样给出,贫穷的城市按顺序排列,并且按顺序给出每个贫穷城市需要的资源,那么能建造的最多的道路数 ...

  9. pandas 将多个dataframe保存为一个excel文件的多个sheet表中

    # 创建文件 def create(): df1 = pd.DataFrame({"a1": [1, 2, 3], "b1": [4, 5, 6]}) df2 ...

  10. 0级搭建类004-中标麒麟 Linux 安装 (V7.0) 公开

    项目文档引子系列是根据项目原型,制作的测试实验文档,目的是为了提升项目过程中的实际动手能力,打造精品文档AskScuti. 项目文档引子系列目前不对外发布,仅作为博客记录.如学员在实际工作过程中需提前 ...