commit 31ad93897d022677ad1195365f166ba5e09370a6 Author: Hashik Donthineni HashikDonthineni@gmail.com Date: Tue Jun 9 12:50:11 2020 +0530
Added WebRTC code --- .../snowflake/MyPeerConnectionObserver.java | 97 ++++++++++++++++++++++ .../torproject/snowflake/MyPersistentService.java | 95 ++++++++++++++++++++- .../interfaces/PeerConnectionObserverCallback.java | 18 ++++ 3 files changed, 208 insertions(+), 2 deletions(-)
diff --git a/app/src/main/java/org/torproject/snowflake/MyPeerConnectionObserver.java b/app/src/main/java/org/torproject/snowflake/MyPeerConnectionObserver.java new file mode 100644 index 0000000..5d96dae --- /dev/null +++ b/app/src/main/java/org/torproject/snowflake/MyPeerConnectionObserver.java @@ -0,0 +1,97 @@ +package org.torproject.snowflake; + +import android.util.Log; + +import org.torproject.snowflake.interfaces.PeerConnectionObserverCallback; +import org.webrtc.DataChannel; +import org.webrtc.IceCandidate; +import org.webrtc.MediaStream; +import org.webrtc.PeerConnection; +import org.webrtc.RtpReceiver; + +public class MyPeerConnectionObserver implements PeerConnection.Observer { + private final String TAG; + private PeerConnectionObserverCallback peerconnectionObserverCallback; + + public MyPeerConnectionObserver(String tag, PeerConnectionObserverCallback callback) { + TAG = tag + ": MyPeerConnectionObserver: "; + this.peerconnectionObserverCallback = callback; + } + + @Override + public void onSignalingChange(PeerConnection.SignalingState signalingState) { + Log.d(TAG, "onSignalingChange: " + signalingState); + } + + @Override + public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) { + Log.d(TAG, "onIceConnectionChange: " + iceConnectionState); + //TODO:Handle Connection Failure. + } + + @Override + public void onIceConnectionReceivingChange(boolean b) { + Log.d(TAG, "onIceConnectionReceivingChange: "); + } + + @Override + public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) { + Log.d(TAG, "onIceGatheringChange: " + iceGatheringState); + if (iceGatheringState.compareTo(PeerConnection.IceGatheringState.COMPLETE) == 0) + peerconnectionObserverCallback.onIceGatheringFinish(); + } + + @Override + public void onIceCandidate(IceCandidate iceCandidate) { + //Fired after each ICE candidate is gathered. AKA ICE trickling. + Log.d(TAG, "onIceCandidate: SDP:" + iceCandidate.sdp); + } + + @Override + public void onIceCandidatesRemoved(IceCandidate[] iceCandidates) { + Log.d(TAG, "onIceCandidatesRemoved: "); + } + + @Override + public void onAddStream(MediaStream mediaStream) { + Log.d(TAG, "onAddStream: "); + } + + @Override + public void onRemoveStream(MediaStream mediaStream) { + Log.d(TAG, "onRemoveStream: "); + } + + @Override + public void onDataChannel(DataChannel dataChannel) { + Log.d(TAG, "onDataChannel: State: " + dataChannel.state() + " Registering Observer..."); + dataChannel.registerObserver(new DataChannel.Observer() { + @Override + public void onBufferedAmountChange(long l) { + + } + + @Override + public void onStateChange() { + peerconnectionObserverCallback.dataChannelStateChange(dataChannel.state()); + } + + @Override + public void onMessage(DataChannel.Buffer buffer) { + Log.d(TAG, "onMessage: Received"); + peerconnectionObserverCallback.onMessage(buffer); + } + }); + peerconnectionObserverCallback.onDataChannel(dataChannel); + } + + @Override + public void onRenegotiationNeeded() { + Log.d(TAG, "onRenegotiationNeeded: "); + } + + @Override + public void onAddTrack(RtpReceiver rtpReceiver, MediaStream[] mediaStreams) { + Log.d(TAG, "onAddTrack: "); + } +} diff --git a/app/src/main/java/org/torproject/snowflake/MyPersistentService.java b/app/src/main/java/org/torproject/snowflake/MyPersistentService.java index 564fe03..2a7c52d 100644 --- a/app/src/main/java/org/torproject/snowflake/MyPersistentService.java +++ b/app/src/main/java/org/torproject/snowflake/MyPersistentService.java @@ -13,12 +13,25 @@ import android.util.Log; import androidx.annotation.Nullable;
import org.torproject.snowflake.constants.ForegroundServiceConstants; +import org.torproject.snowflake.interfaces.PeerConnectionObserverCallback; +import org.webrtc.DataChannel; +import org.webrtc.PeerConnection; +import org.webrtc.PeerConnectionFactory; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.LinkedList; +import java.util.List;
/** * Main Snowflake implementation of foreground service to relay data in the background. */ public class MyPersistentService extends Service { private static final String TAG = "MyPersistentService"; + //WebRTC vars + DataChannel mainDataChannel; + PeerConnection mainPeerConnection; + PeerConnectionFactory factory; private SharedPreferences sharedPreferences; private boolean isServiceStarted; private PowerManager.WakeLock wakeLock; @@ -121,7 +134,7 @@ public class MyPersistentService extends Service { return builder.build(); }
- //Starting and stopping service + /////////////// Start/Stop Service ////////////////////////
/** * Use to star/re-start the service @@ -140,7 +153,7 @@ public class MyPersistentService extends Service { wakeLock.acquire(); //WakeLock acquired for unlimited amount of time.
/// - //TODO: Start WebRTC connection. + startWebRTCConnection(); //Starting WebRTC }
/** @@ -160,5 +173,83 @@ public class MyPersistentService extends Service { isServiceStarted = false; }
+ /////////////// WebRTC //////////////////////// + + /** + * Initializing and starting WebRTC connection. + */ + private void startWebRTCConnection() { + initializePeerConnectionFactory(); //Android Specific, you can Ignore. + mainPeerConnection = createPeerConnection(factory); //Creating New Peer Connection. + //TODO: Fetch Offer from broker. + } + + /** + * Initializing peer connection factory. + */ + private void initializePeerConnectionFactory() { + Log.d(TAG, "initializePeerConnectionFactory: Started"); + PeerConnectionFactory.InitializationOptions initializationOptions = + PeerConnectionFactory.InitializationOptions.builder(this) + .createInitializationOptions(); + PeerConnectionFactory.initialize(initializationOptions); + + PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); + factory = PeerConnectionFactory.builder() + .setOptions(options) + .createPeerConnectionFactory(); + Log.d(TAG, "initializePeerConnectionFactory: Finished"); + } + + /** + * Creating a new peer connection. + * + * @param factory PeerConnectionFactory + * @return New PeerConnection + */ + private PeerConnection createPeerConnection(PeerConnectionFactory factory) { + Log.d(TAG, "createPeerConnection: Creating a new peer connection"); + List<PeerConnection.IceServer> iceServers = new LinkedList<>(); +// iceServers.add(PeerConnection.IceServer.builder("stun:stun.l.google.com:19302").createIceServer()); To Add custom ICE servers. + PeerConnection.RTCConfiguration rtcConfiguration = new PeerConnection.RTCConfiguration(iceServers); + PeerConnection.Observer pcObserver = new MyPeerConnectionObserver(TAG, new PeerConnectionObserverCallback() { + + @Override + public void onIceGatheringFinish() { + if (mainPeerConnection.connectionState() != PeerConnection.PeerConnectionState.CLOSED) { + Log.d(TAG, "onIceGatheringFinish: Ice Gathering Finished. Sending Answer to broker...\n" + mainPeerConnection.getLocalDescription().description); + //Sending the SDP Answer to the server. + //TODO:Send Answer + } + } + + @Override + public void onMessage(DataChannel.Buffer buffer) { + //Relay it to WebSocket + ByteBuffer data = ByteBuffer.wrap("HELLO".getBytes(Charset.defaultCharset())); //Sending some temporary data to test. + mainDataChannel.send(new DataChannel.Buffer(data, false)); + } + + @Override + public void onDataChannel(DataChannel dataChannel) { + Log.d(TAG, "onDataChannel: Setting Data Channel"); + mainDataChannel = dataChannel; + } + + @Override + public void iceConnectionFailed() { + Log.d(TAG, "iceConnectionFailed: "); + //Figuring out with trac ticket. + } + + @Override + public void dataChannelStateChange(final DataChannel.State STATE) { + Log.d(TAG, "dataChannelStateChange: Data Channel State: " + STATE); + } + }); + + Log.d(TAG, "createPeerConnection: Finished creating peer connection."); + return factory.createPeerConnection(rtcConfiguration, pcObserver); + } ///////////////////////////////////// } diff --git a/app/src/main/java/org/torproject/snowflake/interfaces/PeerConnectionObserverCallback.java b/app/src/main/java/org/torproject/snowflake/interfaces/PeerConnectionObserverCallback.java new file mode 100644 index 0000000..56be3ff --- /dev/null +++ b/app/src/main/java/org/torproject/snowflake/interfaces/PeerConnectionObserverCallback.java @@ -0,0 +1,18 @@ +package org.torproject.snowflake.interfaces; + +import org.webrtc.DataChannel; + +/** + * Callback to MyPersistentService when even happens form PeerConnectionObserver. + */ +public interface PeerConnectionObserverCallback { + void onIceGatheringFinish(); + + void onMessage(DataChannel.Buffer buffer); + + void onDataChannel(DataChannel dataChannel); + + void dataChannelStateChange(final DataChannel.State state); + + void iceConnectionFailed(); +}
tor-commits@lists.torproject.org