栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

webrtc视频聊天项目

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

webrtc视频聊天项目

1.环境准备

windows webstorm环境和ubuntu云服务器通过SFTP进行连接,都要进行安装(根据如下命令):

① npm install serve-index

② npm install log4js

③ npm install socket.io@2.0.3

④ npm install express

⑤ npm install sqlite3@5.0.0

用Google浏览器

2.搭建server引入模块
"use strict"

var http = require("http")
var https = require("https")
var fs = require("fs")
var express = require("express")
var serveIndex = require("serve-index")
var log4js = require("log4js")
var socketIO = require("socket.io")
var logger = log4js.getLogger()
logger.level = "info"

var app = express()
app.use(serveIndex("./www"))
app.use(express.static("./www"))

var httpServer = http.createServer(app)
.listen(8888, "0.0.0.0")

var options = {
key: fs.readFileSync("./cert/ssl_server.key"),
cert: fs.readFileSync("./cert/ssl_server.crt")
}

var httpsServer = https.createServer(options, app)
.listen(443, "0.0.0.0")
3.html用户注册登陆界面




myVideoChat



 4.使用数据库sqlite
var sqlite3 = require("sqlite3")
var db = null
var sql = ""

db = new sqlite3.Database("app.db", e=>{
if (e)
logger.info(e)
else
logger.info("suc:" + e)
})

db.run("create table if not exists users(id integer primary key autoincrement, name char(50) unique, pwd char(200))", e=>{
if (e)
logger.info(e)
else
logger.info("create table users successfully")
})

sql = "insert into users(name, pwd) values('haha', '123')"
db.exec(sql, e=>{
if (e)
logger.info(e)
else
logger.info("insert into users successfully")
})
sql = "select id, name, pwd from users"
db.all(sql, (e, rows)=>{
if (e)
logger.info(e)
else
logger.info(rows)
})

 

5.登陆界面的socket.io基于事件的实时双向通信

server端:

var io = socketIO.listen(httpsServer)
io.sockets.on("connection", socket=>{
logger.info("connect:"+socket.id)

//监听信号
socket.on("login", (uname, pwd)=>{
db.all("select id from users where name=? and pwd=?", [uname, pwd], (e, rows)=>{
if (e) {
logger.info(e)
socket.emit("servererr")
} else {
if (rows.length === 1)
socket.emit("logininsuccess", uname)
else
socket.emit("loginerr")
}
})
})
})

client端:

var socket = null
function start() {
socket = io.connect()

//监听来自服务器的消息
socket.on("servererr", ()=>{
alert("服务器异常,请重试")
})
socket.on("logininsuccess", ()=>{
alert("登录成功")
})
socket.on("loginerr", ()=>{
alert("用户名或密码错误")
})
}

start()

function login() {
var uname = unameIpt.value.trim()
var pwd = pwdIpt.value.trim()

if (uname === "" || pwd === "") {
alert("请输入用户名和密码")
return
}

socket.emit("login", uname, pwd)
}

loginBtn.onclick = login

 6.html注册界面




myVideoChat



欢迎到注册界面

按钮事件进入到注册界面

registerBtn.onclick = ()=>{
window.location.href = "../register.html"
}

 

7.注册界面的socket.io基于事件的实时双向通信

server端:

socket.on("register", (uname, pwd)=>{
db.all("select id from users where name=?", uname, (e, rows)=>{
if (e) {
logger.info(e)
socket.emit(err)
} else {
if (rows.length === 1) {
socket.emit("samename")
} else {
db.run("insert into users(name, pwd) values(?,?)", [uname, pwd], e=>{
if (e) {
logger.info(e)
socket.emit("servererr")
} else {
socket.emit("registerok", uname)
}
})
}
}
})
})

client端:

"use strict"

var unameIpt = document.querySelector("input#uname")
var pwdIpt = document.querySelector("input#pwd")
var ppwdIpt = document.querySelector("input#ppwd")
var backBtn = document.querySelector("button#back")
var registerBtn = document.querySelector("button#register")

var socket = null
function start() {
socket = io.connect()
socket.on("samename", ()=>{
alert("该用户已被注册")
})
socket.on("servererr", ()=>{
alert("服务器操作错误,请联系系统管理员")
})
socket.on("registerok", ()=>{
alert("注册成功,返回主界面")
goback()
})
}

start()

function goback() {
history.back()
}

backBtn.onclick = goback

