|
@@ -0,0 +1,471 @@
|
|
|
+package com.cooleshow.teacher.presenter.live;
|
|
|
+
|
|
|
+import android.text.TextUtils;
|
|
|
+import android.util.Log;
|
|
|
+
|
|
|
+import com.cooleshow.base.presenter.BasePresenter;
|
|
|
+import com.cooleshow.base.rx.BaseObserver;
|
|
|
+import com.cooleshow.teacher.api.APIService;
|
|
|
+import com.cooleshow.teacher.bean.LiveRoomInfoBean;
|
|
|
+import com.cooleshow.teacher.contract.LiveRoomContract;
|
|
|
+import com.cooleshow.usercenter.helper.UserHelper;
|
|
|
+import com.rong.io.live.LiveRoomMsgConstants;
|
|
|
+import com.rong.io.live.callback.ClickCallback;
|
|
|
+import com.rong.io.live.callback.IRoomCallBack;
|
|
|
+import com.rong.io.live.helper.LiveEventHelper;
|
|
|
+import com.rong.io.live.helper.LiveRTCEngineInitHelper;
|
|
|
+import com.rong.io.live.manager.RCChatRoomMessageManager;
|
|
|
+import com.rong.io.live.message.RCChatroomLocationMessage;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+import cn.rongcloud.rtc.api.RCRTCEngine;
|
|
|
+import cn.rongcloud.rtc.api.RCRTCRemoteUser;
|
|
|
+import cn.rongcloud.rtc.api.RCRTCRoom;
|
|
|
+import cn.rongcloud.rtc.api.callback.IRCRTCResultDataCallback;
|
|
|
+import cn.rongcloud.rtc.api.callback.IRCRTCRoomEventsListener;
|
|
|
+import cn.rongcloud.rtc.api.stream.RCRTCAudioInputStream;
|
|
|
+import cn.rongcloud.rtc.api.stream.RCRTCInputStream;
|
|
|
+import cn.rongcloud.rtc.api.stream.RCRTCLiveInfo;
|
|
|
+import cn.rongcloud.rtc.api.stream.RCRTCOutputStream;
|
|
|
+import cn.rongcloud.rtc.api.stream.RCRTCVideoInputStream;
|
|
|
+import cn.rongcloud.rtc.api.stream.RCRTCVideoOutputStream;
|
|
|
+import cn.rongcloud.rtc.api.stream.RCRTCVideoStreamConfig;
|
|
|
+import cn.rongcloud.rtc.base.RCRTCLiveRole;
|
|
|
+import cn.rongcloud.rtc.base.RCRTCMediaType;
|
|
|
+import cn.rongcloud.rtc.base.RCRTCParamsType;
|
|
|
+import cn.rongcloud.rtc.base.RTCErrorCode;
|
|
|
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
|
+import io.reactivex.rxjava3.annotations.NonNull;
|
|
|
+import io.reactivex.rxjava3.core.Observable;
|
|
|
+import io.reactivex.rxjava3.core.ObservableEmitter;
|
|
|
+import io.reactivex.rxjava3.core.ObservableOnSubscribe;
|
|
|
+import io.reactivex.rxjava3.core.Observer;
|
|
|
+import io.reactivex.rxjava3.core.Scheduler;
|
|
|
+import io.reactivex.rxjava3.disposables.Disposable;
|
|
|
+import io.reactivex.rxjava3.functions.Consumer;
|
|
|
+import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
|
+import io.rong.imkit.IMCenter;
|
|
|
+import io.rong.imlib.IRongCoreCallback;
|
|
|
+import io.rong.imlib.RongIMClient;
|
|
|
+import io.rong.imlib.model.Message;
|
|
|
+import io.rong.imlib.model.MessageContent;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Author by pq, Date on 2022/6/5.
|
|
|
+ */
|
|
|
+public class LiveRoomPresenter extends BasePresenter<LiveRoomContract.LiveRoomView> implements LiveRoomContract.Presenter {
|
|
|
+ public boolean isInRoom = false;
|
|
|
+ private LiveRoomInfoBean currentRoomInfo;
|
|
|
+ private List<Disposable> disposablesManager = new ArrayList<>();//监听管理器
|
|
|
+ private final IRCRTCRoomEventsListener mRoomEventsListener = new IRCRTCRoomEventsListener() {
|
|
|
+ @Override
|
|
|
+ public void onRemoteUserPublishResource(RCRTCRemoteUser rcrtcRemoteUser, List<RCRTCInputStream> list) {
|
|
|
+ Log.i("pq", "onRemoteUserPublishResource");
|
|
|
+// subscribeAVStream();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onRemoteUserMuteAudio(RCRTCRemoteUser rcrtcRemoteUser, RCRTCInputStream rcrtcInputStream, boolean b) {
|
|
|
+ Log.i("pq", "onRemoteUserMuteAudio:" + b);
|
|
|
+ if (getView() != null) {
|
|
|
+// getView().syncAudioStatus(b);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onRemoteUserMuteVideo(RCRTCRemoteUser rcrtcRemoteUser, RCRTCInputStream rcrtcInputStream, boolean b) {
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onRemoteUserUnpublishResource(RCRTCRemoteUser rcrtcRemoteUser, List<RCRTCInputStream> list) {
|
|
|
+ Log.i("pq", "onRemoteUserUnpublishResource");
|
|
|
+ if (getView() != null) {
|
|
|
+// getView().showCloseVideoView();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onUserJoined(RCRTCRemoteUser rcrtcRemoteUser) {
|
|
|
+ //当房间中用户使用RCRTCLocalUser#switchToBroadcaster 方法上麦成功时
|
|
|
+ // ,房间中观众会收到IRCRTCRoomEventsListener#onUserJoined 回调。
|
|
|
+ if (null != getView()) {
|
|
|
+// getView().onUserJoinRoom(rcrtcRemoteUser);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onSwitchRole(String userId, RCRTCLiveRole role) {
|
|
|
+ super.onSwitchRole(userId, role);
|
|
|
+ //当房间内的用户使用 RCRTCLocalUser#switchToBroadcaster 或 RCRTCLocalUser#switchToAudience 方法上下麦时
|
|
|
+ // ,同房间内的其他主播会收到 IRCRTCRoomEventsListener#onSwitchRole 回调。
|
|
|
+ if (getView() != null) {
|
|
|
+// getView().onSwitchRole(userId, role);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onUserLeft(RCRTCRemoteUser rcrtcRemoteUser) {
|
|
|
+ if (getView() != null) {
|
|
|
+// getView().onUserLeftRoomMic(rcrtcRemoteUser);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onUserOffline(RCRTCRemoteUser rcrtcRemoteUser) {
|
|
|
+ if (getView() != null) {
|
|
|
+// getView().onUserOfflineRoomMic(rcrtcRemoteUser);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onPublishLiveStreams(List<RCRTCInputStream> list) {
|
|
|
+ Log.i("pq", "onPublishLiveStreams");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onUnpublishLiveStreams(List<RCRTCInputStream> list) {
|
|
|
+ Log.i("pq", "onUnpublishLiveStreams");
|
|
|
+ if (getView() != null) {
|
|
|
+// getView().showRestView();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 自己退出房间。 例如断网退出等
|
|
|
+ * @param i 状态码
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void onLeaveRoom(int i) {
|
|
|
+ Log.i("pq", "onLeaveRoom:" + i);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * init
|
|
|
+ *
|
|
|
+ * @param roomId
|
|
|
+ * @param isCreate
|
|
|
+ */
|
|
|
+ public void init(String roomId, boolean isCreate) {
|
|
|
+ isInRoom = TextUtils.equals(LiveEventHelper.getInstance().getRoomId(), roomId);
|
|
|
+ RongIMClient.ConnectionStatusListener.ConnectionStatus currentConnectionStatus = RongIMClient.getInstance().getCurrentConnectionStatus();
|
|
|
+ if (currentConnectionStatus == RongIMClient.ConnectionStatusListener.ConnectionStatus.CONNECTED) {
|
|
|
+ Log.i("pq", "LiveRoomActivity init getRoomInfo");
|
|
|
+ getRoomInfo(roomId);
|
|
|
+ } else {
|
|
|
+ String imtoken = UserHelper.getUserIMToken();
|
|
|
+ Log.i("pq", "im未连接,token:" + imtoken);
|
|
|
+ if (!TextUtils.isEmpty(imtoken)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ connectIM(imtoken);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取房间信息
|
|
|
+ *
|
|
|
+ * @param roomId
|
|
|
+ */
|
|
|
+ public void getRoomInfo(String roomId) {
|
|
|
+ addSubscribe(create(APIService.class).getLiveRoomInfo(roomId), new BaseObserver<LiveRoomInfoBean>(getView()) {
|
|
|
+ @Override
|
|
|
+ protected void onSuccess(LiveRoomInfoBean data) {
|
|
|
+ Log.i("pq", "getRoomInfo success" + data);
|
|
|
+ currentRoomInfo = data;
|
|
|
+ setObMessageListener(data.roomUid);
|
|
|
+ if (getView() != null) {
|
|
|
+ getView().getRoomInfoSuccess(data);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onError(Throwable e) {
|
|
|
+ super.onError(e);
|
|
|
+ e.printStackTrace();
|
|
|
+ if (getView() != null) {
|
|
|
+ getView().getRoomInfoError(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ public void prepareJoinRoom(String roomId, boolean isCreate) {
|
|
|
+ //先离开当前房间
|
|
|
+ initPublishConfig();
|
|
|
+ LiveEventHelper.getInstance().leaveRoom(new IRoomCallBack() {
|
|
|
+ @Override
|
|
|
+ public void onSuccess() {
|
|
|
+ if (getView() != null && getView().getContentView() != null) {
|
|
|
+ getView().getContentView().postDelayed(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ joinRoom(roomId, isCreate);
|
|
|
+ }
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onError(int code, String message) {
|
|
|
+ Log.i("pq", "leaveRoom onError:" + code + "-msg:" + message);
|
|
|
+ joinRoom(roomId, isCreate);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void initPublishConfig() {
|
|
|
+ try {
|
|
|
+
|
|
|
+ RCRTCVideoStreamConfig config =
|
|
|
+ RCRTCVideoStreamConfig.Builder.create()
|
|
|
+ .setMinRate(200)
|
|
|
+ .setMaxRate(900)
|
|
|
+ .setVideoFps(RCRTCParamsType.RCRTCVideoFps.Fps_30)
|
|
|
+ .setVideoResolution(RCRTCParamsType.RCRTCVideoResolution.RESOLUTION_720_1280)
|
|
|
+ .build();
|
|
|
+ RCRTCEngine.getInstance().getDefaultVideoStream().setVideoConfig(config);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 加入房间
|
|
|
+ *
|
|
|
+ * @param roomId
|
|
|
+ * @param isCreate
|
|
|
+ */
|
|
|
+ private void joinRoom(String roomId, boolean isCreate) {
|
|
|
+ //如果是观众就直接加入房间
|
|
|
+ Log.i("pq", "joinRoom");
|
|
|
+ LiveEventHelper.getInstance().joinRoom(roomId, RCRTCLiveRole.BROADCASTER, new ClickCallback<Boolean>() {
|
|
|
+ @Override
|
|
|
+ public void onResult(Boolean result, String msg) {
|
|
|
+ Log.i("pq", "joinRoom onResult:" + result);
|
|
|
+ if (result) {
|
|
|
+ setCurrentRoom(currentRoomInfo);
|
|
|
+ } else {
|
|
|
+ //加入直播房间失败
|
|
|
+ if (getView() != null) {
|
|
|
+ getView().showFinishView();
|
|
|
+ }
|
|
|
+ leaveRoom();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置当前房间
|
|
|
+ *
|
|
|
+ * @param roomInfo
|
|
|
+ */
|
|
|
+ public void setCurrentRoom(LiveRoomInfoBean roomInfo) {
|
|
|
+ initLiveRoomListener(roomInfo.roomUid);
|
|
|
+// if (isInRoom) {
|
|
|
+// //恢复一下当前信息就可以了
|
|
|
+// List<MessageContent> messageList = LiveEventHelper.getInstance().getMessageList();
|
|
|
+// getView().addMessageList(messageList, true);
|
|
|
+// } else {
|
|
|
+// // 发送默认消息
|
|
|
+// sendDefaultMessage();
|
|
|
+// }
|
|
|
+ //设置创建者id
|
|
|
+ LiveEventHelper.getInstance().setCreateUserId(roomInfo.speakerId);
|
|
|
+// getShield();获取敏感词汇
|
|
|
+ startPublish();
|
|
|
+ if (getView() != null) {
|
|
|
+ getView().setRoomData(currentRoomInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 加入房间后,开始摄像头采集并发布音视频流。
|
|
|
+ */
|
|
|
+ private void startPublish() {
|
|
|
+ RCRTCRoom rcrtcRoom = LiveEventHelper.getInstance().getRtcRoom();
|
|
|
+ RCRTCEngine.getInstance().getDefaultVideoStream().startCamera(null);
|
|
|
+ rcrtcRoom.getLocalUser().publishDefaultLiveStreams(new IRCRTCResultDataCallback<RCRTCLiveInfo>() {
|
|
|
+ @Override
|
|
|
+ public void onSuccess(RCRTCLiveInfo liveInfo) {
|
|
|
+ if (getView() != null) {
|
|
|
+ getView().onPublishSuccess();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onFailed(RTCErrorCode code) {
|
|
|
+ Log.i("pq", "publishDefaultLiveStreamError:" + code);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置直播房的各种监听
|
|
|
+ *
|
|
|
+ * @param roomId
|
|
|
+ */
|
|
|
+ public void initLiveRoomListener(String roomId) {
|
|
|
+ LiveEventHelper.getInstance().getRtcRoom().registerRoomListener(mRoomEventsListener);
|
|
|
+ //添加消息监听
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 进入房间后发送默认的消息
|
|
|
+ */
|
|
|
+ public void sendDefaultMessage() {
|
|
|
+ if (currentRoomInfo != null) {
|
|
|
+ RCChatroomLocationMessage tips = new RCChatroomLocationMessage();
|
|
|
+ tips.setContent("欢迎进入直播课堂,请遵守相关法规,禁止传播低俗、暴力等不良信息。为孩子创造健康绿色的学习环境。");
|
|
|
+ sendMessage(tips);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送消息
|
|
|
+ * 默认显示在本地
|
|
|
+ *
|
|
|
+ * @param messageContent
|
|
|
+ */
|
|
|
+ public void sendMessage(MessageContent messageContent) {
|
|
|
+ sendMessage(messageContent, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送消息
|
|
|
+ *
|
|
|
+ * @param messageContent 消息体
|
|
|
+ * @param isShowLocation 是否显示在本地
|
|
|
+ */
|
|
|
+ public void sendMessage(MessageContent messageContent, boolean isShowLocation) {
|
|
|
+ if (!isContainsShield(messageContent)) {
|
|
|
+ LiveEventHelper.getInstance().sendMessage(messageContent, isShowLocation);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 是否包含屏蔽词
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private boolean isContainsShield(MessageContent messageContent) {
|
|
|
+ boolean isContains = false;
|
|
|
+// if (shields != null) {
|
|
|
+// for (String shield : shields) {
|
|
|
+// if (messageContent instanceof RCChatroomBarrage) {
|
|
|
+// if (((RCChatroomBarrage) messageContent).getContent().contains(shield)) {
|
|
|
+// isContains = true;
|
|
|
+// break;
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+// if (isContains) {
|
|
|
+// //如果是包含了敏感词'
|
|
|
+// mView.addMessageContent(messageContent, false);
|
|
|
+// return true;
|
|
|
+// }
|
|
|
+// }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获得当前视频流
|
|
|
+ */
|
|
|
+ public void getVideoStream(List<RCRTCVideoOutputStream> outputStreams, List<RCRTCVideoInputStream> inputStreams, List<RCRTCAudioInputStream> audioinputstream) {
|
|
|
+ RCRTCRoom mRtcRoom = LiveEventHelper.getInstance().getRtcRoom();
|
|
|
+ if (mRtcRoom == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ for (final RCRTCRemoteUser remoteUser : mRtcRoom.getRemoteUsers()) {
|
|
|
+ if (remoteUser.getStreams().size() == 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ List<RCRTCInputStream> userStreams = remoteUser.getStreams();
|
|
|
+ for (RCRTCInputStream i : userStreams) {
|
|
|
+ if (i.getMediaType() == RCRTCMediaType.VIDEO) {
|
|
|
+ inputStreams.add((RCRTCVideoInputStream) i);
|
|
|
+ }
|
|
|
+ if (i.getMediaType() == RCRTCMediaType.AUDIO) {
|
|
|
+ audioinputstream.add((RCRTCAudioInputStream) i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (RCRTCOutputStream o : mRtcRoom.getLocalUser().getStreams()) {
|
|
|
+ if (o.getMediaType() == RCRTCMediaType.VIDEO) {
|
|
|
+ outputStreams.add((RCRTCVideoOutputStream) o);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 离开房间
|
|
|
+ */
|
|
|
+ public void leaveRoom() {
|
|
|
+ LiveEventHelper.getInstance().leaveRoom(new IRoomCallBack() {
|
|
|
+ @Override
|
|
|
+ public void onSuccess() {
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onError(int code, String message) {
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 监听接收房间的所有信息
|
|
|
+ *
|
|
|
+ * @param roomId
|
|
|
+ */
|
|
|
+ public void setObMessageListener(String roomId) {
|
|
|
+ if (disposablesManager.size() != 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Disposable subscribe = RCChatRoomMessageManager.
|
|
|
+ obMessageReceiveByRoomId(roomId)
|
|
|
+ .observeOn(AndroidSchedulers.mainThread())
|
|
|
+ .subscribe(new Consumer<Message>() {
|
|
|
+ @Override
|
|
|
+ public void accept(Message message) {
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ disposablesManager.add(subscribe);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void joinChartRoom(String chatroomId, final IRongCoreCallback.OperationCallback callback) {
|
|
|
+ LiveEventHelper.getInstance().joinChatRoom(chatroomId, callback);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 连接融云IM
|
|
|
+ *
|
|
|
+ * @param imToken
|
|
|
+ */
|
|
|
+ private void connectIM(String imToken) {
|
|
|
+ IMCenter.getInstance().connect(imToken, new RongIMClient.ConnectCallback() {
|
|
|
+ @Override
|
|
|
+ public void onSuccess(String t) {
|
|
|
+ Log.i("pq", "连接成功");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onError(RongIMClient.ConnectionErrorCode e) {
|
|
|
+ Log.i("pq", "connect error" + e);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onDatabaseOpened(RongIMClient.DatabaseOpenStatus code) {
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|