webrtc 点对点聊天 不需要服务器

selfl.html

点击查看代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>视频聊天</title>
    <link rel="stylesheet" type="text/css" href="css/common.css"/>
    <link rel="stylesheet" type="text/css" href="css/jquery-ui.css"/>
    <script src="./js/peerjs.min.js"></script>
    <script src="./js/jquery-1.12.4.js"></script>
    <script src="./js/jquery-ui.js"></script>
    <script src="./js/util.js"></script>
    <script>

      var peer = null
      var startId = null
      var receiveId = null
      var conn = null
      var localStream = null

      //页面加载后
      window.onload = function () {
        var videoSelect = document.querySelector('select#videoSelect')
        var localVideo = document.querySelector('video#localVideo')
        var remoteVideo = document.querySelector('video#remoteVideo')
        var lblFrom = document.querySelector('label#lblFrom')
        var tip = document.querySelector('#tip')
        if (!navigator.mediaDevices ||
          !navigator.mediaDevices.getUserMedia) {
          console.log('webrtc is not supported!')
          alert('webrtc is not supported!')
          return
        }

        //获取摄像头列表
        navigator.mediaDevices
          .enumerateDevices()
          .then(getDevices)
          .catch(handleError)

        //改变摄像头重新获取流
        videoSelect.onchange = function () {
          start()
          pleaseCallMe() //让那边重新call 就能同步画面
        }
        start() //默认直接获取流

        $('#dialog-confirm').hide() //隐藏接收提示框

        //每次使用同一个startId
        if (localStorage.getItem('startId') == null) {
          startId = new Date().getTime()
          localStorage.setItem('startId', startId)
        } else {
          startId = localStorage.getItem('startId')
        }

        peer = new Peer(startId)
        console.log(peer)

        peer.on('open', function (id) {
          startId = id
          console.log('My peer ID is: ' + id)
          console.log(`接收端链接${location.href.replace('self', 'target')}?startId=${startId}`)
          document.getElementById('receivedUrl').innerHTML = `<a target="_blank" href="${location.href.replace('self', 'target')}?startId=${startId}">${location.href.replace('self', 'target')}?startId=${startId}</a>`
        })

        peer.on('call', function (call) {
          console.log('oncall')
          call.answer(localStream)
        })

        peer.on('connection', function (conn) {
          console.log('被连接', conn)
          receiveId = conn.peer
          conn.on('data', (data) => {
            var msg = JSON.parse(data)
            console.log('收到消息', msg)
            //收到视频邀请时,弹出询问对话框
            if (msg.action === 'call') {
              console.log('call')
              tip.innerHTML = '被别人call'
              lblFrom.innerText = msg.from
              $('#dialog-confirm').dialog({
                resizable: false,
                height: 'auto',
                width: 400,
                modal: true,
                buttons: {
                  'Accept': function () {
                    $(this).dialog('close')
                    sendMessage(msg.to, msg.from, 'accept')
                  },
                  Cancel: function () {
                    $(this).dialog('close')
                  }
                }
              })
            }

            //接受视频通话邀请后,通知另一端    
            if (msg.action === 'accept-ok') {
              console.log('accept-ok call => ' + JSON.stringify(msg))
              var call = peer.call(receiveId, localStream)
              call.on('stream', function (stream) {
                console.log('received remote stream')
                remoteVideo.srcObject = stream
              })
              tip.innerHTML = '已连接'
            }
          })
        })

      }
    </script>
</head>
<body>
<div class="container" style="text-align: center;">
    <h1>基于PeerJS的点对点视频聊天程序</h1>
    <p>
        <span style="font-weight: 700;">切换设备</span>
        <select id="videoSelect" style="width:100px"></select>
    </p>
    <p>
        把下方链接发送给你对象即可开始视频啦<br/>
        <span>对象链接:</span><span id="receivedUrl">生成中...</span>
    </p>
    <div style="display: flex;flex-flow: wrap;justify-content: center;">
        <div style="border: 5px solid #ccc;">
            <h4>你的画面</h4>
            <video id="localVideo" autoplay controls></video>
        </div>
        <div style="border: 5px solid #ccc;">
            <h4>对象画面</h4>
            <video id="remoteVideo" autoplay controls></video>
        </div>
    </div>

    <div id="dialog-confirm" title="接受视频通话吗?">
        <p>
            <span class="ui-icon ui-icon-info" style="float:left; margin:12px 12px 20px 0;"></span><label
                id="lblFrom"></label>
            打你,是否接受?
        </p>
    </div>
    <div id="tip">
        等待分享链接给对象...
    </div>
