index.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. const io = require("socket.io-client")
  2. const { PeerConnection, Video, Audio } = require('node-datachannel');
  3. const { spawn } = require('child_process')
  4. const UDP = require('./lib/udp')
  5. class CarServer {
  6. constructor() {
  7. this.Peer = null
  8. this.videoChild = null
  9. this.videoUDP = null
  10. this.audioChild = null
  11. this.audioUDP = null
  12. this.socket = io('wss://**********', {
  13. auth: {
  14. roomID: 'test213',
  15. name: 'control'
  16. }
  17. });
  18. this.socket.on('connect', this.connected.bind(this))
  19. this.socket.on('msg', this.onMsg.bind(this))
  20. this.socket.on('leaved', this.onLeved.bind(this))
  21. this.socket.on('joined', this.startVideo.bind(this))
  22. }
  23. // socket 连接
  24. connected() {
  25. console.log('connected');
  26. this.Peer = new PeerConnection("Peer1", { iceServers: [] });
  27. // 发送offer
  28. this.Peer.onGatheringStateChange(state => {
  29. console.log('GatheringState: ', state);
  30. if (state === 'complete') {
  31. const offer = this.Peer.localDescription();
  32. this.socket.emit("msg", offer);
  33. }
  34. })
  35. }
  36. // 用户信息
  37. onMsg(data) {
  38. try {
  39. if (data.type == 'answer') {
  40. this.Peer.setRemoteDescription(data.sdp, data.type);
  41. } else if (data.type === 'startRTC') {
  42. this.startVideo()
  43. }
  44. } catch (error) {
  45. console.log('msg error:', error);
  46. }
  47. }
  48. // 用户离开
  49. onLeved() {
  50. if (this.videoChild) this.videoChild.kill()
  51. if (this.audioChild) this.audioChild.kill()
  52. if (this.videoUDP) this.videoUDP.close()
  53. if (this.audioUDP) this.audioUDP.close()
  54. this.videoChild = null
  55. this.videoUDP = null
  56. this.audioChild = null
  57. this.audioUDP = null
  58. process.exit(1)
  59. }
  60. // 开始视频
  61. startVideo() {
  62. try {
  63. if (this.videoChild) this.videoChild.kill()
  64. if (this.audioChild) this.audioChild.kill()
  65. if (this.videoUDP) this.videoUDP.close()
  66. if (this.audioUDP) this.audioUDP.close()
  67. // ------------video----------------
  68. const video = new Video('video', 'SendOnly')
  69. video.addH264Codec(97)
  70. video.addSSRC(43, "video-send")
  71. const videoTrack = this.Peer.addTrack(video)
  72. const videoPort = 47788
  73. const videoArgs = [
  74. "libcamerasrc",
  75. "video/x-raw,width=320,height=240",
  76. "videoconvert",
  77. "queue",
  78. "x264enc tune=zerolatency bitrate=1000 key-int-max=30",
  79. "video/x-h264, profile=constrained-baseline",
  80. "rtph264pay pt=97 mtu=1200 ssrc=43",
  81. `udpsink host=127.0.0.1 port=${videoPort}`,
  82. ].join(" ! ").split(" ")
  83. this.videoChild = spawn("gst-launch-1.0", videoArgs)
  84. this.videoUDP = new UDP(videoPort, data => {
  85. if (!videoTrack.isOpen()) return
  86. videoTrack.sendMessageBinary(data)
  87. })
  88. // -----------audio--------------
  89. const audio = new Audio('audio','SendOnly')
  90. audio.addOpusCodec(96)
  91. audio.addSSRC(42, "audio-send")
  92. const audioTrack = this.Peer.addTrack(audio)
  93. const audioPort = 47789
  94. // alsamixer F6 查看当前声卡,默认是3-0
  95. // "alsasrc device=plughw:1,0",
  96. const audioArgs = [
  97. 'alsasrc device=plughw:3,0',
  98. "audio/x-raw,rate=8000,channels=1",
  99. "audioconvert",
  100. "queue",
  101. "opusenc",
  102. "rtpopuspay",
  103. `udpsink host=127.0.0.1 port=${audioPort}`,
  104. ].join(" ! ").split(" ")
  105. this.audioChild = spawn("gst-launch-1.0", audioArgs)
  106. this.audioUDP = new UDP(audioPort, data => {
  107. if (!audioTrack.isOpen()) return
  108. audioTrack.sendMessageBinary(data)
  109. })
  110. // ---------
  111. this.Peer.setLocalDescription()
  112. } catch (error) {
  113. console.log('startvideo:', error)
  114. }
  115. }
  116. }
  117. new CarServer()