for DataSize {
143 | type Output = DataSize;
144 |
145 | fn add(self, other: DataSize) -> DataSize {
146 | DataSize::from_bits(self.bits + other.bits)
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/src/android/api/org/signal/ringrtc/Connection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019-2021 Signal Messenger, LLC
3 | * SPDX-License-Identifier: AGPL-3.0-only
4 | */
5 |
6 | package org.signal.ringrtc;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.annotation.Nullable;
10 |
11 | import org.webrtc.AudioSource;
12 | import org.webrtc.AudioTrack;
13 | import org.webrtc.NativePeerConnectionFactory;
14 | import org.webrtc.PeerConnection;
15 |
16 | /**
17 | *
18 | * Represents the connection to a remote peer
19 | *
20 | * This class inherits from org.webrtc.PeerConnection and
21 | * encapsulates the lifecycle of establishing, creating, and tearing
22 | * down a connection.
23 | *
24 | */
25 | public class Connection extends PeerConnection {
26 |
27 | @NonNull
28 | private static final String TAG = Connection.class.getSimpleName();
29 | @NonNull
30 | private final CallId callId;
31 | private long nativePeerConnection;
32 | private int remoteDevice;
33 | @Nullable
34 | private AudioSource audioSource;
35 | @Nullable
36 | private AudioTrack audioTrack;
37 |
38 | Connection(NativeFactory factory) {
39 | super(factory);
40 | this.nativePeerConnection = factory.nativePeerConnection;
41 | this.callId = factory.callId;
42 | this.remoteDevice = factory.remoteDevice;
43 | Log.i(TAG, "ctor(): connectionId: " + callId.format(remoteDevice));
44 | }
45 |
46 | @Override
47 | public String toString() {
48 | return callId.format(remoteDevice);
49 | }
50 |
51 | private void checkConnectionExists() {
52 | if (nativePeerConnection == 0) {
53 | throw new IllegalStateException("Connection has been closed.");
54 | }
55 | }
56 |
57 | void setAudioSource(@NonNull AudioSource audioSource,
58 | @NonNull AudioTrack audioTrack) {
59 | checkConnectionExists();
60 |
61 | this.audioSource = audioSource;
62 | this.audioTrack = audioTrack;
63 |
64 | }
65 |
66 | void setAudioEnabled(boolean enabled) {
67 | Log.i(TAG, "audioTrack.setEnabled(" + enabled + ")");
68 | audioTrack.setEnabled(enabled);
69 | }
70 |
71 | /**
72 | *
73 | * Close the Connection object and clean up.
74 | *
75 | */
76 | void shutdown() {
77 | checkConnectionExists();
78 |
79 | audioSource.dispose();
80 |
81 | try {
82 | Log.i(TAG, "Connection.shutdown(): calling super.close()");
83 | close();
84 | Log.i(TAG, "Connection.shutdown(): calling super.dispose()");
85 | dispose();
86 | Log.i(TAG, "Connection.shutdown(): after calling super.dispose()");
87 | } catch (Exception e) {
88 | Log.e(TAG, "Problem closing PeerConnection: ", e);
89 | }
90 |
91 | nativePeerConnection = 0;
92 |
93 | }
94 |
95 | /**
96 | *
97 | * Represents the native call connection factory
98 | *
99 | * This class is an implementation detail, used to encapsulate the
100 | * native call connection pointer created by the call connection
101 | * factory.
102 | *
103 | * One way of constructing a PeerConnection (Connection's super
104 | * class) is by passing an object that implements
105 | * NativePeerConnectionFactory, which is done here.
106 | *
107 | */
108 | static class NativeFactory implements NativePeerConnectionFactory {
109 | private long nativePeerConnection;
110 | private CallId callId;
111 | private int remoteDevice;
112 |
113 | protected NativeFactory( long nativePeerConnection,
114 | @NonNull CallId callId,
115 | int remoteDevice) {
116 | this.nativePeerConnection = nativePeerConnection;
117 | this.callId = callId;
118 | this.remoteDevice = remoteDevice;
119 | }
120 |
121 | @Override
122 | public long createNativePeerConnection() {
123 | return nativePeerConnection;
124 | }
125 |
126 | }
127 |
128 | }
129 |
--------------------------------------------------------------------------------
/src/android/api/org/signal/ringrtc/CallLinkEpoch.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019-2025 Signal Messenger, LLC
3 | * SPDX-License-Identifier: AGPL-3.0-only
4 | */
5 |
6 | package org.signal.ringrtc;
7 |
8 | import androidx.annotation.NonNull;
9 |
10 | /**
11 | * Represents a call link epoch. When a call link is created, the calling server will issue
12 | * a randomly-generated "epoch". This gets included in the URL and in requests to use the link.
13 | * If it is mismatched, the request will fail.
14 | *
15 | * Internally, the epoch is stored as a 32-bit integer.
16 | */
17 | public final class CallLinkEpoch {
18 | private final String TAG = CallLinkEpoch.class.getSimpleName();
19 |
20 | private final int epoch;
21 |
22 | /**
23 | *
24 | * Create a new CallLinkEpoch from a raw integer value.
25 | *
26 | * @param epoch 32-bit epoch identifier.
27 | *
28 | */
29 | @CalledByNative
30 | private CallLinkEpoch(int epoch) {
31 | this.epoch = epoch;
32 | }
33 |
34 | /**
35 | *
36 | * Create a new CallLinkEpoch from a consonant base-16 encoded string.
37 | *
38 | * @param epoch Encoded string.
39 | *
40 | */
41 | public CallLinkEpoch(@NonNull String epoch) throws CallException {
42 | this.epoch = nativeParse(epoch);
43 | }
44 |
45 | public static final int SERIALIZED_SIZE = 4;
46 |
47 | /**
48 | *
49 | * Serializes this {@code CallLinkEpoch} into a byte array.
50 | *
51 | * @return Byte array.
52 | *
53 | */
54 | @NonNull
55 | public byte[] getBytes() {
56 | return new byte[]{
57 | (byte) ((epoch & 0x000000ff)),
58 | (byte) ((epoch & 0x0000ff00) >> 8),
59 | (byte) ((epoch & 0x00ff0000) >> 16),
60 | (byte) ((epoch & 0xff000000) >> 24)
61 | };
62 | }
63 |
64 | /**
65 | *
66 | * Deserializes a {@link CallLinkEpoch} from the given byte array.
67 | *
68 | * @param bytes Byte array
69 | * @throws IllegalArgumentException if {@code bytes} does not contain enough data.
70 | *
71 | * @return Instance of {@link CallLinkEpoch}.
72 | *
73 | */
74 | @NonNull
75 | public static CallLinkEpoch fromBytes(@NonNull byte[] bytes) {
76 | return fromBytes(bytes, 0);
77 | }
78 |
79 | /**
80 | *
81 | * Deserializes a {@link CallLinkEpoch} from the given byte array.
82 | *
83 | * @param bytes Byte array
84 | * @param from Starting offset
85 | * @throws IllegalArgumentException if {@code bytes} does not contain enough data.
86 | *
87 | * @return Instance of {@link CallLinkEpoch}.
88 | *
89 | */
90 | @NonNull
91 | public static CallLinkEpoch fromBytes(@NonNull byte[] bytes, int from) {
92 | if (bytes.length - from < SERIALIZED_SIZE) {
93 | throw new IllegalArgumentException("length");
94 | }
95 | int epoch = (bytes[from] & 0xff) |
96 | (bytes[from + 1] & 0xff) << 8 |
97 | (bytes[from + 2] & 0xff) << 16 |
98 | (bytes[from + 3] & 0xff) << 24;
99 | return new CallLinkEpoch(epoch);
100 | }
101 |
102 | /**
103 | *
104 | * Creates a consonant base-16 encoded string representation of the epoch.
105 | *
106 | * @return String value.
107 | *
108 | */
109 | @NonNull
110 | @Override
111 | public String toString() {
112 | try {
113 | return nativeToFormattedString(epoch);
114 | } catch (CallException e) {
115 | throw new AssertionError(e);
116 | }
117 | }
118 |
119 | @Override
120 | public boolean equals(Object obj) {
121 | if (obj == this) {
122 | return true;
123 | }
124 | if (obj != null) {
125 | if (this.getClass() == obj.getClass()) {
126 | CallLinkEpoch that = (CallLinkEpoch)obj;
127 | return this.epoch == that.epoch;
128 | }
129 | }
130 | return false;
131 | }
132 |
133 | @Override
134 | public int hashCode() {
135 | return epoch;
136 | }
137 |
138 | private static native int nativeParse(String s) throws CallException;
139 | private static native String nativeToFormattedString(int v) throws CallException;
140 | }
141 |
--------------------------------------------------------------------------------