I've looked more closely at this and I think it is incorrectly
configuring itself asymmetrically
Both endpoints have obtained a TURN allocation on a TURN server, they
both access the same TURN server
Each endpoint log shows that it thinks it is sending to the peer through
its TURN allocation, e.g. caller logs
Selected pair for stream audio.RTP: 184.108.40.206:49398/udp/relay ->
and callee logs:
Selected pair for stream audio.RTP: 220.127.116.11:49400/udp/relay ->
Focusing on the caller:
- all the packets it sends out are sent to port 3478 on the TURN server
- all the packets it receives are from port 49400 on the TURN server
(the port allocated to the peer/callee) and so the
RelayedCandidateDatagramSocket doesn't accept them, it expects them to
come back from source port 3478 and be encapsulated
The callee sees things much the same way - it is also sending to port
3478 and receiving a flow from port 49398 and ignoring it.
I came across this mailing list post about such problems:
Has anybody else seen ice4j behave like this? Is there something that
should be done to avoid this when configuring the agent? Is there any
way it could detect this situation and log a warning when a flow starts
arriving from the wrong source port?
On 16/12/14 07:40, Daniel Pocock wrote:
On 15/12/14 10:02, Daniel Pocock wrote:
On 15/12/14 08:17, Lyubomir Marinov wrote:
2014-12-14 23:30 GMT+02:00 Daniel Pocock <email@example.com>:
and when the call is hung up and the RtpStreamReceiver destroyed, it
gives a stack showing that it was stuck in
org.ice4j.socket.MultiplexingDatagramSocket.receive(), here is an example:
Well... when an application reads from a socket, the very reading is
usually instantaneous and most of the time the application waits for a
packet to arrive. In other words, the expected behaviour for
XXXDatagramSocket is to spend most of its time blocked in receive.
Agreed, that is how the API should work. However, I see packets going
through the wifi router to the Android device where ice4j is running so
each time it receives a packet I would expect the receive() call to
return. When this problem occurs, it seems to stay in receive()
forever, as if 0 packets are received.
I am going to add some more logging to the code to try and understand
why it is behaving like this and whether it is really receiving packets
from the network.
One thing I notice is that my code tries to use the sockets as soon as
the COMPLETED event is sent by ice4j. Should I be waiting for the
TERMINATED event instead?
I also notice in the ice4j javadoc it suggests that the TERMINATED event
is related to the garbage collection/clean-up of the agent. That part
of the documentation is a bit confusing. Does it mean the IceAgent
should be garbage collected but the sockets should remain valid and can
be used after free()?
I think there is some confusion about the socket type
The stack shows that it was blocked in
In the MultiplexingDatagramSocket, the packets are received from the
wire but none of them match the filter for
RelayedCandidateDatagramSocket and so they can't be returned by the
receive() method of that socket.
Looking at them with Wireshark, they are just raw RTP packets from the
TURN server - this is what I expect, as it is the other peer that is
behind a bad NAT.
It seems that either
a) my user agent has somehow received the wrong socket object from the
ice4j ICE agent, or
b) the ice4j socket is in a bad state and
MultiplexingDatagramSocket.receive() shouldn't be trying to use
I was trying to get the sockets immediately after the COMPLETED event,
I've tweaked the code to wait for the TERMINATED event but the problem
is still there.