2024年最全流媒体协议之WebRTC实现p2p视频通话(二),特殊渠道拿到阿里大厂面试真题

最后

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

async getLocalMedia() {
let localMedia = await navigator.mediaDevices
.getUserMedia({ video: { facingMode: “user” }, audio: true })
.catch(e => {
console.log(e)
})
this.localMedia = localMedia
return this
}
// 设置媒体流到video
setMediaTo(eleId, media) {
document.getElementById(eleId).srcObject = media
}
// 被叫响应
called(callingInfo) {
this.calledHandle && this.calledHandle(callingInfo)
}
// 创建RTC
createLoacalPeer() {
this.peer = new RTCPeerConnection()
return this
}
// 将媒体流加入通信
addTrack() {
if (!this.peer || !this.localMedia) return
//this.localMedia.getTracks().forEach(track => this.peer.addTrack(track, this.localMedia));
this.peer.addStream(this.localMedia)
return this
}
// 创建 SDP offer
async createOffer(cb) {
if (!this.peer) return
let offer = await this.peer.createOffer({ OfferToReceiveAudio: true, OfferToReceiveVideo: true })
this.peer.setLocalDescription(offer)
cb && cb(offer)
return this
}
async createAnswer(offer, cb) {
if (!this.peer) return
this.peer.setRemoteDescription(offer)
let answer = await this.peer.createAnswer({ OfferToReceiveAudio: true, OfferToReceiveVideo: true })
this.peer.setLocalDescription(answer)
cb && cb(answer)
return this

}
listenerAddStream(cb) {
this.peer.addEventListener(‘addstream’, event => {
console.log(‘addstream事件触发’, event.stream);
cb && cb(event.stream);
})
return this
}
// 监听候选加入
listenerCandidateAdd(cb) {
this.peer.addEventListener(‘icecandidate’, event => {
let iceCandidate = event.candidate;
if (iceCandidate) {
console.log(‘发送candidate给远端’);
cb && cb(iceCandidate);
}

})
return this
}
// 检测ice协商过程
listenerGatheringstatechange () {
this.peer.addEventListener(‘icegatheringstatechange’, e => {
console.log('ice协商中: ', e.target.iceGatheringState);
})
return this
}
// 关闭RTC
closeRTC() {
// …
}
}

后端

const SocketIO = require(‘socket.io’)
const socketIO = new SocketIO({
path: ‘/websocket’
})

