From bfa35883bfa99628966b32153ce7e011e0c2c82d Mon Sep 17 00:00:00 2001 From: SendableMetatype <263203301+SendableMetatype@users.noreply.github.com> Date: Mon, 3 Aug 2026 20:12:12 +0200 Subject: [PATCH] feat: bridge OnIceSelectedCandidatePairChanged to Java observers --- .../cpp/include/api/PeerConnectionObserver.h | 2 ++ .../cpp/src/api/PeerConnectionObserver.cpp | 23 +++++++++++++++++++ .../onvoid/webrtc/PeerConnectionObserver.java | 16 +++++++++++++ 3 files changed, 41 insertions(+) diff --git a/webrtc-jni/src/main/cpp/include/api/PeerConnectionObserver.h b/webrtc-jni/src/main/cpp/include/api/PeerConnectionObserver.h index 55b5ef96..29403190 100644 --- a/webrtc-jni/src/main/cpp/include/api/PeerConnectionObserver.h +++ b/webrtc-jni/src/main/cpp/include/api/PeerConnectionObserver.h @@ -47,6 +47,7 @@ namespace jni void OnIceCandidateError(const std::string & address, int port, const std::string & url, int error_code, const std::string & error_text) override; void OnIceCandidatesRemoved(const std::vector & candidates) override; void OnIceConnectionReceivingChange(bool receiving) override; + void OnIceSelectedCandidatePairChanged(const webrtc::CandidatePairChangeEvent & event) override; private: class JavaPeerConnectionObserverClass : public JavaClass @@ -67,6 +68,7 @@ namespace jni jmethodID onIceCandidateError; jmethodID onIceCandidatesRemoved; jmethodID onIceConnectionReceivingChange; + jmethodID onSelectedCandidatePairChanged; }; private: diff --git a/webrtc-jni/src/main/cpp/src/api/PeerConnectionObserver.cpp b/webrtc-jni/src/main/cpp/src/api/PeerConnectionObserver.cpp index 576aa0e4..b6c19f01 100644 --- a/webrtc-jni/src/main/cpp/src/api/PeerConnectionObserver.cpp +++ b/webrtc-jni/src/main/cpp/src/api/PeerConnectionObserver.cpp @@ -24,6 +24,7 @@ #include "JavaEnums.h" #include "JavaFactories.h" #include "JavaRuntimeException.h" +#include "JavaString.h" #include "JavaUtils.h" #include "JNI_WebRTC.h" @@ -193,6 +194,27 @@ namespace jni ExceptionCheck(env); } + void PeerConnectionObserver::OnIceSelectedCandidatePairChanged(const webrtc::CandidatePairChangeEvent & event) + { + JNIEnv * env = AttachCurrentThread(); + + const webrtc::Candidate & remote = event.selected_candidate_pair.remote_candidate(); + + std::string ip = remote.address().ipaddr().ToString(); + int port = remote.address().port(); + + const auto typeName = remote.type_name(); + std::string type(typeName.data(), typeName.size()); + + JavaLocalRef jAddress = JavaString::toJava(env, ip); + JavaLocalRef jType = JavaString::toJava(env, type); + + env->CallVoidMethod(observer, javaClass->onSelectedCandidatePairChanged, + jAddress.get(), static_cast(port), jType.get()); + + ExceptionCheck(env); + } + PeerConnectionObserver::JavaPeerConnectionObserverClass::JavaPeerConnectionObserverClass(JNIEnv * env) { jclass cls = FindClass(env, PKG"PeerConnectionObserver"); @@ -210,5 +232,6 @@ namespace jni onIceCandidateError = GetMethod(env, cls, "onIceCandidateError", "(L" PKG "RTCPeerConnectionIceErrorEvent;)V"); onIceCandidatesRemoved = GetMethod(env, cls, "onIceCandidatesRemoved", "([L" PKG "RTCIceCandidate;)V"); onIceConnectionReceivingChange = GetMethod(env, cls, "onIceConnectionReceivingChange", "(Z)V"); + onSelectedCandidatePairChanged = GetMethod(env, cls, "onSelectedCandidatePairChanged", "(Ljava/lang/String;ILjava/lang/String;)V"); } } diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/PeerConnectionObserver.java b/webrtc/src/main/java/dev/onvoid/webrtc/PeerConnectionObserver.java index b4ec1f27..3f90880a 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/PeerConnectionObserver.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/PeerConnectionObserver.java @@ -170,4 +170,20 @@ default void onRemoveTrack(RTCRtpReceiver receiver) { default void onTrack(RTCRtpTransceiver transceiver) { } + /** + * ICE has selected (or later re-selected) a candidate pair for this + * connection. Fires once connectivity checks nominate a pair, which is + * before DTLS and SCTP are established and before data channels open, so + * the remote transport address is known before the connection becomes + * usable. May fire again if ICE re-nominates mid session. + * + * @param remoteAddress The remote candidate's IP address. For a relayed + * connection this is the TURN relay's address. + * @param remotePort The remote candidate's port. + * @param candidateType The remote candidate type: "host", "srflx", + * "prflx", or "relay". + */ + default void onSelectedCandidatePairChanged(String remoteAddress, int remotePort, String candidateType) { + } + }