写点什么

webRTC(十四):webrtc 端到端文本聊天

用户头像
Android架构
关注
发布于: 21 小时前

}


.text_chat{


display: flex;


}


.text_chat textarea{


width: 350px;


height: 350px;


}


.send{


margin-top: 20px;


}


</style>


</head>


<body>


<div>


<div>


<button i


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


d="connserver">Connect Sig Server</button>


<button id="leave" disabled>Leave</button>


</div>


<div class="preview">


<div>


<h2>Local:</h2>


<video id="localvideo" autoplay playsinline></video>


</div>


<div class="remote">


<h2>Remote:</h2>


<video id="remotevideo" autoplay playsinline></video>


</div>


</div>


<h2>Chat:</h2>


<div class="text_chat">


<div>


<textarea id="chat" disabled></textarea>


</div>


<div class="remote">


<textarea id="sendtext" disabled></textarea>


</div>


</div>


<div class="send">


<button id="send" disabled>Send</button>


</div>


</div>


<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>


<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>


<script src="./js/client.js"></script>


</body>


</html>


  • js


'use strict'


var localVideo = document.querySelector('video#localvideo');


var remoteVideo = document.querySelector('video#remotevideo');


var btnConn = document.querySelector('button#connserver');


var btnLeave = document.querySelector('button#leave');


// 文本聊天


var chat = document.querySelector('textarea#chat');


var send_txt = document.querySelector('textarea#sendtext');


var btnSend = document.querySelector('button#send');


var localStream = null;


var roomid = '555555';


var socket =null;


var state = 'init';


var pc = null;


var dc = null;


var pcConfig={


'iceServers':[{


'urls':'turn:121.41.76.43:3478',


'credential':'123456',


'username':'huang'


}]


}


function sendMessage(roomid,data){


if(socket){


socket.emit('message',roomid,data);


}


}


function getAnswer(desc){


pc.setLocalDescription(desc);


sendMessage(roomid,desc);


}


function handleAnswerError(err){


console.error('Failed to get Answer!',err);


}


function getOffer(desc){


pc.setLocalDescription(desc);


sendMessage(roomid,desc)


}


function handleOfferError(err){


console.error('Failed to get Offer!',err);


}


//接收远端流通道


function call(){


if(state === 'joined_conn'){


if(pc){


var options = {


offerToReceiveAudio:1,


offerToReceiveVideo:1


}


pc.createOffer(options)


.then(getOffer)


.catch(handleOfferError);


}


}


}


// 第一步:开始服务


function connSignalServer(){


//开启本地视频


start();


return true;


}


//文本对方传过来的数据


function reveivemsg(e){


var msg = e.data;


console.log('recreived msg is :'+e.data);


if(msg){


chat.value += '->' + msg + '\r\n';


}else{


console.error('recreived msg is null');


}


}


function dataChannelStateChange(){


var readyState=dc.readyState;


if(readyState==='open'){


send_txt.disabled =false;


btnSend.disabled=false;


}else{


send_txt.disabled = true;


btnSend.disabled =true;


}


}


function dataChannelError(error){


console.log("Data Channel Error:", error);


}


