From b197f0e7b78a7326d9572c26243b1f3786c225fd Mon Sep 17 00:00:00 2001 From: Doominika Date: Wed, 11 Mar 2026 09:59:23 +0100 Subject: [PATCH 1/5] feat: implement getting iceServers and passing them when creating peer connection --- .../modules/stream/JanusConnection.java | 16 +++++++++++++- .../modules/stream/JanusPublisher.java | 15 +++++++++---- .../modules/stream/JanusSubscriber.java | 14 +++++++++--- .../modules/stream/PeerConnectionManager.java | 8 ++++--- .../modules/stream/RoomJanusSession.java | 22 ++++++++++++------- .../modules/stream/StreamApi.java | 10 +++++++-- 6 files changed, 64 insertions(+), 21 deletions(-) diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusConnection.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusConnection.java index 96b438f7..ffc40ef7 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusConnection.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusConnection.java @@ -10,12 +10,14 @@ import org.webrtc.SessionDescription; import java.util.Collections; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; public class JanusConnection { protected final PeerConnection peerConnection; protected final PeerConnectionFactory peerConnectionFactory; + private final List configuration; protected PmxKeyStore keyStore; public final ConnectionType connectionType; private long sessionId = -1L; @@ -27,6 +29,17 @@ public JanusConnection( ConnectionType connectionType, TrackObserver trackObserver, BiConsumer onTrickle + ) { + this(pcFactory, keyStore, connectionType, trackObserver, onTrickle, Collections.emptyList()); + } + + public JanusConnection( + PeerConnectionFactory pcFactory, + PmxKeyStore keyStore, + ConnectionType connectionType, + TrackObserver trackObserver, + BiConsumer onTrickle, + List configuration ) { this.peerConnectionFactory = pcFactory; this.connectionType = connectionType; @@ -53,6 +66,7 @@ public JanusConnection( } } ); + this.configuration = configuration; this.peerConnection = createPeerConnection(pcObserver); } @@ -87,7 +101,7 @@ public void onSetFailure(String s) { //TODO: We need method to pass framecryptorOptions and TrackObserver private PeerConnection createPeerConnection(PcObserver pcObserver) { return peerConnectionFactory.createPeerConnection( - new PeerConnection.RTCConfiguration(Collections.emptyList()), + new PeerConnection.RTCConfiguration(configuration), pcObserver ); } diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusPublisher.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusPublisher.java index e70a33de..437deea6 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusPublisher.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusPublisher.java @@ -7,6 +7,7 @@ import com.simplito.java.privmx_endpoint.model.VideoTrackInfo; import org.webrtc.MediaConstraints; +import org.webrtc.PeerConnection; import org.webrtc.PeerConnectionFactory; import org.webrtc.PmxFrameCryptor; import org.webrtc.PmxFrameCryptorFactory; @@ -16,6 +17,7 @@ import org.webrtc.VideoCapturer; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; @@ -26,9 +28,14 @@ public class JanusPublisher extends JanusConnection{ //TODO: Add videoCapturer to VideoTrackInfo public final Map videoCapturers = new HashMap<>(); - - public JanusPublisher(PeerConnectionFactory pcFactory, PmxKeyStore keyStore, TrackObserver observer, BiConsumer onTrickle) { - super(pcFactory, keyStore, ConnectionType.Publisher, observer, onTrickle); + public JanusPublisher( + PeerConnectionFactory pcFactory, + PmxKeyStore keyStore, + TrackObserver observer, + BiConsumer onTrickle, + List configuration + ) { + super(pcFactory, keyStore, ConnectionType.Publisher, observer, onTrickle, configuration); } public void addAudioTrack(org.webrtc.AudioTrack audioTrack) { @@ -82,7 +89,7 @@ public void addVideoTrack( } public void addVideoTrack(org.webrtc.VideoTrack videoTrack) { - addVideoTrack(videoTrack,null); + addVideoTrack(videoTrack, null); } public void removeAudioTrack(String id) { diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusSubscriber.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusSubscriber.java index cc0cbe9f..d6d83b81 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusSubscriber.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusSubscriber.java @@ -3,16 +3,24 @@ import com.simplito.java.privmx_endpoint.model.ConnectionType; import org.webrtc.MediaConstraints; +import org.webrtc.PeerConnection; import org.webrtc.PeerConnectionFactory; import org.webrtc.PmxKeyStore; import org.webrtc.SessionDescription; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; -public class JanusSubscriber extends JanusConnection{ - public JanusSubscriber(PeerConnectionFactory pcFactory, PmxKeyStore keyStore, TrackObserver observer, BiConsumer onTrickle) { - super(pcFactory, keyStore, ConnectionType.Publisher, observer, onTrickle); +public class JanusSubscriber extends JanusConnection { + public JanusSubscriber( + PeerConnectionFactory pcFactory, + PmxKeyStore keyStore, + TrackObserver observer, + BiConsumer onTrickle, + List configuration + ) { + super(pcFactory, keyStore, ConnectionType.Publisher, observer, onTrickle, configuration); } public String createAnswer(String offerSdp){ diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/PeerConnectionManager.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/PeerConnectionManager.java index 26257fb0..3499bf2d 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/PeerConnectionManager.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/PeerConnectionManager.java @@ -5,20 +5,22 @@ import com.simplito.java.privmx_endpoint.model.stream.StreamHandle; +import org.webrtc.PeerConnection; import org.webrtc.PeerConnectionFactory; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.BiConsumer; -import java.util.function.Function; class PeerConnectionManager { private final Map sessions = new HashMap<>(); private final Map sessionHandles = new HashMap<>(); protected final PeerConnectionFactory pcFactory; private final BiConsumer onTrickle; + private List configuration; PeerConnectionManager( PeerConnectionFactory pcFactory, @@ -29,9 +31,9 @@ class PeerConnectionManager { } @NonNull - public RoomJanusSession createSession(@NonNull String streamRoomId) { + public RoomJanusSession createSession(@NonNull String streamRoomId, List configuration) { return Optional.ofNullable( - sessions.putIfAbsent(streamRoomId, new RoomJanusSession(streamRoomId, pcFactory, onTrickle)) + sessions.putIfAbsent(streamRoomId, new RoomJanusSession(streamRoomId, pcFactory, onTrickle, configuration)) ).orElse(Objects.requireNonNull(sessions.get(streamRoomId))); } diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/RoomJanusSession.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/RoomJanusSession.java index 1e98131b..c8cc1409 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/RoomJanusSession.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/RoomJanusSession.java @@ -3,7 +3,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; - import com.simplito.java.privmx_endpoint.model.stream.Key; import com.simplito.java.privmx_endpoint.model.stream.KeyType; import org.webrtc.MediaStreamTrack; @@ -37,13 +36,20 @@ public class RoomJanusSession { private final BiConsumer onTrickle; private final Map trackObserversByStreamId = new HashMap<>(); private final TrackObserver trackObserver = new TrackObserverImpl(); + private List configuration = Collections.emptyList(); //TODO: Add error listener for catch errors from webrtcInterface - public RoomJanusSession(@NonNull String roomId, @NonNull PeerConnectionFactory pcFactory, BiConsumer onTrickle) { + public RoomJanusSession( + @NonNull String roomId, + @NonNull PeerConnectionFactory pcFactory, + BiConsumer onTrickle, + List configuration + ) { this.pcFactory = pcFactory; this.roomID = roomId; this.keyStore = PmxFrameCryptorFactory.createPmxKeyStore(); this.onTrickle = onTrickle; + this.configuration = configuration; } @Nullable @@ -62,11 +68,11 @@ public synchronized void createSubscriber() { public synchronized void createSubscriber(TrackObserver observer) { if (subscriber == null) { - subscriber = new JanusSubscriber(pcFactory, keyStore, observer, onTrickle); - }else if (subscriber.isEnded()) { + subscriber = new JanusSubscriber(pcFactory, keyStore, observer, onTrickle, configuration); + } else if (subscriber.isEnded()) { subscriber.close(); - subscriber = new JanusSubscriber(pcFactory, keyStore, observer, onTrickle); - }else{ + subscriber = new JanusSubscriber(pcFactory, keyStore, observer, onTrickle, configuration); + } else { throw new IllegalStateException("Subscriber is currently active."); } } @@ -77,10 +83,10 @@ public synchronized void createPublisher() { public synchronized void createPublisher(TrackObserver observer) { if (publisher == null) { - publisher = new JanusPublisher(pcFactory, keyStore, observer, onTrickle); + publisher = new JanusPublisher(pcFactory, keyStore, observer, onTrickle, configuration); }else if (publisher.isEnded()) { publisher.close(); - publisher = new JanusPublisher(pcFactory, keyStore, observer, onTrickle); + publisher = new JanusPublisher(pcFactory, keyStore, observer, onTrickle, configuration); }else{ throw new IllegalStateException("Publisher is currently active."); } diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java index 956fca55..d3bc18d8 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java @@ -23,6 +23,7 @@ import org.webrtc.DefaultVideoEncoderFactory; import org.webrtc.EglBase; import org.webrtc.MediaStreamTrack; +import org.webrtc.PeerConnection; import org.webrtc.PeerConnectionFactory; import org.webrtc.PmxFrameCryptor; import org.webrtc.VideoDecoderFactory; @@ -31,7 +32,6 @@ import org.webrtc.audio.AudioDeviceModule; import org.webrtc.audio.JavaAudioDeviceModule; -import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -165,8 +165,14 @@ public List listStreams(String streamRoomId) { public void joinStreamRoom( String streamRoomId ) { + List iceServers = api.getTurnCredentials().stream().map(item -> PeerConnection.IceServer.builder(item.url) + .setUsername(item.username) + .setPassword(item.password) + .createIceServer() + ).collect(Collectors.toList()); + //TODO: Rollback this change, it is do only for run test - RoomJanusSession session = pcManager.createSession(streamRoomId); + RoomJanusSession session = pcManager.createSession(streamRoomId, iceServers); api.joinStreamRoom(streamRoomId, session.webrtc); } From af6026b73463ac601ed91474f646115265763d93 Mon Sep 17 00:00:00 2001 From: Doominika Date: Fri, 13 Mar 2026 09:34:37 +0100 Subject: [PATCH 2/5] feat: add methods for getting RTC configuration --- .../modules/stream/StreamApi.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java index d3bc18d8..538535cd 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java @@ -370,4 +370,46 @@ public String buildSubscriptionQuery( selectorId ); } + + // ----- PRIV + private List getRTCConfiguration() { + return api.getTurnCredentials().stream().map(item -> + PeerConnection.IceServer.builder(item.url) + .setUsername(item.username) + .setPassword(item.password) + .createIceServer() + ).collect(Collectors.toList()); + } + + private enum Mode {PUBLISHER, SUBSCRIBER} + + private void setRTCConfiguration(Object key, Mode mode) { + RoomJanusSession session = key instanceof StreamHandle + ? pcManager.getSession((StreamHandle) key) + : pcManager.getSession((String) key); + + if (session == null) { + throw new IllegalStateException( + "No active session to this Stream Room. Join stream room first" + ); + } + + applyRTCConfiguration(session, mode); + } + + private void applyRTCConfiguration(RoomJanusSession session, Mode mode) { + switch (mode) { + case PUBLISHER: + if (session.getPublisher() != null) { + session.getPublisher().setRTCConfiguration(getRTCConfiguration()); + } + break; + + case SUBSCRIBER: + if (session.getSubscriber() != null) { + session.getSubscriber().setRTCConfiguration(getRTCConfiguration()); + } + break; + } + } } From 2ab3141faf5572c28590216350ec211774d9a738 Mon Sep 17 00:00:00 2001 From: Doominika Date: Fri, 13 Mar 2026 09:38:48 +0100 Subject: [PATCH 3/5] feat: get turn credentials when publishing, updating, modifying and subscribing --- .../privmx_endpoint/modules/stream/StreamApi.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java index 538535cd..6045c912 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java @@ -165,14 +165,8 @@ public List listStreams(String streamRoomId) { public void joinStreamRoom( String streamRoomId ) { - List iceServers = api.getTurnCredentials().stream().map(item -> PeerConnection.IceServer.builder(item.url) - .setUsername(item.username) - .setPassword(item.password) - .createIceServer() - ).collect(Collectors.toList()); - //TODO: Rollback this change, it is do only for run test - RoomJanusSession session = pcManager.createSession(streamRoomId, iceServers); + RoomJanusSession session = pcManager.createSession(streamRoomId, getRTCConfiguration()); api.joinStreamRoom(streamRoomId, session.webrtc); } @@ -268,11 +262,13 @@ public void removeTrack( public StreamPublishResult publishStream(StreamHandle streamHandle) { Objects.requireNonNull(streamHandle); + setRTCConfiguration(streamHandle, Mode.PUBLISHER); return api.publishStream(streamHandle); } public StreamPublishResult updateStream(StreamHandle streamHandle) { Objects.requireNonNull(streamHandle); + setRTCConfiguration(streamHandle, Mode.PUBLISHER); return api.updateStream(streamHandle); } @@ -298,6 +294,7 @@ public void subscribeToRemoteStreams( throw new IllegalStateException("No active session to this Stream Room. Join stream room first"); try { session.createSubscriber(); + setRTCConfiguration(streamRoomId, Mode.SUBSCRIBER); } catch (IllegalStateException ignored) {} api.subscribeToRemoteStreams(streamRoomId, subscriptions, options); } @@ -321,6 +318,7 @@ public void modifyRemoteStreamsSubscriptions( List subscriptionsToRemove, Settings options ) { + setRTCConfiguration(streamRoomId, Mode.SUBSCRIBER); api.modifyRemoteStreamsSubscriptions( streamRoomId, subscriptionsToAdd, @@ -333,6 +331,7 @@ public void unsubscribeFromRemoteStreams( String streamRoomId, List subscriptionsToRemove ) { + setRTCConfiguration(streamRoomId, Mode.SUBSCRIBER); api.unsubscribeFromRemoteStreams( streamRoomId, subscriptionsToRemove From 2f5f52e79aba398308c882eeaf8753a788ac8f3b Mon Sep 17 00:00:00 2001 From: Doominika Date: Fri, 13 Mar 2026 09:39:50 +0100 Subject: [PATCH 4/5] feat: add function for setting configuration in JanusSession --- .../privmx_endpoint/modules/stream/JanusConnection.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusConnection.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusConnection.java index ffc40ef7..ab9abc48 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusConnection.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusConnection.java @@ -17,7 +17,7 @@ public class JanusConnection { protected final PeerConnection peerConnection; protected final PeerConnectionFactory peerConnectionFactory; - private final List configuration; + private List configuration; protected PmxKeyStore keyStore; public final ConnectionType connectionType; private long sessionId = -1L; @@ -134,4 +134,9 @@ public void close(){ peerConnection.dispose(); } } + + public void setRTCConfiguration(List configuration) { + this.configuration = configuration; + this.peerConnection.setConfiguration(new PeerConnection.RTCConfiguration(configuration)); + } } \ No newline at end of file From dc4d72aa8c2f6d61e2c5b0db1ed5e340b43ad525 Mon Sep 17 00:00:00 2001 From: Doominika Date: Fri, 13 Mar 2026 12:06:07 +0100 Subject: [PATCH 5/5] chore: change enum to an existing type from library --- .../modules/stream/StreamApi.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java index 6045c912..c857eb96 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java @@ -6,6 +6,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.simplito.java.privmx_endpoint.model.ConnectionType; import com.simplito.java.privmx_endpoint.model.ContainerPolicy; import com.simplito.java.privmx_endpoint.model.PagingList; import com.simplito.java.privmx_endpoint.model.UserWithPubKey; @@ -262,13 +263,13 @@ public void removeTrack( public StreamPublishResult publishStream(StreamHandle streamHandle) { Objects.requireNonNull(streamHandle); - setRTCConfiguration(streamHandle, Mode.PUBLISHER); + setRTCConfiguration(streamHandle, ConnectionType.Publisher); return api.publishStream(streamHandle); } public StreamPublishResult updateStream(StreamHandle streamHandle) { Objects.requireNonNull(streamHandle); - setRTCConfiguration(streamHandle, Mode.PUBLISHER); + setRTCConfiguration(streamHandle, ConnectionType.Publisher); return api.updateStream(streamHandle); } @@ -294,7 +295,7 @@ public void subscribeToRemoteStreams( throw new IllegalStateException("No active session to this Stream Room. Join stream room first"); try { session.createSubscriber(); - setRTCConfiguration(streamRoomId, Mode.SUBSCRIBER); + setRTCConfiguration(streamRoomId, ConnectionType.Subscriber); } catch (IllegalStateException ignored) {} api.subscribeToRemoteStreams(streamRoomId, subscriptions, options); } @@ -318,7 +319,7 @@ public void modifyRemoteStreamsSubscriptions( List subscriptionsToRemove, Settings options ) { - setRTCConfiguration(streamRoomId, Mode.SUBSCRIBER); + setRTCConfiguration(streamRoomId, ConnectionType.Subscriber); api.modifyRemoteStreamsSubscriptions( streamRoomId, subscriptionsToAdd, @@ -331,7 +332,7 @@ public void unsubscribeFromRemoteStreams( String streamRoomId, List subscriptionsToRemove ) { - setRTCConfiguration(streamRoomId, Mode.SUBSCRIBER); + setRTCConfiguration(streamRoomId,ConnectionType.Subscriber); api.unsubscribeFromRemoteStreams( streamRoomId, subscriptionsToRemove @@ -380,9 +381,7 @@ private List getRTCConfiguration() { ).collect(Collectors.toList()); } - private enum Mode {PUBLISHER, SUBSCRIBER} - - private void setRTCConfiguration(Object key, Mode mode) { + private void setRTCConfiguration(Object key, ConnectionType mode) { RoomJanusSession session = key instanceof StreamHandle ? pcManager.getSession((StreamHandle) key) : pcManager.getSession((String) key); @@ -396,15 +395,15 @@ private void setRTCConfiguration(Object key, Mode mode) { applyRTCConfiguration(session, mode); } - private void applyRTCConfiguration(RoomJanusSession session, Mode mode) { + private void applyRTCConfiguration(RoomJanusSession session, ConnectionType mode) { switch (mode) { - case PUBLISHER: + case Publisher: if (session.getPublisher() != null) { session.getPublisher().setRTCConfiguration(getRTCConfiguration()); } break; - case SUBSCRIBER: + case Subscriber: if (session.getSubscriber() != null) { session.getSubscriber().setRTCConfiguration(getRTCConfiguration()); }