[asterisk-users] Call bridged, but no sound

Brian Candler B.Candler at pobox.com
Fri Oct 13 01:20:09 MST 2006


On Fri, Oct 13, 2006 at 01:35:04AM +0200, Norbert Zawodsky wrote:
> I've set canreinvite=no on the channel to the SIP provider and it
> immediately worked. O.k., I'm happy about that but I want to
> *understand* what's going on here.
> .
> My setup is:
> 
> Asterisk is connected on one side via eth1 to the "outside world" (IP
> adress 81.223.xxx.xxx) and on the other side via eth0 to the internal
> LAN (eth0 has IP 192.168.1.200, SNOM phone has 192.168.1.201, ...).

A good question, for which it's hard to give a short answer :-)

Firstly, you need to understand how SIP itself was designed to set up calls
between handsets.

The SIP 'INVITE' message says "I want to set up a call". In the body of this
message is a block of SDP (Session Description Protocol) which says "my
audio endpoint is IP x.x.x.x port x, and I can use codecs A, B and C".

In the intended architecture of SIP, the INVITE is forwarded via a series of
proxies until it reaches the requested destination. The remote end responds
with a 200 saying "OK, my audio stream is on IP y.y.y.y port y, and I choose
codec B", which is sent back to the first phone. At this point, the first
phone starts sending RTP audio packets from x.x.x.x:x to y.y.y.y:y, and the
second phone sends them from y.y.y.y:y to x.x.x.x:x. That is, the audio path
is direct, whereas the SIP messages went via intervening proxies.

[This is horrendously over-simplified, but it's enough to make the point]

Now, the second thing to understand is that Asterisk is *not* a SIP proxy,
and its default behaviour is to set up the two legs as two separate audio
streams: phone X to Asterisk and Asterisk to phone Y. The way this works is:

* Phone sends INVITE saying "I am on IP x.x.x.x:x, I can use codecs A,B,C"

* Asterisk decides where the next leg is. If it is another SIP device,
  it sends a fresh SIP INVITE to the second phone saying "I am on IP
  z.z.z.z:z, I can use codecs C and D" where z.z.z.z is Asterisk's own IP
  address and :z is a port it has chosen.

* This arrives at the second phone, which says "OK, I am on IP y.y.y.y:y,
  I choose codec C", and sends it back to Asterisk

* Asterisk is happy, so it completes the first leg by replying to the
  first phone "OK, I am on IP z.z.z.z:q, I choose codec C"

So now the first phone is sending packets between x.x.x.x:x and z.z.z.z:q,
and the second phone is sending packets between y.y.y.y:y and z.z.z.z:z

This means that Asterisk is in the media path - each RTP packet has to be
received and resent, in both directions. On the minus side, this means more
workload on the Asterisk server. On the plus side, being in the media stream
means that Asterisk can perform a whole bunch of useful voice services -
recording, conferencing, call parking, music on hold, even codec conversion
(i.e. the stream from phone X to Asterisk can be using one codec, and phone
Y to Asterisk a different one)

With me so far?

The third thing to realise is that Asterisk *can* optimise this out so that
the media path is set up directly between the endpoints. This is what it
means by "native bridging" - connecting two compatible endpoints directly
together, instead of relaying the audio via Asterisk.

So, under the right conditions, the SIP message Asterisk sends to the second
phone will contain the IP address of the first phone, and vice versa. This
means it looks and smells almost like a SIP proxy.

What do I mean by "the right conditions"? Well I'm not sure what the
complete set is, but one of those conditions is that both SIP channels must
be marked "canreinvite=yes". If either has "canreinvite=no", then Asterisk
falls back to the default behaviour of setting up two separate legs.

In your case, you need the default behaviour when calling the provider,
because the SIP phone is on a private IP 192.168.1.201, whilst the provider
is on a public IP P.P.P.P. If the SIP messages were to try to set up a
direct media path between the two it wouldn't work [*]; in particular,
there's no point the public SIP provider trying to send an RTP packet to
192.168.1.201, because it won't be able to route to it.

[*] To be fair, if you have a NAT firewall between your internal network and
the Internet, then *some* packets will be able to go directly between your
network and the outside world, with the firewall modifying the source IP
address and/or port in the process. There are a whole bunch of nasty tricks
which can be done, both on the phone and at the provider, which mean that if
you are really lucky you can make VoIP work this way. However I recommend
you avoid this. You are in the fortunate situation that your Asterisk box
has a real public IP address, so make use of it.

The last thing, which took me a while to figure out, is why the option which
means "I prefer to use a direct RTP media path" is called "canreinvite=yes".

Even if the normal audio path for a call can be set up with native bridging,
Asterisk sometimes *needs* to be able to re-insert itself into the media
path in the middle of a call - to provide services such as music on hold,
transfer, parking and so on when they are requested.

The SIP mechanism for this is called re-INVITE. Two phones which are happily
talking to each other can have the media stream changed mid-call using this
mechanism, so Asterisk can unstitch the direct link and re-connect the two
legs to itself.

However, not all phones support this mechanism. If you set canreinvite=no on
a SIP channel, it's saying "this phone doesn't support the re-INVITE
mechanism for reconnecting the audio mid-call". Asterisk therefore decides
that it must insert itself into the media stream for the *whole* duration of
the call, so that it is already there if later on one of the parties
requests one of these in-call features.

Hopefully that's enough to answer your question :-) The best way to see
what's going on is to look at the SIP/SDP packets themselves, which you can
do either using 'sip debug' in Asterisk, or using tcpdump:

    # tcpdump -i eth0 -n -s0 -v udp port 5060
    # tcpdump -i eth1 -n -s0 -v udp port 5060

With a recent version of tcpdump, the -v option will show you the SIP/SDP
payload. If it doesn't, use -X instead (capital X) which will show you hex
and ASCII. -s0 means capture the whole packet, and -n means don't try to do
reverse DNS lookups on every packet's IP address.

Regards,

Brian.


More information about the asterisk-users mailing list