use of org.matrix.androidsdk.rest.model.Event 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);
}
}
use of org.matrix.androidsdk.rest.model.Event in project matrix-android-sdk by matrix-org.
the class MXWebRtcCall method sendInvite.
/**
* Send the invite event
*
* @param sessionDescription the session description.
*/
private void sendInvite(final SessionDescription sessionDescription) {
// check if the call has not been killed
if (isCallEnded()) {
Log.d(LOG_TAG, "## sendInvite(): isCallEnded");
return;
}
Log.d(LOG_TAG, "## sendInvite()");
// build the invitation event
JsonObject inviteContent = new JsonObject();
inviteContent.addProperty("version", 0);
inviteContent.addProperty("call_id", mCallId);
inviteContent.addProperty("lifetime", CALL_TIMEOUT_MS);
JsonObject offerContent = new JsonObject();
offerContent.addProperty("sdp", sessionDescription.description);
offerContent.addProperty("type", sessionDescription.type.canonicalForm());
inviteContent.add("offer", offerContent);
Event event = new Event(Event.EVENT_TYPE_CALL_INVITE, inviteContent, mSession.getCredentials().userId, mCallSignalingRoom.getRoomId());
mPendingEvents.add(event);
try {
mCallTimeoutTimer = new Timer();
mCallTimeoutTimer.schedule(new TimerTask() {
@Override
public void run() {
try {
if (getCallState().equals(IMXCall.CALL_STATE_RINGING) || getCallState().equals(IMXCall.CALL_STATE_INVITE_SENT)) {
Log.d(LOG_TAG, "sendInvite : CALL_ERROR_USER_NOT_RESPONDING");
dispatchOnCallError(CALL_ERROR_USER_NOT_RESPONDING);
hangup(null);
}
// cancel the timer
mCallTimeoutTimer.cancel();
mCallTimeoutTimer = null;
} catch (Exception e) {
Log.e(LOG_TAG, "## sendInvite(): Exception Msg= " + e.getMessage());
}
}
}, CALL_TIMEOUT_MS);
} catch (Throwable throwable) {
Log.e(LOG_TAG, "## sendInvite(): failed " + throwable.getMessage());
if (null != mCallTimeoutTimer) {
mCallTimeoutTimer.cancel();
mCallTimeoutTimer = null;
}
}
sendNextEvent();
}
use of org.matrix.androidsdk.rest.model.Event in project matrix-android-sdk by matrix-org.
the class MXWebRtcCall method sendAnswer.
/**
* Send the answer event
*
* @param sessionDescription the session description
*/
private void sendAnswer(final SessionDescription sessionDescription) {
// check if the call has not been killed
if (isCallEnded()) {
Log.d(LOG_TAG, "sendAnswer isCallEnded");
return;
}
Log.d(LOG_TAG, "sendAnswer");
// build the invitation event
JsonObject answerContent = new JsonObject();
answerContent.addProperty("version", 0);
answerContent.addProperty("call_id", mCallId);
answerContent.addProperty("lifetime", CALL_TIMEOUT_MS);
JsonObject offerContent = new JsonObject();
offerContent.addProperty("sdp", sessionDescription.description);
offerContent.addProperty("type", sessionDescription.type.canonicalForm());
answerContent.add("answer", offerContent);
Event event = new Event(Event.EVENT_TYPE_CALL_ANSWER, answerContent, mSession.getCredentials().userId, mCallSignalingRoom.getRoomId());
mPendingEvents.add(event);
sendNextEvent();
mIsAnswered = true;
}
use of org.matrix.androidsdk.rest.model.Event in project matrix-android-sdk by matrix-org.
the class MXMegolmDecryption method addEventToPendingList.
/**
* Add an event to the list of those we couldn't decrypt the first time we
* saw them.
*
* @param event the event to try to decrypt later
* @param timelineId the timeline identifier
*/
private void addEventToPendingList(Event event, String timelineId) {
EncryptedEventContent encryptedEventContent = JsonUtils.toEncryptedEventContent(event.getWireContent().getAsJsonObject());
String senderKey = encryptedEventContent.sender_key;
String sessionId = encryptedEventContent.session_id;
String k = senderKey + "|" + sessionId;
// avoid undefined timelineId
if (TextUtils.isEmpty(timelineId)) {
timelineId = "";
}
if (!mPendingEvents.containsKey(k)) {
mPendingEvents.put(k, new HashMap<String, ArrayList<Event>>());
}
if (!mPendingEvents.get(k).containsKey(timelineId)) {
mPendingEvents.get(k).put(timelineId, new ArrayList<Event>());
}
if (mPendingEvents.get(k).get(timelineId).indexOf(event) < 0) {
Log.d(LOG_TAG, "## addEventToPendingList() : add Event " + event.eventId + " in room id " + event.roomId);
mPendingEvents.get(k).get(timelineId).add(event);
}
}
use of org.matrix.androidsdk.rest.model.Event in project matrix-android-sdk by matrix-org.
the class MXMemoryStore method eventsAfter.
/**
* Return a list of stored events after the parameter one.
* It could the ones sent by the user excludedUserId.
* A filter can be applied to ignore some event (Event.EVENT_TYPE_...).
*
* @param roomId the roomId
* @param eventId the start event Id.
* @param excludedUserId the excluded user id
* @param allowedTypes the filtered event type (null to allow anyone)
* @return the evnts list
*/
private List<Event> eventsAfter(String roomId, String eventId, String excludedUserId, List<String> allowedTypes) {
// events list
ArrayList<Event> events = new ArrayList<>();
// sanity check
if (null != roomId) {
synchronized (mRoomEventsLock) {
LinkedHashMap<String, Event> roomEvents = mRoomEvents.get(roomId);
if (roomEvents != null) {
List<Event> linkedEvents = new ArrayList<>(roomEvents.values());
// Check messages from the most recent
for (int i = linkedEvents.size() - 1; i >= 0; i--) {
Event event = linkedEvents.get(i);
if ((null == eventId) || !TextUtils.equals(event.eventId, eventId)) {
// Keep events matching filters
if ((null == allowedTypes || (allowedTypes.indexOf(event.getType()) >= 0)) && !TextUtils.equals(event.getSender(), excludedUserId)) {
events.add(event);
}
} else {
// We are done
break;
}
}
// some messages are not defined as unreadable
for (int index = 0; index < events.size(); index++) {
Event event = events.get(index);
if (TextUtils.equals(event.getSender(), mCredentials.userId) || TextUtils.equals(event.getType(), Event.EVENT_TYPE_STATE_ROOM_MEMBER)) {
events.remove(index);
index--;
}
}
Collections.reverse(events);
}
}
}
return events;
}
Aggregations