基于webrtc实现音视频通话 | laravel china 社区-金年会app官方网

最近闲暇时间(摸鱼时间很难熬)都在搞这个仿微信的项目,于是乎今天就接了个音视频通话。
在线体验:
已存在用户:13006789001~13006789010 密码都是123456
前端项目
github:
后端项目
github:

客户端采用webrtc技术(推流),通讯用websocket。

webrtc像是一个面试过程:
第一步:发起方(拨打电话者)点击拨打电话时,获取本地媒体流并推流给接收方同时捕获接收方推过来的流,捕获到后把流设置到dom上,监听ice候选确保能点对连接,生成offer,通过websocket告知接收方并拉起等待接听界面。

//获取媒体流
stream.value = await navigator.mediadevices.getusermedia({
    video: true,
    audio: true
});
// 初始化 peerconnection
peerconnection.value = new rtcpeerconnection({
    iceservers: [
        {
            urls: 'stun:stun.l.google.com:19302'
        }
    ]
});
// 推流给接收方
stream.value.gettracks().foreach((track) => {
    peerconnection.value.addtrack(track, stream.value);
});
// 捕获接收方的流
peerconnection.value.ontrack = (event) => {
    remotestream.value = event.streams[0];
    if (calltype.value === typevideo) {
        remotevideo.value.srcobject = remotestream.value;
    } else {
        remoteaudio.value.srcobject = remotestream.value;
    }
};
// 监听ice候选,确保 webrtc 的点对点连接能够成功建立
peerconnection.value.onicecandidate = (event) => {
    if (event.candidate) {
        //发送candidate
        ws.send(event.candidate);
    }
};
// 创建 offer
const offer = await peerconnection.value.createoffer();
await peerconnection.value.setlocaldescription(offer);
//发送offer,这里发送的offer可以理解成是接收方用来捕获发起方流的一个凭证,接收方通过peerconnection.value.ontrack可以捕获到。
ws.send(offer);
//拉起等待接听界面
showcall.value = true;
//状态等待接听
callstatus.value = 'wating';

第二步:接收方收到offer后,第一步是拉起来电界面,第二步是选择接听或者挂断。
1)拉起来电接听界面

//拉起来电接听界面
showcall.vue = true;
//状态来电接听
callstatus.value = 'coming';
//初始化来电人信息等
....

2)挂断,就是告诉发起方我挂断了,发起方就把rtc关掉、停止推流,dom置空就好了

//接收方
showcall.value = false;
callstatus.value = 'closing';
ws.send('reject');
//发起方
if (peerconnection.value) {
    peerconnection.value.close();
    peerconnection.value = null;
}
if (stream.value) {
    const tracks = stream.value.gettracks();
    tracks.foreach((track) => track.stop());
}
if (localvideo.value)
    localvideo.value.srcobject = null;
if (remotevideo.value)
    remotevideo.value.srcobject = null;
if (remoteaudio.value)
    remoteaudio.value.srcobject = null;
showcall.value = false;
callstatus.value = 'closing';

2)接听,操作跟拨打流程差不多,需要设置远端sdp(发起方的offer),添加ice候选(发起方的ice,这里需要注意的是只有远端sdp初始化完毕状态下才能设置ice)

// 获取本地媒体流
...同发起方
// 初始化 peerconnection
...同发起方
// 推流给发起方
...同发起方
// 捕获发起方的流
...同发起方
// 监听ice候选
...同发起方
//设置远端sdp
await peerconnection.value.setremotedescription(new rtcsessiondescription(caller.value.offer));
// 添加发起方发过来的ice
icecandidatequeue.value.foreach(async (candidate) => {
await  peerconnection.value.addicecandidate(candidate);
});
icecandidatequeue.value  = [];
// 创建 answer
const  answer  =  await  peerconnection.value.createanswer();
await  peerconnection.value.setlocaldescription(answer);
//发送answer给发起方
ws.send(answer);
//状态通话中
callstatus.value = 'calling';

关于ice的处理,就是远端sdp初始化完毕状态可以直接设置,未初始化完毕就存到icecandidatequeue队列备用

// 处理新的 ice 候选
const handlenewicecandidate = async (candidate) => {
    const icecandidate = new rtcicecandidate(candidate);
    if (peerconnection.value?.signalingstate === 'have-remote-offer' || peerconnection.value?.signalingstate === 'stable') {
        peerconnection.value.addicecandidate(icecandidate);
    } else {
        icecandidatequeue.value.push(icecandidate);
    }
};

最后一步:发起方收到接收方的答复(接收方接听了),设置远端sdp(接收方的answer),设置ice(接受方的ice)

//设置远端sdp
await peerconnection.value.setremotedescription(new rtcsessiondescription(caller.value.answer));
//添加ice
icecandidatequeue.value.foreach(async (candidate) => {
    await peerconnection.value.addicecandidate(candidate);
});
icecandidatequeue.value = [];
//状态接听中
callstatus.value = 'calling';

这就是webrtc视频通话的关键代码跟流程!

我的项目实现效果图:


本作品采用《cc 协议》,转载必须注明作者和本文链接
从零开发一个电商项目,功能包括电商后台、商品 & sku 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
以构建论坛项目 larabbs 为线索,展开对 laravel 框架的全面学习。应用程序架构思路贴近 laravel 框架的设计哲学。
讨论数量: 13

: 1: : 1: : 1:

1个月前

牛呗

1个月前

1块钱的域名真香啊 :kissing_closed_eyes:

1个月前

技术稳定吗?能否获取到通话时长之类的?演示网站好像打不开

1个月前
提桶跑路了 (楼主) 1个月前
提桶跑路了 (楼主) 1个月前
php_yt (作者) 3周前

mark

1个月前

今年也在处理相关 webrtc 的项目。 webrtc 对接相对是很简单的。处理不同设备间的编码兼容和开放环境下的回声,噪音处理才是难点。

2周前
xini2603 2周前
提桶跑路了 (楼主) 2周前
snowlyg (作者) 2周前
提桶跑路了 (楼主) 1周前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
网站地图