use of org.webrtc.RtpReceiver in project matrix-android-sdk by matrix-org.
the class MXWebRtcCall method createLocalStream.
/**
* create the local stream
*/
private void createLocalStream() {
Log.d(LOG_TAG, "## createLocalStream(): IN");
// check there is at least one stream to start a call
if ((null == mLocalVideoTrack) && (null == mLocalAudioTrack)) {
Log.d(LOG_TAG, "## createLocalStream(): CALL_ERROR_CALL_INIT_FAILED");
dispatchOnCallError(CALL_ERROR_CALL_INIT_FAILED);
hangup("no_stream");
terminate(IMXCall.END_CALL_REASON_UNDEFINED);
return;
}
// create our local stream to add our audio and video tracks
mLocalMediaStream = mPeerConnectionFactory.createLocalMediaStream("ARDAMS");
// add video track to local stream
if (null != mLocalVideoTrack) {
mLocalMediaStream.addTrack(mLocalVideoTrack);
}
// add audio track to local stream
if (null != mLocalAudioTrack) {
mLocalMediaStream.addTrack(mLocalAudioTrack);
}
if (null != mFullScreenRTCView) {
mFullScreenRTCView.setStream(mLocalMediaStream);
mFullScreenRTCView.setVisibility(View.VISIBLE);
}
// build ICE servers list
ArrayList<PeerConnection.IceServer> iceServers = new ArrayList<>();
if (null != mTurnServer) {
try {
String username = null;
String password = null;
JsonObject object = mTurnServer.getAsJsonObject();
if (object.has("username")) {
username = object.get("username").getAsString();
}
if (object.has("password")) {
password = object.get("password").getAsString();
}
JsonArray uris = object.get("uris").getAsJsonArray();
for (int index = 0; index < uris.size(); index++) {
String url = uris.get(index).getAsString();
if ((null != username) && (null != password)) {
iceServers.add(new PeerConnection.IceServer(url, username, password));
} else {
iceServers.add(new PeerConnection.IceServer(url));
}
}
} catch (Exception e) {
Log.e(LOG_TAG, "## createLocalStream(): Exception in ICE servers list Msg=" + e.getMessage());
}
}
Log.d(LOG_TAG, "## createLocalStream(): " + iceServers.size() + " known ice servers");
// define at least on server
if (iceServers.isEmpty()) {
Log.d(LOG_TAG, "## createLocalStream(): use the default google server");
iceServers.add(new PeerConnection.IceServer("stun:stun.l.google.com:19302"));
}
// define constraints
MediaConstraints pcConstraints = new MediaConstraints();
pcConstraints.optional.add(new MediaConstraints.KeyValuePair("RtpDataChannels", "true"));
// start connecting to the other peer by creating the peer connection
mPeerConnection = mPeerConnectionFactory.createPeerConnection(iceServers, pcConstraints, new PeerConnection.Observer() {
@Override
public void onSignalingChange(PeerConnection.SignalingState signalingState) {
Log.d(LOG_TAG, "## mPeerConnection creation: onSignalingChange state=" + signalingState);
}
@Override
public void onIceConnectionChange(final PeerConnection.IceConnectionState iceConnectionState) {
Log.d(LOG_TAG, "## mPeerConnection creation: onIceConnectionChange " + iceConnectionState);
mUIThreadHandler.post(new Runnable() {
@Override
public void run() {
if (iceConnectionState == PeerConnection.IceConnectionState.CONNECTED) {
if ((null != mLocalVideoTrack) && mUsingLargeLocalRenderer && isVideo()) {
mLocalVideoTrack.setEnabled(false);
// the local attendee video is sent by the server among the others conference attendees.
if (!isConference()) {
// add local preview, only for 1:1 call
// mLocalVideoTrack.addRenderer(mSmallLocalRenderer);
mPipRTCView.setStream(mLocalMediaStream);
mPipRTCView.setVisibility(View.VISIBLE);
// to be able to display the avatar video above the large one
mPipRTCView.setZOrder(1);
}
mLocalVideoTrack.setEnabled(true);
mUsingLargeLocalRenderer = false;
mCallView.post(new Runnable() {
@Override
public void run() {
if (null != mCallView) {
mCallView.invalidate();
}
}
});
}
dispatchOnStateDidChange(IMXCall.CALL_STATE_CONNECTED);
} else /*else if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED) {
// TODO warn the user ?
hangup(null);
} else if (iceConnectionState == PeerConnection.IceConnectionState.CLOSED) {
// TODO warn the user ?
terminate();
}*/
if (iceConnectionState == PeerConnection.IceConnectionState.FAILED) {
dispatchOnCallError(CALL_ERROR_ICE_FAILED);
hangup("ice_failed");
}
}
});
}
@Override
public void onIceConnectionReceivingChange(boolean var1) {
Log.d(LOG_TAG, "## mPeerConnection creation: onIceConnectionReceivingChange " + var1);
}
@Override
public void onIceCandidatesRemoved(IceCandidate[] var1) {
Log.d(LOG_TAG, "## mPeerConnection creation: onIceCandidatesRemoved " + var1);
}
@Override
public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
Log.d(LOG_TAG, "## mPeerConnection creation: onIceGatheringChange " + iceGatheringState);
}
@Override
public void onAddTrack(RtpReceiver var1, MediaStream[] var2) {
Log.d(LOG_TAG, "## mPeerConnection creation: onAddTrack " + var1 + " -- " + var2);
}
@Override
public void onIceCandidate(final IceCandidate iceCandidate) {
Log.d(LOG_TAG, "## mPeerConnection creation: onIceCandidate " + iceCandidate);
mUIThreadHandler.post(new Runnable() {
@Override
public void run() {
if (!isCallEnded()) {
JsonObject content = new JsonObject();
content.addProperty("version", 0);
content.addProperty("call_id", mCallId);
JsonArray candidates = new JsonArray();
JsonObject cand = new JsonObject();
cand.addProperty("sdpMLineIndex", iceCandidate.sdpMLineIndex);
cand.addProperty("sdpMid", iceCandidate.sdpMid);
cand.addProperty("candidate", iceCandidate.sdp);
candidates.add(cand);
content.add("candidates", candidates);
boolean addIt = true;
// merge candidates
if (mPendingEvents.size() > 0) {
try {
Event lastEvent = mPendingEvents.get(mPendingEvents.size() - 1);
if (TextUtils.equals(lastEvent.getType(), Event.EVENT_TYPE_CALL_CANDIDATES)) {
// return the content cast as a JsonObject
// it is not a copy
JsonObject lastContent = lastEvent.getContentAsJsonObject();
JsonArray lastContentCandidates = lastContent.get("candidates").getAsJsonArray();
JsonArray newContentCandidates = content.get("candidates").getAsJsonArray();
Log.d(LOG_TAG, "Merge candidates from " + lastContentCandidates.size() + " to " + (lastContentCandidates.size() + newContentCandidates.size() + " items."));
lastContentCandidates.addAll(newContentCandidates);
// replace the candidates list
lastContent.remove("candidates");
lastContent.add("candidates", lastContentCandidates);
// don't need to save anything, lastContent is a reference not a copy
addIt = false;
}
} catch (Exception e) {
Log.e(LOG_TAG, "## createLocalStream(): createPeerConnection - onIceCandidate() Exception Msg=" + e.getMessage());
}
}
if (addIt) {
Event event = new Event(Event.EVENT_TYPE_CALL_CANDIDATES, content, mSession.getCredentials().userId, mCallSignalingRoom.getRoomId());
mPendingEvents.add(event);
sendNextEvent();
}
}
}
});
}
@Override
public void onAddStream(final MediaStream mediaStream) {
Log.d(LOG_TAG, "## mPeerConnection creation: onAddStream " + mediaStream);
mUIThreadHandler.post(new Runnable() {
@Override
public void run() {
if ((mediaStream.videoTracks.size() == 1) && !isCallEnded()) {
mRemoteVideoTrack = mediaStream.videoTracks.get(0);
mRemoteVideoTrack.setEnabled(true);
mFullScreenRTCView.setStream(mediaStream);
mFullScreenRTCView.setVisibility(View.VISIBLE);
}
}
});
}
@Override
public void onRemoveStream(final MediaStream mediaStream) {
Log.d(LOG_TAG, "## mPeerConnection creation: onRemoveStream " + mediaStream);
mUIThreadHandler.post(new Runnable() {
@Override
public void run() {
if (null != mRemoteVideoTrack) {
mRemoteVideoTrack.dispose();
mRemoteVideoTrack = null;
mediaStream.videoTracks.get(0).dispose();
}
}
});
}
@Override
public void onDataChannel(DataChannel dataChannel) {
Log.d(LOG_TAG, "## mPeerConnection creation: onDataChannel " + dataChannel);
}
@Override
public void onRenegotiationNeeded() {
Log.d(LOG_TAG, "## mPeerConnection creation: onRenegotiationNeeded");
}
});
if (null == mPeerConnection) {
dispatchOnCallError(CALL_ERROR_ICE_FAILED);
hangup("cannot create peer connection");
return;
}
// send our local video and audio stream to make it seen by the other part
mPeerConnection.addStream(mLocalMediaStream);
MediaConstraints constraints = new MediaConstraints();
constraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
constraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", isVideo() ? "true" : "false"));
// call createOffer only for outgoing calls
if (!isIncoming()) {
Log.d(LOG_TAG, "## createLocalStream(): !isIncoming() -> createOffer");
mPeerConnection.createOffer(new SdpObserver() {
@Override
public void onCreateSuccess(SessionDescription sessionDescription) {
Log.d(LOG_TAG, "createOffer onCreateSuccess");
final SessionDescription sdp = new SessionDescription(sessionDescription.type, sessionDescription.description);
mUIThreadHandler.post(new Runnable() {
@Override
public void run() {
if (mPeerConnection != null) {
// must be done to before sending the invitation message
mPeerConnection.setLocalDescription(new SdpObserver() {
@Override
public void onCreateSuccess(SessionDescription sessionDescription) {
Log.d(LOG_TAG, "setLocalDescription onCreateSuccess");
}
@Override
public void onSetSuccess() {
Log.d(LOG_TAG, "setLocalDescription onSetSuccess");
sendInvite(sdp);
dispatchOnStateDidChange(IMXCall.CALL_STATE_INVITE_SENT);
}
@Override
public void onCreateFailure(String s) {
Log.e(LOG_TAG, "setLocalDescription onCreateFailure " + s);
dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED);
hangup(null);
}
@Override
public void onSetFailure(String s) {
Log.e(LOG_TAG, "setLocalDescription onSetFailure " + s);
dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED);
hangup(null);
}
}, sdp);
}
}
});
}
@Override
public void onSetSuccess() {
Log.d(LOG_TAG, "createOffer onSetSuccess");
}
@Override
public void onCreateFailure(String s) {
Log.d(LOG_TAG, "createOffer onCreateFailure " + s);
dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED);
}
@Override
public void onSetFailure(String s) {
Log.d(LOG_TAG, "createOffer onSetFailure " + s);
dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED);
}
}, constraints);
dispatchOnStateDidChange(IMXCall.CALL_STATE_WAIT_CREATE_OFFER);
}
}
Aggregations