function register() {
var uname = unameIpt.value.trim()
var pwd = pwdIpt.value.trim()
var ppwd = ppwdIpt.value.trim()

if (uname === "" || pwd === "" || ppwd === "" || pwd !== ppwd) {
alert("请输入用户名,并输入两次相同密码")
return
}

socket.emit("register", uname, pwd)
}

registerBtn.onclick = register
8.html聊天界面




myVideoChat



欢迎来到聊天室:

 

9.聊天界面的socket.io基于事件的实时双向通信

server端:

socket.on("cjoin", (room, uname)=>{
logger.info("cjoin:", room, uname)
socket.join(room)
var myRoom = io.sockets.adapter.rooms[room]
var users = Object.keys(myRoom.sockets).length
logger.info("房间中有:" + users + "人")
socket.emit("cjoinsuccess", room, users)
socket.to(room).emit("cotherjoined", room, uname, users)
})

socket.on("cexit", (room, uname)=>{
var myRoom = io.sockets.adapter.rooms[room]
var users = Object.keys(myRoom.sockets).length - 1
socket.leave(room)
socket.emit("cexited")
socket.to(room).emit("cotherexited", uname, users)
})

socket.on("cmsg", (room, uname, msg)=>{
io.in(room).emit("cgetmsg", uname, msg)
})

client端:

 "use strict"

var url = window.location.href

var uname = url.split("?")[1].split("=")[1]

var welcomeH1 = document.querySelector("h1#welcome")
welcomeH1.textContent = "欢迎来到聊天室:" + uname

var exitBtn = document.querySelector("button#exit")
var msglistTxt = document.querySelector("textarea#msglist")
var msgIpt = document.querySelector("input#msg")
var sendBtn = document.querySelector("button#send")
var videoRoomBtn = document.querySelector("button#videoRoom")
var userlabel = document.querySelector("label#users")

var room = "defaultRoom"

var socket = null
function start() {
socket = io.connect()

socket.emit("cjoin", room, uname)

socket.on("cjoinsuccess", (room, users)=>{
userlabel.textContent = "当前在线人数:" + users
msglistTxt.value = "欢迎" + uname + "进入房间n"
})

socket.on("cotherjoined", (room, uname, users)=>{
msglistTxt.value += "欢迎" + uname + "进入房间n"
})

socket.on("cexited", ()=>{
history.back()
})

socket.on("cotherexited", (uname, users)=>{
msglistTxt.value += uname + "离开了房间n"
userlabel.textContent = "当前在线人数:" + users
})

socket.on("cgetmsg", (uname, msg)=>{
msglistTxt.value += uname + ":" + msg + "n"
})
}

start()

exitBtn.onclick = ()=>{
socket.emit("cexit", room, uname)
}

function sendMsg(){
var msg = msgIpt.value.trim()
if (msg === "") return

socket.emit("cmsg", room, uname, msg)
msgIpt.value = ""
}

sendBtn.onclick = sendMsg

msgIpt.onkeydown = e=>{
var event = window.event || e
if (event.keyCode === 13)
sendMsg()
}
10.html视频界面




myVideoChat



欢迎到1v1视频聊天界面

 

11. 视频界面的socket.io基于事件的实时双向通信

server端:

socket.on("vjoin", (room, uname)=>{
logger.info("vjoin:", room, uname)
socket.join(room)
var myRoom = io.sockets.adapter.rooms[room]
var users = Object.keys(myRoom.sockets).length
if (users > 2) {
socket.leave(room)
socket.emit("vfull", room)
} else {
socket.emit("vjoined", room)
if (users > 1) {
socket.to(room).emit("votherjoined", room, uname)
}
}
})

socket.on("vdata", (room, data)=>{
socket.to(room).emit("vgetdata", room, data)
logger.info("vdata:", room, data)
})

socket.on("vleave", (room, uname)=>{
try {
var myRoom = io.sockets.adapter.rooms[room]
var users = Object.keys(myRoom.sockets).length - 1
} catch (ex) {
logger.info(ex)
return
}

socket.leave(room)
logger.info("vleave users=" + users)
socket.emit("vleft", room)
socket.to(room).emit("votherleft", room, uname)
})

client端:

"use strict"

var url = location.href
var uname = url.split("?")[1].split("=")[1]

var welcomeH1 = document.querySelector("h1#welcome")
welcomeH1.textContent = "欢迎到1v1视频聊天界面:" + uname

var roomIpt = document.querySelector("input#room")
var enterRoomBtn = document.querySelector("button#enterRoom")
var leaveRoomBtn = document.querySelector("button#leaveRoom")
var localVideo = document.querySelector("video#localVideo")
var remoteVideo = document.querySelector("video#remoteVideo")

