Kurento端点订单以便录制截屏视频

时间:2016-04-05 10:27:52

标签: javascript node.js kurento

我尝试使用kurento媒体服务器录制网络摄像头,这是我在后端使用的功能:

var startScreen = (sessionId, ws, sdpOffer, callback) => {
    console.log("Start screen")
  getKurentoClient((error, kurentoClient) => {
    if (error) {
      return callback(error)
    }

    kurentoClient.create('MediaPipeline', (error, pipeline) => {
      if (error) {
        return callback(error)
      }


     var recordParams = {
        stopOnEndOfStream: true,
        mediaProfile: 'WEBM_VIDEO_ONLY',
        uri: 'file:///PATH/TO/VIDEO/screen.webm'
      }
      pipeline.create('RecorderEndpoint', recordParams, (error, recorder) => {
        if (error) return callback(error)

        screenRecorder = recorder
        recorder.record(() => console.log("recording"))
        pipeline.create('WebRtcEndpoint', (error, webRtcEndpoint) => {
          if (error) {
            pipeline.release()
            return callback(error)
          }

        screenRtcEndpoint = webRtcEndpoint

          if (candidatesQueue[sessionId]) {
            while(candidatesQueue[sessionId].length) {
              var candidate = candidatesQueue[sessionId].shift()
              webRtcEndpoint.addIceCandidate(candidate)
            }
          }
          webRtcEndpoint.on('OnIceCandidate', (event) => {
            var candidate = kurento.register.complexTypes.IceCandidate(event.candidate)
            ws.send(JSON.stringify({
              id: 'iceCandidateScreen',
              candidate: candidate
            }))
          })

          webRtcEndpoint.processOffer(sdpOffer, (error, sdpAnswer) => {
            if (error) {
              pipeline.release()
              return callback(error)
            }

            sessions[sessionId] = {
              'pipeline': pipeline,
              'webRtcEndpoint': webRtcEndpoint
            }

          webRtcEndpoint.connect(webRtcEndpoint, error => {
            if (error) {
              return callback(error)
            }
            console.log("Connect webrtcEndpoint")
            webRtcEndpoint.connect(screenRecorder, error => {
              if (error) {
                return callback(error)
              }
              console.log("connect to the screen recorder")
            })

            callback(null, sdpAnswer)
            })

          })

          webRtcEndpoint.gatherCandidates((error) => {
            if (error) {
              return callback(error)
            }
          })
        })
      })
    })
  })
}

管道看起来像这样:

mediaPipeline -> recorderEndpoint and recorder.record -> WebRtcEndpoint connect webrtcendpoint -> connect recorder endpoint

在前端我这样做:

mediaConstrains = {
  audio: false,
  video: {
    mandatory: {
      maxWidth: 640,
      maxHeight: 480,
      maxFrameRate: 15,
      minFrameRate: 1
    }
  }
}

var getMediaConstrains = () => mediaConstrains

var setMediaConstrains = (config) => {
  mediaConstrains = config
}

var startScreen = () => {
  var options = {
    mediaConstrains: mediaConstrains,
    onicecandidate: onIceCandidate,
    configuration: { iceServers: [
        {'url': 'turn:numb.viagenie.ca:3478',
          'username': 'email@email.com',
        'credential': 'passwordrandom'}
    ] }
  }

  webRtcPeerScreen = kurentoUtils.WebRtcPeer.WebRtcPeerSendonly(options, function (error) {
    if (error) {
      return onError(error)
    }

    this.generateOffer(onOfferScreen)
  })
}

这仅适用于无效的截屏视频,我使用几乎完全相同的代码来录制完全正常工作的网络摄像头,这是停止功能:

var stop = () => {
  if (webRtcPeerWebcam && webRtcPeerScreen) {
    webRtcPeerWebcam.dispose()
    webRtcPeerWebcam = null
    webRtcPeerScreen.dispose()
    webRtcPeerScreen = null

    var message = {
      id: 'stop'
    }
    sendMessage(message)
  }
}

