获取的下载下来的webm文件可以通过ffmpeg插件转成对应的文件格式

音频录制

获取全部音频设备

  1. //获取全部外设
  2. window.onload = navigator.mediaDevices.enumerateDevices().then(res => {
  3. //res是全部的外设
  4. for (let i = 0; i < res.length; ++i) {
  5. if (res[i].kind === 'audioinput') {
  6. carema.push(res[i])
  7. }
  8. }
  9. deviceInfoId = carema[0];
  10. })

将audio标签进行实时播放 通过MediaRecorder对象进行录制 格式只能是webm mp3 mp4不支持但是生成生成连接下载时候可以下载成mp3 mp4

  1. //点击开始按钮 进行实时播放且开始录制
  2. div.onclick = () => {
  3. navigator.mediaDevices.getUserMedia({
  4. video: false,
  5. audio: {deviceId: deviceInfoId.deviceId}
  6. }).then(res => {
  7. video.srcObject = res;
  8. video.play();
  9. //必须进行接受返回值 start开始录制
  10. num = new MediaRecorder(res, {mimeType: 'video/webm;codecs=h264'})
  11. num.start()
  12. })
  13. }

将录制的音频设置到其他audio 且下载下来

  1. //点击结束按钮 获取录制好的二进制数据 生成url设置到新的audio标签上
  2. div1.onclick = () => {
  3. //结束录制
  4. num.stop();
  5. let s0 = null
  6. //当结束录制后触发该方法
  7. num.ondataavailable = e => {
  8. s0 = e.data;//获取到的blob数据
  9. video1.src = window.URL.createObjectURL(s0);//设置到一个新的video标签上
  10. //进行下载
  11. let a = document.createElement('a')
  12. a.href = window.URL.createObjectURL(s0)
  13. a.download = "音频.webm"
  14. document.body.appendChild(a)
  15. a.click()
  16. }

视频录制

和录制音频相同 就是标签不同 和获取的外设不同

获取全部摄像头

  1. //获取全部外设
  2. window.onload = navigator.mediaDevices.enumerateDevices().then(res => {
  3. //res是全部的外设
  4. for (let i = 0; i < res.length; ++i) {
  5. if (res[i].kind === 'videoinput') {
  6. carema.push(res[i])
  7. }
  8. }
  9. deviceInfoId = carema[0];
  10. })

将video标签进行实时播放 通过MediaRecorder对象进行录制

  1. //点击开始按钮 进行实时播放且开始录制
  2. div.onclick = () => {
  3. navigator.mediaDevices.getUserMedia({
  4. video: {deviceId: deviceInfoId.deviceId}//可以在获取音频设备设置上可以将声音也录制上
  5. }
  6. }).then(res => {
  7. video.srcObject = res;
  8. video.play();
  9. //必须进行接受返回值 start开始录制
  10. num = new MediaRecorder(res, {mimeType: 'video/webm;codecs=h264'})
  11. num.start()
  12. })
  13. }

