Getting local media ports to create SDP for SIP Invite

Topics: Question
Jun 3, 2016 at 8:34 AM
Hello Julius

as you know we are developing our xamarin app for interacting with a doorbell with a camera, using SIP and RTP.

We want to create a new Feature:
The Client app starts a call (invite) and we want to create a RTP session with our SDP to send and receive AV data.
We create our SDP to attach it to the invite but we don't know the media ports to be set in the SDP. After the callee sends a 200 OK message we get the callee's SDP.

How can we create a complete SDP with media ports and Setup the RTPClient in this Scenario?

Thanks a lot!
Coordinator
Jun 4, 2016 at 1:05 AM
Sorry, I am having a hard time understanding why you don't know the media ports... You can't determine what ports you want to receive data on?

You would indicate the ports you want or the range in the SDP and the person who accepts the invitation should honor those ports or indicate that it cannot honor those requested ports.

You can easily create a SDP with new Sdp.SessionDescription()

After you have the session description you can create a MediaDescription and add it to the SessionDescription with Add.

There are several examples of this in the UnitTests projects.

Let me know where your having difficultly and I will try to help!
Marked as answer by juliusfriedman on 6/3/2016 at 5:05 PM
Jun 6, 2016 at 7:23 AM
Hi Julius,

we have no problems to create a Sdp.SessionDescription so far. But if we create a MediaDescription to add it to the SessionDescription we don't know what we have to set in the mediaPort field. Can we set any port we want? How to make sure this port isn't already in use?

In our already working scenario with an incoming call we use the received Sdp to create the RtpClient with the static function FromSessionDescription.
How to create the RtpClient in if we start the call?
Can we use the received sdp of the accepting callee and call RtpClient.FromSessionDescription too? Would this make sure that the RtpClient starts with the ports we defined in our MediaDescription we send to the callee?

So our main problems are what to set in the mediaPort fields and how to create the RtpClient instance after we receive the accept message.

Can you please give us a hint?

Thanks a lot!
Coordinator
Jun 6, 2016 at 3:22 PM
Edited Jun 6, 2016 at 3:23 PM
This is the exact text as found in the RFC4566
5.14. Media Descriptions ("m=")
  m=<media> <port> <proto> <fmt> ...
A session description may contain a number of media descriptions.
Each media description starts with an "m=" field and is terminated by
either the next "m=" field or by the end of the session description.
A media field has several sub-fields:

<media> is the media type. Currently defined media are "audio",
  "video", "text", "application", and "message", although this list
  may be extended in the future (see Section 8).
<port> is the transport port to which the media stream is sent.
  The meaning of the transport port depends on the network being used as
  specified in the relevant "c=" field, and on the transport
  protocol defined in the <proto> sub-field of the media field.
  Other ports used by the media application (such as the RTP Control
  Protocol (RTCP) port [19]) MAY be derived algorithmically from the
  base media port or MAY be specified in a separate attribute (for
  example, "a=rtcp:" as defined in [22]).

  If non-contiguous ports are used or if they don't follow the
  parity rule of even RTP ports and odd RTCP ports, the "a=rtcp:"
  attribute MUST be used.  Applications that are requested to send
  media to a <port> that is odd and where the "a=rtcp:" is present
  MUST NOT subtract 1 from the RTP port: that is, they MUST send the
  RTP to the port indicated in <port> and send the RTCP to the port
  indicated in the "a=rtcp" attribute.

  For applications where hierarchically encoded streams are being
  sent to a unicast address, it may be necessary to specify multiple
  transport ports.  This is done using a similar notation to that
  used for IP multicast addresses in the "c=" field:

I need a copy of the whole SDP to give you accurate responses to your questions...

I will assume an IP (v4) conncetion over UDP for this answer.

When you call RtpClient.FromSessionDescription or TransportContext.FromMediaDescription

The connection line and multiple other lines are read to determine what type of socket and protocol to use to setup the RtpClient.

An existing socket can be given to override this information for whatever reason deemed necessary, e.g. NAT or otherwise.

If there was no existing socket passed then a new socket is created which will be used to receive data from the Rtp port and Rtcp ports specified in the Media Description; When the new socket is created it is also optionally connected based on the 'connect' parameter which defaults to false.

During 'TransportContext.Initialize' => 'punchHole' is an option which defaults to true.

If the IPAddress is on the same subnet then it is assumed that there is no outbound or inbound restriction on the connection, if not 4 bytes of data are sent to the remote ports to ensure that the router you are behind will allow traffic through from the remote IP and port. This is known as UDP Hole Punching..

When the remote EndPoint is not reachable a ConnectionReset error will occur if the remote host indicates that the port is closed, the remote host indicates this by echoing the data you send back via ICMP.

The RtpClient translates this into a fallback mode where it will receive from ANY port from the RemoteIP until data arrives.

Once data arrives the RemoteRtp and RemoteRtcp ports are set according.

You can detect when this occurs via TransportContext.RemoteRtp.Port == 0 after an Initialize call.

