package com.shayu.onetoone.manager; import android.Manifest; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.text.TextUtils; import android.view.SurfaceView; import com.blankj.utilcode.util.PermissionUtils; import com.shayu.onetoone.AppContext; import com.shayu.onetoone.R; import com.shayu.onetoone.bean.SendConsumeBean; import com.shayu.onetoone.listener.OnCallStatusListener; import com.shayu.onetoone.listener.OnSendMessageListener; import com.yunbao.common.CommonAppContext; import com.yunbao.common.manager.IMLoginManager; import com.yunbao.common.utils.StringUtil; import com.yunbao.common.utils.ToastUtil; import com.yunbao.faceunity.FaceManager; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Timer; import java.util.TimerTask; import io.rong.callkit.util.CallKitUtils; import io.rong.calllib.CallUserProfile; import io.rong.calllib.IRongCallListener; import io.rong.calllib.IRongReceivedCallListener; import io.rong.calllib.RongCallClient; import io.rong.calllib.RongCallCommon; import io.rong.calllib.RongCallSession; import io.rong.calllib.StartCameraCallback; import io.rong.calllib.message.CallSTerminateMessage; import io.rong.common.RLog; import io.rong.imkit.IMCenter; import io.rong.imlib.RongIMClient; import io.rong.imlib.model.Conversation; public class CallClientManager { public static final String VIDEO_RECEIVED_CALL = "receivedVideoCall";//接听 public static final String VIDEO_CALL = "callVideo";//拨打 public static final String VIDEO_FLOAT = "videoFloatWindow";//浮窗 public static final String AUDIO_RECEIVED_CALL = "receivedAudioCall";//接听 public static final String AUDIO_CALL = "callAudio";//拨打 public static final String AUDIO_FLOAT = "audioFloatWindow";//浮窗 private static CallClientManager manager; private SurfaceView localVideo, remoteVideo; private List listeners; private CallTimeTask timeTask = null; public static CallClientManager getManager() { if (manager == null) { manager = new CallClientManager(); } return manager; } private CallClientManager() { listeners = new ArrayList<>(); init(); } public SurfaceView getLocalVideo() { return localVideo; } public SurfaceView getRemoteVideo() { if (RongCallClient.getInstance() != null) { for (CallUserProfile profile : RongCallClient.getInstance().getCallSession().getParticipantProfileList()) { if (!profile.getUserId().equals(IMLoginManager.get(AppContext.getTopActivity()).getUserInfo().getId() + "")) { return profile.getVideoView(); } } } return remoteVideo; } private void init() { RongCallClient.setReceivedCallListener(new CallMeListener()); } public void addOnVoIPCallListener(OnCallStatusListener statusListener) { listeners.add(statusListener); RongCallClient.getInstance().setVoIPCallListener(new CallStatusListener(new OnCallStatusListener() { @Override public void onCallWait(SurfaceView localVideo) { for (OnCallStatusListener listener : listeners) { listener.onCallWait(localVideo); } } @Override public void onCallStart(String userId, SurfaceView remoteVideo) { for (OnCallStatusListener listener : listeners) { listener.onCallStart(userId, remoteVideo); } startTimer(null); } @Override public void onCallEnd() { for (OnCallStatusListener listener : listeners) { listener.onCallEnd(); } endTimer(); } @Override public void onStartFirstFrame() { for (OnCallStatusListener listener : listeners) { listener.onStartFirstFrame(); } } })); } public void removeOnVoIPCallListener(OnCallStatusListener statusListener) { listeners.remove(statusListener); } public void checkMoney(String targetId, boolean video, OnSendMessageListener listener) { if (video) { SendMessageManager.checkVideoMessage(targetId, "1", listener); } else { SendMessageManager.checkAudioMessage(targetId, "1", listener); } } private void startTimer(String targetId) { if (timeTask != null) { timeTask.cancel(); } timeTask = new CallTimeTask(targetId); new Timer().schedule(timeTask, 0, 1000); } private void endTimer() { if (timeTask != null) { timeTask.cancel(); } timeTask = null; } public void callVideo(String targetId) { RongCallClient.getInstance().setVoIPCallListener(new CallStatusListener(new OnCallStatusListener() { @Override public void onCallWait(SurfaceView localVideo) { for (OnCallStatusListener listener : listeners) { listener.onCallWait(localVideo); } ToastUtil.show(R.string.call_tips1); } @Override public void onCallStart(String userId, SurfaceView remoteVideo) { for (OnCallStatusListener listener : listeners) { listener.onCallStart(userId, remoteVideo); } ToastUtil.show(R.string.call_tips2); startTimer(targetId); } @Override public void onCallEnd() { for (OnCallStatusListener listener : listeners) { listener.onCallEnd(); } endTimer(); } @Override public void onStartFirstFrame() { for (OnCallStatusListener listener : listeners) { listener.onStartFirstFrame(); } } })); List userIds = new ArrayList<>(); userIds.add(targetId); RongCallClient.getInstance().startCall(Conversation.ConversationType.PRIVATE, targetId, userIds, null, RongCallCommon.CallMediaType.VIDEO, null); } public void callAudio(String targetId) { RongCallClient.getInstance().setVoIPCallListener(new CallStatusListener(new OnCallStatusListener() { @Override public void onCallWait(SurfaceView localVideo) { for (OnCallStatusListener listener : listeners) { listener.onCallWait(localVideo); } ToastUtil.show(R.string.call_tips1); } @Override public void onCallStart(String userId, SurfaceView remoteVideo) { for (OnCallStatusListener listener : listeners) { listener.onCallStart(userId, remoteVideo); } ToastUtil.show(R.string.call_tips2); startTimer(targetId); } @Override public void onCallEnd() { for (OnCallStatusListener listener : listeners) { listener.onCallEnd(); } endTimer(); } @Override public void onStartFirstFrame() { for (OnCallStatusListener listener : listeners) { listener.onStartFirstFrame(); } } })); List userIds = new ArrayList<>(); userIds.add(targetId); RongCallClient.getInstance().startCall(Conversation.ConversationType.PRIVATE, targetId, userIds, null, RongCallCommon.CallMediaType.AUDIO, null); } public void acceptCall(String callId) { RongCallClient.getInstance().acceptCall(callId); } public void endCall() { if (RongCallClient.getInstance() != null && RongCallClient.getInstance().getCallSession() != null) { RongCallClient.getInstance().hangUpCall(RongCallClient.getInstance().getCallSession().getCallId()); } } public boolean isCalling() { return RongCallClient.getInstance() != null && RongCallClient.getInstance().getCallSession() != null; } public boolean isCallVideo(RongCallSession callSession) { return callSession.getMediaType().equals(RongCallCommon.CallMediaType.VIDEO); } public long getTime(long activeTime) { return activeTime == 0 ? 0 : (System.currentTimeMillis() - activeTime) / 1000; } private class CallTimeTask extends TimerTask { Handler handler = new Handler(Looper.getMainLooper()); private String targetId; private String sessionId; private boolean isCallVideo = false; long warningTime; long activeTime; public CallTimeTask(String targetId) { this.targetId = targetId; } @Override public boolean cancel() { if(sessionId.equals(targetId)){ System.err.println("接听方不计费 结束"); return super.cancel(); } long time = getTime(activeTime); time = time % 10; if (time == 0) { time = 10; } if (isCallVideo) { SendMessageManager.pingVideoMessage(targetId, time + "", new SendMessageListener()); } else { SendMessageManager.pingAudioMessage(targetId, time + "", new SendMessageListener()); } return super.cancel(); } @Override public void run() { RongCallSession callSession = RongCallClient.getInstance().getCallSession(); if (callSession == null) { cancel(); timeTask = null; return; } isCallVideo = callSession.getMediaType() == RongCallCommon.CallMediaType.VIDEO; activeTime = callSession.getActiveTime(); sessionId=callSession.getCallerUserId(); long time = getTime(activeTime); checkTime(time); String extra; if (time > 0) { if (time >= 3600) { extra = String.format( Locale.ROOT, "%d:%02d:%02d", time / 3600, (time % 3600) / 60, (time % 60)); } else { extra = String.format(Locale.ROOT, "%02d:%02d", (time % 3600) / 60, (time % 60)); } handler.post(() -> { for (OnCallStatusListener listener : listeners) { listener.onTime(extra); if (warningTime <= 60) { listener.onTimeWarning(warningTime--); } } }); } } private void checkTime(long time) { if (StringUtil.isEmpty(targetId)) { return; } if(sessionId.equals(targetId)){ System.err.println("接听方不计费"); return; } if(time==0){ return; } time = time % 10; if (time == 0) { time = 10; } else { return; } if (isCallVideo) { SendMessageManager.pingVideoMessage(targetId, time + "", new SendMessageListener()); } else { SendMessageManager.pingAudioMessage(targetId, time + "", new SendMessageListener()); } } private class SendMessageListener extends OnSendMessageListener { @Override public void onSuccess(String token, SendConsumeBean bean) { super.onSuccess(token, bean); if (isCallVideo) { warningTime = bean.getVideoTime(); } else { warningTime = bean.getMp3Time(); } if (warningTime <= 60) { for (OnCallStatusListener listener : listeners) { listener.onTimeWarning(warningTime); } } } @Override public void onError(int status, String msg) { super.onError(status, msg); if (status == OnSendMessageListener.STATUS_NOT_PRICE) { for (OnCallStatusListener listener : listeners) { listener.onErrorNotPrice(msg); } endCall(); } } } } private static class CallMeListener implements IRongReceivedCallListener { @Override public void onReceivedCall(RongCallSession callSession) { Bundle bundle = new Bundle(); bundle.putString("targetId", callSession.getTargetId()); bundle.putString("callId", callSession.getCallId()); bundle.putString("sessionId", callSession.getSessionId()); if (callSession.getMediaType() == RongCallCommon.CallMediaType.VIDEO) { bundle.putString("model", VIDEO_RECEIVED_CALL); RouteManager.forwardActivity(RouteManager.ACTIVITY_CALL_VIDEO, bundle); } else { bundle.putString("model", AUDIO_RECEIVED_CALL); RouteManager.forwardActivity(RouteManager.ACTIVITY_CALL_AUDIO, bundle); } } @Override public void onCheckPermission(RongCallSession callSession) { ToastUtil.show(R.string.permission_request_title); PermissionUtils.permission(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO).callback(new PermissionUtils.SimpleCallback() { @Override public void onGranted() { RongCallClient.getInstance().onPermissionGranted(); } @Override public void onDenied() { RongCallClient.getInstance().onPermissionDenied(); } }).request(); } } private class CallStatusListener implements IRongCallListener { OnCallStatusListener statusListener; private long time = 0; public CallStatusListener(OnCallStatusListener statusListener) { this.statusListener = statusListener; } public long getTime(long activeTime) { long tmpTime = activeTime == 0 ? 0 : (System.currentTimeMillis() - activeTime) / 1000; time = tmpTime == 0 ? time : tmpTime; return time; } @Override public void onCallIncoming(RongCallSession callSession, SurfaceView localVideo) { System.out.println("CallStatusListener.onCallIncoming"); } /** * 电话已拨出。 * 主叫端拨出电话后,通过回调 onCallOutgoing 通知当前 call 的详细信息。 * * @param callSession 通话实体。 * @param localVideo 本地 camera 信息。 */ @Override public void onCallOutgoing(RongCallSession callSession, SurfaceView localVideo) { if (isCallVideo(callSession)) { localVideo.setZOrderOnTop(true); localVideo.setZOrderMediaOverlay(true); CallClientManager.this.localVideo = localVideo; } statusListener.onCallWait(localVideo); System.out.println("CallStatusListener.onCallOutgoing"); } /** * 已建立通话。 * 通话接通时,通过回调 onCallConnected 通知当前 call 的详细信息。 * * @param callSession 通话实体。 * @param localVideo 本地 camera 信息。 */ @Override public void onCallConnected(RongCallSession callSession, SurfaceView localVideo) { if (isCallVideo(callSession)) { localVideo.setZOrderOnTop(true); localVideo.setZOrderMediaOverlay(true); CallClientManager.this.localVideo = localVideo; } statusListener.onCallWait(localVideo); } /** * 通话结束。 * 通话中,对方挂断,己方挂断,或者通话过程网络异常造成的通话中断,都会回调 onCallDisconnected。 * * @param callSession 通话实体。 * @param reason 通话中断原因。 */ @Override public void onCallDisconnected(RongCallSession callSession, RongCallCommon.CallDisconnectedReason reason) { System.out.println("CallStatusListener.onCallDisconnected"); String senderId; String extra = ""; if (callSession == null) { RLog.e("CallStatusListener", "onCallDisconnected. callSession is null!"); statusListener.onCallEnd(); return; } senderId = callSession.getInviterUserId(); long time = getTime(callSession.getActiveTime()); if (time > 0) { if (time >= 3600) { extra = String.format( Locale.ROOT, "%d:%02d:%02d", time / 3600, (time % 3600) / 60, (time % 60)); } else { extra = String.format(Locale.ROOT, "%02d:%02d", (time % 3600) / 60, (time % 60)); } } if (!TextUtils.isEmpty(senderId)) { CallSTerminateMessage message = new CallSTerminateMessage(); message.setReason(reason); message.setMediaType(callSession.getMediaType()); message.setExtra(extra); long serverTime = System.currentTimeMillis() - RongIMClient.getInstance().getDeltaTime(); if (senderId.equals(callSession.getSelfUserId())) { message.setDirection("MO"); IMCenter.getInstance() .insertOutgoingMessage( Conversation.ConversationType.PRIVATE, callSession.getTargetId(), io.rong.imlib.model.Message.SentStatus.SENT, message, serverTime, null); } else { message.setDirection("MT"); IMCenter.getInstance() .insertIncomingMessage( Conversation.ConversationType.PRIVATE, callSession.getTargetId(), senderId, CallKitUtils.getReceivedStatus(reason), message, serverTime, null); } } statusListener.onCallEnd(); CallClientManager.this.remoteVideo = null; CallClientManager.this.localVideo = null; } @Override public void onRemoteUserRinging(String userId) { System.out.println("CallStatusListener.onRemoteUserRinging"); } @Override public void onRemoteUserAccept(String userId, RongCallCommon.CallMediaType mediaType) { System.out.println("CallStatusListener.onRemoteUserAccept"); } /** * 被叫端加入通话。 * 主叫端拨出电话,被叫端收到请求后,加入通话,回调 onRemoteUserJoined。 * * @param userId 加入用户的 id。
* @param mediaType 加入用户的媒体类型,audio or video。
* @param userType 加入用户的类型,1:正常用户,2:观察者。
* @param remoteVideo 加入用户者的 camera 信息。如果 userType为2,remoteVideo对象为空;
* 如果对端调用{@link RongCallClient#startCall(int, boolean, Conversation.ConversationType, String, List, List, RongCallCommon.CallMediaType, String, StartCameraCallback)} 或 * {@link RongCallClient#acceptCall(String, int, boolean, StartCameraCallback)}开始的音视频通话,则可以使用如下设置改变对端视频流的镜像显示:
*
         *                                                                                                                                                                                                                                                                                                                      public void onRemoteUserJoined(String userId, RongCallCommon.CallMediaType mediaType, int userType, SurfaceView remoteVideo) {
         *                                                                                                                                                                                                                                                                                                                           if (null != remoteVideo) {
         *                                                                                                                                                                                                                                                                                                                               ((RongRTCVideoView) remoteVideo).setMirror( boolean);//观看对方视频流是否镜像处理
         *                                                                                                                                                                                                                                                                                                                           }
         *                                                                                                                                                                                                                                                                                                                      }
         *                                                                                                                                                                                                                                                                                                                      
*/ @Override public void onRemoteUserJoined(String userId, RongCallCommon.CallMediaType mediaType, int userType, SurfaceView remoteVideo) { if (mediaType == RongCallCommon.CallMediaType.AUDIO) { statusListener.onCallStart(userId, null); return; } if (CallClientManager.this.remoteVideo != null) { statusListener.onCallStart(userId, CallClientManager.this.remoteVideo); return; } remoteVideo.setZOrderOnTop(false); remoteVideo.setZOrderMediaOverlay(false); CallClientManager.this.remoteVideo = remoteVideo; statusListener.onCallStart(userId, remoteVideo); System.out.println("CallStatusListener.onRemoteUserJoined"); } @Override public void onRemoteUserInvited(String userId, RongCallCommon.CallMediaType mediaType) { System.out.println("CallStatusListener.onRemoteUserInvited"); } /** * 通话中的远端参与者离开。 * 回调 onRemoteUserLeft 通知状态更新。 * * @param userId 远端参与者的 id。 * @param reason 远端参与者离开原因。 */ @Override public void onRemoteUserLeft(String userId, RongCallCommon.CallDisconnectedReason reason) { System.out.println("CallStatusListener.onRemoteUserLeft"); if (statusListener != null) { statusListener.onCallEnd(); } } @Override public void onMediaTypeChanged(String userId, RongCallCommon.CallMediaType mediaType, SurfaceView video) { System.out.println("CallStatusListener.onMediaTypeChanged"); } @Override public void onError(RongCallCommon.CallErrorCode errorCode) { System.out.println("CallStatusListener.onError"); if (statusListener != null) { statusListener.onCallEnd(); } } @Override public void onRemoteCameraDisabled(String userId, boolean disabled) { } @Override public void onRemoteMicrophoneDisabled(String userId, boolean disabled) { } @Override public void onNetworkReceiveLost(String userId, int lossRate) { } @Override public void onNetworkSendLost(int lossRate, int delay) { } @Override public void onFirstRemoteVideoFrame(String userId, int height, int width) { if (statusListener != null) { statusListener.onStartFirstFrame(); } } @Override public void onFirstRemoteAudioFrame(String userId) { } @Override public void onAudioLevelSend(String audioLevel) { } @Override public void onAudioLevelReceive(HashMap audioLevel) { } @Override public void onRemoteUserPublishVideoStream(String userId, String streamId, String tag, SurfaceView surfaceView) { } @Override public void onRemoteUserUnpublishVideoStream(String userId, String streamId, String tag) { } } }