将录制的视频设置到其他video且下载下来

  1. //点击结束按钮 获取录制好的二进制数据 生成url设置到新的video标签上
  2. div1.onclick = () => {
  3. //结束录制
  4. num.stop();
  5. let s0 = null
  6. //当结束录制后触发该方法
  7. num.ondataavailable = e => {
  8. s0 = e.data;//获取到的blob数据
  9. video1.src = window.URL.createObjectURL(s0);//设置到一个新的video标签上
  10. //进行下载
  11. let a = document.createElement('a')
  12. a.href = window.URL.createObjectURL(s0)
  13. a.download = "视频.webm"
  14. document.body.appendChild(a)
  15. a.click()
  16. }

录制屏幕

获取屏幕且在video实时展示 getDisplayMedia获取屏幕流

  1. div.onclick = () => {
  2. navigator.mediaDevices.getDisplayMedia().then(res => {
  3. video.srcObject = res;
  4. video.play();
  5. num = new MediaRecorder(res, {mimeType: 'video/webm;codecs=h264'})
  6. num.start()
  7. })
  8. }
  1. //点击结束按钮 获取录制好的二进制数据 生成url设置到新的video标签上
  2. div1.onclick = () => {
  3. //结束录制
  4. num.stop();
  5. let s0 = null
  6. //当结束录制后触发该方法
  7. num.ondataavailable = e => {
  8. s0 = e.data;//获取到的blob数据
  9. video1.src = window.URL.createObjectURL(s0);//设置到一个新的video标签上
  10. //进行下载
  11. let a = document.createElement('a')
  12. a.href = window.URL.createObjectURL(s0)
  13. a.download = "屏幕.webm"
  14. document.body.appendChild(a)
  15. a.click()
  16. }

WebRTC

实现视频通话

dqJ93y4dI5-compress.jpg

过程

  1. 教师端获取视频流 通过addTrack将流发送过去(注意:必须要前打开流 否则发送offer后需要在打开一次 这时流还没有发送过去)
  2. 创建RTCPeerConnection连接无参数使用默认的
  3. 通过onicecandidate监听事件获取信令(会在发送过去addicecandidate或者发送过去offer进行应答时触发)
  4. 教师端向学生端发送offer且自己通过setLocalDescription设置上 通过socket传输给学生端 学生端通过进行setRemoteDescription接收且创建answer进行应答通用学生端通过setLocalDescription进行设置,教师端通过setRemoteDescription设置学生端在将接收到的candidate通过addIceCandidate()设置上(注意在设置时要通过new RTCIceCandidate(res.obj)进行构建下)
  5. 这时候教师端的addTrack发送数据流了,学生端ontrack会监听到数据流进行输入到video上去

如果实现两边都互相直播的情况 可以在双方都进行offer answer互传,通过addTrack传输 两边进行onTrack监听

教师端

  1. <body>
  2. <video id="video" controls></video>
  3. <video id="video1" controls></video>
  4. <div id="div" style="background:rosybrown;width: 200px;height: 200px">开启摄像头</div>
  5. <div id="div1" style="background:rosybrown;width: 200px;height: 200px">直播</div>
  6. </body>
  7. <script>
  8. var video = document.getElementById('video');
  9. var video1 = document.getElementById('video1');
  10. var div = document.getElementById('div');
  11. var div1 = document.getElementById('div1');
  12. var canvas = document.getElementById('canvas');
  13. var deviceInfoId = ""; //摄像头ID
  14. let carema = []; //摄像头ID数组
  15. //在页面加载完成后获得设备ID数组
  16. window.onload = navigator.mediaDevices.enumerateDevices().then(res => {
  17. //res是全部的外设 找到摄像头的外设存下来
  18. for (let i = 0; i < res.length; ++i) {
  19. if (res[i].kind === 'videoinput') {
  20. carema.push(res[i])
  21. }
  22. }
  23. deviceInfoId = carema[0];
  24. })
  25. let webSocket = new WebSocket("ws://192.168.0.31:8888/webrtc?roomID=" + 100)
  26. webSocket.onopen = function (e) {
  27. console.log("打开连接了")
  28. }
  29. var configuration = {
  30. iceServers: [{url: "stun:stun1.l.google.com:19302"}]
  31. };
  32. let pc = new RTCPeerConnection(configuration);
  33. pc.onicecandidate = function (event) {
  34. console.log("onicecandidate:"+event)
  35. if (event.candidate) {
  36. webSocket.send(JSON.stringify({sys: "ice", obj: event.candidate}));
  37. }
  38. }
  39. div.onclick = () => {
  40. navigator.mediaDevices.getUserMedia({
  41. video: {deviceId: deviceInfoId.deviceId},
  42. audio: false
  43. }).then(res => {
  44. res.getTracks().forEach(e => {
  45. console.log(e)
  46. pc.addTrack(e,res);
  47. })
  48. video.srcObject = res;
  49. video.play();
  50. })
  51. }
  52. div1.onclick=()=>{
  53. pc.createOffer().then(e => {
  54. pc.setLocalDescription(e);
  55. console.log("offer教师:"+pc.setLocalDescription(e))
  56. if (webSocket.readyState == WebSocket.OPEN) {
  57. webSocket.send(JSON.stringify({sys: "offer", obj: e}))
  58. }
  59. })
  60. }
  61. // pc.ontrack = e => {
  62. // alert("11")
  63. // console.log(e)
  64. // video1.srcObject =e.streams[0]
  65. // }
  66. webSocket.onmessage = e => {
  67. let res = JSON.parse(e.data);
  68. console.log("接受到消息")
  69. if (res.sys == "offer") {
  70. pc.setRemoteDescription(res.obj);
  71. console.log("offer学生")
  72. pc.createAnswer().then(e => {
  73. pc.setLocalDescription(e)
  74. console.log("answer教师")
  75. webSocket.send(JSON.stringify({sys: "answer", obj: e}))
  76. })
  77. } else if (res.sys == "answer") {
  78. pc.setRemoteDescription(res.obj)
  79. console.log("answer学生")
  80. } else if (res.sys == "ice") {
  81. console.log("ice被调用")
  82. pc.addIceCandidate(new RTCIceCandidate(res.obj))
  83. }
  84. }
  85. </script>

学生端

  1. <body>
  2. <video id="video" controls></video>
  3. <video id="video1" controls></video>
  4. <div id="div" style="background:rosybrown;width: 200px;height: 200px">开启摄像头</div>
  5. <div id="div1" style="background:rosybrown;width: 200px;height: 200px">拍照</div>
  6. </body>
  7. <script>
  8. var video = document.getElementById('video');
  9. var video1 = document.getElementById('video1');
  10. var div = document.getElementById('div');
  11. var div1 = document.getElementById('div1');
  12. var canvas = document.getElementById('canvas');
  13. var deviceInfoId = ""; //摄像头ID
  14. let carema = []; //摄像头ID数组
  15. //在页面加载完成后获得设备ID数组
  16. window.onload = navigator.mediaDevices.enumerateDevices().then(res => {
  17. //res是全部的外设 找到摄像头的外设存下来
  18. for (let i = 0; i < res.length; ++i) {
  19. if (res[i].kind === 'videoinput') {
  20. carema.push(res[i])
  21. }
  22. }
  23. deviceInfoId = carema[0];
  24. })
  25. let webSocket = new WebSocket("ws://localhost:8888/webrtc?roomID=" + 100)
  26. webSocket.onopen = function (e) {
  27. console.log("打开连接了")
  28. }
  29. let pc = new RTCPeerConnection();
  30. //学生端如果不需要传输视频流不需要发送ice和offer
  31. //只需要教师端将offer给学生端 学生端给教师端一个answer应该就可以
  32. //学生端需要将教师端给的offer设置上同时返回给教师端个answer 将教师端给的ice添加上 监听ontrack就可以了
  33. pc.onicecandidate = function(event) {
  34. console.log("学生端ice被调用")
  35. if (event.candidate) {
  36. webSocket.send(JSON.stringify({sys: "ice", obj: event.candidate}));
  37. }
  38. }
  39. div.onclick = () => {
  40. navigator.mediaDevices.getUserMedia({
  41. video: {deviceId: deviceInfoId.deviceId},
  42. audio: false
  43. }).then(res => {
  44. video.srcObject = res;
  45. video.play();
  46. })
  47. }
  48. div1.onclick = () => {
  49. pc.createOffer().then(e => {
  50. pc.setLocalDescription(e);
  51. if (webSocket.readyState == WebSocket.OPEN) {
  52. webSocket.send(JSON.stringify({sys: "offer", obj: e}))
  53. }
  54. })
  55. }
  56. pc.ontrack = e => {
  57. video1.srcObject = e.streams[0]
  58. }
  59. webSocket.onmessage = e => {
  60. let res = JSON.parse(e.data);
  61. if (res.sys == "offer") {
  62. pc.setRemoteDescription(res.obj);
  63. pc.createAnswer().then(e => {
  64. pc.setLocalDescription(e)
  65. webSocket.send(JSON.stringify({sys: "answer", obj: e}))
  66. })
  67. } else if (res.sys == "answer") {
  68. console.log(res)
  69. pc.setRemoteDescription(new RTCSessionDescription(res.obj));
  70. } else if (res.sys == "ice") {
  71. pc.addIceCandidate(new RTCIceCandidate(res.obj))
  72. }
  73. }
  74. </script>

socket服务

  1. // 只是简单的将收到的数据发送过去 在前端进行判断 可以在后端进行严谨判断--这里没有需要更改 完成复制可能失败
  2. @OnMessage
  3. public void onMessage(String message, Session session) throws IOException {
  4. String thisRoomID=session.getQueryString();//获取参数
  5. System.out.println(thisRoomID);
  6. for (Session session1 : list){
  7. System.out.println(session1==session);
  8. if (session1==session){
  9. continue;
  10. }
  11. System.out.println(message);
  12. session1.getBasicRemote().sendText(message);
  13. }