Yes, if there is no packet loss FEC will not be used. In my opinion, they are complementary and if you can you should use them together. Here is my take on differences between the two.
- Turning on/off usage of Opus inband FEC is very simple. You feed the packet loss stats to libopus and it does the magic for you. But just like every magic, you can't see what is happening behind the scenes ;) Here is what I mean. Opus FEC data is encapsulated within encoded frame, it does not come out of libopus as a separate chunk of encoded data. Thus there is no easy way to check whether the FEC data is actually exists in encoded frame without sophisticated decoding process. It is not only that what makes it "magical", sometimes you will not get FEC data at all. So you can imagine someone spending some time bending their architecture to provide the packet loss feedback to libopus. It works in the beginning, but then the code around it evolves and it stops producing FEC data at all. The reason why it happened is, as I found out latter, that opus can operate in SILK, CELT and some hybrid mode. Inband FEC is supported only when libopus brain selects SILK encoding mode. I don't remember exactly, but I think it is depending on the encoding settings: sample rate, frame size and bitrate. But if you manage to squeeze out the FEC data out of libopus. It provides very good protection against random packet loss. In case of busty loss, unfortunately, you will be able to hear robotic audio artifacts, as libopus audio packet loss concealment is not the best.
- with ULPFEC on the other hand there is no magic at all. You can grab a pcap and find FEC packets in with wireshark. It is media agnostic, meaning if you support it - you can use it for audio and video. But there is no library which everybody can use. There are other nasty things in rfc5109, but I will not highlight it here.