5

I'm trying to record a webcam with kurento media server, here is the function I'm using at the backend:

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)
            }
          })
        })
      })
    })
  })
}

the pipeline looks something like this:

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

at the front end i do this:

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)
  })
}

This is for only screencast which is not working, I'm using almost the exact same code to record a webcam which its fully working, This is the stop function:

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

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

Where I dispose the pipeline at the front end but, I send this message to the backend and then this wss message calls this function:

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

I think this maybe the problem of why this is not working for recording the screencast or maybe I'm connecting the pipelines improperly

Anyway thanks!

PD: i found this on KMS logs:

KurentoMediaElementImpl MediaElementImpl.cpp:434 mediaFlowOutStateChange() <kmswebrtcendpoint373> Media N OT Flowing OUT in pad default with type video 
Abdul Hamid
  • 168
  • 1
  • 7
  • 25
  • How are you connecting the endpoints? – igracia Apr 05 '16 at 10:48
  • recorder -> webrtc like this: webRtcEndpoint.connect(webRtcEndpoint, error => webRtcEndpoint.connect(screenRecorder, error => console.log(error))) – Abdul Hamid Apr 05 '16 at 10:50
  • Are you able to do screencast correctly? Are you showing that stream somewhere? Maybe the problem is that your screen is not being shared at all. – igracia Apr 05 '16 at 14:59

2 Answers2

4

The first and most important issue, is that you are processing candidates, and gathering those candidates, before the SDP negotiation. This won't work, so I think that your webrtc is not working at all, regardless how you are connecting the endpoints.

Second, you are creating the recorder before the WebRtcEndpoint, and after that invoking record. The recorder does not have anything connected, and no media is flowing IN. I'd suggest you to invoke the record method after you connect the WebRtcEndpoint to the recorder and after media is flowing. For that purpose, you can add a listener to the event MediaStateChanged like so

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

Connect the WebRtcEndpoint to the recorder right after you create it.

Also, just as a side note, this line does not make sense as the endpoint is sendonly

webRtcEndpoint.connect(webRtcEndpoint, error => {

Just to summarize, this is what I'm suggesting. Don't forget to fill in whichever gaps you might find, as without filling the callbacks from OnIceCandidate and so on, it won't work.

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 */ })
            })
          })
        })
      })
    })
  })
}
igracia
  • 3,543
  • 1
  • 18
  • 23
  • thank you again for your answer, i actually did some work and i still cant get the screencast to be recorder, i can with the webcam with no problems, anyway i think now that the problem its that im not getting any media to kurento for some reason – Abdul Hamid Apr 06 '16 at 09:41
  • @AbdulHamid Cool! Most of the times it's either that the connection is not established, or the screen is not being shared. In both cases, the result is that the media is not flowing. – igracia Apr 06 '16 at 20:19
0

It is very recommendable to call stop method on RecorderEndpoint before release it, otherwise there is no guarantee that the media has been written to the file.

Depending on the version of KMS that you are using, you can even wait for the event (Stopped) to be sure that all the media has bee written to the file.

Additionally, your code does not seems to be connecting WebrtcEndpoint with RecorderEndpoint, check this out.

Edit:

You should also check if RecorderEndpoint is receiving media correctly as well as if WebRtcEndpoint is receiving from the network. You can use MediaFlowOutStateChange and MediaFlowInStateChange as well as isMediaFlowingIn isMediaFlowingOut methods (see kmd for accepted parameter)

santoscadenas
  • 1,482
  • 9
  • 17
  • I thought this was my attempt to connect webRtcEndpoint.connect(webRtcEndpoint, error => { ... webRtcEndpoint.connect(screenRecorder, error => { ... }) }) – Abdul Hamid Apr 05 '16 at 11:24
  • Sorry, I missed that one. Seems correct. What version of kms are you using? In order to discard bugs. – santoscadenas Apr 05 '16 at 11:26
  • im using: KMS 6.4.0 – Abdul Hamid Apr 05 '16 at 11:27
  • also im getting this error on the KMS logs: 2016-04-05 11:45:34,275452 11685 [0x00007f23b21df700] debug KurentoMediaElementImpl MediaElementImpl.cpp:434 mediaFlowOutStateChange() Media N OT Flowing OUT in pad default with type video – Abdul Hamid Apr 05 '16 at 11:49
  • This does not have to be a problem is there is a Flowing OUT event later. If there is not, the problem could be that there is no media leaving this endpoint. – santoscadenas Apr 05 '16 at 12:52
  • mmmm i think that might be the problem because im only finding media not flowing in and media not flowing out everywhere, i wonder if properly connected all the endpoints – Abdul Hamid Apr 05 '16 at 12:57