Как добавить icecandidate в sdp?
Сервер требует наличие icecandidatte в sdp. Но когда я отправляю sdp, в нем нет icecandidate. Cразу после отправки sdp я вижу сформированные icecandidate. Не могу понять, как поменять код, чтобы icecandidate отправлялись в sdp. Далее прилагаю код основной активити и sdp:
public class MainActivity extends AppCompatActivity {
private final int MY_PERMISSIONS_REQUEST_CAMERA = 100;
private final int MY_PERMISSIONS_REQUEST_RECORD_AUDIO = 101;
private final int MY_PERMISSIONS_REQUEST = 102;
public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
private PeerConnection localPeer, remotePeer;
private PeerConnectionFactory peerConnectionFactory;
private VideoRenderer remoteRenderer;
private VideoTrack localVideoTrack;
private String socketAddress = "http://193.XXX.XX.XX:XXXXX/offer";
private OkHttpClient webSocket1;
private WebSocket ws1;
private OkHttpClient webSocket2;
private WebSocket ws2;
EglBase rootEglBase;
@BindView(R.id.start_call)
Button start_call;
@BindView(R.id.init_call)
Button init_call;
@BindView(R.id.end_call)
Button end_call;
@BindView(R.id.remote_gl_surface_view)
SurfaceViewRenderer remoteVideoView;
@BindView(R.id.local_gl_surface_view)
SurfaceViewRenderer localVideoView;
private enum MessageType { MESSAGE, LEAVE }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
askForPermissions();
ButterKnife.bind(this);
}
public void setRemoteDescription(SessionDescription sessionDescription) {
localPeer.setRemoteDescription(new CustomSdpObserver("localSetRemoteDesc"), sessionDescription);
}
public void askForPermissions() {
if ((ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) &&
(ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO},
MY_PERMISSIONS_REQUEST);
} else if (ContextCompat.checkSelfPermission(this,
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO},
MY_PERMISSIONS_REQUEST_RECORD_AUDIO);
} else if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
MY_PERMISSIONS_REQUEST_CAMERA);
}
}
public void start(View view) throws JSONException {
start_call.setEnabled(false);
init_call.setEnabled(true);
localVideoView.setMirror(true);
remoteVideoView.setMirror(true);
EglBase rootEglBase = EglBase.create();
localVideoView.init(rootEglBase.getEglBaseContext(), null);
localVideoView.setZOrderMediaOverlay(true);
remoteVideoView.init(rootEglBase.getEglBaseContext(), null);
remoteVideoView.setZOrderMediaOverlay(true);
PeerConnectionFactory.InitializationOptions initializationOptions =
PeerConnectionFactory.InitializationOptions.builder(this)
.createInitializationOptions();
PeerConnectionFactory.initialize(initializationOptions);
//Create a new PeerConnectionFactory instance - using Hardware encoder and decoder.
PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
DefaultVideoEncoderFactory defaultVideoEncoderFactory = new DefaultVideoEncoderFactory(
rootEglBase.getEglBaseContext(), /* enableIntelVp8Encoder */false, /* enableH264HighProfile */true);
DefaultVideoDecoderFactory defaultVideoDecoderFactory = new DefaultVideoDecoderFactory(rootEglBase.getEglBaseContext());
peerConnectionFactory = PeerConnectionFactory.builder()
.setOptions(options)
.setVideoEncoderFactory(defaultVideoEncoderFactory)
.setVideoDecoderFactory(defaultVideoDecoderFactory)
.createPeerConnectionFactory();
VideoCapturer videoGrabberAndroid = createVideoGrabber();
VideoSource videoSource = peerConnectionFactory.createVideoSource(videoGrabberAndroid);
localVideoTrack =
peerConnectionFactory.createVideoTrack("100", videoSource);
videoGrabberAndroid.startCapture(1000, 1000, 30);
final VideoRenderer localRenderer = new VideoRenderer(localVideoView);
localVideoTrack.addRenderer(localRenderer);
MediaConstraints sdpConstraints = new MediaConstraints();
sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("offerToReceiveVideo", "true"));
createLocalPeerConnection(sdpConstraints);
createLocalSocket();
MediaStream stream = peerConnectionFactory.createLocalMediaStream("PIFXfZsA0IWyPxA3kFprHM6dGzVM9lM6aQjq");
stream.addTrack(localVideoTrack);
localPeer.addStream(stream);
createLocalOffer(sdpConstraints);
}
public void createLocalPeerConnection(MediaConstraints sdpConstraints) {
final List<PeerConnection.IceServer> iceServers = new ArrayList<>();
PeerConnection.IceServer peerIceServer = PeerConnection.IceServer.builder("turn:XXXXXXX=udp")
.setUsername("sXXXXXXXXXXXXXXXXXXXXX=")
.setPassword("XXXXXXXXXXXXXXXXXXXXXX")
.createIceServer();
iceServers.add(peerIceServer);
localPeer = peerConnectionFactory.createPeerConnection(iceServers, sdpConstraints, new CustomPeerConnectionObserver("localPeerCreation") {
@Override
public void onIceCandidate(IceCandidate iceCandidate) {
super.onIceCandidate(iceCandidate);
try {
JSONObject json = new JSONObject();
json.put("type", "candidate");
json.put("candidate", iceCandidate.sdp);
json.put("video_transform", "mask");
json.put("exercise_id", "2");
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
public void createLocalSocket() {
Request request = new Request.Builder()
.url(socketAddress)
.build();
AsyncHttpURLConnection listener =
new AsyncHttpURLConnection("POST", socketAddress, localPeer.toString(), new AsyncHttpURLConnection.AsyncHttpEvents() {
@Override
public void onHttpError(String errorMessage) {
}
@Override
public void onHttpComplete(String response) {
try {
JSONObject roomJson = new JSONObject(response);
String result = roomJson.getString("COMPLETE");
ws2.send(roomJson.toString());
if (!result.equals("SUCCESS")) {
}
} catch (JSONException e) {
return;
}
}
});
listener.send();
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
webSocket1 = okHttpClientBuilder.build();
ws1 = webSocket1.newWebSocket(request, listener);
webSocket1.dispatcher().executorService().shutdown();
}
public void call(View view) {
start_call.setEnabled(false);
init_call.setEnabled(false);
end_call.setEnabled(true);
createRemotePeerConnection();
createRemoteSocket();
}
public void createRemotePeerConnection() {
final List<PeerConnection.IceServer> iceServers = new ArrayList<>();
PeerConnection.IceServer
iceServer = PeerConnection.IceServer.builder("turnXXXXXXX=udp")
.setUsername("XXXXXXXXXXXXXXXXXXXX")
.setPassword("XXXXXXXXXXXXXXXXXX")
.createIceServer();
iceServers.add(iceServer);
MediaConstraints sdpConstraints = new MediaConstraints();
sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("offerToReceiveVideo", "true"));
remotePeer = peerConnectionFactory.createPeerConnection(iceServers, sdpConstraints, new CustomPeerConnectionObserver("remotePeerCreation") {
@Override
public void onIceCandidate(IceCandidate iceCandidate) {
super.onIceCandidate(iceCandidate);
try {
JSONObject json = new JSONObject();
json.put("type", "candidate");
json.put("id", iceCandidate.sdpMid);
json.put("candidate", iceCandidate.sdp);
} catch (JSONException e) {
e.printStackTrace();
}
}
public void onAddStream(MediaStream mediaStream) {
super.onAddStream(mediaStream);
gotRemoteStream(mediaStream);
}
@Override
public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
super.onIceGatheringChange(iceGatheringState);
}
});
}
public void createLocalOffer(MediaConstraints sdpConstraints) {
localPeer.createOffer(new CustomSdpObserver("localCreateOffer") {
@Override
public void onCreateSuccess(SessionDescription sessionDescription) {
super.onCreateSuccess(sessionDescription);
localPeer.setLocalDescription(new CustomSdpObserver("localSetLocalDesc"), sessionDescription);
try {
Map<String, String> sdp = new HashMap<>();
sdp.put("desc", sessionDescription.description);
JSONObject json = new JSONObject();
json.put("sdp", sessionDescription.description);
json.put("type", sessionDescription.type);
json.put("video_transform", "mask");
json.put("exercise_id", "5");
sendPostMessage(MessageType.MESSAGE, socketAddress, sdp.toString());
sendPostMessage(MessageType.MESSAGE, socketAddress, json.toString());
JSONObject json1 = new JSONObject();
json1.put("start", "true");
sendPostMessage(MessageType.MESSAGE, socketAddress, json1.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
}, sdpConstraints);
}
public void createRemoteSocket() {
Request request = new Request.Builder().url(socketAddress).build();
AsyncHttpURLConnection listener =
new AsyncHttpURLConnection("POST", socketAddress, remotePeer.toString(), new AsyncHttpURLConnection.AsyncHttpEvents() {
@Override
public void onHttpError(String errorMessage) {
}
@Override
public void onHttpComplete(String response) {
try {
JSONObject roomJson = new JSONObject(response);
String result = roomJson.getString("COMPLETE");
ws2.send(roomJson.toString());
if (!result.equals("SUCCESS")) {
}
} catch (JSONException e) {
return;
}
}
});
listener.send();
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
webSocket2 = okHttpClientBuilder.build();
ws2 = webSocket2.newWebSocket(request, listener);
listener.setWebSocket(ws2);
webSocket2.dispatcher().executorService().shutdown();
}
public void hangup(View view) {
ws1.send("bye");
ws2.send("bye");
localPeer.close();
remotePeer.close();
localPeer = null;
remotePeer = null;
start_call.setEnabled(true);
init_call.setEnabled(false);
end_call.setEnabled(false);
}
public VideoCapturer createVideoGrabber() {
VideoCapturer videoCapturer;
videoCapturer = createCameraGrabber(new Camera1Enumerator(false));
return videoCapturer;
}
public VideoCapturer createCameraGrabber(CameraEnumerator enumerator) {
final String[] deviceNames = enumerator.getDeviceNames();
for (String deviceName : deviceNames) {
if (enumerator.isFrontFacing(deviceName)) {
VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
if (videoCapturer != null) {
return videoCapturer;
}
}
}
for (String deviceName : deviceNames) {
if (!enumerator.isFrontFacing(deviceName)) {
VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
if (videoCapturer != null) {
return videoCapturer;
}
}
}
return null;
}
private void gotRemoteStream(MediaStream stream) {
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
remoteRenderer = new VideoRenderer(remoteVideoView);
remoteVideoView.setVisibility(View.VISIBLE);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void sendPostMessage(
final MessageType messageType, final String url, @Nullable final String message) {
String logInfo = url;
if (message != null) {
logInfo += ". Message: " + message;
}
Log.d(TAG, "C->GAE: " + logInfo);
AsyncHttpURLConnection httpConnection =
new AsyncHttpURLConnection("POST", url, message, new AsyncHttpURLConnection.AsyncHttpEvents() {
@Override
public void onHttpError(String errorMessage) {
Log.d(TAG, "C<-GAE: " + errorMessage);
}
@Override
public void
onHttpComplete(String response) {
if (messageType == MessageType.MESSAGE) {
try {
JSONObject roomJson = new JSONObject(response);
Log.d(TAG, "C<-GAE: " + roomJson);
String result = roomJson.getString("complete");
ws2.send(roomJson.toString());
if (!result.equals("SUCCESS")) {
}
} catch (JSONException e) {
return;
}
}
}
});
httpConnection.send();
}
}
SDP, который я отправляю:
{ v=0
o=- 5019693990448584856 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE video
a=msid-semantic: WMS PIFXfZsA0IWyPxA3kFprHM6dGzVM9lM6aQjq
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 127
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:4wF2
a=ice-pwd:6OUJcsZSraUSzOifM28FUvIX
a=ice-options:trickle renomination
a=fingerprint:sha-256 8B:1B:C0:15:96:9B:B2:FA:F5:C7:3E:05:B6:EB:A7:10:A1:85:35:B8:A4:40:E6:54:C1:40:80:EA:1B:8E:12:F0
a=setup:actpass
a=mid:video
a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:4 urn:3gpp:video-orientation
a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=sendrecv
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtpmap:98 VP9/90000
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtpmap:100 red/90000
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtpmap:127 ulpfec/90000
a=ssrc-group:FID 2141423954 286339792
a=ssrc:2141423954 cname:Ove/zZBrf3D1xV56
a=ssrc:2141423954 msid:PIFXfZsA0IWyPxA3kFprHM6dGzVM9lM6aQjq 100
a=ssrc:2141423954 mslabel:PIFXfZsA0IWyPxA3kFprHM6dGzVM9lM6aQjq
a=ssrc:2141423954 label:100
a=ssrc:286339792 cname:Ove/zZBrf3D1xV56
a=ssrc:286339792 msid:PIFXfZsA0IWyPxA3kFprHM6dGzVM9lM6aQjq 100
a=ssrc:286339792 mslabel:PIFXfZsA0IWyPxA3kFprHM6dGzVM9lM6aQjq
a=ssrc:286339792 label:100
}