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