function conn(){


//1 触发 socke 连接


socket = io.connect();


//2 加入房间后的回调


socket.on('joined',(roomid,id)=>{


state = 'joined';


createPeerConnection();


btnConn.disabled = true;


btnLeave.disabled =false;


console.log("reveive joined message:state=",state);


});


socket.on('otherjoin',(roomid,id)=>{


if (state === 'joined_unbind') {


createPeerConnection();


}


var dataChannelOptions = {


ordered: true, //保证到达顺序


};


//文本聊天


dc=pc.createDataChannel('dataChannel',dataChannelOptions);


dc.onmessage=reveivemsg;


dc.onopen = dataChannelStateChange;


dc.onclose = dataChannelStateChange;


dc.onerror = dataChannelError;


state = 'joined_conn';


//媒体协商


call();


console.log("reveive otherjoin message:state=",state);


});


socket.on('full',(roomid,id)=>{


console.log('receive full message ', roomid, id);


closePeerConnection();


closeLocalMedia();


state = 'leaved';


btnConn.disabled = false;


btnLeave.disabled = true;


console.log("reveive full message:state=",state);


alert("the room is full!");


});


socket.on('leaved',(roomid,id)=>{


state = 'leaved';


socket.disconnect();


btnConn.disabled = false;


btnLeave.disabled = true;


console.log("reveive leaved message:state=",state);


});


socket.on('bye',(roomid,id)=>{


state = 'joined_unbind';


closePeerConnection();


console.log("reveive bye message:state=",state);


});


socket.on('disconnect', (socket) => {


console.log('receive disconnect message!', roomid);


if(!(state === 'leaved')){


closePeerConnection();


closeLocalMedia();


}


state = 'leaved';


});


socket.on('message',(roomid,id,data)=>{


console.log(" message=====>",data);


//媒体协商


if(data){


if(data.type === 'offer'){


pc.setRemoteDescription(new RTCSessionDescription(data));


pc.createAnswer()


.then(getAnswer)


.catch(handleAnswerError);


}else if(data.type === 'answer'){


console.log("reveive client message=====>",data);


pc.setRemoteDescription(new RTCSessionDescription(data));


}else if(data.type === 'candidate'){


var candidate = new RTCIceCandidate({


sdpMLineIndex:data.label,


candidate:data.candidate


});


pc.addIceCandidate(candidate);


}else{


console.error('the message is invalid!',data)


}


}


console.log("reveive client message",roomid,id,data);


});


socket.emit('join',roomid);


return;


}


// 扑捉本地视频


function getMediaStream(stream){


localStream =stream;


//2 ===============显示本地视频===============


localVideo.srcObject = localStream;


//这个函数的调用时机特别重要 一定要在 getMediaStream 之后再调用,否则会出现绑定失败的情况


conn();


}


function handleError(err){


if(err){


console.error("getUserMedia error:",err);


}


}


// 第二步:采集本地视频


function start(){


if (!navigator.mediaDevices||


!navigator.mediaDevices.getUserMedia) {


console.log("getUserMedia is not supported!")


return;


} else {


//1 ===============配置音视频参数===============


var constraints={


video:true,


audio: false


}


navigator.mediaDevices.getUserMedia(constraints)


.then(getMediaStream)


.catch(handleError)


}


}


//关闭流通道


function closeLocalMedia(){


if (localStream&&localStream.getTracks()) {


localStream.getTracks().forEach((track)=>{


track.stop();


});


}


localStream = null;


}


function leave(){


if(socket){


socket.emit('leave',roomid);


}


//释放资源


closePeerConnection();


closeLocalMedia();


btnConn.disabled = false;


btnLeave.disabled = true;


}


//创建本地流媒体链接


function createPeerConnection(){


console.log('create RTCPeerConnection!');


if(!pc){


pc = new RTCPeerConnection(pcConfig);


pc.onicecandidate = (e) =>{


if(e.candidate){


sendMessage(roomid,{


type:'candidate',


label:e.candidate.sdpMLineIndex,


id:e.candidate.sdpMid,


candidate:e.candidate.candidate


});


}


}


//文本聊天


pc.ondatachannel = e =>{


// if(!dc){


dc= e.channel;


dc.onmessage =reveivemsg;


dc.onopen = dataChannelStateChange;


dc.onclose = dataChannelStateChange;


dc.onerror = dataChannelError;


// }


}


pc.ontrack = (e)=>{


remoteVideo.srcObject = e.streams[0];


}


}


if(pc === null || pc === undefined){


console.error('pc is null or undefined!');


return;


}


if(localStream === null || localStream === undefined){


console.error('localStream is null or undefined!');


return;


}


if(localStream){


localStream.getTracks().forEach((track)=>{

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
webRTC(十四):webrtc 端到端文本聊天