package im.actor.core.modules.calls;
import org.jetbrains.annotations.NotNull;
import im.actor.core.api.rpc.RequestDoCall;
import im.actor.core.api.rpc.RequestGetCallInfo;
import im.actor.core.api.rpc.RequestJoinCall;
import im.actor.core.api.rpc.RequestRejectCall;
import im.actor.core.entity.Peer;
import im.actor.core.modules.ModuleContext;
import im.actor.core.modules.calls.peers.AbsCallActor;
import im.actor.core.modules.calls.peers.CallBusActor;
import im.actor.core.viewmodel.CallState;
import im.actor.core.viewmodel.CallVM;
import im.actor.core.viewmodel.CommandCallback;
import im.actor.core.viewmodel.generics.ArrayListMediaTrack;
import im.actor.runtime.actors.messages.PoisonPill;
import im.actor.runtime.power.WakeLock;
import im.actor.runtime.webrtc.WebRTCMediaTrack;
import im.actor.runtime.webrtc.WebRTCTrackType;
import static im.actor.core.entity.EntityConverter.convert;
public class CallActor extends AbsCallActor {
private final boolean isMaster;
private final WakeLock wakeLock;
private long callId;
private Peer peer;
private CallVM callVM;
private CommandCallback<Long> callback;
private boolean isActive;
private boolean isAnswered;
private boolean isRejected;
private boolean isVideoInitiallyEnabled;
public CallActor(long callId, WakeLock wakeLock, ModuleContext context) {
super(context);
this.wakeLock = wakeLock;
this.isMaster = false;
this.callId = callId;
this.isAnswered = false;
this.isActive = false;
}
public CallActor(Peer peer, CommandCallback<Long> callback, WakeLock wakeLock, boolean isVideoInitiallyEnabled, ModuleContext context) {
super(context);
this.wakeLock = wakeLock;
this.isMaster = true;
this.callback = callback;
this.peer = peer;
this.isAnswered = true;
this.isActive = false;
this.isVideoInitiallyEnabled = isVideoInitiallyEnabled;
}
@Override
public void preStart() {
super.preStart();
if (isMaster) {
api(new RequestDoCall(buidOutPeer(peer), CallBusActor.TIMEOUT, false, false, isVideoInitiallyEnabled)).then(responseDoCall -> {
callId = responseDoCall.getCallId();
callBus.joinMasterBus(responseDoCall.getEventBusId(), responseDoCall.getDeviceId());
callBus.changeVideoEnabled(isVideoInitiallyEnabled);
callBus.startOwn();
callVM = callViewModels.spawnNewOutgoingVM(responseDoCall.getCallId(), peer, isVideoInitiallyEnabled,
isVideoInitiallyEnabled);
}).failure(e -> self().send(PoisonPill.INSTANCE));
} else {
api(new RequestGetCallInfo(callId)).then(responseGetCallInfo -> {
peer = convert(responseGetCallInfo.getPeer());
callBus.joinBus(responseGetCallInfo.getEventBusId());
if (responseGetCallInfo.isVideoPreferred() != null) {
isVideoInitiallyEnabled = responseGetCallInfo.isVideoPreferred();
callBus.changeVideoEnabled(isVideoInitiallyEnabled);
}
callVM = callViewModels.spawnNewIncomingVM(callId, peer, isVideoInitiallyEnabled,
isVideoInitiallyEnabled, CallState.RINGING);
}).failure(e -> self().send(PoisonPill.INSTANCE));
}
}
//
// Call lifecycle
//
@Override
public void onBusStarted(@NotNull String busId) {
if (isMaster) {
callManager.send(new CallManagerActor.DoCallComplete(callId), self());
callback.onResult(callId);
callback = null;
} else {
callManager.send(new CallManagerActor.IncomingCallReady(callId), self());
}
}
@Override
public void onCallConnected() {
// callVM.getState().change()
}
@Override
public void onCallEnabled() {
isActive = true;
if (isAnswered) {
callVM.getState().change(CallState.IN_PROGRESS);
callVM.setCallStart(im.actor.runtime.Runtime.getCurrentTime());
}
if (isMaster) {
callManager.send(new CallManagerActor.OnCallAnswered(callId), self());
}
}
public void onAnswerCall() {
if (!isAnswered && !isRejected) {
isAnswered = true;
callBus.startOwn();
request(new RequestJoinCall(callId));
if (isActive) {
callVM.getState().change(CallState.IN_PROGRESS);
callVM.setCallStart(im.actor.runtime.Runtime.getCurrentTime());
} else {
callVM.getState().change(CallState.CONNECTING);
}
}
}
public void onRejectCall() {
if (!isAnswered && !isRejected) {
isRejected = true;
request(new RequestRejectCall(callId));
self().send(PoisonPill.INSTANCE);
}
}
@Override
public void onBusStopped() {
self().send(PoisonPill.INSTANCE);
}
//
// Track Events
//
@Override
public void onTrackAdded(long deviceId, WebRTCMediaTrack track) {
if (track.getTrackType() == WebRTCTrackType.AUDIO) {
ArrayListMediaTrack tracks = new ArrayListMediaTrack(callVM.getTheirAudioTracks().get());
tracks.add(track);
callVM.getTheirAudioTracks().change(tracks);
} else if (track.getTrackType() == WebRTCTrackType.VIDEO) {
ArrayListMediaTrack tracks = new ArrayListMediaTrack(callVM.getTheirVideoTracks().get());
tracks.add(track);
callVM.getTheirVideoTracks().change(tracks);
} else {
// Unknown track type
}
}
@Override
public void onTrackRemoved(long deviceId, WebRTCMediaTrack track) {
if (track.getTrackType() == WebRTCTrackType.AUDIO) {
ArrayListMediaTrack tracks = new ArrayListMediaTrack(callVM.getTheirAudioTracks().get());
tracks.remove(track);
callVM.getTheirAudioTracks().change(tracks);
} else if (track.getTrackType() == WebRTCTrackType.VIDEO) {
ArrayListMediaTrack tracks = new ArrayListMediaTrack(callVM.getTheirVideoTracks().get());
tracks.remove(track);
callVM.getTheirVideoTracks().change(tracks);
} else {
// Unknown track type
}
}
@Override
public void onOwnTrackAdded(WebRTCMediaTrack track) {
if (track.getTrackType() == WebRTCTrackType.AUDIO) {
ArrayListMediaTrack tracks = new ArrayListMediaTrack(callVM.getOwnAudioTracks().get());
tracks.add(track);
callVM.getOwnAudioTracks().change(tracks);
} else if (track.getTrackType() == WebRTCTrackType.VIDEO) {
ArrayListMediaTrack tracks = new ArrayListMediaTrack(callVM.getOwnVideoTracks().get());
tracks.add(track);
callVM.getOwnVideoTracks().change(tracks);
} else {
// Unknown track type
}
}
@Override
public void onOwnTrackRemoved(WebRTCMediaTrack track) {
if (track.getTrackType() == WebRTCTrackType.AUDIO) {
ArrayListMediaTrack tracks = new ArrayListMediaTrack(callVM.getOwnAudioTracks().get());
tracks.remove(track);
callVM.getOwnAudioTracks().change(tracks);
} else if (track.getTrackType() == WebRTCTrackType.VIDEO) {
ArrayListMediaTrack tracks = new ArrayListMediaTrack(callVM.getOwnVideoTracks().get());
tracks.remove(track);
callVM.getOwnVideoTracks().change(tracks);
} else {
// Unknown track type
}
}
@Override
public void onAudioEnableChanged(boolean enabled) {
super.onAudioEnableChanged(enabled);
callVM.getIsAudioEnabled().change(enabled);
}
@Override
public void onVideoEnableChanged(boolean enabled) {
super.onVideoEnableChanged(enabled);
callVM.getIsVideoEnabled().change(enabled);
}
//
// Cleanup
//
@Override
public void postStop() {
super.postStop();
if (callVM != null) {
callVM.getState().change(CallState.ENDED);
callVM.setCallEnd(im.actor.runtime.Runtime.getCurrentTime());
}
callBus.kill();
if (callId != 0) {
callManager.send(new CallManagerActor.OnCallEnded(callId), self());
}
wakeLock.releaseLock();
}
//
// Messages
//
@Override
public void onReceive(Object message) {
if (message instanceof AnswerCall) {
onAnswerCall();
} else if (message instanceof RejectCall) {
onRejectCall();
} else {
super.onReceive(message);
}
}
public static class AnswerCall {
}
public static class RejectCall {
}
}