let userRoom = {
list: [],
add(user) {
this.list.push(user)
return this
},
del(id) {
this.list = this.list.filter(u => u.id !== id)
return this
},
sendAllUser(name, data) {
this.list.forEach(({ id }) => {
console.log(‘>>>>>’, id)
socketIO.to(id).emit(name, data)
})
return this
},
sendTo(id) {
return (eventName, data) => {
socketIO.to(id).emit(eventName, data)
}

2.后端

const SocketIO = require(‘socket.io’)
const socketIO = new SocketIO({
path: ‘/websocket’
})

let userRoom = {
list: [],
add(user) {
this.list.push(user)
return this
},
del(id) {
this.list = this.list.filter(u => u.id !== id)
return this
},
sendAllUser(name, data) {
this.list.forEach(({ id }) => {
console.log(‘>>>>>’, id)
socketIO.to(id).emit(name, data)
})
return this
},
sendTo(id) {
return (eventName, data) => {
socketIO.to(id).emit(eventName, data)
}
},
findName(id) {
return this.list.find(u => u.id === id).name
}
}

socketIO.on(‘connection’, function(socket) {
console.log(‘连接加入.’, socket.id)

socket.on(‘addUser’, function(data) {
console.log(data.name, ‘加入房间’)
let user = {
id: socket.id,
name: data.name,
calling: false
}
userRoom.add(user).sendAllUser(‘updateUserList’, userRoom.list)
})

socket.on(‘sendMessage’, ({ content }) => {
console.log(‘转发消息:’, content)
userRoom.sendAllUser(‘updateMessageList’, { userId: socket.id, content, user: userRoom.findName(socket.id) })
})

socket.on(‘iceCandidate’, ({ id, iceCandidate }) => {
console.log(‘转发信道’)
userRoom.sendTo(id)(‘iceCandidate’, { iceCandidate, id: socket.id })
})

socket.on(‘offer’, ({id, offer}) => {
console.log(‘转发offer’)
userRoom.sendTo(id)(‘called’, { offer, id: socket.id, name: userRoom.findName(socket.id)})
})

socket.on(‘answer’, ({id, answer}) => {
console.log(‘接受视频’);
userRoom.sendTo(id)(‘answer’, {answer})
})

socket.on(‘rejectCall’, id => {
console.log(‘转发拒接视频’)
userRoom.sendTo(id)(‘callRejected’)
})

socket.on(‘disconnect’, () => {
// 断开删除
console.log(‘连接断开’, socket.id)
userRoom.del(socket.id).sendAllUser(‘updateUserList’, userRoom.list)
})
})

module.exports = socketIO

// www.js 这就不关键了
const http = require(‘http’)
const app = require(‘…/app’)
const socketIO = require(‘…/socket.js’)
const server = http.createServer(app.callback())
socketIO.attach(server)
server.listen(3003, () => {
console.log(‘server start on 127.0.0.1:3003’)
})

搭建 STUN/TURN

因为没有钱买服务器 没试过

coturn 据说使用它搭建 STUN/TURN 服务非常的方便

编译

cd coturn
./configure --prefix=/usr/local/coturn
sudo make -j 4 && make install

配置

listening-port=3478 #指定侦听的端口
external-ip=39.105.185.198 #指定云主机的公网IP地址
user=aaaaaa:bbbbbb #访问 stun/turn服务的用户名和密码
realm=stun.xxx.cn #域名,这个一定要设置

#启动
cd /usr/local/coturn/bin
turnserver -c …/etc/turnserver.conf

trickle-ice https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice 按里面的要求输入 stun/turn 地址、用户和密码
输入的信息分别是:
STUN or TURN URI 的值为: turn:stun.xxx.cn
用户名为: aaaaaa
密码为: bbbbbb

STUN参数传递

let ice = {“iceServers”: [
{“url”: “stun:stun.l.google.com:19302”}, // 无需密码的
// TURN 一般需要自己去定义
{
‘url’: ‘turn:192.158.29.39:3478?transport=udp’,
‘credential’: ‘JZEOEt2V3Qb0y27GRntt2u2PAYA=’, // 密码
‘username’: ‘28224511:1379330808’ // 用户名
},
{
‘url’: ‘turn:192.158.29.39:3478?transport=tcp’,

Vue 面试题

1.Vue 双向绑定原理
2.描述下 vue 从初始化页面–修改数据–刷新页面 UI 的过程?
3.你是如何理解 Vue 的响应式系统的?
4.虚拟 DOM 实现原理
5.既然 Vue 通过数据劫持可以精准探测数据变化,为什么还需要虚拟 DOM 进行 diff 检测差异?
6.Vue 中 key 值的作用?
7.Vue 的生命周期
8.Vue 组件间通信有哪些方式?
9.watch、methods 和 computed 的区别?
10.vue 中怎么重置 data?
11.组件中写 name 选项有什么作用?
12.vue-router 有哪些钩子函数?
13.route 和 router 的区别是什么?
14.说一下 Vue 和 React 的认识,做一个简单的对比
15.Vue 的 nextTick 的原理是什么?
16.Vuex 有哪几种属性?
17.vue 首屏加载优化
18.Vue 3.0 有没有过了解?
19.vue-cli 替我们做了哪些工作?

如果你觉得对你有帮助,可以戳这里获取:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

e 中怎么重置 data?
11.组件中写 name 选项有什么作用?
12.vue-router 有哪些钩子函数?
13.route 和 router 的区别是什么?
14.说一下 Vue 和 React 的认识,做一个简单的对比
15.Vue 的 nextTick 的原理是什么?
16.Vuex 有哪几种属性?
17.vue 首屏加载优化
18.Vue 3.0 有没有过了解?
19.vue-cli 替我们做了哪些工作?
[外链图片转存中…(img-VZgRW3mI-1715685030112)]

如果你觉得对你有帮助,可以戳这里获取:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值