What I would do is start with a port >= 1000 <= 15000 for local networks and port >= 30000 for remote networks.

You can find out what ports are open to you by using the ProbeForOpenPort function or using the IPGlobalProperties for your network adapter if supported.

Typically an Invite contains an SDP which indicates the connection address and ports which are already known to be available for the recipients to use.

You don't have to worry about what ports they can receive or other such nuances such as what IP address they can receive from because the data is coming from your router outside your network and from your PC within your network.

When they receive the Invite they will say okay the data is coming from 'IP X (Your External IP) @ Port Y (RTP) and Z (RTCP)'

They will setup a socket to receive from X @ Y and Z.

They will then send back an Acknowledgement with an SessionDescription which has their connection address and a Media Description indicating the destination ports they expect data to send data on if required to.

This forms a two way mapping from your source to their destination ports which you control and a mapping from their source ports which you do not control to where you must receive data from (destination end point) but only if you want to.

If you cannot receive data at those ports for whatever reason or the client cannot receive data on your ports for whatever reason the Invite must be responded to accordingly. Thus you or the client may respond to the Invite with ClientError or otherwise to indicate this mapping does be completed as expected.

Please let me know if I can make that example any clearer.
Marked as answer by juliusfriedman on 6/6/2016 at 7:22 AM
Jun 9, 2016 at 7:29 AM
Hi Julius,

we got the following situation. we are programming an app which interacts with a server over SIP to make audio and video calls.

The direction from the server to the app is already running.
If the server invites the app it sends its SDP with its opened local ports it want to receive data at.
With this SDP we start the RtpClient via FromSessionDescription. After the RtpClient is started we read the local ports from the contexts of the RtpClient it opened to place these ports in the SDP we send back to the server.
So the server knows our local ports we want to receive data at.
This is running very well.

Our first problem comes with the direction from the app to the server.
In this case we have to create an invite with our SDP and gets the server's SDP if it accepts the call.
So we have to specify our media ports (local udp socket ports) we want to receive data at before the RtpClient.FromSessionDescription method can be called with the server's SDP.
We found that the method Media.Common.Extensions.Socket.SocketExtensions.ProbeForOpenPort will check if a port is free to use.
So we used this function to check for free ports to be set in our SDP.
But the RtpClient.FromSessionDescription select its local udp socket ports by itself. So it's possible our ports are different to the ports selected by the RtpClient.
We need a possibility to pre initialize the RtpClient or to set the local ports the RtpClient has to open in the FromSessionDescription method.
Then the ports we send will match the ports the RtpClient will open.
Or is there another solution to this problem?

To clarify what we mean with pre initialize the RtpClient:
The RtpClient creates its local socket and binds them to free local ports without any SDP so that we can use the opened ports in our SDP. If we receive the server's SDP we then set the SDP in the pre initialized RtpClient so it can connect to the remote ports and finish initializing the connection.


Our other problem is that we get a broadcast SDP to start the RtpClient.
This is used to access the audio and video streams before the call is accepted by the app (early media feature with group calls).
The server supports this SIP feature only in single call but unfortunately not in group calls. So we have to realize this with broadcast SDP.
The broadcast SDP contains an IP address like 255.255.255.255 in the connection line.
If we try to use this SDP in the RtpClient.FromSessionDescription it crashes with a socket exception.
Is there a way to set up an RtpClient with such a SDP?
The broadcast SDP looks like this:

v=0
o=sip 1247 1247 IN IP4 255.255.255.255
s=Talk
c=IN IP4 255.255.255.255
t=0 0
m=video 5550 RTP/AVP 99
a=rtpmap:99 H264/90000
a=sendonly

Thanks a lot!
Coordinator
Jun 9, 2016 at 12:51 PM
Edited Jun 9, 2016 at 12:54 PM
Isnt that supposed to be a multicast address? SEE

Or the broadcast address for your interface?

To answer your question though they should also include a port src for their media, they dont.

You can't complete that mapping without it.

You should reply with an error and see how the agent replies to your error it may offer a different sdp.

You can also try to accept and specify your source ports and even if the client doesn't provide source ports the RtpClient will figure it out based on the remote Ip. In multicast though your going to have the potential for a lot of different source packets even from other protocols going to your broadcast addresss.

I already support multicast so I can't see how broadcast can't be used.

What's the exception and stack trace?

I'll also try to replicate with the sdp you gave and see if and how I need to adjust there.
Marked as answer by juliusfriedman on 6/9/2016 at 4:51 AM
Coordinator
Jun 9, 2016 at 7:26 PM
Edited Jun 9, 2016 at 7:26 PM
I have made another update which should allow for your session description to work as you need it to.

Let me know how that works out!

I also changed the poll time to be slightly more responsive, for the first few seconds of transport may seem latent until the receive buffer gets filled but it should be better overall.

Let me know if I need to adjust further for your use case and Thank You again for your continued testing!
Marked as answer by juliusfriedman on 6/9/2016 at 11:26 AM