var localStream = null
var remoteStream = null
var socket = null
var room = null
var state = "init"
var pc = null

function start() {
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
alert("rtc not supported")
return
}

var constraints = {
video: true,
audio: true
}

navigator.mediaDevices.getUserMedia(constraints)
.then(getStream)
.catch(handleErr)

conn()
}

start()

function getOffer(desc) {
pc.setLocalDescription(desc)
sendMessage(desc)
}

function negotiate() {
if (state === "joined_conn") {
if (pc) {
var options = {
offerToReceiveVideo: true,
offerToReceiveAudio: true
}
pc.createOffer(options)
.then(getOffer)
.catch(handleErr)
}
}
}

function conn() {
socket = io.connect()
//监听消息
socket.on("vjoined", room=>{
alert("成功加入房间:" + room)
state = "joined"
createPeerConnection()
console.log("vjoined:", state)
})

socket.on("votherjoined", (room, uname)=>{
console.log("别人也进来了:" + uname)
if (state === "joined_unbind") {
createPeerConnection()
}
state = "joined_conn"
//媒体协商
negotiate()
console.log("votherjoined state=", state)
})

socket.on("vfull", room=>{
console.log("房间已满:" + room)
state = "left"
alert("房间已满:" + room)
console.log("vfull:", state)
})

socket.on("vgetdata", (room, data)=>{
console.log(data)
if (!data)
return
if (data.type === "candidate") {
console.log("get candidate")
var cddt = new RTCIceCandidate({
sdpMLineIndex: data.label,
candidate: data.candidate
})

pc.addIceCandidate(cddt)
} else if (data.type === "offer") {
console.log("other offer")
pc.setRemoteDescription(new RTCSessionDescription(data))
pc.createAnswer()
.then(getAnswer)
.catch(handleErr)
} else if (data.type === "answer") {
console.log("other answer")
pc.setRemoteDescription(new RTCSessionDescription(data))
} else {
console.log("err message")
}
})

socket.on("vleft", (room)=>{
console.log("离开房间:" + room)
state = "left"
console.log("vleft:", state)
})

socket.on("votherleft", (room, uname)=>{
console.log("别人离开了房间:"+ uname)
state = "joined_unbind"
closePeerConnection()
console.log("votherleft", state)
})
}

function getAnswer(desc) {
pc.setLocalDescription(desc)
sendMessage(desc)
}

function closePeerConnection() {
console.log("close closePeerConnection")
if (pc) {
pc.close()
pc = null
}
}

function createPeerConnection() {
if (!pc) {
var pcConfig = {
"iceServers:":[{
"urls": "turn:111.67.195.158:3478",
"username": "trafalgar",
"credential": "123456"
}]
}

pc = new RTCPeerConnection(pcConfig)
pc.onicecandidate = (e)=>{
if (e.candidate) {
console.log("Candidate:", e.candidate)
sendMessage({
type: "candidate",
label: e.candidate.sdpMLineIndex,
id: e.candidate.sdpMid,
candidate: e.candidate.candidate
})
}
}

pc.ontrack = (e) => {
remoteStream = e.streams[0]
remoteVideo.srcObject = remoteStream
}
}

if (localStream) {
localStream.getTracks().forEach(track=>{
pc.addTrack(track, localStream)
})
}

}

function sendMessage(data) {
if (socket) {
socket.emit("vdata", room, data)
}
}

function getStream(stream) {
localStream = stream
localVideo.srcObject = stream
}

function enterRoom() {
room = roomIpt.value.trim()
if (room === "") {
alert("请输入房间号")
return
}

socket.emit("vjoin", room, uname)
}

function leaveRoom() {
socket.emit("vleave", room, uname)
closePeerConnection()
}


function handleErr(err) {
console.log(err)
}

enterRoomBtn.onclick = enterRoom
leaveRoomBtn.onclick = leaveRoom
12.关于stun/turn服务器验证

Trickle ICE

13.md5加密


var secpwd = hex_md5(pwd)

socket.emit("login", uname, secpwd)

14.解决中文字错误显示问题

window.location.href = "../chat.html?uname=" + encodeURI(uname)

var uname = decodeURI(url.split("?")[1].split("=")[1])

window.location.href = "../videoRoom.html?uname=" + encodeURI(uname)

 

15.进行html优化

使用bootstrap

①登陆界面:




  • 登陆
②注册界面:




  • 登陆
  • 注册
③聊天界面:




  • 登陆

欢迎来到聊天室:

④视频界面:






欢迎到1v1视频聊天界面

16.最终效果

 

 

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/885034.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号