</div>
</body>

</html>

target.html

点击查看代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>视频聊天</title>
    <link rel="stylesheet" type="text/css" href="css/common.css"/>
    <link rel="stylesheet" type="text/css" href="css/jquery-ui.css"/>
    <script src="./js/peerjs.min.js"></script>
    <script src="./js/jquery-1.12.4.js"></script>
    <script src="./js/jquery-ui.js"></script>
    <script src="./js/util.js"></script>
    <script>

      var peer = null
      var startId = null
      var receiveId = null
      var conn = null
      var localStream = null

      //页面加载后
      window.onload = function () {
        var videoSelect = document.querySelector('select#videoSelect')
        var localVideo = document.querySelector('video#localVideo')
        var remoteVideo = document.querySelector('video#remoteVideo')
        var lblFrom = document.querySelector('label#lblFrom')
        var tip = document.querySelector('#tip')
        if (!navigator.mediaDevices ||
          !navigator.mediaDevices.getUserMedia) {
          console.log('webrtc is not supported!')
          alert('webrtc is not supported!')
          return
        }

        //获取摄像头列表
        navigator.mediaDevices
          .enumerateDevices()
          .then(getDevices)
          .catch(handleError)

        //改变摄像头重新获取流
        videoSelect.onchange = function () {
          start()
          pleaseCallMe() //让那边重新call 就能同步画面
        }
        start() //默认直接获取流

        $('#dialog-confirm').hide() //隐藏接收提示框

        //每次使用同一个startId
        if (localStorage.getItem('startId') == null) {
          startId = new Date().getTime()
          localStorage.setItem('startId', startId)
        } else {
          startId = localStorage.getItem('startId')
        }

        peer = new Peer(startId)
        console.log(peer)

        peer.on('open', function (id) {
          startId = id
          console.log('My peer ID is: ' + id)
          console.log(`接收端链接${location.href.replace('self', 'target')}?startId=${startId}`)
          document.getElementById('receivedUrl').innerHTML = `<a target="_blank" href="${location.href.replace('self', 'target')}?startId=${startId}">${location.href.replace('self', 'target')}?startId=${startId}</a>`
        })

        peer.on('call', function (call) {
          console.log('oncall')
          call.answer(localStream)
        })

        peer.on('connection', function (conn) {
          console.log('被连接', conn)
          receiveId = conn.peer
          conn.on('data', (data) => {
            var msg = JSON.parse(data)
            console.log('收到消息', msg)
            //收到视频邀请时,弹出询问对话框
            if (msg.action === 'call') {
              console.log('call')
              tip.innerHTML = '被别人call'
              lblFrom.innerText = msg.from
              $('#dialog-confirm').dialog({
                resizable: false,
                height: 'auto',
                width: 400,
                modal: true,
                buttons: {
                  'Accept': function () {
                    $(this).dialog('close')
                    sendMessage(msg.to, msg.from, 'accept')
                  },
                  Cancel: function () {
                    $(this).dialog('close')
                  }
                }
              })
            }

            //接受视频通话邀请后,通知另一端    
            if (msg.action === 'accept-ok') {
              console.log('accept-ok call => ' + JSON.stringify(msg))
              var call = peer.call(receiveId, localStream)
              call.on('stream', function (stream) {
                console.log('received remote stream')
                remoteVideo.srcObject = stream
              })
              tip.innerHTML = '已连接'
            }
          })
        })

      }
    </script>
