[webRTC for android vol3] trickle ICE

今回は [Trickle ICE](https://html5experts.jp/mganeko/19814/) やります。
接続が早くなるやつ。
だいぶ早くなった。

複数台接続はこちら → [webRTC for android vol4 複数台接続](http://qiita.com/nakadoribooks/items/9cb58dbdddb439b5add9)
普通に接続する前回はこちら [webRTC for android vol2](http://qiita.com/nakadoribooks/items/d046fb68d59c7fffbc42)
Ios版はこちら [webRTC for ios vol3](http://qiita.com/nakadoribooks/items/a0f19dd96b0763c35ed2)

# 成果物
https://github.com/nakadoribooks/webrtc-android/releases/tag/v0.0.3

<img src="https://j.gifs.com/Q1xr17.gif" />

# [前回](http://qiita.com/nakadoribooks/items/d046fb68d59c7fffbc42)からの差分

```diff:trickleIce.diff
diff --git a/app/src/main/java/com/nakadoribooks/webrtcexample/MainActivity.java b/app/src/main/java/com/nakadoribooks/webrtcexample/MainActivity.java
index e79a927..b3d09f0 100644
--- a/app/src/main/java/com/nakadoribooks/webrtcexample/MainActivity.java
+++ b/app/src/main/java/com/nakadoribooks/webrtcexample/MainActivity.java
@@ -106,6 +106,11 @@ public class MainActivity extends AppCompatActivity {
 
                 webRTC.receiveAnswer(sdp);
             }
+
+            @Override
+            public void onIceCandidate(String sdp, String sdpMid, int sdpMLineIndex) {
+                webRTC.addIceCandidate(sdp, sdpMid, sdpMLineIndex);
+            }
         });
     }
 
@@ -126,6 +131,11 @@ public class MainActivity extends AppCompatActivity {
             public void didReceiveRemoteStream() {
                 changeState(State.Done);
             }
+
+            @Override
+            public void onIceCandidate(String sdp, String sdpMid, int sdpMLineIndex) {
+                wamp.publishIceCandidate(sdp, sdpMid, sdpMLineIndex);
+            }
         });
         webRTC.startCapture();
     }
diff --git a/app/src/main/java/com/nakadoribooks/webrtcexample/Wamp.java b/app/src/main/java/com/nakadoribooks/webrtcexample/Wamp.java
index f6d2b57..a7580f1 100644
--- a/app/src/main/java/com/nakadoribooks/webrtcexample/Wamp.java
+++ b/app/src/main/java/com/nakadoribooks/webrtcexample/Wamp.java
@@ -26,11 +26,13 @@ public class Wamp {
         void onConnected();
         void onReceiveOffer(String sdp);
         void onReceiveAnswer(String sdp);
+        void onIceCandidate(String sdp, String sdpMid, int sdpMLineIndex);
     }
 
     private static final String TAG = "Wamp";
     private static final String AnswerTopic = "com.nakadoribook.webrtc.answer";
     private static final String OfferTopic = "com.nakadoribook.webrtc.offer";
+    private static final String CandidateTopic = "com.nakadoribook.webrtc.candidate";
 
     private final Activity activity;
     private WampClient wampClient;
@@ -55,6 +57,10 @@ public class Wamp {
         _publishAnswer(sdp);
     }
 
+    public void publishIceCandidate(String sdp, String sdpMid, int sdpMLineIndex){
+        _publishIceCandidate(sdp, sdpMid, sdpMLineIndex);
+    }
+
     // implements --------
 
     private void _connect(){
@@ -108,6 +114,22 @@ public class Wamp {
                                 @Override
                                 public void call(Throwable arg0) {}
                             });
+
+                            wampClient.makeSubscription(CandidateTopic).subscribe(new Action1<PubSubData>(){
+                                @Override
+                                public void call(PubSubData arg0) {
+                                    JsonNode json = arg0.arguments().get(0);
+                                    String sdp = json.get("sdp").asText();
+                                    String sdpMid = json.get("sdpMid").asText();
+                                    int sdpMLineIndex = json.get("sdpMLineIndex").asInt();
+
+                                    callbacks.onIceCandidate(sdp, sdpMid, sdpMLineIndex);
+                                }
+
+                            }, new Action1<Throwable>(){
+                                @Override
+                                public void call(Throwable arg0) {}
+                            });
                         }
                     }
                 }, new Action1<Throwable>() {
@@ -140,4 +162,15 @@ public class Wamp {
         wampClient.publish(AnswerTopic, node);
     }
 
+    public void _publishIceCandidate(String sdp, String sdpMid, int sdpMLineIndex){
+        final ObjectMapper mapper = new ObjectMapper();
+        ObjectNode node = mapper.createObjectNode();
+        node.put("type", "candidate");
+        node.put("candidate", sdp);
+        node.put("id", sdpMid);
+        node.put("kRTCICECandidateMLineIndexKey", sdpMLineIndex);
+
+        wampClient.publish(CandidateTopic, node);
+    }
+
 }
diff --git a/app/src/main/java/com/nakadoribooks/webrtcexample/WebRTC.java b/app/src/main/java/com/nakadoribooks/webrtcexample/WebRTC.java
index a2103d1..9399788 100644
--- a/app/src/main/java/com/nakadoribooks/webrtcexample/WebRTC.java
+++ b/app/src/main/java/com/nakadoribooks/webrtcexample/WebRTC.java
@@ -3,7 +3,6 @@ package com.nakadoribooks.webrtcexample;
 import android.app.Activity;
 import android.content.Context;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.view.WindowManager;
 
 import org.webrtc.*;
@@ -20,6 +19,7 @@ public class WebRTC implements PeerConnection.Observer {
     public static interface WebRTCCallbacks{
         void onCreateLocalSdp(String sdp);
         void didReceiveRemoteStream();
+        void onIceCandidate(String sdp, String sdpMid, int sdpMLineIndex);
     }
 
     private static abstract class SkeletalSdpObserver implements SdpObserver{
@@ -80,6 +80,11 @@ public class WebRTC implements PeerConnection.Observer {
         _receiveAnswer(sdp);
     }
 
+    void addIceCandidate(String sdp, String sdpMid, int sdpMLineIndex){
+        IceCandidate iceCandidate = new IceCandidate(sdpMid, sdpMLineIndex, sdp);
+        peerConnection.addIceCandidate(iceCandidate);
+    }
+
     // implements -------------
 
     private void setupPeerConnection(){
@@ -117,8 +122,15 @@ public class WebRTC implements PeerConnection.Observer {
                 // createAnswer
                 peerConnection.createAnswer(new SkeletalSdpObserver() {
                     @Override
-                    public void onCreateSuccess(SessionDescription sessionDescription) {
-                        peerConnection.setLocalDescription(new SkeletalSdpObserver() {}, sessionDescription);
+                    public void onCreateSuccess(final SessionDescription sessionDescription) {
+                        peerConnection.setLocalDescription(new SkeletalSdpObserver() {
+
+                            @Override
+                            public void onSetSuccess() {
+                                callbacks.onCreateLocalSdp(sessionDescription.description);
+                            }
+
+                        }, sessionDescription);
                     }
                 }, WebRTCUtil.answerConnectionConstraints());
 
@@ -129,8 +141,15 @@ public class WebRTC implements PeerConnection.Observer {
     private void _createOffer(){
         peerConnection.createOffer(new SkeletalSdpObserver() {
             @Override
-            public void onCreateSuccess(SessionDescription sessionDescription) {
-                peerConnection.setLocalDescription(new SkeletalSdpObserver() {}, sessionDescription);
+            public void onCreateSuccess(final SessionDescription sessionDescription) {
+                peerConnection.setLocalDescription(new SkeletalSdpObserver() {
+
+                    @Override
+                    public void onSetSuccess() {
+                        callbacks.onCreateLocalSdp(sessionDescription.description);
+                    }
+
+                }, sessionDescription);
             }
         }, WebRTCUtil.offerConnectionConstraints());
     }
@@ -214,18 +233,13 @@ public class WebRTC implements PeerConnection.Observer {
     @Override
     public void onAddTrack(RtpReceiver rtpReceiver, MediaStream[] mediaStreams) {}
     @Override
-    public void onIceCandidate(IceCandidate iceCandidate) {}
-    @Override
     public void onIceCandidatesRemoved(IceCandidate[] iceCandidates) {}
+    @Override
+    public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {}
 
     @Override
-    public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
-        Log.d(TAG, "onIceGatheringChange");
-        if(iceGatheringState == PeerConnection.IceGatheringState.COMPLETE){
-            Log.d(TAG, "Complete");
-            SessionDescription localSdp = peerConnection.getLocalDescription();
-            callbacks.onCreateLocalSdp(localSdp.description);
-        }
+    public void onIceCandidate(IceCandidate iceCandidate) {
+        callbacks.onIceCandidate(iceCandidate.sdp, iceCandidate.sdpMid, iceCandidate.sdpMLineIndex);
     }
 
     @Override
diff --git a/libraries/Android-wamp-client b/libraries/Android-wamp-client
--- a/libraries/Android-wamp-client
+++ b/libraries/Android-wamp-client
@@ -1 +1 @@
-Subproject commit 41c885326943177281ff3e835fc07fa9fe1c3fcf
+Subproject commit 41c885326943177281ff3e835fc07fa9fe1c3fcf-dirty

```

# CHILL OUT

http://butfirstchillout.com/
情報過多、ストレス増大している昨今。
必要なものは「エナジー」ではなく、「リラクゼーション」。
あなたの「安らぎ」と「パフォーマンス」をサポートする
次世代リラクゼーションドリンク


# 次

ブラウザ。