Reland the CL to remove candidates when doing continual gathering

When doing candidate re-gathering in the same ICE generation, signal the remote side to remove its remote candidates.

Fixed the pure virtual method in jsep.h

BUG=
R=glaznev@webrtc.org, pthatcher@webrtc.org

Review URL: https://codereview.webrtc.org/1788703003 .

Cr-Commit-Position: refs/heads/master@{#11985}
This commit is contained in:
Honghai Zhang
2016-03-14 11:59:18 -07:00
parent 1122dc0d9b
commit 7fb69db670
35 changed files with 711 additions and 94 deletions

View File

@ -58,6 +58,11 @@ public interface AppRTCClient {
*/
public void sendLocalIceCandidate(final IceCandidate candidate);
/**
* Send removed ICE candidates to the other participant.
*/
public void sendLocalIceCandidateRemovals(final IceCandidate[] candidates);
/**
* Disconnect from room.
*/
@ -112,6 +117,11 @@ public interface AppRTCClient {
*/
public void onRemoteIceCandidate(final IceCandidate candidate);
/**
* Callback fired once remote Ice candidate removals are received.
*/
public void onRemoteIceCandidatesRemoved(final IceCandidate[] candidates);
/**
* Callback fired once channel is closed.
*/

View File

@ -558,8 +558,7 @@ public class CallActivity extends Activity
@Override
public void run() {
if (peerConnectionClient == null) {
Log.e(TAG,
"Received ICE candidate for non-initilized peer connection.");
Log.e(TAG, "Received ICE candidate for a non-initialized peer connection.");
return;
}
peerConnectionClient.addRemoteIceCandidate(candidate);
@ -567,6 +566,20 @@ public class CallActivity extends Activity
});
}
@Override
public void onRemoteIceCandidatesRemoved(final IceCandidate[] candidates) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (peerConnectionClient == null) {
Log.e(TAG, "Received ICE candidate removals for a non-initialized peer connection.");
return;
}
peerConnectionClient.removeRemoteIceCandidates(candidates);
}
});
}
@Override
public void onChannelClose() {
runOnUiThread(new Runnable() {
@ -617,6 +630,18 @@ public class CallActivity extends Activity
});
}
@Override
public void onIceCandidatesRemoved(final IceCandidate[] candidates) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (appRtcClient != null) {
appRtcClient.sendLocalIceCandidateRemovals(candidates);
}
}
});
}
@Override
public void onIceConnected() {
final long delta = System.currentTimeMillis() - callStartedTimeMs;

View File

@ -183,6 +183,11 @@ public class PeerConnectionClient {
*/
public void onIceCandidate(final IceCandidate candidate);
/**
* Callback fired once local ICE candidates are removed.
*/
public void onIceCandidatesRemoved(final IceCandidate[] candidates);
/**
* Callback fired once connection is established (IceConnectionState is
* CONNECTED).
@ -655,6 +660,21 @@ public class PeerConnectionClient {
});
}
public void removeRemoteIceCandidates(final IceCandidate[] candidates) {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection == null || isError) {
return;
}
// Drain the queued remote candidates if there is any so that
// they are processed in the proper order.
drainCandidates();
peerConnection.removeIceCandidates(candidates);
}
});
}
public void setRemoteDescription(final SessionDescription sdp) {
executor.execute(new Runnable() {
@Override
@ -923,6 +943,16 @@ public class PeerConnectionClient {
});
}
@Override
public void onIceCandidatesRemoved(final IceCandidate[] candidates) {
executor.execute(new Runnable() {
@Override
public void run() {
events.onIceCandidatesRemoved(candidates);
}
});
}
@Override
public void onSignalingChange(
PeerConnection.SignalingState newState) {

View File

@ -19,6 +19,7 @@ import org.appspot.apprtc.util.LooperExecutor;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.IceCandidate;
@ -252,6 +253,37 @@ public class WebSocketRTCClient implements AppRTCClient,
});
}
// Send removed Ice candidates to the other participant.
@Override
public void sendLocalIceCandidateRemovals(final IceCandidate[] candidates) {
executor.execute(new Runnable() {
@Override
public void run() {
JSONObject json = new JSONObject();
jsonPut(json, "type", "remove-candidates");
JSONArray jsonArray = new JSONArray();
for (final IceCandidate candidate : candidates) {
jsonArray.put(toJsonCandidate(candidate));
}
jsonPut(json, "candidates", jsonArray);
if (initiator) {
// Call initiator sends ice candidates to GAE server.
if (roomState != ConnectionState.CONNECTED) {
reportError("Sending ICE candidate removals in non connected state.");
return;
}
sendPostMessage(MessageType.MESSAGE, messageUrl, json.toString());
if (connectionParameters.loopback) {
events.onRemoteIceCandidatesRemoved(candidates);
}
} else {
// Call receiver sends ice candidates to websocket server.
wsClient.send(json.toString());
}
}
});
}
// --------------------------------------------------------------------
// WebSocketChannelEvents interface implementation.
// All events are called by WebSocketChannelClient on a local looper thread
@ -270,11 +302,14 @@ public class WebSocketRTCClient implements AppRTCClient,
json = new JSONObject(msgText);
String type = json.optString("type");
if (type.equals("candidate")) {
IceCandidate candidate = new IceCandidate(
json.getString("id"),
json.getInt("label"),
json.getString("candidate"));
events.onRemoteIceCandidate(candidate);
events.onRemoteIceCandidate(toJavaCandidate(json));
} else if (type.equals("remove-candidates")) {
JSONArray candidateArray = json.getJSONArray("candidates");
IceCandidate[] candidates = new IceCandidate[candidateArray.length()];
for (int i =0; i < candidateArray.length(); ++i) {
candidates[i] = toJavaCandidate(candidateArray.getJSONObject(i));
}
events.onRemoteIceCandidatesRemoved(candidates);
} else if (type.equals("answer")) {
if (initiator) {
SessionDescription sdp = new SessionDescription(
@ -376,4 +411,20 @@ public class WebSocketRTCClient implements AppRTCClient,
});
httpConnection.send();
}
// Converts a Java candidate to a JSONObject.
private JSONObject toJsonCandidate(final IceCandidate candidate) {
JSONObject json = new JSONObject();
jsonPut(json, "label", candidate.sdpMLineIndex);
jsonPut(json, "id", candidate.sdpMid);
jsonPut(json, "candidate", candidate.sdp);
return json;
}
// Converts a JSON candidate to a Java object.
IceCandidate toJavaCandidate(JSONObject json) throws JSONException {
return new IceCandidate(json.getString("id"),
json.getInt("label"),
json.getString("candidate"));
}
}