Index: components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServerSession.java |
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServerSession.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServerSession.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..90c8b34fb6ab17ea0e84d9c4bc1097ee63d36d3b |
--- /dev/null |
+++ b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/ServerSession.java |
@@ -0,0 +1,178 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.components.devtools_bridge; |
+ |
+import java.util.List; |
+ |
+/** |
+ * DevTools Bridge server session. Handles connection with a ClientSession. |
+ * See SessionBase description for more detais. |
+ */ |
+public class ServerSession extends SessionBase implements SessionBase.ServerSessionInterface { |
+ private NegotiationCallback mNegotiationCallback; |
+ private IceExchangeCallback mIceExchangeCallback; |
+ private boolean mIceEchangeRequested = false; |
+ |
+ protected int mGatheringDelayMs = 200; |
+ |
+ public ServerSession(SessionDependencyFactory factory, |
+ Executor executor, |
+ String defaultSocketName) { |
+ super(factory, executor, new SocketTunnelServer(defaultSocketName)); |
+ } |
+ |
+ @Override |
+ public void stop() { |
+ super.stop(); |
+ if (mNegotiationCallback != null) { |
+ mNegotiationCallback.onFailure("Session stopped"); |
+ mNegotiationCallback = null; |
+ } |
+ if (mIceExchangeCallback != null) { |
+ mIceExchangeCallback.onFailure("Session stopped"); |
+ mIceExchangeCallback = null; |
+ } |
+ } |
+ |
+ @Override |
+ public void startSession(RTCConfiguration config, |
+ String offer, |
+ NegotiationCallback callback) { |
+ checkCalledOnSessionThread(); |
+ if (isStarted()) { |
+ callback.onFailure("Session already started"); |
+ return; |
+ } |
+ |
+ ClientMessageHandler handler = new ClientMessageHandler(); |
+ start(config, handler); |
+ |
+ negotiate(offer, callback); |
+ } |
+ |
+ @Override |
+ public void renegotiate(String offer, NegotiationCallback callback) { |
+ checkCalledOnSessionThread(); |
+ if (!isStarted()) { |
+ callback.onFailure("Session is not started"); |
+ return; |
+ } |
+ |
+ callback.onFailure("Not implemented"); |
+ } |
+ |
+ private void negotiate(String offer, NegotiationCallback callback) { |
+ if (mNegotiationCallback != null) { |
+ callback.onFailure("Negotiation already in progress"); |
+ return; |
+ } |
+ |
+ mNegotiationCallback = callback; |
+ // If success will call onRemoteDescriptionSet. |
+ connection().setRemoteDescription( |
+ AbstractPeerConnection.SessionDescriptionType.OFFER, offer); |
+ } |
+ |
+ protected void onRemoteDescriptionSet() { |
+ // If success will call onLocalDescriptionCreatedAndSet. |
+ connection().createAndSetLocalDescription( |
+ AbstractPeerConnection.SessionDescriptionType.ANSWER); |
+ } |
+ |
+ @Override |
+ protected void onLocalDescriptionCreatedAndSet( |
+ AbstractPeerConnection.SessionDescriptionType type, String description) { |
+ assert type == AbstractPeerConnection.SessionDescriptionType.ANSWER; |
+ |
+ mNegotiationCallback.onSuccess(description); |
+ mNegotiationCallback = null; |
+ onSessionNegotiated(); |
+ } |
+ |
+ protected void onSessionNegotiated() { |
+ if (!isControlChannelOpened()) |
+ startAutoCloseTimer(); |
+ } |
+ |
+ @Override |
+ public void iceExchange(List<String> clientCandidates, |
+ IceExchangeCallback callback) { |
+ checkCalledOnSessionThread(); |
+ if (!isStarted()) { |
+ callback.onFailure("Session disposed"); |
+ return; |
+ } |
+ |
+ if (mNegotiationCallback != null || mIceExchangeCallback != null) { |
+ callback.onFailure("Concurrent requests detected"); |
+ return; |
+ } |
+ |
+ mIceExchangeCallback = callback; |
+ addIceCandidates(clientCandidates); |
+ |
+ // Give libjingle some time for gathering ice candidates. |
+ postOnSessionThread(mGatheringDelayMs, new Runnable() { |
+ @Override |
+ public void run() { |
+ if (isStarted()) |
+ sendIceCandidatesBack(); |
+ } |
+ }); |
+ } |
+ |
+ private void sendIceCandidatesBack() { |
+ mIceExchangeCallback.onSuccess(takeIceCandidates()); |
+ mIceExchangeCallback = null; |
+ mIceEchangeRequested = false; |
+ } |
+ |
+ @Override |
+ protected void onControlChannelOpened() { |
+ stopAutoCloseTimer(); |
+ } |
+ |
+ @Override |
+ protected void onFailure(String message) { |
+ if (mNegotiationCallback != null) { |
+ mNegotiationCallback.onFailure(message); |
+ mNegotiationCallback = null; |
+ } |
+ super.onFailure(message); |
+ } |
+ |
+ @Override |
+ protected void onIceCandidate(String candidate) { |
+ super.onIceCandidate(candidate); |
+ if (isControlChannelOpened() && !mIceEchangeRequested) { |
+ // New ICE candidate may improve connection even if control channel operable. |
+ // If control channel closed client will exchange candidates anyway. |
+ sendControlMessage(new SessionControlMessages.IceExchangeMessage()); |
+ mIceEchangeRequested = true; |
+ } |
+ } |
+ |
+ protected SocketTunnelServer createSocketTunnelServer(String serverSocketName) { |
+ return new SocketTunnelServer(serverSocketName); |
+ } |
+ |
+ private final class ClientMessageHandler extends SessionControlMessages.ClientMessageHandler { |
+ @Override |
+ protected void onMessage(SessionControlMessages.ClientMessage message) { |
+ switch (message.type) { |
+ case UNKNOWN_REQUEST: |
+ sendControlMessage(((SessionControlMessages.UnknownRequestMessage) message) |
+ .createResponse()); |
+ break; |
+ } |
+ } |
+ } |
+ |
+ @Override |
+ protected void sendControlMessage(SessionControlMessages.Message<?> message) { |
+ assert message instanceof SessionControlMessages.ServerMessage; |
+ super.sendControlMessage(message); |
+ } |
+} |