Problems making WebRTC > Kurento > RtpEndpoint bridge (Node client)

1,423 views
Skip to first unread message

Sebastian Greco

unread,
Apr 3, 2017, 7:57:14 AM4/3/17
to kurento
Hello!
I'm trying to make a simple Proof Of Concept of a bridge from WebRTC to RTP (like many others, for what I have been reading in the group).
So, the idea is having the Browser stream the webcam via WebRTC to Kurento and been able to publish that stream via RTP (The final idea is make use of that RTP to publish to Facebook live using ffmpeg, but that's not important right now).

So I have been trying to make this to work for the past weeks, since I have no previous experience with video streaming, it has been pretty difficult to me so far, I have started all over again at least 3 times already, using node client and java client with no success so far.

For I have been reading in this group, the idea is simple in theory, get the WebRtcEndpoint connect it to an RtpEndpoint, then make a manual negotiation using SDP, and should be set.

So I have started using the one2many example as a base., after different approaches , I ended up adding a new message only to create the RtpEndopoint (instead of doing it on startPresenter)

These is are the logic steps

  1. Make sure presenter pipeline and webRtc is already created and that the rtpEndpoint is not
  2. Create the RtpEndpoint
  3. Process offer with a hardcoded SDP
  4. Connect presenter webRtcEndpoint to the rtpEndpoint
  5. Once connected, write down the sdp answer to a file.
  6. Try to open that file with ffmpeg or VLC


function startRtpEndpoint(sessionId, ws, callback) {

   if (presenter === null || presenter.pipeline === null || presenter.webRtcEndpoint === null) {
return callback("Server not yet ready. Try again later ...");
   }

   if (presenter !== null && presenter.rtpEndpoint !== null) {
return callback("RtpEndpoint already created");
   }

   presenter.pipeline.create('RtpEndpoint', function(error, rtpEndpoint) {
      if (error) {
         stop(sessionId);
         return callback(error);
      }

      if (presenter === null) {
         stop(sessionId);
         return callback(noPresenterMessage);
      }

      presenter.rtpEndpoint = rtpEndpoint;

      rtpEndpoint.on('MediaStateChanged',function(response) {
         console.log('rtpEndpoint > MediaStateChanged');
      });

      rtpEndpoint.on('MediaFlowInStateChange',function(response) {
         console.log('rtpEndpoint > IN', response.mediaType);
      });

      rtpEndpoint.on('MediaFlowOutStateChange',function(response) {
         console.log('rtpEndpoint > OUT', response.mediaType);
      });

      rtpEndpoint.on('ElementConnected',function(response) {
         console.log('rtpEndpoint > ElementConnected');
      });

      var sdp = "v=0\r\n"+
                  "o=BOB 0 0 IN IP4 127.0.0.1\r\n"+
                  "s=-\r\n"+
                  "c=IN IP4 127.0.0.1\r\n"+
                  "t=0 0\r\n"+
                  "m=audio 9000 RTP/AVPF 96 0 97\r\n"+
                  "a=rtpmap:97 AMR/8000\r\n"+
                  "a=recvonly\r\n"+
                  "m=video 9010 RTP/AVP 100\r\n"+
                  "a=rtpmap:100 H264/90000\r\n"+
                  "a=recvonly\r\n";

      rtpEndpoint.processOffer(sdp).then((answer) => {
         console.warn('Offer processed.');

         presenter.webRtcEndpoint.connect(rtpEndpoint).then(() => {
            console.log('webRtcEndpoint connected to rtpEndpoint, saving sdp file');
            fs.writeFile('file_'+sessionId+'.sdp',answer);

            return callback(null, answer);

         }).catch((error) => console.error(error));

      }).catch((error) => console.error('Connection: '+error));
   });
}

So far no luck, ffmpeg is telling me "bind failed: Address already in use", VLC says "live555 error: no data received in 10s, aborting"

That SDP offer string is the result of a lot of search here in the group, I'm guessing the error is there, and that's why I can't connect correctly. the recvonly attribute was an addition I made in hoping that kurento understand I'm not sending any data via RTP.

Not sure if the SDP answer gives you any clue, but it's something like this:

v=0
o=- 3700206843 3700206843 IN IP4 192.168.1.107
s=Kurento Media Server
c=IN IP4 192.168.1.107
t=0 0
m=audio 42608 RTP/AVPF 0 97
a=rtpmap:97 AMR/8000
a=sendonly
a=ssrc:2655517972 cname:user3152391354@host-9152cb3c
m=video 30408 RTP/AVP 100
a=rtpmap:100 H264/90000
a=sendonly
a=ssrc:2083157989 cname:user3152391354@host-9152cb3c



Looking at the ports, looks like all 4 ports are being used by kurento server (audio+control, and video+control) but not in "listening" state (is that the problem here? is expecting data instead of sending it?).

My guess is, I'm missing a super basic concept of RTP, and that's why I can't tell what is the problem or the way of using those SDP offering and answering.

My vague idea of how this should work is this:
  1. the SDPOffer I hardcoded in the code, works like a presentation letter to Kurento, saying, "hey this is a possible client with IP, and these codec requirements, and I'm only receiving video and audio"
  2. That is processed by Kurento with a response that says "Ok, sure, connect to this IP address, with audio in this port, and video in this port" 
  3. The client, read that Kurento answer, and connects to the pointed ports
I'm I missing something? is this entirely wrong?

Thanks in advance, and sorry for the noob questions, I really tried to make this using other threads, but looks like I'm still missing something.

Cheers!

PS: By the way if I manage to solve this I'm going to post how I did it, lots of threads here ends in nothing concrete.

Mario Gasparoni Junior

unread,
Apr 3, 2017, 8:02:37 AM4/3/17
to kur...@googlegroups.com

--
You received this message because you are subscribed to the Google Groups "kurento" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kurento+unsubscribe@googlegroups.com.
To post to this group, send email to kur...@googlegroups.com.
Visit this group at https://groups.google.com/group/kurento.
To view this discussion on the web visit https://groups.google.com/d/msgid/kurento/cbaec784-308d-4b49-9bec-9504cdb7fcf8%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Att. Mário Gasparoni.

Sebastian Greco

unread,
Apr 3, 2017, 9:14:30 AM4/3/17
to kurento
It does!
Thank you very much! 

I just tested your example and works perfectly, I'm going to dive into the code to see what I was doing wrong

Again... Thanks much!
To unsubscribe from this group and stop receiving emails from it, send an email to kurento+u...@googlegroups.com.

To post to this group, send email to kur...@googlegroups.com.
Visit this group at https://groups.google.com/group/kurento.
To view this discussion on the web visit https://groups.google.com/d/msgid/kurento/cbaec784-308d-4b49-9bec-9504cdb7fcf8%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Be Simplified

unread,
Jul 18, 2018, 8:03:47 AM7/18/18
to kurento
Dear Sebastian,

I have an RTSP stream which I need to broadcast via RTP to multiple viewers.

So my requirement is RTSP -> RTP, so I am trying to use PlayerEndPoint(RTSP) -> connect() -> RTPEndpoint as below

This example has been written in JAVA but it should be similar as with Node


KurentoClient kurentoClient = Constants.getKurentoClient(); //Method to fetch Kurento Client
MediaPipeline mediaPipeline = kurentoClient.createMediaPipeline();

//Variable rtsp_url holds RTSP source like ex: rtsp://192.168.1.171/cam.mp4

String clientHost = "192.168.1.167"; //Client host where I want to play .sdp

PlayerEndpoint playerEndpoint = new PlayerEndpoint.Builder(mediaPipeline, rtsp_url)
.useEncodedMedia().build();
playerEndpoint.play();


RtpEndpoint rtpEndpoint = new RtpEndpoint.Builder(mediaPipeline).build();

String sdpInfo= "v=0";
sdpInfo+= "\no=- 3641290734 3641290734 IN IP4 " + clientHost + " ";
sdpInfo+= "\ns=Kurento Media Server";
sdpInfo+= "\nc=IN " + clientHost + " ";
sdpInfo+= "\nt=0 0";
sdpInfo+= "\nm=audio 0 RTP/AVP 97";
sdpInfo+= "\na=rtpmap:97 mpeg4-generic/48000/2";
sdpInfo+= "\na=recvonly";
sdpInfo+= "\ndf27e8d8";
sdpInfo+= "\nm=video 0 RTP/AVP 96";
sdpInfo+= "\na=rtpmap:96 H264/90000";
sdpInfo+= "\na=recvonly";


log.info("#############################################################################################");
log.info("Adding sdp offer: \n " + sdpInfo);
log.info("#############################################################################################");

playerEndpoint.connect(rtpEndpoint);

//String generatedOffer = rtpEndpoint.generateOffer();
//System.out.println("Generated sdp offer : \n " + generatedOffer);

String generatedAnswer = rtpEndpoint.processOffer(sdpInfo);
log.info("#############################################################################################");
log.info("Generated answer is : \n " + generatedAnswer);
log.info("#############################################################################################");

try (PrintWriter out = new PrintWriter("/home/user/Desktop/play.sdp")) {
out.println(generatedAnswer);
} catch (FileNotFoundException e) {
e.printStackTrace();
}



But the generated play.sdp when played via VLC Player gives error as,

ps error: cannot peek

vobsub debug: could not read vobsub IDX file

core debug: no demux modules matched

core error: no suitable demux module for `file/any:///D:/userdata/kantipud/Desktop/play.sdp'

core debug: removing module "record"

core debug: removing module "filesystem"

core debug: dead input

core debug: changing item without a request (current 0/1)

core debug: nothing to play

qt4 debug: IM: Deleting the input



Please let me know if this is the ideal way to connect RTSP(via Playerendpoint) to RTP endpoint with Kurento

The actual rtsp url(rtsp://192.168.1.171/cam.mp4) when played via VLC player gives SDP as below,





Please suggest if there  is something missing

Thanks,
Chakra

Be Simplified

unread,
Aug 1, 2018, 1:58:43 AM8/1/18
to kurento
Thanks all,

Finally I could make it work



RTSP -> PlayerEndpoint -> Connect() -> RtpEndpoint -> Played via Gstreamer/VLC Clients


And it works without any trans-coding between PlayerEndpoint -> Connect() -> RtpEndpoint


Missing was the sps and pps information which come  up in original SDP from RTSP source as sprop-parameter-sets. These I manually copied from SDP and pasted in request SDP for RTP and its work now

Full example can be found here RTPEndpoint Sender

Thanks
Chakra

giang nam

unread,
Sep 16, 2018, 12:59:32 AM9/16/18
to kurento
Hi,

How do you enable the audio as well? From the SDP it seems only video is sent.

Thanks

Neil Young

unread,
Sep 16, 2018, 3:13:36 AM9/16/18
to kurento
Please note that the node server realization might appear - as many, many other existing solutions based on the Kurento sample code - sporadically failing connections due to the problem of delayed enumeration of valid ICE candidates, which are not taken into account, since candidatesQueue is already drained but sessionId does not already have a slot in sessions...

https://groups.google.com/forum/m/#!topic/kurento/ZLRYbk5JAPc

Be Simplified

unread,
Sep 17, 2018, 4:04:39 AM9/17/18
to kur...@googlegroups.com
Currently only VIDEO is connected,
RtpEndpointCreator.java :52 
playerEndpoint.connect(rtpEndpoint, MediaType.VIDEO); 

You need to add audio also, say
playerEndpoint.connect(rtpEndpoint, MediaType.AUDIO);


and update SDP (adding attributes for audio in sdp string) in SdpConstant.java  to read AUDIO stream also may be like 

m=audio 0 RTP/AVP 97
a=rtpmap:97 mpeg4-generic/90000/2
a=control:trackID=1
a=fmtp:97 streamType=5;profile-level-id=22;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1190


or whatever codecs your are streaming from source and intended to receive

Thanks,
Chakra



   

Reply all
Reply to author
Forward
0 new messages