RtpCapability.java

  1package eu.siacs.conversations.xmpp.jingle;
  2
  3import com.google.common.base.Strings;
  4import com.google.common.collect.Collections2;
  5import com.google.common.collect.ImmutableSet;
  6
  7import java.util.ArrayList;
  8import java.util.Arrays;
  9import java.util.Collection;
 10import java.util.Collections;
 11import java.util.List;
 12import java.util.Map;
 13import java.util.Set;
 14
 15import eu.siacs.conversations.entities.Contact;
 16import eu.siacs.conversations.entities.Presence;
 17import eu.siacs.conversations.entities.Presences;
 18import eu.siacs.conversations.entities.ServiceDiscoveryResult;
 19import eu.siacs.conversations.xml.Namespace;
 20import eu.siacs.conversations.xmpp.Jid;
 21
 22public class RtpCapability {
 23
 24    private static final List<String> BASIC_RTP_REQUIREMENTS = Arrays.asList(
 25            Namespace.JINGLE,
 26            Namespace.JINGLE_TRANSPORT_ICE_UDP,
 27            Namespace.JINGLE_APPS_RTP,
 28            Namespace.JINGLE_APPS_DTLS
 29    );
 30    private static final Collection<String> VIDEO_REQUIREMENTS = Arrays.asList(
 31            Namespace.JINGLE_FEATURE_AUDIO,
 32            Namespace.JINGLE_FEATURE_VIDEO
 33    );
 34
 35    public static Capability check(final Presence presence) {
 36        final ServiceDiscoveryResult disco = presence.getServiceDiscoveryResult();
 37        final Set<String> features = disco == null ? Collections.emptySet() : ImmutableSet.copyOf(disco.getFeatures());
 38        if (features.containsAll(BASIC_RTP_REQUIREMENTS)) {
 39            if (features.containsAll(VIDEO_REQUIREMENTS)) {
 40                return Capability.VIDEO;
 41            }
 42            if (features.contains(Namespace.JINGLE_FEATURE_AUDIO)) {
 43                return Capability.AUDIO;
 44            }
 45        }
 46        return Capability.NONE;
 47    }
 48
 49    public static String[] filterPresences(final Contact contact, Capability required) {
 50        final Presences presences = contact.getPresences();
 51        final ArrayList<String> resources = new ArrayList<>();
 52        for (final Map.Entry<String, Presence> presence : presences.getPresencesMap().entrySet()) {
 53            final Capability capability = check(presence.getValue());
 54            if (capability == Capability.NONE) {
 55                continue;
 56            }
 57            if (required == Capability.AUDIO || capability == required) {
 58                resources.add(presence.getKey());
 59            }
 60        }
 61        return resources.toArray(new String[0]);
 62    }
 63
 64    public static Capability check(final Contact contact) {
 65        return check(contact, true);
 66    }
 67
 68    public static Capability check(final Contact contact, final boolean allowFallback) {
 69        final Presences presences = contact.getPresences();
 70
 71        if (presences.isEmpty() && allowFallback && contact.getAccount().isEnabled()) {
 72            Contact gateway = contact.getAccount().getRoster().getContact(Jid.of(contact.getJid().getDomain()));
 73            if (gateway.showInRoster() && gateway.getPresences().anyIdentity("gateway", "pstn")) {
 74                return Capability.AUDIO;
 75            }
 76
 77            return contact.getRtpCapability();
 78        }
 79        Capability result = Capability.NONE;
 80        for (final Presence presence : presences.getPresences()) {
 81            Capability capability = check(presence);
 82            if (capability == Capability.VIDEO) {
 83                result = capability;
 84            } else if (capability == Capability.AUDIO && result == Capability.NONE) {
 85                result = capability;
 86            }
 87        }
 88        return result;
 89    }
 90
 91    // do all devices that support Rtp Call also support JMI?
 92    public static boolean jmiSupport(final Contact contact) {
 93        return !Collections2.transform(
 94                Collections2.filter(
 95                        contact.getPresences().getPresences(),
 96                        p -> RtpCapability.check(p) != RtpCapability.Capability.NONE),
 97                p -> {
 98                    ServiceDiscoveryResult disco = p.getServiceDiscoveryResult();
 99                    return disco != null && disco.getFeatures().contains(Namespace.JINGLE_MESSAGE);
100                }).contains(false);
101    }
102
103    public enum Capability {
104        NONE, AUDIO, VIDEO;
105
106        public static Capability of(String value) {
107            if (Strings.isNullOrEmpty(value)) {
108                return NONE;
109            }
110            try {
111                return valueOf(value);
112            } catch (IllegalArgumentException e) {
113                return NONE;
114            }
115        }
116    }
117
118}