1package eu.siacs.conversations.xmpp.jingle;
 2
 3import android.util.Log;
 4
 5import com.google.common.base.CaseFormat;
 6import com.google.common.base.Optional;
 7import com.google.common.base.Preconditions;
 8
 9import eu.siacs.conversations.Config;
10
11import org.webrtc.MediaStreamTrack;
12import org.webrtc.PeerConnection;
13import org.webrtc.RtpSender;
14import org.webrtc.RtpTransceiver;
15
16import java.util.UUID;
17
18import javax.annotation.Nonnull;
19import javax.annotation.Nullable;
20
21class TrackWrapper<T extends MediaStreamTrack> {
22    public final T track;
23    public final RtpSender rtpSender;
24
25    private TrackWrapper(final T track, final RtpSender rtpSender) {
26        Preconditions.checkNotNull(track);
27        Preconditions.checkNotNull(rtpSender);
28        this.track = track;
29        this.rtpSender = rtpSender;
30    }
31
32    public static <T extends MediaStreamTrack> TrackWrapper<T> addTrack(
33            final PeerConnection peerConnection, final T mediaStreamTrack) {
34        final RtpSender rtpSender = peerConnection.addTrack(mediaStreamTrack);
35        return new TrackWrapper<>(mediaStreamTrack, rtpSender);
36    }
37
38    public static <T extends MediaStreamTrack> Optional<T> get(
39            @Nullable final PeerConnection peerConnection, final TrackWrapper<T> trackWrapper) {
40        if (trackWrapper == null) {
41            return Optional.absent();
42        }
43        final RtpTransceiver transceiver =
44                peerConnection == null ? null : getTransceiver(peerConnection, trackWrapper);
45        if (transceiver == null) {
46            final String id;
47            try {
48                id = trackWrapper.rtpSender.id();
49            } catch (final IllegalStateException e) {
50                return Optional.absent();
51            }
52            Log.w(Config.LOGTAG, "unable to detect transceiver for " + id);
53            return Optional.of(trackWrapper.track);
54        }
55        final RtpTransceiver.RtpTransceiverDirection direction = transceiver.getDirection();
56        if (direction == RtpTransceiver.RtpTransceiverDirection.SEND_ONLY
57                || direction == RtpTransceiver.RtpTransceiverDirection.SEND_RECV) {
58            return Optional.of(trackWrapper.track);
59        } else {
60            Log.d(Config.LOGTAG, "withholding track because transceiver is " + direction);
61            return Optional.absent();
62        }
63    }
64
65    public static <T extends MediaStreamTrack> RtpTransceiver getTransceiver(
66            @Nonnull final PeerConnection peerConnection, final TrackWrapper<T> trackWrapper) {
67        final RtpSender rtpSender = trackWrapper.rtpSender;
68        final String rtpSenderId;
69        try {
70            rtpSenderId = rtpSender.id();
71        } catch (final IllegalStateException e) {
72            return null;
73        }
74        for (final RtpTransceiver transceiver : peerConnection.getTransceivers()) {
75            try {
76                if (transceiver.getSender().id().equals(rtpSenderId)) {
77                    return transceiver;
78                }
79            } catch (final IllegalStateException e) { }
80        }
81        return null;
82    }
83
84    public static String id(final Class<? extends MediaStreamTrack> clazz) {
85        return String.format(
86                "%s-%s",
87                CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, clazz.getSimpleName()),
88                UUID.randomUUID().toString());
89    }
90}