我在前端处理管道但是,我将此消息发送到后端,然后此wss消息调用此函数:

var stop = (sessionId) => {
  if (sessions[sessionId]) {
    var pipeline = sessions[sessionId].pipeline
    pipeline.release()
    delete sessions[sessionId]
    delete candidatesQueue[sessionId]
  }
}

我认为这可能是为什么这不能用于录制截屏视频的问题,或者我可能不正确地连接管道

无论如何,谢谢!

PD:我在KMS日志上找到了这个:

KurentoMediaElementImpl MediaElementImpl.cpp:434 mediaFlowOutStateChange() <kmswebrtcendpoint373> Media N OT Flowing OUT in pad default with type video 

2 个答案:

答案 0 :(得分:2)

第一个也是最重要的问题是,在SDP谈判之前,您正在处理候选人并收集这些候选人。这不起作用,所以我认为你的webrtc根本不工作,无论你如何连接端点。

其次,您在WebRtcEndpoint之前创建记录器,然后在调用record之后创建记录器。录像机没有任何连接,没有媒体流入。将WebRtcEndpoint连接到录像机后以及媒体流动后,我建议您调用record方法。为此,您可以像这样添加一个监听器MediaStateChanged

webRtcEndpoint.on('MediaStateChanged', function (event) {
  if ((event.oldState !== event.newState) && (event.newState === 'CONNECTED')) {
    // Start recording
    recorderEndpoint.record();
  }
});

创建后立即将WebRtcEndpoint连接到录像机。

另外,作为旁注,这条线没有意义,因为端点是sendonly

webRtcEndpoint.connect(webRtcEndpoint, error => {

总结一下,这就是我的建议。不要忘记填写您可能找到的任何空白,因为如果没有填写OnIceCandidate等的回调,它将无效。

var startScreen = (sessionId, ws, sdpOffer, callback) => {
  console.log("Start screen")
  getKurentoClient((error, kurentoClient) => {
    if (error) {
      return callback(error)
    }

    kurentoClient.create('MediaPipeline', (error, pipeline) => {
      pipeline.create('RecorderEndpoint', recordParams, (error, recorder) => {
        pipeline.create('WebRtcEndpoint', (error, webRtcEndpoint) => {
          webRtcEndpoint.connect(screenRecorder, error => {
            webRtcEndpoint.processOffer(sdpOffer, (error, sdpAnswer) => {
              // The SDP negotiation must be completed before processing candidates
              callback(null, sdpAnswer)
              if (candidatesQueue[sessionId]) {
                while (candidatesQueue[sessionId].length) {
                  var candidate = candidatesQueue[sessionId].shift()
                  webRtcEndpoint.addIceCandidate(candidate)
                }
              }

              webRtcEndpoint.on('MediaStateChanged', function(event) {
                // This will start recording right after media starts flowing
                if ((event.oldState !== event.newState) && (event.newState === 'CONNECTED')) {
                  // Start recording
                  recorderEndpoint.record();
                }
              })
              
              webRtcEndpoint.on('OnIceCandidate', (event) => { /* your code here */ })
                // Candidates must be gathered after the negotiation is completed, and the
                // event handler is bound
              webRtcEndpoint.gatherCandidates((error) => { /* your code here */ })
            })
          })
        })
      })
    })
  })
}

答案 1 :(得分:0)

建议在stop之前调用RecorderEndpoint方法,然后再将其发布到文件中,否则无法保证媒体已被写入文件。

根据您使用的KMS版本,您甚至可以等待事件(Stopped)以确保所有媒体都已写入文件。

此外,您的代码似乎没有将WebrtcEndpointRecorderEndpoint联系起来,请查看此内容。

修改

您还应该检查RecorderEndpoint是否正在正确接收媒体,以及WebRtcEndpoint是否正在从网络接收媒体。您可以使用MediaFlowOutStateChangeMediaFlowInStateChange以及isMediaFlowingIn isMediaFlowingOut方法(请参阅kmd了解已接受的参数)