Sorry for the long delay on this topic. Personal matters prevented me from investigating for a while and the original occurrence of the problem went away for the first client (because they changed something on their end), but now I have another apparently-identical problem with calls originating from a big-iron switch who isn't willing to change their settings like the first client did.
The problem is easily reproducible for those of you who wish to hear (or not hear) it themselves. (instructions below)
To recap, the problem is that per rtpproxys own documentation rtpproxy won't pass a packet in either direction for a given session until it has received audio from both sides of a given session. The README says:
[0]- after the session has been created, the proxy listens on the port it has [0] allocated for that session and waits for receiving at least one UDP [0] packet from each of two parties participating in the call. Once such [0] packet is received, the proxy fills one of two ip:port structures [0] associated with each call with source ip:port of that packet. When both [0] structures are filled in, the proxy starts relaying UDP packets between [0] parties;
This is exactly the behavior I am experiencing, but it is causing interoperability problems and really needs to change.
In my case, there is a new calling switch/SBC that won't send rtpproxy any audio packets when it places a call to us until it receives audio for that call from us first. I can see the switch on my side sending the RTP to the port that rtpproxy stipulated (following a 183 or 200 message), and absolutely none of that audio being sent out of rtpproxy and onto the calling switch/SBC. In other words, it is behaving exactly like what the README statement says.
Meanwhile, the equipment at other clients that send me calls usually send at least one RTP packet to rtpproxy shortly after receiving the 183 message (certainly by the time the 200 message shows up), and so two-way audio commences for that call. We have always noted a slight truncation of initial audio, but apparently no one is upset by that, but I suspect that was a result of rtpproxy behavior. This noted behavior also supports the statement in the README that audio must come from both directions before audio is sent in any direction by rtpproxy.
So, the original question was (and now still is), is there a way to disable this "both sides must send" criteria of rtpproxy? I don't see a technical reason for it, and I have a client with a NexTone or a Sonus (or perhaps both) and when they send us calls, there is no audio. Now, there may be some knob they can turn on their system to not wait to send audio to the called party (of which our rtpproxy is in the middle somewhere) until audio is received from the called party (as is happening now), but some of these companies see no need to alter their settings in such a way. It would be better if I could fix this behavior in rtpproxy to allow audio in both directions from the moment that it selects the ports to listen to for a given call and hands those back to SER.
NOTE: We do run rtpproxy with two interfaces, and did have to alter SER* to actually pay attention to passed address parameters passed to force_rtp_proxy(), as the stock logic in SER quietly ignored a provided IP address if two interfaces are in use. I also had to change fix_nated_contact() to accept and use an IP address provided if one was passed as a parameter because the value SER came up with was always wrong for our environment. We've had those two fixes in SER for eight months and it works fine with numerous clients. Rtpproxy is handed the right IP address for each interface and customer, along with desired settings to force_send_socket(), rewritehost() and fix_nated_contact(), and everybody gets the IP addresses that are correct for their network. It works, although I will admit ser.cfg is a bit klunky due to the lack of a way in SER to pass non-constants, eg "variables" to functions, but we manage. *These alterations were all in SER nathelper and rtpproxy is untouched. SER nathelper patches available on request.
However, we have this condition that rtpproxy (as claimed by its own documentation), won't pass traffic unless it receives at least one packet from both parties, which probably isn't going to happen in this situation because the maker of that equipment says they aren't doing anything that violates RFC in waiting to receive audio from the called system before sending audio to the called system and so see no need to change their stuff.
Let's see, someone asked earlier which rtpproxy interface is which? Well we ended up with "e" being the side facing our equipment and "i" being the side facing the rest of the world. That seemed backwards, but it worked first and the more logical combination did not for some reason that was never investigated. I suspect either way would work because interfaces are different netblocks in the 10.x.x.x space. The interface details are:
(internal/trusted side - no further NAT conversions to reach in-house switches)) em4: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 options=1b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING> inet 10.33.168.18 netmask 0xffffffc0 broadcast 10.33.168.63
(external/untrusted side) em5: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500 options=1b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING> inet 10.83.168.2 netmask 0xffffffc0 broadcast 10.83.168.63
Destination Gateway Flags Refs Use Netif Expire default 10.83.168.1 UGS 0 6480075550 em5 (causes packets with public IPaddrs destinations to flow to router and out to Internet. (On outbound packets, Router replaces source IP with a matched public IP addr but destination is not altered, nor is packet content.)
/usr/local/bin/rtpproxy -l 10.33.168.18/10.83.168.20
As you see, the external/untrusted interface is also where the default route is, so that public IPaddrs will flow to the directly-connected router. Inbound rtp is NATed from a public address to an internal one on the rtpproxy interface em5. Again, all that has been passing millions of calls for months now, but now I've got one customer who won't send audio until we send audio, and apparently rtpproxy won't do this for some reason. All IP addresses check out as being reachable, it's just that nothing comes out of rtpproxy. Since the packet doesn't even come out of rtpproxy, the lack of audio can't be blamed on NAT, since there are no packets being emitted in first place that a NAT conversion might mess up. That isn't it. The problem appears to be rtpproxy, and the documentation says it is supposed to behave like this. The question is, why?
I am able to easily replicate the problem using an Asterisk box as the PBX for a Cisco SIP phone, by having the router immediately in front of the SER/rtpproxy server block all incoming UDP but port 5060 for packets coming from the asterisk server. Allow outgoing everything.
Remove the port block/access-list rule and the phone works fine. Add the block of RTP and calls set up and answer, but both parties hear nothing, not even 183 ring-back, even though the caller should be able to hear the called party. (All other calls occuring simultaneously are unaffected since I only blocked incoming RTP from one call source.) tcpdump running on all the interfaces on the SER/rtpproxy server also show that audio coming in on the one side to rtpproxy but is not emitted by the other side.
Now, wait ten seconds or so after you know the called party has answered (so far no audio of for either party), and remove the incoming RTP block and ding! You now have two-way audio, even though you should have had one-way audio up until the moment the inbound RTP block was removed. This basically emulates the behavior of the switch that won't send audio unless it receives audio and how this puts the calling switch and rtpproxy in a deadly embrace.
So that seems to demonstrate that rtpproxy is behaving exactly as documented, but that this is terrible behavior. What can be done to fix this?
(tcpdumps of the sample calls available on request)
Thanks in advance for staying awake and bonus points for suggesting a fix or coming up with one!