</head>
<body>
<div class="container" style="text-align: center;">
    <h1>基于PeerJS的点对点视频聊天程序</h1>
    <p>
        <span style="font-weight: 700;">切换设备</span>
        <select id="videoSelect" style="width:100px"></select>
    </p>
    <p>
        把下方链接发送给你对象即可开始视频啦<br/>
        <span>对象链接:</span><span id="receivedUrl">生成中...</span>
    </p>
    <div style="display: flex;flex-flow: wrap;justify-content: center;">
        <div style="border: 5px solid #ccc;">
            <h4>你的画面</h4>
            <video id="localVideo" autoplay controls></video>
        </div>
        <div style="border: 5px solid #ccc;">
            <h4>对象画面</h4>
            <video id="remoteVideo" autoplay controls></video>
        </div>
    </div>

    <div id="dialog-confirm" title="接受视频通话吗?">
        <p>
            <span class="ui-icon ui-icon-info" style="float:left; margin:12px 12px 20px 0;"></span><label
                id="lblFrom"></label>
            打你,是否接受?
        </p>
    </div>
    <div id="tip">
        等待分享链接给对象...
    </div>
</div>
</body>

</html>

公共函数 util.js

点击查看代码


//获取url后面的参数
getRequest = function () {
  var url = location.search
  var theRequest = new Object()
  if (url.indexOf('?') != -1) {
    let str = url.substr(1)
    let strs = str.split('&')
    for (let i = 0; i < strs.length; i++) {
      theRequest[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1])
    }
  }
  return theRequest
}

//绑定摄像头列表到下拉框
function getDevices (deviceInfos) {
  if (deviceInfos === undefined) {
    return
  }
  console.log(`设备信息${deviceInfos}`)
  for (let i = 0; i !== deviceInfos.length; ++i) {
    const deviceInfo = deviceInfos[i]
    const option = document.createElement('option')
    option.value = deviceInfo.deviceId
    if (deviceInfo.kind === 'videoinput') {
      option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`
      console.log(option)
      videoSelect.appendChild(option)
    }
  }
}

//获取设备错误
function handleError (error) {
  console.log('navigator.MediaDevices.getUserMedia error: ', error.message, error.name)
}

//获取流
function getStream (stream) {
  console.log('received local stream')
  localStream = stream
  localVideo.srcObject = localStream //显示到页面
}

//开启本地摄像头
function start () {
  if (localStream) { //停止
    localStream.getTracks().forEach(track => {
      track.stop()
    })
  }
  const videoSource = videoSelect.value
  const constraints = {
    audio: true,
    video: { width: 6020, deviceId: videoSource ? { exact: videoSource } : undefined }
  }
  navigator.mediaDevices
    .getUserMedia(constraints)
    .then(getStream)
    .then(getDevices)
    .catch(handleError)
}

//封装发送消息
function sendMessage (from, to, action) {
  var message = { 'from': from, 'to': to, 'action': action }
  if (!conn) {
    conn = peer.connect(receiveId)
    conn.on('open', () => {
      conn.send(JSON.stringify(message))
      console.log('发消息', message)
    })
  }
  if (conn.open) {
    conn.send(JSON.stringify(message))
    console.log(message)
  }
}

//当此端改变摄像头 请求那边重新call一次 不然画面传不过去
function pleaseCallMe () {
  sendMessage(startId, receiveId, 'pleaseCallMe')
}
#### common.css
点击查看代码
.w60 {
    width: 60px;
}

.w120 {
    width: 120px;
}

.align_right {
    text-align: right;
    background-color: beige;
    line-height: 150%;
    padding: 3px
}

.align_left {
    text-align: left;
    line-height: 150%;
    padding: 3px
}

.chatMessageBox {
    height: 200px;
    overflow-y: scroll;
    vertical-align: top
}

video{
    width:320px;
    height:240px
}

#container {
    position: relative;
}

#demoCanvas {
    border: 1px solid #000;
}
posted @ 2022-05-26 00:17  vx_guanchaoguo0  阅读(312)  评论(0编辑  收藏  举报