Pārlūkot izejas kodu

更新老师端直播间

Pq 3 gadi atpakaļ
vecāks
revīzija
2dda19cf0d
58 mainītis faili ar 3008 papildinājumiem un 533 dzēšanām
  1. 5 2
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/InputBar.java
  2. 79 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/dialog/CommonConfirmDialog.java
  3. 7 3
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/dialog/InputBarDialog.java
  4. 5 0
      BaseLibrary/src/main/res/drawable/shape_8dp_01c1b5.xml
  5. 5 0
      BaseLibrary/src/main/res/drawable/shape_8dp_white.xml
  6. 65 0
      BaseLibrary/src/main/res/layout/dialog_common_confirm_layout.xml
  7. 3 0
      BaseLibrary/src/main/res/values/colors.xml
  8. 1 1
      rong_im/kit/src/main/java/io/rong/imkit/picture/tools/DoubleUtils.java
  9. 3 0
      rong_im/live/src/main/java/com/rong/io/live/LiveRoomMsgConstants.java
  10. 1 1
      rong_im/live/src/main/java/com/rong/io/live/bean/ImUserState.java
  11. 12 0
      rong_im/live/src/main/java/com/rong/io/live/config/LiveConfig.java
  12. 36 0
      rong_im/live/src/main/java/com/rong/io/live/helper/LiveMemberHelper.java
  13. 20 0
      rong_im/live/src/main/java/com/rong/io/live/helper/LiveMessageHelper.java
  14. 83 0
      rong_im/live/src/main/java/com/rong/io/live/helper/LiveRoomMicMemberHelper.java
  15. 18 0
      rong_im/live/src/main/java/com/rong/io/live/message/RCUserSeatApplyMessage.java
  16. 1 1
      student/src/main/java/com/cooleshow/student/presenter/live/LiveRoomPresenter.java
  17. 1 1
      teacher/src/main/AndroidManifest.xml
  18. 2 2
      teacher/src/main/java/com/cooleshow/teacher/adapter/LiveRoomMessageAdapter.java
  19. 42 1
      teacher/src/main/java/com/cooleshow/teacher/api/APIService.java
  20. 49 0
      teacher/src/main/java/com/cooleshow/teacher/contract/LiveRoomContract.java
  21. 80 0
      teacher/src/main/java/com/cooleshow/teacher/helper/LiveRoomAnimatorHelper.java
  22. 262 25
      teacher/src/main/java/com/cooleshow/teacher/presenter/live/LiveRoomPresenter.java
  23. 1 1
      teacher/src/main/java/com/cooleshow/teacher/ui/live/CreateLiveActivity.java
  24. 125 0
      teacher/src/main/java/com/cooleshow/teacher/ui/live/LiveApplyMicFragment.java
  25. 130 0
      teacher/src/main/java/com/cooleshow/teacher/ui/live/LiveOnMicFragment.java
  26. 0 481
      teacher/src/main/java/com/cooleshow/teacher/ui/live/LiveRoomActivity.java
  27. 1267 0
      teacher/src/main/java/com/cooleshow/teacher/ui/live/TeacherLiveRoomActivity.java
  28. 166 0
      teacher/src/main/java/com/cooleshow/teacher/widgets/dialog/LiveMicManagerDialog.java
  29. 86 0
      teacher/src/main/java/com/cooleshow/teacher/widgets/dialog/LiveRoomManagerDialog.java
  30. BIN
      teacher/src/main/res/drawable-xhdpi/icon_live_barrage_buy_tag.png
  31. BIN
      teacher/src/main/res/drawable-xhdpi/icon_live_delay_high.png
  32. BIN
      teacher/src/main/res/drawable-xhdpi/icon_live_delay_middle.png
  33. BIN
      teacher/src/main/res/drawable-xhdpi/icon_live_delay_normal.png
  34. BIN
      teacher/src/main/res/drawable-xhdpi/icon_live_finish.png
  35. BIN
      teacher/src/main/res/drawable-xhdpi/icon_live_pause.png
  36. BIN
      teacher/src/main/res/drawable-xhdpi/icon_live_room_close_menu.png
  37. BIN
      teacher/src/main/res/drawable-xhdpi/icon_mic_contro.png
  38. BIN
      teacher/src/main/res/drawable-xxhdpi/icon_live_barrage_buy_tag.png
  39. BIN
      teacher/src/main/res/drawable-xxhdpi/icon_live_delay_high.png
  40. BIN
      teacher/src/main/res/drawable-xxhdpi/icon_live_delay_middle.png
  41. BIN
      teacher/src/main/res/drawable-xxhdpi/icon_live_delay_normal.png
  42. BIN
      teacher/src/main/res/drawable-xxhdpi/icon_live_finish.png
  43. BIN
      teacher/src/main/res/drawable-xxhdpi/icon_live_pause.png
  44. BIN
      teacher/src/main/res/drawable-xxhdpi/icon_live_room_close_menu.png
  45. BIN
      teacher/src/main/res/drawable-xxhdpi/icon_mic_contro.png
  46. 7 0
      teacher/src/main/res/drawable/shape_live_barrage_for_join_msg.xml
  47. 7 0
      teacher/src/main/res/drawable/shape_live_barrage_for_snap_up_msg.xml
  48. 5 0
      teacher/src/main/res/drawable/shape_live_finish_bg.xml
  49. 8 0
      teacher/src/main/res/drawable/shape_live_mic_bt_bg.xml
  50. 11 0
      teacher/src/main/res/drawable/shape_live_on_mic_tip_bg.xml
  51. 5 0
      teacher/src/main/res/drawable/shape_live_pause_bg.xml
  52. 93 0
      teacher/src/main/res/layout/dialog_live_manager_layout.xml
  53. 48 0
      teacher/src/main/res/layout/dialog_live_mic_manager_layout.xml
  54. 50 0
      teacher/src/main/res/layout/fragment_live_apply_mic_layout.xml
  55. 35 0
      teacher/src/main/res/layout/fragment_live_on_mic_layout.xml
  56. 58 0
      teacher/src/main/res/layout/item_live_mic_manager_layout.xml
  57. 117 14
      teacher/src/main/res/layout/view_live_room_main_layout.xml
  58. 9 0
      teacher/src/main/res/values/strings.xml

+ 5 - 2
BaseLibrary/src/main/java/com/cooleshow/base/widgets/InputBar.java

@@ -111,7 +111,10 @@ public class InputBar extends LinearLayout implements OnEmojiPopupShownListener,
         etInput.setText("");
 
         if (inputBarListener != null) {
-            inputBarListener.onClickSend(message);
+            boolean isSuccess = inputBarListener.onClickSend(message);
+            if (isSuccess) {
+                etInput.setText("");
+            }
         }
     }
 
@@ -147,7 +150,7 @@ public class InputBar extends LinearLayout implements OnEmojiPopupShownListener,
 
     public interface InputBarListener {
 
-        void onClickSend(String message);
+        boolean onClickSend(String message);
 
         boolean onClickEmoji();
     }

+ 79 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/dialog/CommonConfirmDialog.java

@@ -0,0 +1,79 @@
+package com.cooleshow.base.widgets.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.TextView;
+
+import com.cooleshow.base.R;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Author by pq, Date on 2022/6/17.
+ */
+public class CommonConfirmDialog extends Dialog {
+
+    private TextView mTvContent;
+    private TextView mTvCancel;
+    private TextView mTvConfirm;
+
+    public CommonConfirmDialog(@NonNull Context context) {
+        super(context, R.style.BaseDialog);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.dialog_common_confirm_layout);
+        mTvContent = findViewById(R.id.tv_content);
+        mTvCancel = findViewById(R.id.tv_cancel);
+        mTvConfirm = findViewById(R.id.tv_confirm);
+        mTvCancel.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                dismiss();
+            }
+        });
+    }
+
+    /**
+     * 设置主文本
+     *
+     * @param text
+     */
+    public void setContent(String text) {
+        if (mTvContent != null) {
+            mTvContent.setText(text);
+        }
+    }
+
+    /**
+     * 设置取消按钮text
+     *
+     * @param text
+     */
+    public void setCancelText(String text) {
+        if (mTvCancel != null) {
+            mTvCancel.setText(text);
+        }
+    }
+
+    /**
+     * 设置确认按钮text
+     *
+     * @param text
+     */
+    public void setConfirmText(String text) {
+        if (mTvConfirm != null) {
+            mTvConfirm.setText(text);
+        }
+    }
+
+    public void setOnConfirmClickListener(View.OnClickListener listener) {
+        if (mTvConfirm != null) {
+            mTvConfirm.setOnClickListener(listener);
+        }
+    }
+}

+ 7 - 3
BaseLibrary/src/main/java/com/cooleshow/base/widgets/dialog/InputBarDialog.java

@@ -23,11 +23,15 @@ public class InputBarDialog extends Dialog {
         inputBar = new InputBar(context);
         inputBar.setInputBarListener(new InputBar.InputBarListener() {
             @Override
-            public void onClickSend(String message) {
-                dismiss();
+            public boolean onClickSend(String message) {
                 if (inputBarListener != null) {
-                    inputBarListener.onClickSend(message);
+                    boolean isSuccess = inputBarListener.onClickSend(message);
+                    if (isSuccess) {
+                        dismiss();
+                    }
+                    return isSuccess;
                 }
+                return false;
             }
 
             @Override

+ 5 - 0
BaseLibrary/src/main/res/drawable/shape_8dp_01c1b5.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/color_01c1b5" />
+    <corners android:radius="8dp" />
+</shape>

+ 5 - 0
BaseLibrary/src/main/res/drawable/shape_8dp_white.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/white" />
+    <corners android:radius="8dp" />
+</shape>

+ 65 - 0
BaseLibrary/src/main/res/layout/dialog_common_confirm_layout.xml

@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/shape_8dp_white">
+
+    <TextView
+        android:id="@+id/tv_content"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="14dp"
+        android:layout_marginEnd="14dp"
+        android:gravity="center"
+        android:paddingTop="30dp"
+        android:paddingBottom="30dp"
+        android:textColor="@color/color_666666"
+        android:textSize="@dimen/sp_14"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:text="结束后直播间关闭本场直播结束,不可再次开启" />
+
+    <View
+        android:id="@+id/view_line"
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="@color/color_dedede"
+        app:layout_constraintTop_toBottomOf="@+id/tv_content" />
+
+    <TextView
+        android:id="@+id/tv_cancel"
+        android:layout_width="0dp"
+        android:layout_height="47dp"
+        android:gravity="center"
+        android:text="取消"
+        android:textColor="@color/color_666666"
+        android:textSize="@dimen/sp_16"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toLeftOf="@+id/view_line1"
+        app:layout_constraintTop_toBottomOf="@+id/view_line" />
+
+    <TextView
+        android:id="@+id/tv_confirm"
+        android:layout_width="0dp"
+        android:layout_height="47dp"
+        android:gravity="center"
+        android:text="确认"
+        android:textColor="@color/color_333333"
+        android:textSize="@dimen/sp_16"
+        app:layout_constraintLeft_toRightOf="@+id/view_line1"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/view_line" />
+
+    <View
+        android:id="@+id/view_line1"
+        android:layout_width="1dp"
+        android:layout_height="0dp"
+        android:background="@color/color_dedede"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/view_line" />
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 3 - 0
BaseLibrary/src/main/res/values/colors.xml

@@ -112,4 +112,7 @@
     <color name="gray_F2F4F8">#F2F4F8</color>
     <color name="gray_32FFD8">#32FFD8</color>
     <color name="color_ff4e1a">#FF4E1A</color>
+    <color name="color_e4f8f7">#E4F8F7</color>
+    <color name="color_01c1b5">#01C1B5</color>
+
 </resources>

+ 1 - 1
rong_im/kit/src/main/java/io/rong/imkit/picture/tools/DoubleUtils.java

@@ -13,7 +13,7 @@ public class DoubleUtils {
      * Prevent continuous click, jump two pages
      */
     private static long lastClickTime;
-    private final static long TIME = 800;
+    private final static long TIME = 1000;
 
     public static boolean isFastDoubleClick() {
         long time = System.currentTimeMillis();

+ 3 - 0
rong_im/live/src/main/java/com/rong/io/live/LiveRoomMsgConstants.java

@@ -14,6 +14,9 @@ public class LiveRoomMsgConstants {
     public static final int ACTION_SEND_ADD_LIKE_COUNT = -107;//点赞数量发送
     public static final int ACTION_SEND_ON_SNAP_UP = -108;//XX正在抢购
 
+    public static final int ACTION_AGREE_MIC_APPLY = -109;//主播同意观众连麦
+    public static final int ACTION_SEND_PAUSE_LIVE = -110;//暂停直播
+
     public static final int MIC_ACTION_INVITE_SEAT_BY_CREATE = 1;//连麦-主讲人邀请
     public static final int MIC_ACTION_CANCEL_INVITE_SEAT_BY_CREATE = 2;//连麦-主讲人取消邀请
     public static final int MIC_ACTION_SEAT_BY_USER = 3;//连麦-观众申请

+ 1 - 1
student/src/main/java/com/cooleshow/student/bean/ImUserState.java → rong_im/live/src/main/java/com/rong/io/live/bean/ImUserState.java

@@ -1,4 +1,4 @@
-package com.cooleshow.student.bean;
+package com.rong.io.live.bean;
 
 import java.io.Serializable;
 

+ 12 - 0
rong_im/live/src/main/java/com/rong/io/live/config/LiveConfig.java

@@ -5,4 +5,16 @@ package com.rong.io.live.config;
  */
 public class LiveConfig {
     public static boolean isNeedReInitRTC =false;
+    public static final int LIVE_MODE_PREVIEW = 1;//预览模式
+    public static final int LIVE_MODE_LIVE_START = 2;//直播模式
+    public static final int LIVE_STATUS_NORMAL = 1;//正常直播状态(包括预览或者直播中)
+    public static final int LIVE_STATUS_PAUSE = 2;//暂停直播状态
+
+    public static final int LIVE_DELAY_NORMAL = 100;//直播正常延迟
+    public static final int LIVE_DELAY_MIDDLE = 200;//直播一般延迟
+    public static final int LIVE_DELAY_HIGH = 300;//直播高延迟
+    public static final int LIVE_HIDE_BARRAGE_VIEW_TIME = 2000;//隐藏直播间弹幕消息时长
+    public static final String OPEN_OPS_LIVE_VIDEO_TYPE = "1";//开启直播间录像
+    public static final String CLOSE_OPS_LIVE_VIDEO_TYPE = "2";//关闭直播间录像
+    public static final int LIVE_MAX_INPUT_TEXT_LENGTH = 40;//直播间发送文本消息最大程度
 }

+ 36 - 0
rong_im/live/src/main/java/com/rong/io/live/helper/LiveMemberHelper.java

@@ -0,0 +1,36 @@
+package com.rong.io.live.helper;
+
+import android.text.TextUtils;
+
+import com.rong.io.live.message.RCChatJoinRoomMessage;
+import com.rong.io.live.message.RCOnSnappingUpMessage;
+
+import io.rong.imlib.model.MessageContent;
+import io.rong.imlib.model.UserInfo;
+
+/**
+ * Author by pq, Date on 2022/6/20.
+ */
+public class LiveMemberHelper {
+    public static String getMessageName(MessageContent messageContent) {
+        String name = "";
+        UserInfo userInfo = messageContent.getUserInfo();
+        if (userInfo != null) {
+            name = userInfo.getName();
+        }
+        if (TextUtils.isEmpty(name)) {
+            if (messageContent instanceof RCChatJoinRoomMessage) {
+                RCChatJoinRoomMessage joinRoomMessage = (RCChatJoinRoomMessage) messageContent;
+                name = joinRoomMessage.getUserName();
+            }
+            if (messageContent instanceof RCOnSnappingUpMessage) {
+                RCOnSnappingUpMessage onSnappingUpMessage = (RCOnSnappingUpMessage) messageContent;
+                name = onSnappingUpMessage.getUserName();
+            }
+        }
+        if (TextUtils.isEmpty(name)) {
+            name = "用户";
+        }
+        return name;
+    }
+}

+ 20 - 0
rong_im/live/src/main/java/com/rong/io/live/helper/LiveMessageHelper.java

@@ -0,0 +1,20 @@
+package com.rong.io.live.helper;
+
+/**
+ * Author by pq, Date on 2022/6/20.
+ */
+public class LiveMessageHelper {
+    // 两次消息间隔不能少于1000毫秒
+    private static final int MIN_CLICK_DELAY_TIME = 3000;
+    private static long lastClickTime;
+
+    public static boolean isQuickAction() {
+        boolean flag = false;
+        long curClickTime = System.currentTimeMillis();
+        if ((curClickTime - lastClickTime) < MIN_CLICK_DELAY_TIME) {
+            return true;
+        }
+        lastClickTime = curClickTime;
+        return flag;
+    }
+}

+ 83 - 0
rong_im/live/src/main/java/com/rong/io/live/helper/LiveRoomMicMemberHelper.java

@@ -0,0 +1,83 @@
+package com.rong.io.live.helper;
+
+
+import android.text.TextUtils;
+
+import com.rong.io.live.bean.User;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Author by pq, Date on 2022/6/15.
+ * 直播间连麦用户管理
+ */
+public class LiveRoomMicMemberHelper {
+    private ArrayList<User> onApplyMicUsers;
+    private HashMap<String, User> onMicUser;
+
+    public LiveRoomMicMemberHelper() {
+        onApplyMicUsers = new ArrayList<>();
+        onMicUser = new HashMap<>();
+    }
+
+    /**
+     * 添加连麦用户
+     *
+     * @param user
+     */
+    public void addApplyUser(User user) {
+        int i = checkApplyExist(user);
+        if (i == -1) {
+            onApplyMicUsers.add(user);
+        }
+    }
+
+    /**
+     * 删除单个连麦用户
+     *
+     * @param user
+     */
+    public void delApplyUser(User user) {
+        int i = checkApplyExist(user);
+        if (i != -1) {
+            onApplyMicUsers.remove(i);
+        }
+    }
+
+    /**
+     * 删除全部申请连麦用户
+     */
+    public void delAllApplyUser() {
+        onApplyMicUsers.clear();
+    }
+
+    /**
+     * 检查目标连麦用户是否已存在
+     *
+     * @param targetUser
+     * @return
+     */
+    private int checkApplyExist(User targetUser) {
+        if (targetUser == null) {
+            return -1;
+        }
+        for (int i = 0; i < onApplyMicUsers.size(); i++) {
+            User user1 = onApplyMicUsers.get(i);
+            if (TextUtils.equals(user1.getUserId(), targetUser.getUserId())) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+
+    /**
+     * 获取连麦申请中的用户
+     *
+     * @return
+     */
+    public ArrayList<User> getOnApplyMicUsers() {
+        return onApplyMicUsers;
+    }
+}

+ 18 - 0
rong_im/live/src/main/java/com/rong/io/live/message/RCUserSeatApplyMessage.java

@@ -24,6 +24,15 @@ public class RCUserSeatApplyMessage extends MessageContent {
     private String teacherId;
     private String audienceId;
     private String audienceName;
+    private String audienceAvatar;
+
+    public String getAudienceAvatar() {
+        return audienceAvatar;
+    }
+
+    public void setAudienceAvatar(String audienceAvatar) {
+        this.audienceAvatar = audienceAvatar;
+    }
 
     public int getType() {
         return type;
@@ -96,6 +105,9 @@ public class RCUserSeatApplyMessage extends MessageContent {
             if (jsonObject.has("audienceName")) {
                 audienceName = jsonObject.optString("audienceName");
             }
+            if (jsonObject.has("audienceAvatar")) {
+                audienceAvatar = jsonObject.optString("audienceAvatar");
+            }
 
             if (jsonObject.has("user")) {
                 setUserInfo(this.parseJsonToUserInfo(jsonObject.getJSONObject("user")));
@@ -129,6 +141,10 @@ public class RCUserSeatApplyMessage extends MessageContent {
                 jsonObj.putOpt("audienceName", audienceName);
             }
 
+            if (!TextUtils.isEmpty(audienceAvatar)) {
+                jsonObj.putOpt("audienceAvatar", audienceAvatar);
+            }
+
             JSONObject jsonUserInfo = this.getJSONUserInfo();
             if (jsonUserInfo != null) {
                 jsonObj.putOpt("user", jsonUserInfo);
@@ -157,6 +173,7 @@ public class RCUserSeatApplyMessage extends MessageContent {
         dest.writeString(this.teacherId);
         dest.writeString(this.audienceId);
         dest.writeString(this.audienceName);
+        dest.writeString(this.audienceAvatar);
         ParcelUtils.writeToParcel(dest, getExtra());
         ParcelUtils.writeToParcel(dest, getUserInfo());
     }
@@ -167,6 +184,7 @@ public class RCUserSeatApplyMessage extends MessageContent {
         this.teacherId = in.readString();
         this.audienceId = in.readString();
         this.audienceName = in.readString();
+        this.audienceAvatar = in.readString();
         this.setExtra(ParcelUtils.readFromParcel(in));
         this.setUserInfo((UserInfo) ParcelUtils.readFromParcel(in, UserInfo.class));
     }

+ 1 - 1
student/src/main/java/com/cooleshow/student/presenter/live/LiveRoomPresenter.java

@@ -9,7 +9,7 @@ import com.cooleshow.base.rx.BaseObserver;
 import com.cooleshow.base.utils.RequestBodyUtil;
 import com.cooleshow.student.api.APIService;
 import com.cooleshow.student.bean.FriendInfoBean;
-import com.cooleshow.student.bean.ImUserState;
+import com.rong.io.live.bean.ImUserState;
 import com.cooleshow.student.bean.LiveRoomInfoBean;
 import com.cooleshow.student.contract.LiveRoomContract;
 import com.rong.io.live.helper.LiveRTCEngineInitHelper;

+ 1 - 1
teacher/src/main/AndroidManifest.xml

@@ -281,7 +281,7 @@
             android:configChanges="orientation|screenSize|keyboardHidden"
             android:screenOrientation="portrait" />
         <activity
-            android:name=".ui.live.LiveRoomActivity"
+            android:name=".ui.live.TeacherLiveRoomActivity"
             android:configChanges="orientation|screenSize|keyboardHidden"
             android:exported="false"
             android:launchMode="singleTask"

+ 2 - 2
teacher/src/main/java/com/cooleshow/teacher/adapter/MessageAdapter.java → teacher/src/main/java/com/cooleshow/teacher/adapter/LiveRoomMessageAdapter.java

@@ -38,7 +38,7 @@ import io.rong.message.TextMessage;
 /**
  * Author by pq, Date on 2022/3/31.
  */
-public class MessageAdapter extends RecyclerView.Adapter {
+public class LiveRoomMessageAdapter extends RecyclerView.Adapter {
     private Context context;
     private String roomAuthorId = "";
     private ArrayList<Message> mMessageList;
@@ -57,7 +57,7 @@ public class MessageAdapter extends RecyclerView.Adapter {
             LiveRoomMsgConstants.TAG_CHAT_ROOM_SEAT_RESPONSE, LiveRoomMsgConstants.TAG_LIVE_ON_SNAP_UP};
     public List<String> msgTags;
 
-    public MessageAdapter(Context context) {
+    public LiveRoomMessageAdapter(Context context) {
         this.context = context;
         mMessageList = new ArrayList();
         msgTags = Arrays.asList(MSG_TAGS);

+ 42 - 1
teacher/src/main/java/com/cooleshow/teacher/api/APIService.java

@@ -600,7 +600,7 @@ public interface APIService {
      *
      * @return
      */
-    @GET(TEACHER_GROUP + "liveRoom/queryRoomInfo")
+    @GET(TEACHER_GROUP + "liveRoom/speakerCheckRoomInfo")
     Observable<BaseResponse<LiveRoomInfoBean>> getLiveRoomInfo(@Query("roomUid") String roomUid);
 
     /**
@@ -612,4 +612,45 @@ public interface APIService {
     @GET
     @Headers("User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4)")
     Observable<ResponseBody> downloadFileWithFixedUrl(@Url String url);
+
+
+    /**
+     * 通知加入直播房间成功
+     *
+     * @return
+     */
+    @GET(TEACHER_GROUP + "liveRoom/speakerJoinRoom")
+    Observable<BaseResponse<Object>> notifyJoinRoomAction(@Query("roomUid") String roomUid, @Query("userId") String userId);
+
+    /**
+     * 通知离开直播房间
+     *
+     * @return
+     */
+    @POST(TEACHER_GROUP+"liveRoom/syncUserStatus")
+    Observable<BaseResponse<Object>> notifyLeaveRoomAction(@Body RequestBody body);
+
+    /**
+     * 通知(关闭/开启)直播录像
+     *
+     * @return type 1:开始直播-开始录像 2:关闭直播关闭录像
+     */
+    @GET(TEACHER_GROUP + "imLiveBroadcastRoom/opsLiveVideo")
+    Observable<BaseResponse<Object>> notifyOpenOpsLiveVideoAction(@Query("roomUid") String roomUid, @Query("type") String type, @Query("userId") String userId,@Query("videoResolution") String videoResolution);
+
+    /**
+     * 关闭直播间
+     *
+     * @return
+     */
+    @GET(TEACHER_GROUP + "liveRoom/destroyLiveRoom")
+    Observable<BaseResponse<Object>> notifyCloseLiveRoomAction(@Query("roomUid") String roomUid);
+
+    /**
+     * 同步点赞数量
+     *
+     * @return
+     */
+    @GET(TEACHER_GROUP + "liveRoom/syncLike")
+    Observable<BaseResponse<Object>> syncAddLikeNum(@Query("likeNum") String likeNum, @Query("roomUid") String roomUid);
 }

+ 49 - 0
teacher/src/main/java/com/cooleshow/teacher/contract/LiveRoomContract.java

@@ -4,10 +4,16 @@ import android.view.View;
 
 import com.cooleshow.base.presenter.view.BaseView;
 import com.cooleshow.teacher.bean.LiveRoomInfoBean;
+import com.rong.io.live.message.RCChatJoinRoomMessage;
+import com.rong.io.live.message.RCOnSnappingUpMessage;
+import com.rong.io.live.message.RCUserAddLikeMessage;
+import com.rong.io.live.message.RCUserSeatApplyMessage;
 
 import java.util.List;
 
+import cn.rongcloud.rtc.api.RCRTCRemoteUser;
 import cn.rongcloud.rtc.api.stream.RCRTCVideoView;
+import cn.rongcloud.rtc.base.RCRTCLiveRole;
 import io.rong.imlib.model.Message;
 import io.rong.imlib.model.MessageContent;
 
@@ -66,8 +72,51 @@ public interface LiveRoomContract {
         void openCameraSuccess(Boolean data);
 
         void openCameraError(String errorMsg);
+
+        /**
+         * 成员同步
+         *
+         * @param count
+         */
+        void syncMemberCount(String count);
+
+        /**
+         * 加入房间消息
+         *
+         * @param joinRoomMessage
+         */
+        void receiveJoinMessage(RCChatJoinRoomMessage joinRoomMessage);
+        /**
+         * 抢购消息
+         *
+         * @param
+         */
+        void receiveSnapUpMessage(RCOnSnappingUpMessage snappingUpMessage);
+
+        void liveRoomOffline();
+
+        void onAddLikeMessage(RCUserAddLikeMessage addLikeMessage);
+
+        void onUserJoinRoom(RCRTCRemoteUser rcrtcRemoteUser);
+
+        void onUserLeftRoomMic(RCRTCRemoteUser rcrtcRemoteUser);
+
+        void onUserOfflineRoomMic(RCRTCRemoteUser rcrtcRemoteUser);
+
+        void onSwitchRole(String userId, RCRTCLiveRole role);
+
+        /**
+         * 连麦申请
+         */
+        void onSeatApplyMessage(RCUserSeatApplyMessage seatApplyMessage);
+
     }
 
     interface Presenter {
+        void handleAction(int action, Object... params);
+
+        void notifyJoinRoomAction(String roomId, String userId);
+
+        void notifyLeaveRoomAction();
     }
 }

+ 80 - 0
teacher/src/main/java/com/cooleshow/teacher/helper/LiveRoomAnimatorHelper.java

@@ -0,0 +1,80 @@
+package com.cooleshow.teacher.helper;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.view.View;
+import android.view.animation.LinearInterpolator;
+
+import java.util.ArrayList;
+
+/**
+ * Author by pq, Date on 2022/4/7.
+ */
+public class LiveRoomAnimatorHelper {
+    private volatile static LiveRoomAnimatorHelper mHelper;
+    private ArrayList<View> animaViews = new ArrayList<>();
+    private ArrayList<AnimatorSet> animations = new ArrayList<>();
+
+
+    private LiveRoomAnimatorHelper() {
+
+    }
+
+    public static LiveRoomAnimatorHelper getInstance() {
+        if (mHelper == null) {
+            synchronized (LiveRoomAnimatorHelper.class) {
+                if (mHelper == null) {
+                    mHelper = new LiveRoomAnimatorHelper();
+                }
+            }
+        }
+        return mHelper;
+    }
+
+    public void startBarrageViewAnimation(Context context, View targetView) {
+        targetView.setVisibility(View.VISIBLE);
+        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(targetView, "translationX", -300, 0f);
+        ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(targetView, "alpha", 0.2f, 1f);
+        AnimatorSet animatorSet = new AnimatorSet();
+        LinearInterpolator linearInterpolator = new LinearInterpolator();
+        animatorSet.setInterpolator(linearInterpolator);
+        animatorSet.play(objectAnimator).with(objectAnimator2);
+        animatorSet.setDuration(1000);
+        animatorSet.start();
+        animaViews.add(targetView);
+        animations.add(animatorSet);
+        animatorSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                if (animaViews != null) {
+                    animaViews.remove(targetView);
+                }
+                if (animations != null) {
+                    animations.remove(animatorSet);
+                }
+            }
+        });
+    }
+
+    public void releaseAnimator() {
+        if (animaViews != null) {
+            for (int i = 0; i < animaViews.size(); i++) {
+                View view = animaViews.get(i);
+                view.clearAnimation();
+            }
+        }
+        if (animations != null) {
+            for (int i = 0; i < animations.size(); i++) {
+                AnimatorSet animatorSet = animations.get(i);
+                animatorSet.cancel();
+                animatorSet = null;
+            }
+        }
+    }
+
+
+}

+ 262 - 25
teacher/src/main/java/com/cooleshow/teacher/presenter/live/LiveRoomPresenter.java

@@ -3,20 +3,30 @@ package com.cooleshow.teacher.presenter.live;
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.cooleshow.base.data.net.BaseResponse;
 import com.cooleshow.base.presenter.BasePresenter;
 import com.cooleshow.base.rx.BaseObserver;
+import com.cooleshow.base.utils.RequestBodyUtil;
 import com.cooleshow.base.utils.Utils;
 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.daya.live_teaching.common.ErrorCode;
+import com.daya.live_teaching.common.ResultCallback;
+import com.google.gson.Gson;
 import com.rong.io.live.LiveRoomMsgConstants;
+import com.rong.io.live.bean.ImUserState;
+import com.rong.io.live.bean.User;
 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 com.rong.io.live.message.RCPauseLiveMessage;
+import com.rong.io.live.message.RCUserSeatResponseMessage;
+import com.rong.io.live.message.RCUserSyncAddLikeCountMessage;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -24,6 +34,7 @@ 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.IRCRTCResultCallback;
 import cn.rongcloud.rtc.api.callback.IRCRTCResultDataCallback;
 import cn.rongcloud.rtc.api.callback.IRCRTCRoomEventsListener;
 import cn.rongcloud.rtc.api.stream.RCRTCAudioInputStream;
@@ -48,12 +59,14 @@ 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.observers.DisposableObserver;
 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;
+import okhttp3.RequestBody;
 
 /**
  * Author by pq, Date on 2022/6/5.
@@ -160,12 +173,7 @@ public class LiveRoomPresenter extends BasePresenter<LiveRoomContract.LiveRoomVi
             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);
+            connectIM();
         }
     }
 
@@ -201,7 +209,7 @@ public class LiveRoomPresenter extends BasePresenter<LiveRoomContract.LiveRoomVi
     /**
      * 初始化配置以及预览模式
      */
-    public void openVideoPreview(){
+    public void openVideoPreview() {
         initPublishConfig();
         startVideoPreview();
     }
@@ -209,7 +217,7 @@ public class LiveRoomPresenter extends BasePresenter<LiveRoomContract.LiveRoomVi
     /**
      * 切换摄像头
      */
-    public void reverseCamera(){
+    public void reverseCamera() {
         RCRTCEngine.getInstance().getDefaultVideoStream().switchCamera(new CameraVideoCapturer.CameraSwitchHandler() {
             @Override
             public void onCameraSwitchDone(boolean isFrontCamera) {
@@ -247,6 +255,18 @@ public class LiveRoomPresenter extends BasePresenter<LiveRoomContract.LiveRoomVi
     }
 
     /**
+     * 取消发布流
+     */
+    public void cancelPublish(IRCRTCResultCallback resultCallback) {
+        RCRTCRoom rcrtcRoom = LiveEventHelper.getInstance().getRtcRoom();
+        if (rcrtcRoom == null) {
+            return;
+        }
+        rcrtcRoom.getLocalUser().unpublishDefaultLiveStreams(resultCallback);
+    }
+
+
+    /**
      * 开启预览
      *
      * @param
@@ -275,22 +295,58 @@ public class LiveRoomPresenter extends BasePresenter<LiveRoomContract.LiveRoomVi
         });
     }
 
-    private void initPublishConfig() {
+    public void initPublishConfig() {
         try {
-
             RCRTCVideoStreamConfig config =
                     RCRTCVideoStreamConfig.Builder.create()
-                            .setMinRate(200)
-                            .setMaxRate(900)
                             .setVideoFps(RCRTCParamsType.RCRTCVideoFps.Fps_30)
-                            .setVideoResolution(RCRTCParamsType.RCRTCVideoResolution.RESOLUTION_720_1280)
+                            .setVideoResolution(RCRTCParamsType.RCRTCVideoResolution.RESOLUTION_1080_1920)
                             .build();
+            //音乐教学场景。不建议在会议、语聊房、直播场景中使用 MUSIC_CLASSROOM,否则有出现回声问题的风险。
             RCRTCEngine.getInstance().getDefaultVideoStream().setVideoConfig(config);
+            RCRTCEngine.getInstance().getDefaultAudioStream().setAudioQuality(RCRTCParamsType.AudioQuality.MUSIC_HIGH, RCRTCParamsType.AudioScenario.MUSIC_CHATROOM);
+            RCRTCEngine.getInstance().getDefaultVideoStream().enableTinyStream(false);//只发布大流
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
 
+    @Override
+    public void handleAction(int action, Object... params) {
+        //处理教师端直播间操作
+        if (action == LiveRoomMsgConstants.ACTION_AGREE_MIC_APPLY) {
+            //主讲人同意连麦申请
+            Object param = params[0];
+            if (param instanceof User) {
+                User user = (User) param;
+                RCUserSeatResponseMessage rcUserSeatResponseMessage = new RCUserSeatResponseMessage();
+                rcUserSeatResponseMessage.setTeacherId(UserHelper.getUserId());
+                rcUserSeatResponseMessage.setTeacherName(UserHelper.getUserName());
+                rcUserSeatResponseMessage.setAudienceId(user.getUserId());
+                rcUserSeatResponseMessage.setAudienceName(user.getUserName());
+                rcUserSeatResponseMessage.setType(LiveRoomMsgConstants.MIC_RESPONSE_AGREE);
+                sendMessage(rcUserSeatResponseMessage, false);
+            }
+            return;
+        }
+
+        if (action == LiveRoomMsgConstants.ACTION_SEND_ADD_LIKE_COUNT) {
+            //发送点赞数量总数
+            int count = (int) params[0];
+            RCUserSyncAddLikeCountMessage syncAddLikeCountMessage = new RCUserSyncAddLikeCountMessage();
+            syncAddLikeCountMessage.setCount(count);
+            sendMessage(syncAddLikeCountMessage, false);
+            return;
+        }
+
+        if (action == LiveRoomMsgConstants.ACTION_SEND_PAUSE_LIVE) {
+            //暂停直播消息
+            RCPauseLiveMessage pauseLiveMessage = new RCPauseLiveMessage();
+            sendMessage(pauseLiveMessage, false);
+            return;
+        }
+    }
+
     /**
      * 加入房间
      *
@@ -324,14 +380,6 @@ public class LiveRoomPresenter extends BasePresenter<LiveRoomContract.LiveRoomVi
      */
     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();获取敏感词汇
@@ -344,7 +392,7 @@ public class LiveRoomPresenter extends BasePresenter<LiveRoomContract.LiveRoomVi
     /**
      * 加入房间后,开始摄像头采集并发布音视频流。
      */
-    private void startPublish() {
+    public void startPublish() {
         RCRTCRoom rcrtcRoom = LiveEventHelper.getInstance().getRtcRoom();
         RCRTCEngine.getInstance().getDefaultVideoStream().startCamera(null);
         rcrtcRoom.getLocalUser().publishDefaultLiveStreams(new IRCRTCResultDataCallback<RCRTCLiveInfo>() {
@@ -504,10 +552,18 @@ public class LiveRoomPresenter extends BasePresenter<LiveRoomContract.LiveRoomVi
     /**
      * 连接融云IM
      *
-     * @param imToken
+     * @param
      */
-    private void connectIM(String imToken) {
-        IMCenter.getInstance().connect(imToken, new RongIMClient.ConnectCallback() {
+    public void connectIM() {
+        String imtoken = UserHelper.getUserIMToken();
+        Log.i("pq", "im未连接,token:" + imtoken);
+        if (TextUtils.isEmpty(imtoken)) {
+            return;
+        }
+        if (getView() != null) {
+            getView().showLoading();
+        }
+        IMCenter.getInstance().connect(imtoken, new RongIMClient.ConnectCallback() {
             @Override
             public void onSuccess(String t) {
                 Log.i("pq", "连接成功");
@@ -524,4 +580,185 @@ public class LiveRoomPresenter extends BasePresenter<LiveRoomContract.LiveRoomVi
             }
         });
     }
+
+    @Override
+    public void notifyJoinRoomAction(String roomId, String userId) {
+        //主进程调用,因为BaseObserver onStart show了loading控件,防止在子线程创建
+        addSubscribe(create(APIService.class).notifyJoinRoomAction(roomId, userId), new DisposableObserver() {
+            @Override
+            public void onNext(Object o) {
+                //通知服务端加入成功即可,无须关注结果
+            }
+
+            @Override
+            public void onError(Throwable e) {
+                e.printStackTrace();
+            }
+
+            @Override
+            public void onComplete() {
+
+            }
+        });
+    }
+
+    /**
+     * 通知服务端离开直播间
+     */
+    @Override
+    public void notifyLeaveRoomAction() {
+        handleAction(LiveRoomMsgConstants.ACTION_SEND_LEAVE_ROOM);
+        ImUserState imUserState = new ImUserState();
+        imUserState.setStatus(ImUserState.ACTION_LEAVE_LIVE_ROOM);
+        imUserState.setUserid(UserHelper.getUserId());
+        ArrayList<ImUserState> imUserStates = new ArrayList();
+        imUserStates.add(imUserState);
+        RequestBody body = RequestBodyUtil.convertToRequestBodyJson(new Gson().toJson(imUserStates));
+        create(APIService.class).notifyLeaveRoomAction(body)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new Observer<BaseResponse<Object>>() {
+                    @Override
+                    public void onSubscribe(Disposable d) {
+
+                    }
+
+                    @Override
+                    public void onNext(BaseResponse<Object> objectBaseResponse) {
+                        //通知服务端离开即可,无须关注结果
+                    }
+
+                    @Override
+                    public void onError(Throwable e) {
+
+                    }
+
+                    @Override
+                    public void onComplete() {
+                        //通知服务端离开即可,无须关注结果
+                    }
+                });
+    }
+
+
+    /**
+     * 通知(开启/关闭)直播间录像
+     *
+     * @param roomId
+     * @param type
+     * @param userId
+     */
+    public void notifyOpenOpsLiveVideoAction(String roomId, String type, String userId) {
+        addSubscribe(create(APIService.class).notifyOpenOpsLiveVideoAction(roomId, type, userId,"1080x1920"), new DisposableObserver() {
+            @Override
+            public void onNext(Object o) {
+                //通知服务端加入成功即可,无须关注结果
+            }
+
+            @Override
+            public void onError(Throwable e) {
+                e.printStackTrace();
+            }
+
+            @Override
+            public void onComplete() {
+
+            }
+        });
+    }
+
+    /**
+     * 通知关闭直播间
+     *
+     * @param roomId
+     */
+    public void notifyCloseLiveRoomAction(String roomId) {
+        addSubscribe(create(APIService.class).notifyCloseLiveRoomAction(roomId), new DisposableObserver() {
+            @Override
+            public void onNext(Object o) {
+                //通知服务端加入成功即可,无须关注结果
+            }
+
+            @Override
+            public void onError(Throwable e) {
+                e.printStackTrace();
+            }
+
+            @Override
+            public void onComplete() {
+
+            }
+        });
+    }
+
+    /**
+     * 同步点赞数量
+     *
+     * @param addLikeNum
+     * @param roomUid
+     */
+    public void syncAddLikeNum(String addLikeNum, String roomUid) {
+        addSubscribe(create(APIService.class).syncAddLikeNum(addLikeNum, roomUid), new DisposableObserver() {
+            @Override
+            public void onNext(Object o) {
+
+            }
+
+            @Override
+            public void onError(Throwable e) {
+
+            }
+
+            @Override
+            public void onComplete() {
+
+            }
+        });
+    }
+
+    /**
+     * 取消订阅指定的流
+     *
+     * @param userId
+     */
+    public void unSubscribeStream(final String userId, final ResultCallback<String> callback) {
+        RCRTCRoom rcrtcRoom = LiveEventHelper.getInstance().getRtcRoom();
+        if (rcrtcRoom == null) {
+            Log.i("pq", "unSubscribeStream failed , rcrtcRoom is null");
+            if (callback != null) {
+                callback.onFail(ErrorCode.RTC_ERROR.getCode(), null);
+            }
+            return;
+        }
+        RCRTCRemoteUser remoteUser = rcrtcRoom.getRemoteUser(userId);
+
+        if (remoteUser == null || remoteUser.getStreams() == null) {
+            Log.i("pq", "unSubscribeStream failed , remoteUser  = " + remoteUser);
+            if (callback != null) {
+                callback.onFail(ErrorCode.RTC_ERROR.getCode(), null);
+            }
+            return;
+        }
+
+        List<RCRTCInputStream> inputStreams = remoteUser.getStreams();
+        Log.i("pq", "unSubscribeStream , inputStreams  = " + inputStreams);
+        rcrtcRoom.getLocalUser().unsubscribeStreams(inputStreams, new IRCRTCResultCallback() {
+            @Override
+            public void onSuccess() {
+                Log.i("pq", "unSubscribeStream success,user = " + userId);
+                if (callback != null) {
+                    callback.onSuccess(userId);
+                }
+            }
+
+            @Override
+            public void onFailed(RTCErrorCode rtcErrorCode) {
+                Log.i("pq", "unSubscribeStream  error - " + rtcErrorCode.getReason());
+                if (callback != null) {
+                    callback.onFail(ErrorCode.RTC_ERROR.getCode(), null);
+                }
+            }
+        });
+
+    }
 }

+ 1 - 1
teacher/src/main/java/com/cooleshow/teacher/ui/live/CreateLiveActivity.java

@@ -73,7 +73,7 @@ public class CreateLiveActivity extends BaseMVPActivity<ActivityCreateLiveBindin
     @Override
     public void onCreateLiveSuccess(String roomId) {
         ToastUtils.showShort("创建成功");
-        LiveRoomActivity.start(this, roomId);
+        TeacherLiveRoomActivity.start(this, roomId);
         finish();
     }
 }

+ 125 - 0
teacher/src/main/java/com/cooleshow/teacher/ui/live/LiveApplyMicFragment.java

@@ -0,0 +1,125 @@
+package com.cooleshow.teacher.ui.live;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.bumptech.glide.Glide;
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.viewholder.BaseViewHolder;
+import com.cooleshow.base.ui.fragment.BaseFragment;
+import com.cooleshow.teacher.R;
+import com.cooleshow.teacher.databinding.FragmentLiveApplyMicLayoutBinding;
+import com.cooleshow.teacher.widgets.dialog.LiveMicManagerDialog;
+import com.rong.io.live.bean.User;
+
+import java.util.ArrayList;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * Author by pq, Date on 2022/6/13.
+ * 直播间申请连麦列表页面
+ */
+public class LiveApplyMicFragment extends BaseFragment<FragmentLiveApplyMicLayoutBinding> {
+    RecyclerView recyclerView;
+
+    private LiveMicManagerDialog.OnEventListener mEventListener;
+
+    private ArrayList<User> mList = new ArrayList<>();
+    private Adapter mAdapter;
+
+
+    @Override
+    protected FragmentLiveApplyMicLayoutBinding getLayoutView() {
+        return FragmentLiveApplyMicLayoutBinding.inflate(getLayoutInflater());
+    }
+
+    @Override
+    protected void initView(View rootView) {
+
+    }
+
+    @Override
+    protected void initData() {
+        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
+        recyclerView.setLayoutManager(linearLayoutManager);
+        mAdapter = new Adapter(R.layout.item_live_mic_manager_layout);
+        recyclerView.setAdapter(mAdapter);
+    }
+
+    public void onClick(View view) {
+        int id = view.getId();
+        if (id == R.id.tv_refuse_all) {
+            //全部拒绝
+            if (mEventListener != null) {
+                mEventListener.onRefuseAllMicApply();
+            }
+            return;
+        }
+
+        if (id == R.id.tv_enable_mic) {
+            //禁止连麦
+            return;
+        }
+    }
+
+    /**
+     * 刷新
+     *
+     * @param applyListData
+     */
+    public void refresh(ArrayList<User> applyListData) {
+        mList.clear();
+        mList.addAll(applyListData);
+        if (mAdapter != null) {
+            mAdapter.notifyDataSetChanged();
+        }
+    }
+
+    public void setOnEventListener(LiveMicManagerDialog.OnEventListener listener) {
+        this.mEventListener = listener;
+    }
+
+    private class Adapter extends BaseQuickAdapter<User,Adapter.ViewHolder> {
+
+        public Adapter(int layoutResId) {
+            super(layoutResId);
+        }
+
+        @Override
+        public int getItemCount() {
+            return mList != null ? mList.size() : 0;
+        }
+
+        @Override
+        protected void convert(@NonNull ViewHolder viewHolder, User user) {
+            //创建人头像
+            Glide.with(getContext()).load(user.getPortraitUrl()).placeholder(R.drawable.icon_teacher_default_head).error(R.drawable.icon_teacher_default_head).into(viewHolder.ivAvatar);
+            //名称
+            viewHolder.tvName.setText(user.getUserName());
+            viewHolder.tvTip.setText("申请连麦中");
+            viewHolder.tvHandle.setText("上麦");
+        }
+
+        public class ViewHolder extends BaseViewHolder {
+            ImageView ivAvatar;
+            TextView tvName;
+            TextView tvTip;
+            TextView tvHandle;
+
+            public ViewHolder(View itemView) {
+                super(itemView);
+                ivAvatar = itemView.findViewById(R.id.iv_avatar);
+                tvName = itemView.findViewById(R.id.tv_name);
+                tvTip = itemView.findViewById(R.id.tv_tip);
+                tvHandle = itemView.findViewById(R.id.tv_handle);
+            }
+        }
+    }
+
+}

+ 130 - 0
teacher/src/main/java/com/cooleshow/teacher/ui/live/LiveOnMicFragment.java

@@ -0,0 +1,130 @@
+package com.cooleshow.teacher.ui.live;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.bumptech.glide.Glide;
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.viewholder.BaseViewHolder;
+import com.cooleshow.base.ui.fragment.BaseFragment;
+import com.cooleshow.teacher.R;
+import com.cooleshow.teacher.databinding.FragmentLiveOnMicLayoutBinding;
+import com.cooleshow.teacher.widgets.dialog.LiveMicManagerDialog;
+import com.rong.io.live.bean.User;
+
+import java.util.ArrayList;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * Author by pq, Date on 2022/6/13.
+ * 直播间连麦中列表页面
+ */
+public class LiveOnMicFragment extends BaseFragment<FragmentLiveOnMicLayoutBinding> {
+    RecyclerView recyclerView;
+    private LiveMicManagerDialog.OnEventListener mEventListener;
+    private ArrayList<User> mList = new ArrayList<>();
+    ;
+    private Adapter mAdapter;
+
+
+    @Override
+    protected FragmentLiveOnMicLayoutBinding getLayoutView() {
+        return FragmentLiveOnMicLayoutBinding.inflate(getLayoutInflater());
+    }
+
+    @Override
+    protected void initView(View rootView) {
+
+    }
+
+    @Override
+    protected void initData() {
+        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
+        recyclerView.setLayoutManager(linearLayoutManager);
+
+        mAdapter = new Adapter(R.layout.item_live_mic_manager_layout);
+//        mAdapter.setOnSubViewClickListener(new BaseRecyclerAdapter.OnSubViewClickListener() {
+//            @Override
+//            public void onSubViewClick(View v, int position) {
+//                if (v.getId() == R.id.tv_handle) {
+//                    //下麦操作
+//                    User user = mList.get(position);
+//                    if (mEventListener != null) {
+//                        mEventListener.onAgreeApply(user);
+//                    }
+//                }
+//            }
+//        });
+        recyclerView.setAdapter(mAdapter);
+    }
+
+    public void onClick(View view) {
+        int id = view.getId();
+        if (id == R.id.tv_down_all_mic) {
+            //全部下麦
+            return;
+        }
+    }
+
+    /**
+     * 刷新
+     *
+     * @param applyListData
+     */
+    public void refresh(ArrayList<User> applyListData) {
+        mList.clear();
+        mList.addAll(applyListData);
+        if (mAdapter != null) {
+            mAdapter.notifyDataSetChanged();
+        }
+    }
+
+    public void setOnEventListener(LiveMicManagerDialog.OnEventListener listener) {
+        this.mEventListener = listener;
+    }
+
+    private class Adapter extends BaseQuickAdapter<User,Adapter.ViewHolder> {
+
+        public Adapter(int layoutResId) {
+            super(layoutResId);
+        }
+
+        @Override
+        public int getItemCount() {
+            return mList != null ? mList.size() : 0;
+        }
+
+        @Override
+        protected void convert(@NonNull ViewHolder viewHolder, User user) {
+            //创建人头像
+            Glide.with(getContext()).load(user.getPortraitUrl()).placeholder(R.drawable.icon_teacher_default_head).error(R.drawable.icon_teacher_default_head).into(viewHolder.ivAvatar);
+            //名称
+
+            viewHolder.tvName.setText(user.getUserName());
+            viewHolder.tvTip.setText("连麦中");
+            viewHolder.tvHandle.setText("下麦");
+        }
+
+        public class ViewHolder extends BaseViewHolder {
+            ImageView ivAvatar;
+            TextView tvName;
+            TextView tvTip;
+            TextView tvHandle;
+
+            public ViewHolder(View itemView) {
+                super(itemView);
+                ivAvatar = itemView.findViewById(R.id.iv_avatar);
+                tvName = itemView.findViewById(R.id.tv_name);
+                tvTip = itemView.findViewById(R.id.tv_tip);
+                tvHandle = itemView.findViewById(R.id.tv_handle);
+            }
+
+        }
+    }
+}

+ 0 - 481
teacher/src/main/java/com/cooleshow/teacher/ui/live/LiveRoomActivity.java

@@ -1,481 +0,0 @@
-package com.cooleshow.teacher.ui.live;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.alibaba.android.arouter.facade.annotation.Route;
-import com.bumptech.glide.Glide;
-import com.cooleshow.base.router.RouterPath;
-import com.cooleshow.base.ui.activity.BaseMVPActivity;
-import com.cooleshow.base.utils.LogUtils;
-import com.cooleshow.base.utils.ToastUtil;
-import com.cooleshow.base.utils.ToastUtils;
-import com.cooleshow.base.utils.Utils;
-import com.cooleshow.teacher.R;
-import com.cooleshow.teacher.adapter.MessageAdapter;
-import com.cooleshow.teacher.bean.LiveRoomInfoBean;
-import com.cooleshow.teacher.contract.LiveRoomContract;
-import com.cooleshow.teacher.databinding.ActivityTeacherLiveRoomLayoutBinding;
-import com.cooleshow.teacher.presenter.live.LiveRoomPresenter;
-import com.cooleshow.teacher.widgets.dialog.LiveBeautyOptionsDialog;
-import com.cooleshow.teacher.widgets.helper.VideoViewManager;
-import com.cooleshow.usercenter.helper.UserHelper;
-import com.rong.io.live.config.LiveConfig;
-import com.rong.io.live.helper.LiveEventHelper;
-import com.rong.io.live.helper.LiveRTCEngineInitHelper;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import cn.rongcloud.rtc.api.RCRTCAudioRouteManager;
-import cn.rongcloud.rtc.api.RCRTCVideoStream;
-import cn.rongcloud.rtc.api.stream.RCRTCAudioInputStream;
-import cn.rongcloud.rtc.api.stream.RCRTCVideoInputStream;
-import cn.rongcloud.rtc.api.stream.RCRTCVideoOutputStream;
-import cn.rongcloud.rtc.api.stream.RCRTCVideoView;
-import cn.rongcloud.rtc.base.RCRTCMediaType;
-import cn.rongcloud.rtc.base.RCRTCResourceState;
-import io.rong.imkit.IMCenter;
-import io.rong.imlib.IRongCoreCallback;
-import io.rong.imlib.IRongCoreEnum;
-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.
- * 老师端直播间页面
- */
-@Route(path = RouterPath.LiveCenter.ACTIVITY_LIVE_ROOM_TEACHER)
-public class LiveRoomActivity extends BaseMVPActivity<ActivityTeacherLiveRoomLayoutBinding, LiveRoomPresenter> implements LiveRoomContract.LiveRoomView, View.OnClickListener {
-    public static final String ROOMID_KEY = "roomid_key";
-    private TextView mTvNumPeople;
-    private TextView mTvRoomCreateName;
-    private ImageView mIvAvatar;
-    public String mRoomId = "";
-    private VideoViewManager mVideoViewManager;
-    private boolean isNeedRefresh = false;//是否需要重新刷新房间信息
-    private LiveRoomInfoBean mRoomInfoBean;
-    private String mUserId;
-    private RongIMClient.ConnectionStatusListener connectStatusListener = new RongIMClient.ConnectionStatusListener() {
-        @Override
-        public void onChanged(ConnectionStatus status) {
-            Log.i("pq", "LiveRoomActivity receive ConnectionStatus:" + status);
-            if (status == ConnectionStatus.KICKED_OFFLINE_BY_OTHER_CLIENT
-                    || status == ConnectionStatus.SIGN_OUT || status == ConnectionStatus.TIMEOUT) {
-                finish();
-            }
-            if (status == ConnectionStatus.CONNECTED) {
-                //IM连接成功
-                if (presenter != null && isNeedRefresh) {
-                    presenter.init(mRoomId, true);
-                }
-            } else {
-                //其他状态的时候需要重新刷新房间信息
-                isNeedRefresh = true;
-            }
-        }
-    };
-    private MessageAdapter mMessageAdapter;
-    private LinearLayoutManager mLinearLayoutManager;
-    private LiveBeautyOptionsDialog mOptionsDialog;
-
-    public static void start(Context context, String roomId) {
-        Intent intent = new Intent(context, LiveRoomActivity.class);
-        intent.putExtra(ROOMID_KEY, roomId);
-        context.startActivity(intent);
-    }
-
-    @Override
-    protected void initView() {
-        viewBinding.viewCreateOptions.ivReverseCamera.setOnClickListener(this);
-        viewBinding.viewCreateOptions.ivLiveBeauty.setOnClickListener(this);
-        viewBinding.viewCreateOptions.ivLiveShare.setOnClickListener(this);
-        viewBinding.viewCreateOptions.tvStartLive.setOnClickListener(this);
-        viewBinding.viewCreateOptions.tvClose.setOnClickListener(this);
-        mTvNumPeople = viewBinding.viewMainLayout.tvNumPeople;
-        mTvRoomCreateName = viewBinding.viewMainLayout.tvRoomAuthorName;
-        mIvAvatar = viewBinding.viewMainLayout.ivAvatar;
-    }
-
-    @Override
-    public void initData() {
-        super.initData();
-        mRoomId = getIntent().getStringExtra(ROOMID_KEY);
-        if (TextUtils.isEmpty(mRoomId)) {
-            ToastUtil.getInstance().show(this, "房间id不可为空");
-            finish();
-            return;
-        }
-        String userToken = UserHelper.getUserToken();
-        if (TextUtils.isEmpty(userToken)) {
-            finish();
-            return;
-        }
-        mUserId = UserHelper.getUserId();
-        if (LiveConfig.isNeedReInitRTC) {
-            //检查是否需要重新初始化RTC
-            LiveRTCEngineInitHelper.initRTC();
-        }
-        //开启美颜
-        LiveRTCEngineInitHelper.openBeauty();
-
-        // 初始化音频路由管理类
-        RCRTCAudioRouteManager.getInstance().init(Utils.getApp());
-        viewBinding.flLiveView.post(new Runnable() {
-            @Override
-            public void run() {
-                checkVideoViewManager();
-            }
-        });
-        mMessageAdapter = new MessageAdapter(this);
-        mLinearLayoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false);
-        viewBinding.viewMainLayout.recyclerMsg.setLayoutManager(mLinearLayoutManager);
-        viewBinding.viewMainLayout.recyclerMsg.setAdapter(mMessageAdapter);
-        IMCenter.getInstance().addConnectionStatusListener(connectStatusListener);
-//        SoftKeyboardUtil.registerSoftInputChangedListener(getWindow(), this);
-        prepareInitRoom();
-    }
-
-    private void prepareInitRoom() {
-        //根据融云的IM连接状态判断是否需要获取房间信息
-        RongIMClient.ConnectionStatusListener.ConnectionStatus currentConnectionStatus = RongIMClient.getInstance().getCurrentConnectionStatus();
-        if (currentConnectionStatus == RongIMClient.ConnectionStatusListener.ConnectionStatus.CONNECTED) {
-            isNeedRefresh = false;
-            if (presenter != null) {
-                presenter.init(mRoomId, true);
-            }
-        } else {
-            //如果IM未连接,等待connectStatusListener回调
-            isNeedRefresh = true;
-        }
-    }
-
-
-    /**
-     * 检查VideoViewManager是否未null;
-     */
-    private void checkVideoViewManager() {
-        if (mVideoViewManager == null) {
-            mVideoViewManager = new VideoViewManager(viewBinding.flLiveView, viewBinding.flLiveView.getWidth(), viewBinding.flLiveView.getHeight());
-            mVideoViewManager.setRetryClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    if (presenter != null) {
-                        //重新订阅房间的流信息
-//                        presenter.subscribeAVStream();
-                    }
-                }
-            });
-        }
-    }
-
-    @Override
-    protected ActivityTeacherLiveRoomLayoutBinding getLayoutView() {
-        return ActivityTeacherLiveRoomLayoutBinding.inflate(getLayoutInflater());
-    }
-
-    @Override
-    protected LiveRoomPresenter createPresenter() {
-        return new LiveRoomPresenter();
-    }
-
-    /**
-     * 获取房间信息成功
-     *
-     * @param roomInfoBean
-     */
-    @Override
-    public void getRoomInfoSuccess(LiveRoomInfoBean roomInfoBean) {
-        if (isFinishing() || isDestroyed()) {
-            return;
-        }
-        if (roomInfoBean == null) {
-            ToastUtils.showShort("获取房间信息失败,请退出重试");
-            finish();
-            return;
-        }
-        mRoomInfoBean = roomInfoBean;
-        if (mMessageAdapter != null) {
-            mMessageAdapter.setRoomAuthorId(roomInfoBean.speakerId);
-        }
-        int peopleCount = roomInfoBean.lookNum + 1;//加上自己
-        mTvNumPeople.setText(peopleCount + "人");
-        //创建人头像
-        Glide.with(LiveRoomActivity.this).load(roomInfoBean.speakerPic).placeholder(R.drawable.icon_teacher_default_head).error(R.drawable.icon_teacher_default_head).into(mIvAvatar);
-        //创建人昵称
-        mTvRoomCreateName.setText(roomInfoBean.speakerName);
-        if (presenter != null) {
-            //加入聊天室
-            //加入直播间
-            showLoading();
-            LiveEventHelper.getInstance().register(roomInfoBean.roomUid);
-            presenter.openVideoPreview();
-//            presenter.joinChartRoom(mRoomInfoBean.roomUid, new IRongCoreCallback.OperationCallback() {
-//                @Override
-//                public void onSuccess() {
-//                    Log.i("pq", "加入聊天房间成功");
-//                    if (presenter != null) {
-////                        presenter.handleAction(LiveRoomMsgConstants.ACTION_SEND_JOIN_ROOM);
-//                        presenter.sendDefaultMessage();
-//                    }
-//                }
-//
-//                @Override
-//                public void onError(IRongCoreEnum.CoreErrorCode coreErrorCode) {
-//                    Log.i("pq", "加入聊天房间fail:" + coreErrorCode);
-//                    Toast.makeText(LiveRoomActivity.this, "加入聊天房间fail:" + coreErrorCode, Toast.LENGTH_SHORT).show();
-//                }
-//            });
-        }
-    }
-
-    @Override
-    public void onClick(View v) {
-        int id = v.getId();
-        if (id == R.id.iv_reverse_camera) {
-            //翻转摄像头
-            presenter.reverseCamera();
-            return;
-        }
-        if (id == R.id.iv_live_beauty) {
-            //美颜
-            showBeautyOptionsDialog();
-            return;
-        }
-
-        if (id == R.id.tv_start_live) {
-            //开始直播
-            if (mRoomInfoBean != null) {
-                presenter.prepareJoinRoom(mRoomInfoBean.roomUid, true);
-            }
-        }
-    }
-
-    /**
-     * 获取房间信息失败
-     *
-     * @param throwable
-     */
-    @Override
-    public void getRoomInfoError(Throwable throwable) {
-        if (isFinishing() || isDestroyed()) {
-            return;
-        }
-        ToastUtils.showShort("获取房间信息失败,请退出重试");
-        finish();
-    }
-
-    @Override
-    public void showFinishView() {
-
-    }
-
-    @Override
-    public void addMessageList(List<MessageContent> messageContents, boolean isReset) {
-
-    }
-
-    @Override
-    public void addMessageContent(Message message, boolean isReset) {
-        //添加单条消息至页面
-        Log.i("pq", "收到需要显示msg:" + message);
-        //只处理直播间消息,以及本直播间消息
-        if (mMessageAdapter != null) {
-            mMessageAdapter.addMessage(message);
-            if (mLinearLayoutManager != null) {
-                viewBinding.viewMainLayout.recyclerMsg.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (viewBinding.viewMainLayout.recyclerMsg != null) {
-                            viewBinding.viewMainLayout.recyclerMsg.scrollToPosition(mMessageAdapter.getItemCount() - 1);
-                        }
-                    }
-                });
-            }
-        }
-    }
-
-    @Override
-    public void setRoomData(LiveRoomInfoBean roomInfoBean) {
-        //加入聊天房间
-        presenter.joinChartRoom(roomInfoBean.roomUid, new IRongCoreCallback.OperationCallback() {
-            @Override
-            public void onSuccess() {
-                Log.i("pq", "加入聊天房间成功");
-                presenter.sendDefaultMessage();
-            }
-
-            @Override
-            public void onError(IRongCoreEnum.CoreErrorCode coreErrorCode) {
-                Log.i("pq", "加入聊天房间fail:" + coreErrorCode);
-            }
-        });
-    }
-
-    @Override
-    public void onPublishSuccess() {
-        refresh();
-    }
-
-    @Override
-    public View getContentView() {
-        return viewBinding.flLiveView;
-    }
-
-    /**
-     * 预览模式
-     *
-     * @param videoView
-     */
-    @Override
-    public void addVideoPreview(RCRTCVideoView videoView) {
-        checkVideoViewManager();
-        if (mVideoViewManager != null) {
-            ArrayList<RCRTCVideoView> videoViews = new ArrayList<>();
-            videoViews.add(videoView);
-            mVideoViewManager.update(videoViews, false);
-        } else {
-            LogUtils.i("pq", "mVideoViewManager == null");
-        }
-    }
-
-    @Override
-    public void openCameraSuccess(Boolean data) {
-        Log.i("pq", "openCameraSuccess:" + data);
-    }
-
-    @Override
-    public void openCameraError(String errorMsg) {
-        viewBinding.flLiveView.post(new Runnable() {
-            @Override
-            public void run() {
-                ToastUtil.getInstance().show(LiveRoomActivity.this, errorMsg);
-            }
-        });
-    }
-
-
-    private void refresh() {
-        List<RCRTCVideoOutputStream> outputStreams = new ArrayList<>();
-        List<RCRTCVideoInputStream> input = new ArrayList<>();
-        List<RCRTCAudioInputStream> audioinputstream = new ArrayList<>();
-        presenter.getVideoStream(outputStreams, input, audioinputstream);
-        updateVideoView(outputStreams, input, audioinputstream);
-    }
-
-    public void updateVideoView(List<RCRTCVideoOutputStream> outputStreams, List<RCRTCVideoInputStream> inputStreams, List<RCRTCAudioInputStream> audioInputStreams) {
-        viewBinding.flLiveView.post(new Runnable() {
-            @Override
-            public void run() {
-                //隐藏配置页
-                if (viewBinding.viewCreateOptions.getRoot().getVisibility() == View.VISIBLE) {
-                    viewBinding.viewCreateOptions.getRoot().setVisibility(View.GONE);
-                    viewBinding.viewMainLayout.getRoot().setVisibility(View.VISIBLE);
-                }
-                ArrayList<RCRTCVideoStream> videoStreams = new ArrayList<RCRTCVideoStream>();
-                videoStreams.addAll(outputStreams);
-                videoStreams.addAll(inputStreams);
-                ArrayList<RCRTCVideoView> list = new ArrayList<>();
-                ArrayList<String> otherAudioUserIds = new ArrayList<>();
-                boolean isNormalCreateAudioStatus = true;
-
-                //视频流
-                for (int i = 0; i < videoStreams.size(); i++) {
-                    RCRTCVideoStream rcrtcVideoStream = videoStreams.get(i);
-                    RCRTCVideoView rongRTCVideoView = new RCRTCVideoView(LiveRoomActivity.this);
-                    rcrtcVideoStream.setVideoView(rongRTCVideoView);
-                    list.add(rongRTCVideoView);
-                }
-
-                //音频流
-                for (int i = 0; i < audioInputStreams.size(); i++) {
-                    RCRTCAudioInputStream audioInputStream = audioInputStreams.get(i);
-                    if (audioInputStream.getMediaType() == RCRTCMediaType.AUDIO) {
-                        //音频流判断显示上麦用户
-                        String userId = audioInputStream.getUserId();
-                        if (TextUtils.equals(mUserId, userId)) {
-                            continue;
-                        }
-                        if (mRoomInfoBean != null) {
-                            if (!TextUtils.equals(mRoomInfoBean.speakerId, userId)) {
-                                otherAudioUserIds.add(userId);
-                            } else {
-                                //主播的音频流
-                                RCRTCResourceState resourceState = audioInputStream.getResourceState();
-                                isNormalCreateAudioStatus = resourceState == RCRTCResourceState.NORMAL;
-                            }
-                        }
-                    }
-                }
-                mVideoViewManager.update(list, true);
-
-//                if (otherAudioUserIds.size() != 0) {
-//                    mLlMicContainer.delAllExcludeOwn();
-//                    for (int i = 0; i < otherAudioUserIds.size(); i++) {
-//                        String onMicUserId = otherAudioUserIds.get(i);
-//                        notifyMicContainerAdd(onMicUserId, "");
-//                    }
-//                } else {
-//                    mLlMicContainer.delAllExcludeOwn();
-//                }
-//                if (list.size() != 0) {
-//                    creatorIsCloseVideoStream = false;
-//                    mViewLiveStatus.setVisibility(View.GONE);
-//                    checkVideoViewManager();
-//                    mVideoViewManager.update(list, 0, true);
-//                } else {
-//                    creatorIsCloseVideoStream = true;
-//                    if (isNormalCreateAudioStatus) {
-//                        showCloseVideoView();
-//                    } else {
-//                        //主播关闭了视频流,同时音频流的状态也不是normal状态时
-//                        showRestView();
-//                    }
-//                }
-            }
-        });
-    }
-
-    private void showBeautyOptionsDialog() {
-        if (mOptionsDialog == null) {
-            mOptionsDialog = new LiveBeautyOptionsDialog(this);
-            mOptionsDialog.setFragmentActivity(this);
-            mOptionsDialog.setOnShowListener(new DialogInterface.OnShowListener() {
-                @Override
-                public void onShow(DialogInterface dialog) {
-                    viewBinding.viewCreateOptions.getRoot().setVisibility(View.GONE);
-                }
-            });
-
-            mOptionsDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
-                @Override
-                public void onDismiss(DialogInterface dialog) {
-                    viewBinding.viewCreateOptions.getRoot().setVisibility(View.VISIBLE);
-                }
-            });
-        }
-        if (!mOptionsDialog.isShowing()) {
-            mOptionsDialog.show();
-        }
-    }
-
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        if (mVideoViewManager != null) {
-            mVideoViewManager.onRelease();
-        }
-    }
-
-}

+ 1267 - 0
teacher/src/main/java/com/cooleshow/teacher/ui/live/TeacherLiveRoomActivity.java

@@ -0,0 +1,1267 @@
+package com.cooleshow.teacher.ui.live;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.alibaba.android.arouter.facade.annotation.Route;
+import com.bumptech.glide.Glide;
+import com.cooleshow.base.common.BaseApplication;
+import com.cooleshow.base.data.net.ApiException;
+import com.cooleshow.base.router.RouterPath;
+import com.cooleshow.base.ui.activity.BaseMVPActivity;
+import com.cooleshow.base.utils.AppUtils;
+import com.cooleshow.base.utils.ClickUtils;
+import com.cooleshow.base.utils.PermissionUtils;
+import com.cooleshow.base.utils.SoftKeyboardUtil;
+import com.cooleshow.base.utils.ToastUtil;
+import com.cooleshow.base.utils.Utils;
+import com.cooleshow.base.widgets.InputBar;
+import com.cooleshow.base.widgets.dialog.CommonConfirmDialog;
+import com.cooleshow.base.widgets.dialog.InputBarDialog;
+import com.cooleshow.teacher.R;
+import com.cooleshow.teacher.adapter.LiveRoomMessageAdapter;
+import com.cooleshow.teacher.bean.LiveRoomInfoBean;
+import com.cooleshow.teacher.contract.LiveRoomContract;
+import com.cooleshow.teacher.databinding.ActivityTeacherLiveRoomLayoutBinding;
+import com.cooleshow.teacher.helper.LiveRoomAnimatorHelper;
+import com.cooleshow.teacher.presenter.live.LiveRoomPresenter;
+import com.cooleshow.teacher.widgets.dialog.LiveBeautyOptionsDialog;
+import com.cooleshow.teacher.widgets.dialog.LiveMicManagerDialog;
+import com.cooleshow.teacher.widgets.dialog.LiveRoomManagerDialog;
+import com.cooleshow.teacher.widgets.helper.VideoViewManager;
+import com.cooleshow.usercenter.helper.UserHelper;
+import com.daya.live_teaching.utils.ToastUtils;
+import com.gyf.immersionbar.ImmersionBar;
+import com.rong.io.live.LiveRoomMsgConstants;
+import com.rong.io.live.bean.User;
+import com.rong.io.live.config.LiveConfig;
+import com.rong.io.live.helper.LiveEventHelper;
+import com.rong.io.live.helper.LiveMemberHelper;
+import com.rong.io.live.helper.LiveMessageHelper;
+import com.rong.io.live.helper.LiveRTCEngineInitHelper;
+import com.rong.io.live.helper.LiveRoomMicMemberHelper;
+import com.rong.io.live.message.RCChatJoinRoomMessage;
+import com.rong.io.live.message.RCOnSnappingUpMessage;
+import com.rong.io.live.message.RCUserAddLikeMessage;
+import com.rong.io.live.message.RCUserSeatApplyMessage;
+import com.tbruyelle.rxpermissions3.RxPermissions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import androidx.annotation.NonNull;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import cn.rongcloud.rtc.api.RCRTCAudioRouteManager;
+import cn.rongcloud.rtc.api.RCRTCEngine;
+import cn.rongcloud.rtc.api.RCRTCRemoteUser;
+import cn.rongcloud.rtc.api.RCRTCVideoStream;
+import cn.rongcloud.rtc.api.callback.IRCRTCStatusReportListener;
+import cn.rongcloud.rtc.api.report.StatusBean;
+import cn.rongcloud.rtc.api.report.StatusReport;
+import cn.rongcloud.rtc.api.stream.RCRTCAudioInputStream;
+import cn.rongcloud.rtc.api.stream.RCRTCVideoInputStream;
+import cn.rongcloud.rtc.api.stream.RCRTCVideoOutputStream;
+import cn.rongcloud.rtc.api.stream.RCRTCVideoView;
+import cn.rongcloud.rtc.base.RCRTCLiveRole;
+import cn.rongcloud.rtc.base.RCRTCMediaType;
+import cn.rongcloud.rtc.base.RCRTCResourceState;
+import io.reactivex.rxjava3.disposables.Disposable;
+import io.rong.imkit.IMCenter;
+import io.rong.imkit.picture.tools.DoubleUtils;
+import io.rong.imlib.IRongCoreCallback;
+import io.rong.imlib.IRongCoreEnum;
+import io.rong.imlib.RongIMClient;
+import io.rong.imlib.model.Message;
+import io.rong.imlib.model.MessageContent;
+import io.rong.imlib.model.UserInfo;
+import io.rong.message.TextMessage;
+
+/**
+ * Author by pq, Date on 2022/6/5.
+ * 老师端直播间页面
+ */
+@Route(path = RouterPath.LiveCenter.ACTIVITY_LIVE_ROOM_TEACHER)
+public class TeacherLiveRoomActivity extends BaseMVPActivity<ActivityTeacherLiveRoomLayoutBinding, LiveRoomPresenter> implements LiveRoomContract.LiveRoomView, View.OnClickListener, SoftKeyboardUtil.OnSoftInputChangedListener {
+    public static final String ROOMID_KEY = "roomid_key";
+    public static final int SYNC_ADD_LIKE_TIME = 10000;//同步点赞数时长(兼心跳功能)
+    public static final int SEND_APP_BACKGROUND_MSG = 1001;//退到后台消息
+
+
+    ImageView ivReverseCamera;
+    ImageView ivLiveBeauty;
+    ImageView ivLiveShare;
+    TextView tvStartLive;
+    TextView tvClose;
+    ImageView mIvAvatar;
+    TextView mTvRoomCreateName;
+    TextView mTvNumPeople;
+    RelativeLayout flLiveView;
+    RecyclerView recyclerMsg;
+    FrameLayout mFlCreateOptions;
+    ConstraintLayout mCsMainLayout;
+    TextView mTvOnMicNumTip;
+    TextView mTvAddLikeCount;
+    TextView mTvLiveDelay;
+    ImageView mIvLiveDelay;
+    FrameLayout mFlJoinBarrage;
+    TextView mTvJoinBarrage;
+    FrameLayout mFlSnapUpBarrage;
+    TextView mTvSnapUpBarrage;
+
+    public String mRoomId = "";
+    private VideoViewManager mVideoViewManager;
+    private int currentAddLikeCount = 0;//当前点赞数量
+    private boolean isNeedRefresh = false;//是否需要重新刷新房间信息
+    private LiveRoomInfoBean mRoomInfoBean;
+    private String mUserId;
+    private InputBarDialog mInputBarDialog;
+    private int currentLiveMode = LiveConfig.LIVE_MODE_PREVIEW;//默认是预览模式
+    private int currentLiveStatus = LiveConfig.LIVE_STATUS_NORMAL;
+    private RongIMClient.ConnectionStatusListener connectStatusListener = new RongIMClient.ConnectionStatusListener() {
+        @Override
+        public void onChanged(ConnectionStatus status) {
+            Log.i("pq", "LiveRoomActivity receive ConnectionStatus:" + status);
+            if (status == ConnectionStatus.KICKED_OFFLINE_BY_OTHER_CLIENT
+                    || status == ConnectionStatus.SIGN_OUT || status == ConnectionStatus.TIMEOUT) {
+                finish();
+            }
+            if (status == ConnectionStatus.CONNECTED) {
+                //IM连接成功
+                if (presenter != null && isNeedRefresh) {
+                    isNeedRefresh = false;
+                    presenter.init(mRoomId, true);
+                }
+            } else {
+                //其他状态的时候需要重新刷新房间信息
+                isNeedRefresh = true;
+            }
+        }
+    };
+
+    private Runnable mRunnable = new Runnable() {
+        @Override
+        public void run() {
+            //10S更新一次当前UI,通知服务端点赞数量
+            Log.i("pq", "sync add like:" + currentAddLikeCount);
+            updateAddLikeCountView();
+            if (presenter != null) {
+                presenter.syncAddLikeNum(String.valueOf(currentAddLikeCount), mRoomId);
+                presenter.handleAction(LiveRoomMsgConstants.ACTION_SEND_ADD_LIKE_COUNT, currentAddLikeCount);
+            }
+            syncAddLikeNum();
+        }
+    };
+    private LiveRoomMessageAdapter mMessageAdapter;
+    private LinearLayoutManager mLinearLayoutManager;
+    private LiveBeautyOptionsDialog mOptionsDialog;
+    private LiveRoomMicMemberHelper mRoomMicMemberHelper;
+    private LiveMicManagerDialog mLiveMicManagerDialog;
+
+    private Handler mHandler = new Handler(Looper.myLooper()) {
+        @Override
+        public void handleMessage(@NonNull android.os.Message msg) {
+            int what = msg.what;
+            if (what == SEND_APP_BACKGROUND_MSG) {
+                if (!isOnResume && AppUtils.isApplicationInBackground(TeacherLiveRoomActivity.this)) {
+                    Log.i("pq", "onPause publish");
+                    pauseLive();
+                }
+                return;
+            }
+        }
+    };
+
+    private LiveRoomManagerDialog mRoomManagerDialog;
+    private CommonConfirmDialog mConfirmDialog;
+    private boolean isOnResume = false;
+
+    public static void start(Context context, String roomId) {
+        Intent intent = new Intent(context, TeacherLiveRoomActivity.class);
+        intent.putExtra(ROOMID_KEY, roomId);
+        context.startActivity(intent);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected void initView() {
+        setStatusBarColor();
+        ivReverseCamera = viewBinding.viewCreateOptions.ivReverseCamera;
+        ivLiveBeauty = viewBinding.viewCreateOptions.ivLiveBeauty;
+        ivLiveShare = viewBinding.viewCreateOptions.ivLiveShare;
+        tvStartLive = viewBinding.viewCreateOptions.tvStartLive;
+        tvClose = viewBinding.viewCreateOptions.tvClose;
+        mIvAvatar = viewBinding.viewMainLayout.ivAvatar;
+        mTvRoomCreateName = viewBinding.viewMainLayout.tvRoomAuthorName;
+        mTvNumPeople = viewBinding.viewMainLayout.tvNumPeople;
+        flLiveView = viewBinding.flLiveView;
+        recyclerMsg = viewBinding.viewMainLayout.recyclerMsg;
+        mFlCreateOptions = viewBinding.viewCreateOptions.getRoot();
+        mCsMainLayout = viewBinding.viewMainLayout.getRoot();
+        mTvOnMicNumTip = viewBinding.viewMainLayout.tvOnMicNumTip;
+        mTvAddLikeCount = viewBinding.viewMainLayout.tvAddLikeCount;
+        mTvLiveDelay = viewBinding.viewMainLayout.tvLiveDelay;
+        mIvLiveDelay = viewBinding.viewMainLayout.ivLiveDelay;
+        mFlJoinBarrage = viewBinding.viewMainLayout.flJoinBarrage;
+        mTvJoinBarrage = viewBinding.viewMainLayout.tvJoinBarrage;
+        mFlSnapUpBarrage = viewBinding.viewMainLayout.flSnapUpBarrage;
+        mTvSnapUpBarrage = viewBinding.viewMainLayout.tvSnapUpBarrage;
+        ivReverseCamera.setOnClickListener(this);
+        ivLiveBeauty.setOnClickListener(this);
+        tvStartLive.setOnClickListener(this);
+        tvClose.setOnClickListener(this);
+        viewBinding.viewMainLayout.tvInput.setOnClickListener(this);
+        viewBinding.viewMainLayout.ivMic.setOnClickListener(this);
+        viewBinding.viewMainLayout.iconFinishLive.setOnClickListener(this);
+    }
+
+    @Override
+    protected ActivityTeacherLiveRoomLayoutBinding getLayoutView() {
+        return ActivityTeacherLiveRoomLayoutBinding.inflate(getLayoutInflater());
+    }
+
+    public void setStatusBarColor() {
+        ImmersionBar.with(this)
+                .keyboardEnable(false)//为了防止软键盘顶起底部布局
+                .transparentStatusBar()
+                .statusBarDarkFont(false, 0.2f) //原理:如果当前设备支持状态栏字体变色,会设置状态栏字体为黑色,如果当前设备不支持状态栏字体变色,会使当前状态栏加上透明度,否则不执行透明度
+                .autoDarkModeEnable(false)
+                .flymeOSStatusBarFontColor(R.color.white)  //修改flyme OS状态栏字体颜色
+                .init();  //必须调用方可沉浸
+    }
+
+    @Override
+    public void initData() {
+        super.initData();
+        mRoomId = getIntent().getStringExtra(ROOMID_KEY);
+        if (TextUtils.isEmpty(mRoomId)) {
+            ToastUtil.getInstance().show(this, "房间id不可为空");
+            finish();
+            return;
+        }
+        String userToken = UserHelper.getUserToken();
+        if (TextUtils.isEmpty(userToken)) {
+            finish();
+            return;
+        }
+        mUserId = UserHelper.getUserId();
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                checkVideoViewManager();
+            }
+        });
+        mRoomMicMemberHelper = new LiveRoomMicMemberHelper();
+        mMessageAdapter = new LiveRoomMessageAdapter(this);
+        mLinearLayoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false);
+        recyclerMsg.setLayoutManager(mLinearLayoutManager);
+        recyclerMsg.setAdapter(mMessageAdapter);
+        checkNeedPermission();
+    }
+
+    private void initLiveConfig() {
+        initListener();
+        if (LiveConfig.isNeedReInitRTC) {
+            //检查是否需要重新初始化RTC
+            LiveRTCEngineInitHelper.initRTC();
+        }
+        //开启美颜
+        LiveRTCEngineInitHelper.openBeauty();
+        // 初始化音频路由管理类
+        RCRTCAudioRouteManager.getInstance().init(Utils.getApp());
+        prepareInitRoom();
+    }
+
+    private void checkNeedPermission() {
+        Disposable disposable = new RxPermissions(TeacherLiveRoomActivity.this)
+                .request(Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE
+                        , Manifest.permission.CAMERA)
+                .subscribe(permission -> {
+                    if (permission) {
+                        initLiveConfig();
+                    } else {
+                        CommonConfirmDialog confirmDialog = new CommonConfirmDialog(TeacherLiveRoomActivity.this);
+                        confirmDialog.show();
+                        confirmDialog.setContent("直播需要麦克风、摄像头、储存权限,去设置?");
+                        confirmDialog.setConfirmText("去设置");
+                        confirmDialog.setOnConfirmClickListener(new View.OnClickListener() {
+                            @Override
+                            public void onClick(View v) {
+                                PermissionUtils.toSelfSetting(TeacherLiveRoomActivity.this);
+                            }
+                        });
+                    }
+                });
+    }
+
+    private void initListener() {
+        IMCenter.getInstance().addConnectionStatusListener(connectStatusListener);
+        SoftKeyboardUtil.registerSoftInputChangedListener(getWindow(), this);
+    }
+
+    private void bindLiveStatusReport() {
+        //注册通话状态数据监听器 全局监听需要在重新加入房间之后重新设置(重新加入房间,角色属性变更,融云的全局监听都会失效)
+        RCRTCEngine.getInstance().registerStatusReportListener(new IRCRTCStatusReportListener() {
+            @Override
+            public void onConnectionStats(StatusReport statusReport) {
+                super.onConnectionStats(statusReport);
+                long lossRate = 0;
+                for (Map.Entry<String, StatusBean> entry : statusReport.statusVideoSends.entrySet()) {
+                    StatusBean statusBean = entry.getValue();
+                    //获取userID
+                    String userId = statusBean.uid;
+                    //获取视频 宽x高@帧率
+                    String resolution = statusBean.frameWidth + "x" + statusBean.frameHeight + "@" + statusBean.frameRate;
+                    //获取码率
+                    long bitRate = statusBean.bitRate;
+                    //丢包率:超过30,视频卡顿现象会很明显
+                    lossRate = statusBean.packetLostRate;
+                }
+                if (statusReport != null) {
+                    int rtt = statusReport.rtt;
+                    if (rtt > 999) {
+                        rtt = 999;
+                    }
+                    updateLiveDelayUI(rtt, lossRate);
+                }
+            }
+        });
+    }
+
+
+    private void prepareInitRoom() {
+        //根据融云的IM连接状态判断是否需要获取房间信息
+        RongIMClient.ConnectionStatusListener.ConnectionStatus currentConnectionStatus = RongIMClient.getInstance().getCurrentConnectionStatus();
+        if (currentConnectionStatus == RongIMClient.ConnectionStatusListener.ConnectionStatus.CONNECTED) {
+            isNeedRefresh = false;
+            if (presenter != null) {
+                presenter.init(mRoomId, true);
+            }
+        } else {
+            //如果IM未连接,等待connectStatusListener回调
+            isNeedRefresh = true;
+            presenter.connectIM();
+        }
+    }
+
+
+    /**
+     * 暂停直播
+     */
+    private void pauseLive() {
+        if (presenter != null) {
+            presenter.handleAction(LiveRoomMsgConstants.ACTION_SEND_PAUSE_LIVE);
+            currentLiveStatus = LiveConfig.LIVE_STATUS_PAUSE;
+            presenter.cancelPublish(null);
+        }
+    }
+
+    /**
+     * 检查VideoViewManager是否未null;
+     */
+    private void checkVideoViewManager() {
+        if (mVideoViewManager == null) {
+            mVideoViewManager = new VideoViewManager(flLiveView, flLiveView.getWidth(), flLiveView.getHeight());
+            mVideoViewManager.setRetryClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (presenter != null) {
+                        //重新订阅房间的流信息
+//                        presenter.subscribeAVStream();
+                    }
+                }
+            });
+        }
+    }
+
+
+    @Override
+    protected LiveRoomPresenter createPresenter() {
+        return new LiveRoomPresenter();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        this.isOnResume = true;
+        if (isLiveMode() && isLivePause()) {
+            Log.i("pq", "onResume publish");
+            currentLiveMode = LiveConfig.LIVE_STATUS_NORMAL;
+            presenter.startPublish();
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        this.isOnResume = false;
+        if (isLiveMode()) {
+            //退到后台,延迟2S发送检测消息,
+            android.os.Message obtain = android.os.Message.obtain();
+            obtain.what = SEND_APP_BACKGROUND_MSG;
+            mHandler.sendMessageDelayed(obtain, 2000);
+        }
+    }
+
+    /**
+     * 获取房间信息成功
+     *
+     * @param roomInfoBean
+     */
+    @Override
+    public void getRoomInfoSuccess(LiveRoomInfoBean roomInfoBean) {
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        if (roomInfoBean == null) {
+            ToastUtils.showToast("获取房间信息失败,请退出重试");
+            finish();
+            return;
+        }
+        mRoomInfoBean = roomInfoBean;
+        if (mMessageAdapter != null) {
+            mMessageAdapter.setRoomAuthorId(roomInfoBean.speakerId);
+        }
+        int peopleCount = roomInfoBean.lookNum;
+        mTvNumPeople.setText(peopleCount + "人");
+        //同步点赞数
+        currentAddLikeCount = roomInfoBean.likeNum;
+        updateAddLikeCountView();
+        //创建人头像
+        Glide.with(TeacherLiveRoomActivity.this).load(roomInfoBean.speakerPic).placeholder(R.drawable.icon_teacher_default_head).error(R.drawable.icon_teacher_default_head).into(mIvAvatar);
+        //创建人昵称
+        mTvRoomCreateName.setText(roomInfoBean.speakerName);
+        if (presenter != null) {
+            //配置直播的config配置
+            presenter.initPublishConfig();
+            LiveEventHelper.getInstance().register(roomInfoBean.roomUid);
+            Log.i("pq", "initPublishConfig");
+            Log.i("pq", "isPreviewMode:" + isPreviewMode());
+            if (isPreviewMode()) {
+                openPreViewMode();
+            } else {
+                //加入房间
+                presenter.prepareJoinRoom(roomInfoBean.roomUid, true);
+            }
+        }
+    }
+
+    /**
+     * 是否是预览模式
+     *
+     * @return
+     */
+    private boolean isPreviewMode() {
+        return currentLiveMode == LiveConfig.LIVE_MODE_PREVIEW;
+    }
+
+    /**
+     * \
+     * 是否是直播中
+     *
+     * @return
+     */
+    private boolean isLiveMode() {
+        return currentLiveMode == LiveConfig.LIVE_MODE_LIVE_START;
+    }
+
+    /**
+     * 直播暂停状态
+     *
+     * @return
+     */
+    private boolean isLivePause() {
+        return currentLiveStatus == LiveConfig.LIVE_STATUS_PAUSE;
+    }
+
+    /**
+     * 切换直播模式
+     *
+     * @param mode
+     */
+    private void switchLiveMode(int mode) {
+        //切换直播模式
+        currentLiveMode = mode;
+        if (mode == LiveConfig.LIVE_MODE_PREVIEW) {
+            //直播暂停模式,切换成预览模式
+            //通知关闭直播录像
+            switchOpsLiveVideoMode(LiveConfig.CLOSE_OPS_LIVE_VIDEO_TYPE);
+            openPreViewMode();
+        } else {
+            //直播模式
+            presenter.startPublish();
+        }
+    }
+
+    /**
+     * 开启预览模式
+     */
+    private void openPreViewMode() {
+        if (presenter != null) {
+            showLoading();
+            switchMainUI();
+            presenter.openVideoPreview();
+        }
+    }
+
+    /**
+     * 切换主场景
+     */
+    private void switchMainUI() {
+        if (currentLiveMode == LiveConfig.LIVE_MODE_PREVIEW) {
+            mFlCreateOptions.setVisibility(View.VISIBLE);
+            mCsMainLayout.setVisibility(View.GONE);
+        } else {
+            mFlCreateOptions.setVisibility(View.GONE);
+            mCsMainLayout.setVisibility(View.VISIBLE);
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        int id = v.getId();
+        if (id == R.id.tv_close) {
+            finish();
+            return;
+        }
+        if (id == R.id.iv_reverse_camera) {
+            //翻转摄像头
+            presenter.reverseCamera();
+            return;
+        }
+        if (id == R.id.iv_live_beauty) {
+            //美颜
+            showBeautyOptionsDialog();
+            return;
+        }
+
+        if (id == R.id.tv_start_live) {
+            //开始直播
+            if (DoubleUtils.isFastDoubleClick()) {
+                return;
+            }
+            if (mRoomInfoBean != null) {
+                if (isLivePause()) {
+                    //直播暂停模式,恢复直播
+                    presenter.startPublish();
+                } else {
+                    //预览模式,开启直播
+                    //点开启直播之前再次验证一下房间信息
+                    currentLiveMode = LiveConfig.LIVE_MODE_LIVE_START;
+                    presenter.getRoomInfo(mRoomId);
+                }
+            }
+        }
+
+        if (id == R.id.iv_mic) {
+            //连麦管理
+//            showMicManagerDialog();
+            return;
+        }
+
+        if (id == R.id.tv_input) {
+            //底部输入框
+            showInputDialog();
+            return;
+        }
+
+        if (id == R.id.icon_finish_live) {
+            //显示直播间管理弹窗
+            showLiveRoomManagerDialog();
+            return;
+        }
+    }
+
+    /**
+     * 同步点赞数并且
+     */
+    private void syncAddLikeNum() {
+        if (mHandler != null) {
+            mHandler.removeCallbacks(mRunnable);
+            //10S发送一次同步点赞兼心跳
+            mHandler.postDelayed(mRunnable, SYNC_ADD_LIKE_TIME);
+        }
+    }
+
+    private void updateAddLikeCountView() {
+        if (mTvAddLikeCount != null) {
+            mTvAddLikeCount.setText(getString(R.string.live_room_add_like_count_str, currentAddLikeCount));
+        }
+    }
+
+    @Override
+    public void syncMemberCount(String count) {
+        //同步成员数量
+        Log.i("pq", "syncMemberCount" + count);
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        if (mTvNumPeople != null) {
+            mTvNumPeople.setText(count + "人");
+        }
+    }
+
+    @Override
+    public void receiveJoinMessage(RCChatJoinRoomMessage joinRoomMessage) {
+        //收到加入房间消息
+        if (checkActivityIsFinish()) {
+            return;
+        }
+        if (joinRoomMessage == null) {
+            return;
+        }
+        if (isCanShowBarrage()) {
+            mTvJoinBarrage.setText(getString(R.string.enter_live_tip_str, LiveMemberHelper.getMessageName(joinRoomMessage)));
+            showBarrageViewAnim(mFlJoinBarrage);
+        }
+    }
+
+    /**
+     * 判断是否显示弹幕消息
+     *
+     * @return
+     */
+    private boolean isCanShowBarrage() {
+        return mFlJoinBarrage.getVisibility() != View.VISIBLE && mFlSnapUpBarrage.getVisibility() != View.VISIBLE;
+    }
+
+    /**
+     * 显示弹幕消息
+     */
+    private void showBarrageViewAnim(View targetView) {
+        if (mFlJoinBarrage.getVisibility() == View.VISIBLE || mFlSnapUpBarrage.getVisibility() == View.VISIBLE) {
+            return;
+        }
+        LiveRoomAnimatorHelper.getInstance().startBarrageViewAnimation(this, targetView);
+        hideBarrageView();
+    }
+
+    /**
+     * 隐藏弹幕消息
+     */
+    private void hideBarrageView() {
+        mHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                if (mFlJoinBarrage != null) {
+                    mFlJoinBarrage.setVisibility(View.GONE);
+                }
+                if (mFlSnapUpBarrage != null) {
+                    mFlSnapUpBarrage.setVisibility(View.GONE);
+                }
+            }
+        }, LiveConfig.LIVE_HIDE_BARRAGE_VIEW_TIME);
+    }
+
+    @Override
+    public void receiveSnapUpMessage(RCOnSnappingUpMessage onSnappingUpMessage) {
+        //收到抢购消息
+        if (checkActivityIsFinish()) {
+            return;
+        }
+        if (onSnappingUpMessage == null) {
+            return;
+        }
+        if (isCanShowBarrage()) {
+            mTvSnapUpBarrage.setText(getString(R.string.live_snap_up_tip_str, LiveMemberHelper.getMessageName(onSnappingUpMessage)));
+            showBarrageViewAnim(mFlSnapUpBarrage);
+        }
+    }
+
+    @Override
+    public void liveRoomOffline() {
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        ToastUtil.getInstance().show(this, "直播已结束");
+        finish();
+    }
+
+    /**
+     * 获取房间信息失败
+     *
+     * @param throwable
+     */
+    @Override
+    public void getRoomInfoError(Throwable throwable) {
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        if (throwable instanceof ApiException) {
+            ApiException apiException = (ApiException) throwable;
+            ToastUtil.getInstance().show(TeacherLiveRoomActivity.this, apiException.getErrmsg());
+        }
+        finish();
+    }
+
+    @Override
+    public void showFinishView() {
+
+    }
+
+    /**
+     * 观众端发送的点赞消息
+     *
+     * @param addLikeMessage
+     */
+    @Override
+    public void onAddLikeMessage(RCUserAddLikeMessage addLikeMessage) {
+        if (isFinishing() || isDestroyed() || addLikeMessage == null) {
+            return;
+        }
+        Log.i("pq", "receive addlikeNum:" + addLikeMessage.getCounts());
+        currentAddLikeCount += addLikeMessage.getCounts();
+    }
+
+    @Override
+    public void addMessageList(List<MessageContent> messageContents, boolean isReset) {
+
+    }
+
+    @Override
+    public void addMessageContent(Message message, boolean isReset) {
+        //添加单条消息至页面
+        Log.i("pq", "收到需要显示msg:" + message);
+        //只处理直播间消息,以及本直播间消息
+        if (mMessageAdapter != null) {
+            mMessageAdapter.addMessage(message);
+            if (mLinearLayoutManager != null) {
+                recyclerMsg.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (recyclerMsg != null) {
+                            recyclerMsg.scrollToPosition(mMessageAdapter.getItemCount() - 1);
+                        }
+                    }
+                });
+            }
+        }
+    }
+
+    @Override
+    public void setRoomData(LiveRoomInfoBean roomInfoBean) {
+        if (presenter != null) {
+            bindLiveStatusReport();
+            startPublish();
+            syncAddLikeNum();
+            //通知加入房间成功
+            presenter.notifyJoinRoomAction(mRoomId, mUserId);
+            //加入聊天房间
+            presenter.joinChartRoom(roomInfoBean.roomUid, new IRongCoreCallback.OperationCallback() {
+                @Override
+                public void onSuccess() {
+                    Log.i("pq", "加入聊天房间成功");
+                    if (presenter != null) {
+                        presenter.handleAction(LiveRoomMsgConstants.ACTION_SEND_JOIN_ROOM);
+                        presenter.sendDefaultMessage();
+                    }
+                }
+
+                @Override
+                public void onError(IRongCoreEnum.CoreErrorCode coreErrorCode) {
+                    Log.i("pq", "加入聊天房间fail:" + coreErrorCode);
+                }
+            });
+        }
+    }
+
+    /**
+     * 开始推流
+     */
+    private void startPublish() {
+        //切换直播模式
+        currentLiveMode = LiveConfig.LIVE_MODE_LIVE_START;
+        if (isLivePause()) {
+            //直播暂停模式
+            return;
+        }
+        if (presenter != null) {
+            presenter.startPublish();
+        }
+    }
+
+    @Override
+    public void onPublishSuccess() {
+        Log.i("pq", "onPublishSuccess");
+        //通知开启直播间回放
+        switchOpsLiveVideoMode(LiveConfig.OPEN_OPS_LIVE_VIDEO_TYPE);
+        refresh();
+    }
+
+    @Override
+    public View getContentView() {
+        return flLiveView;
+    }
+
+    /**
+     * 预览模式
+     *
+     * @param videoView
+     */
+    @Override
+    public void addVideoPreview(RCRTCVideoView videoView) {
+        checkVideoViewManager();
+        if (mVideoViewManager != null) {
+            ArrayList<RCRTCVideoView> videoViews = new ArrayList<>();
+            videoViews.add(videoView);
+            mVideoViewManager.update(videoViews, false);
+        } else {
+            Log.i("pq", "mVideoViewManager == null");
+        }
+    }
+
+    @Override
+    public void openCameraSuccess(Boolean data) {
+        hideLoading();
+        Log.i("pq", "openCameraSuccess:" + data);
+    }
+
+    @Override
+    public void openCameraError(String errorMsg) {
+        Log.i("pq", "openCameraError:" + errorMsg);
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                ToastUtil.getInstance().show(TeacherLiveRoomActivity.this, errorMsg);
+            }
+        });
+    }
+
+    @Override
+    public void onUserJoinRoom(RCRTCRemoteUser rcrtcRemoteUser) {
+
+    }
+
+    @Override
+    public void onUserLeftRoomMic(RCRTCRemoteUser rcrtcRemoteUser) {
+        if (presenter != null && rcrtcRemoteUser != null) {
+            presenter.unSubscribeStream(rcrtcRemoteUser.getUserId(), null);
+        }
+    }
+
+    @Override
+    public void onUserOfflineRoomMic(RCRTCRemoteUser rcrtcRemoteUser) {
+        if (presenter != null && rcrtcRemoteUser != null) {
+            presenter.unSubscribeStream(rcrtcRemoteUser.getUserId(), null);
+        }
+    }
+
+    @Override
+    public void onSwitchRole(String userId, RCRTCLiveRole role) {
+        Log.i("pq", "receive onSwitchRole:" + role.getType());
+        if (role.getType() == RCRTCLiveRole.AUDIENCE.getType()) {
+            //role转换为观众,主播取消订阅该用户的流
+            if (presenter != null) {
+                //取消订阅该成员消息
+                presenter.unSubscribeStream(userId, null);
+            }
+        }
+    }
+
+    @Override
+    public void onSeatApplyMessage(RCUserSeatApplyMessage seatApplyMessage) {
+        //连麦申请消息
+        if (isFinishing() || isDestroyed() || seatApplyMessage == null) {
+            return;
+        }
+        if (!isOwn(seatApplyMessage.getTeacherId())) {
+            return;
+        }
+        if (seatApplyMessage.getType() == LiveRoomMsgConstants.MIC_ACTION_SEAT_BY_USER) {
+            //观众申请
+            User user = new User();
+            user.setUserName(seatApplyMessage.getAudienceName());
+            user.setUserId(seatApplyMessage.getAudienceId());
+            user.setPortrait(seatApplyMessage.getAudienceAvatar());
+            mRoomMicMemberHelper.addApplyUser(user);
+//            updateMicManagerData();
+        }
+        if (seatApplyMessage.getType() == LiveRoomMsgConstants.MIC_ACTION_CANCEL_SEAT_BY_USER) {
+            //观众取消
+        }
+    }
+
+    private void updateMicManagerData() {
+        if (mLiveMicManagerDialog != null) {
+            mLiveMicManagerDialog.setApplyListData(mRoomMicMemberHelper.getOnApplyMicUsers());
+        }
+        if (mTvOnMicNumTip != null) {
+            ArrayList<User> onApplyMicUsers = mRoomMicMemberHelper.getOnApplyMicUsers();
+            if (onApplyMicUsers != null && onApplyMicUsers.size() > 0) {
+                mTvOnMicNumTip.setVisibility(View.VISIBLE);
+                mTvOnMicNumTip.setText(String.valueOf(onApplyMicUsers.size()));
+            } else {
+                mTvOnMicNumTip.setVisibility(View.GONE);
+            }
+        }
+    }
+
+    /**
+     * 用户判断消息目标是否是自己
+     *
+     * @param targetId
+     * @return
+     */
+    private boolean isOwn(String targetId) {
+        return TextUtils.equals(targetId, mUserId);
+    }
+
+    private void refresh() {
+        List<RCRTCVideoOutputStream> outputStreams = new ArrayList<>();
+        List<RCRTCVideoInputStream> input = new ArrayList<>();
+        List<RCRTCAudioInputStream> audioinputstream = new ArrayList<>();
+        presenter.getVideoStream(outputStreams, input, audioinputstream);
+        updateVideoView(outputStreams, input, audioinputstream);
+    }
+
+    public void updateVideoView(List<RCRTCVideoOutputStream> outputStreams, List<RCRTCVideoInputStream> inputStreams, List<RCRTCAudioInputStream> audioInputStreams) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                currentLiveStatus = LiveConfig.LIVE_STATUS_NORMAL;
+                currentLiveMode = LiveConfig.LIVE_MODE_LIVE_START;
+                switchMainUI();
+                ArrayList<RCRTCVideoStream> videoStreams = new ArrayList<RCRTCVideoStream>();
+                videoStreams.addAll(outputStreams);
+                videoStreams.addAll(inputStreams);
+                ArrayList<RCRTCVideoView> list = new ArrayList<>();
+                ArrayList<String> otherAudioUserIds = new ArrayList<>();
+                boolean isNormalCreateAudioStatus = true;
+
+                //视频流
+                for (int i = 0; i < videoStreams.size(); i++) {
+                    RCRTCVideoStream rcrtcVideoStream = videoStreams.get(i);
+                    RCRTCVideoView rongRTCVideoView = new RCRTCVideoView(TeacherLiveRoomActivity.this);
+                    rcrtcVideoStream.setVideoView(rongRTCVideoView);
+                    list.add(rongRTCVideoView);
+                }
+
+                //音频流
+                for (int i = 0; i < audioInputStreams.size(); i++) {
+                    RCRTCAudioInputStream audioInputStream = audioInputStreams.get(i);
+                    if (audioInputStream.getMediaType() == RCRTCMediaType.AUDIO) {
+                        //音频流判断显示上麦用户
+                        String userId = audioInputStream.getUserId();
+                        if (TextUtils.equals(mUserId, userId)) {
+                            continue;
+                        }
+                        if (mRoomInfoBean != null) {
+                            if (!TextUtils.equals(mRoomInfoBean.speakerId, userId)) {
+                                otherAudioUserIds.add(userId);
+                            } else {
+                                //主播的音频流
+                                RCRTCResourceState resourceState = audioInputStream.getResourceState();
+                                isNormalCreateAudioStatus = resourceState == RCRTCResourceState.NORMAL;
+                            }
+                        }
+                    }
+                }
+                mVideoViewManager.update(list, true);
+            }
+        });
+    }
+
+    /**
+     * 显示通用提示弹窗
+     *
+     * @param content
+     * @param confirmText
+     */
+    private void showCommonTipDialog(String content, String confirmText, View.OnClickListener listener) {
+        if (mConfirmDialog == null) {
+            mConfirmDialog = new CommonConfirmDialog(this);
+        }
+        if (!mConfirmDialog.isShowing()) {
+            mConfirmDialog.show();
+        }
+        mConfirmDialog.setContent(content);
+        mConfirmDialog.setConfirmText(confirmText);
+        mConfirmDialog.setOnConfirmClickListener(listener);
+    }
+
+
+    /**
+     * 显示直播间管理弹窗
+     */
+    private void showLiveRoomManagerDialog() {
+        if (mRoomManagerDialog == null) {
+            mRoomManagerDialog = new LiveRoomManagerDialog(this);
+            mRoomManagerDialog.setOnEventListener(new LiveRoomManagerDialog.OnEventListener() {
+                @Override
+                public void onPauseLive() {
+                    //暂停直播
+                    showCommonTipDialog(getString(R.string.live_pause_tip_str), getString(R.string.pause_live), new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+                            if (mConfirmDialog != null) {
+                                mConfirmDialog.dismiss();
+                            }
+                            if (mRoomManagerDialog != null) {
+                                mRoomManagerDialog.dismiss();
+                            }
+                            pauseLive();
+                            switchLiveMode(LiveConfig.LIVE_MODE_PREVIEW);
+                        }
+                    });
+                }
+
+                @Override
+                public void onFinishLive() {
+                    //结束直播
+                    showCommonTipDialog(getString(R.string.finish_live_tip_str), getString(R.string.live_finish_str), new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+                            if (presenter != null) {
+                                presenter.notifyCloseLiveRoomAction(mRoomId);
+                            }
+                            finish();
+                        }
+                    });
+                }
+            });
+        }
+        if (!mRoomManagerDialog.isShowing()) {
+            mRoomManagerDialog.show();
+        }
+    }
+
+    /**
+     * 显示连麦控制弹窗
+     */
+    private void showMicManagerDialog() {
+        if (mLiveMicManagerDialog == null) {
+            mLiveMicManagerDialog = new LiveMicManagerDialog(this);
+            mLiveMicManagerDialog.setOnEventListener(new LiveMicManagerDialog.OnEventListener() {
+                @Override
+                public void onAgreeApply(User user) {
+                    //同意连麦申请
+                    presenter.handleAction(LiveRoomMsgConstants.ACTION_AGREE_MIC_APPLY, user);
+                    if (mRoomMicMemberHelper != null) {
+                        mRoomMicMemberHelper.delApplyUser(user);
+                    }
+                    updateMicManagerData();
+                }
+
+                @Override
+                public void onRefuseAllMicApply() {
+                    if (mRoomMicMemberHelper != null) {
+                        mRoomMicMemberHelper.delAllApplyUser();
+                    }
+                    updateMicManagerData();
+                }
+
+                @Override
+                public void onSwitchMicMode(boolean isEnable) {
+
+                }
+            });
+        }
+        if (!mLiveMicManagerDialog.isShowing()) {
+            mLiveMicManagerDialog.show();
+        }
+        mLiveMicManagerDialog.setApplyListData(mRoomMicMemberHelper.getOnApplyMicUsers());
+    }
+
+    private void showBeautyOptionsDialog() {
+        if (mOptionsDialog == null) {
+            mOptionsDialog = new LiveBeautyOptionsDialog(this);
+            mOptionsDialog.setFragmentActivity(this);
+            mOptionsDialog.setOnShowListener(new DialogInterface.OnShowListener() {
+                @Override
+                public void onShow(DialogInterface dialog) {
+                    mFlCreateOptions.setVisibility(View.GONE);
+                }
+            });
+
+            mOptionsDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+                @Override
+                public void onDismiss(DialogInterface dialog) {
+                    mFlCreateOptions.setVisibility(View.VISIBLE);
+                }
+            });
+        }
+        if (!mOptionsDialog.isShowing()) {
+            mOptionsDialog.show();
+        }
+    }
+
+    private void showInputDialog() {
+        if (mRoomInfoBean == null) {
+            return;
+        }
+        if (mInputBarDialog == null) {
+            mInputBarDialog = new InputBarDialog(TeacherLiveRoomActivity.this, new InputBar.InputBarListener() {
+                @Override
+                public boolean onClickSend(String message) {
+                    //发送消息
+                    if (TextUtils.isEmpty(message)) {
+                        ToastUtil.getInstance().show(TeacherLiveRoomActivity.this, "消息不能为空");
+                        return false;
+                    }
+                    if (message.length() > LiveConfig.LIVE_MAX_INPUT_TEXT_LENGTH) {
+                        ToastUtil.getInstance().show(TeacherLiveRoomActivity.this, "聊天消息需在40个字以内哦");
+                        return false;
+                    }
+                    if (LiveMessageHelper.isQuickAction()) {
+                        ToastUtil.getInstance().show(TeacherLiveRoomActivity.this, "您说话太快啦");
+                        return false;
+                    }
+                    sendTextMessage(message);
+                    return true;
+                }
+
+
+                @Override
+                public boolean onClickEmoji() {
+                    return false;
+                }
+            });
+
+            mInputBarDialog.setOnShowListener(new DialogInterface.OnShowListener() {
+                @Override
+                public void onShow(DialogInterface dialog) {
+                    if (mInputBarDialog != null) {
+                        mInputBarDialog.showInput();
+                    }
+                }
+            });
+        }
+        if (!mInputBarDialog.isShowing()) {
+            mInputBarDialog.show();
+        }
+    }
+
+    private void sendTextMessage(String message) {
+        if (presenter != null) {
+            TextMessage textMessage = TextMessage.obtain(message);
+            UserInfo userInfo = new UserInfo(mUserId, UserHelper.getUserName(), null);
+            textMessage.setUserInfo(userInfo);
+            presenter.sendMessage(textMessage);
+        }
+    }
+
+    private void updateLiveDelayUI(int delay, long lossRate) {
+        if (mHandler != null) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    if (mTvLiveDelay == null || mIvLiveDelay == null) {
+                        return;
+                    }
+                    if (lossRate == 100) {
+                        mTvLiveDelay.setText(getString(R.string.net_error_tip));
+                        mIvLiveDelay.setImageResource(R.drawable.icon_live_delay_high);
+                        return;
+                    }
+                    mTvLiveDelay.setText(getString(R.string.live_delay_text, delay));
+                    if (delay <= LiveConfig.LIVE_DELAY_NORMAL) {
+                        //正常延迟模式
+                        mIvLiveDelay.setImageResource(R.drawable.icon_live_delay_normal);
+                        return;
+                    }
+                    if (delay <= LiveConfig.LIVE_DELAY_MIDDLE) {
+                        //一般延迟模式
+                        mIvLiveDelay.setImageResource(R.drawable.icon_live_delay_middle);
+                    } else {
+                        //一般延迟模式
+                        mIvLiveDelay.setImageResource(R.drawable.icon_live_delay_high);
+                    }
+                }
+            });
+        }
+    }
+
+
+    @Override
+    public void onDestroy() {
+        if (presenter != null) {
+            presenter.notifyLeaveRoomAction();
+        }
+        switchOpsLiveVideoMode(LiveConfig.CLOSE_OPS_LIVE_VIDEO_TYPE);
+        super.onDestroy();
+        if (mVideoViewManager != null) {
+            mVideoViewManager.onRelease();
+        }
+        if (mHandler != null) {
+            mHandler.removeCallbacksAndMessages(null);
+        }
+        if (connectStatusListener != null) {
+            IMCenter.getInstance().removeConnectionStatusListener(connectStatusListener);
+        }
+        SoftKeyboardUtil.unregisterSoftInputChangedListener(getWindow());
+        LiveEventHelper.getInstance().unRegister();
+        RCRTCAudioRouteManager.getInstance().unInit();
+        //取消注册通话状态数据监听器
+        RCRTCEngine.getInstance().unregisterStatusReportListener();
+        LiveRoomAnimatorHelper.getInstance().releaseAnimator();
+    }
+
+    /**
+     * 通知(开启/关闭)直播录像
+     *
+     * @param type
+     */
+    private void switchOpsLiveVideoMode(String type) {
+        //酷乐秀暂时先不需要这个流程,暂时先注释掉,后续考虑优化去掉
+//        if (presenter != null) {
+//            presenter.notifyOpenOpsLiveVideoAction(mRoomId, type, mUserId);
+//        }
+    }
+
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_BACK) {
+            return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public void onSoftInputChanged(int height) {
+        Log.i("pq", "height" + height);
+        if (height == 0) {
+            //软键盘隐藏
+            Log.i("pq", "SoftInput hide");
+            if (mInputBarDialog != null && mInputBarDialog.isShowing()) {
+                mInputBarDialog.dismiss();
+            }
+        } else {
+            //软键盘弹出
+            Log.i("pq", "SoftInput show");
+        }
+    }
+
+    private boolean checkActivityIsFinish() {
+        if (isFinishing() || isDestroyed()) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void onPointerCaptureChanged(boolean hasCapture) {
+        super.onPointerCaptureChanged(hasCapture);
+    }
+}

+ 166 - 0
teacher/src/main/java/com/cooleshow/teacher/widgets/dialog/LiveMicManagerDialog.java

@@ -0,0 +1,166 @@
+package com.cooleshow.teacher.widgets.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import com.cooleshow.teacher.R;
+import com.cooleshow.teacher.adapter.LiveBeautyPagerAdapter;
+import com.cooleshow.teacher.ui.live.LiveApplyMicFragment;
+import com.cooleshow.teacher.ui.live.LiveOnMicFragment;
+import com.google.android.material.tabs.TabLayout;
+import com.google.android.material.tabs.TabLayoutMediator;
+import com.rong.io.live.bean.User;
+
+import java.util.ArrayList;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.viewpager2.widget.ViewPager2;
+
+/**
+ * Author by pq, Date on 2022/6/11.
+ */
+public class LiveMicManagerDialog extends Dialog implements View.OnClickListener {
+    private TabLayout mTabLayout;
+    private ViewPager2 mViewPager;
+    private LiveApplyMicFragment mApplyMicFragment;
+    private LiveOnMicFragment onMicFragment;
+    private OnEventListener mEventListener;
+    private FragmentActivity mFragmentActivity;
+    private String[] titles = new String[]{"连麦中", "申请中"};
+
+
+    public LiveMicManagerDialog(@NonNull Context context) {
+        super(context, R.style.MyBottomDialogStyle);
+        if (context instanceof FragmentActivity) {
+            mFragmentActivity = (FragmentActivity) context;
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.dialog_live_mic_manager_layout);
+        Window window = getWindow();
+        //设置dialog在屏幕底部
+        window.setGravity(Gravity.BOTTOM);
+        //设置dialog弹出时的动画效果,从屏幕底部向上弹出
+        window.setWindowAnimations(com.cooleshow.base.R.style.BottomAnimation);
+        window.getDecorView().setPadding(0, 0, 0, 0);
+        //获得window窗口的属性
+        WindowManager.LayoutParams lp = window.getAttributes();
+        //设置窗口宽度为充满全屏
+        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+        //设置窗口高度为包裹内容
+        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+        lp.horizontalMargin = 0;
+        lp.verticalMargin = 0;
+        //将设置好的属性set回去
+        window.setAttributes(lp);
+        mTabLayout = findViewById(R.id.tab_layout);
+        mViewPager = findViewById(R.id.viewPager);
+
+        TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(mTabLayout, mViewPager, new TabLayoutMediator.TabConfigurationStrategy() {
+            @Override
+            public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
+//                createTab(tab, titles[position]);
+//                tab.setText(titles[position]);
+            }
+        });
+        LiveBeautyPagerAdapter beautyPagerAdapter = new LiveBeautyPagerAdapter(mFragmentActivity);
+        onMicFragment = new LiveOnMicFragment();
+        mApplyMicFragment = new LiveApplyMicFragment();
+        if (mEventListener != null) {
+            mApplyMicFragment.setOnEventListener(mEventListener);
+            onMicFragment.setOnEventListener(mEventListener);
+        }
+        ArrayList<Fragment> fragments = new ArrayList();
+        fragments.add(onMicFragment);
+        fragments.add(mApplyMicFragment);
+        beautyPagerAdapter.setData(fragments);
+        mViewPager.setAdapter(beautyPagerAdapter);
+        tabLayoutMediator.attach();
+        initListener();
+    }
+
+    private void initListener() {
+        mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
+            @Override
+            public void onTabSelected(TabLayout.Tab tab) {
+                if (tab != null && tab.getCustomView() != null) {
+                    View customView = tab.getCustomView();
+                    TextView tv_text = customView.findViewById(R.id.tv_text);
+                    tv_text.setTextColor(getContext().getResources().getColor(com.cooleshow.base.R.color.color_333333));
+                }
+            }
+
+            @Override
+            public void onTabUnselected(TabLayout.Tab tab) {
+                if (tab != null && tab.getCustomView() != null) {
+                    View customView = tab.getCustomView();
+                    TextView tv_text = customView.findViewById(R.id.tv_text);
+                    tv_text.setTextColor(getContext().getResources().getColor(com.cooleshow.base.R.color.color_666666));
+                }
+            }
+
+            @Override
+            public void onTabReselected(TabLayout.Tab tab) {
+
+            }
+        });
+    }
+
+    public void setFragmentActivity(FragmentActivity fragmentActivity) {
+        this.mFragmentActivity = fragmentActivity;
+    }
+
+    public void setOnMicListData(ArrayList<User> onMicListData) {
+        if (onMicFragment != null) {
+            onMicFragment.refresh(onMicListData);
+        }
+    }
+
+    public void setApplyListData(ArrayList<User> applyListData) {
+        if (mApplyMicFragment != null) {
+            mApplyMicFragment.refresh(applyListData);
+        }
+    }
+
+    private TabLayout.Tab createTab(TabLayout.Tab tab, String text) {
+        View view = LayoutInflater.from(getContext()).inflate(R.layout.view_live_beauty_tab_layout, null);
+        TextView tv_text = view.findViewById(R.id.tv_text);
+        tv_text.setTextColor(getContext().getResources().getColor(com.cooleshow.base.R.color.color_666666));
+        tv_text.setText(text);
+        tab.setCustomView(view);
+        return tab;
+    }
+
+
+    @Override
+    public void onClick(View v) {
+
+    }
+
+    public void setOnEventListener(OnEventListener listener) {
+        this.mEventListener = listener;
+    }
+
+    public interface OnEventListener {
+        //同意连麦申请
+        void onAgreeApply(User user);
+
+        //拒绝全部连麦申请
+        void onRefuseAllMicApply();
+
+        //连麦模式控制
+        void onSwitchMicMode(boolean isEnable);
+    }
+}

+ 86 - 0
teacher/src/main/java/com/cooleshow/teacher/widgets/dialog/LiveRoomManagerDialog.java

@@ -0,0 +1,86 @@
+package com.cooleshow.teacher.widgets.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+
+import com.cooleshow.teacher.R;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Author by pq, Date on 2022/6/11.
+ * 暂停直播或结束直播
+ */
+public class LiveRoomManagerDialog extends Dialog implements View.OnClickListener {
+    private OnEventListener mEventListener;
+
+    public LiveRoomManagerDialog(@NonNull Context context) {
+        super(context, R.style.MyBottomDialogStyle);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.dialog_live_manager_layout);
+        Window window = getWindow();
+        //设置dialog在屏幕底部
+        window.setGravity(Gravity.BOTTOM);
+        //设置dialog弹出时的动画效果,从屏幕底部向上弹出
+        window.setWindowAnimations(com.cooleshow.base.R.style.BottomAnimation);
+        window.getDecorView().setPadding(0, 0, 0, 0);
+        //获得window窗口的属性
+        WindowManager.LayoutParams lp = window.getAttributes();
+        //设置窗口宽度为充满全屏
+        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+        //设置窗口高度为包裹内容
+        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+        lp.horizontalMargin = 0;
+        lp.verticalMargin = 0;
+        //将设置好的属性set回去
+        window.setAttributes(lp);
+        findViewById(R.id.view_pause_live).setOnClickListener(this);
+        findViewById(R.id.view_pause_finish).setOnClickListener(this);
+        initListener();
+    }
+
+    private void initListener() {
+    }
+
+
+    @Override
+    public void onClick(View v) {
+        int id = v.getId();
+        if (id == R.id.view_pause_live) {
+            //暂停直播
+            if (mEventListener != null) {
+                mEventListener.onPauseLive();
+            }
+            return;
+        }
+
+        if (id == R.id.view_pause_finish) {
+            //结束直播
+            if (mEventListener != null) {
+                mEventListener.onFinishLive();
+            }
+            return;
+        }
+    }
+
+    public void setOnEventListener(OnEventListener listener) {
+        this.mEventListener = listener;
+    }
+
+    public interface OnEventListener {
+        //同意连麦申请
+        void onPauseLive();
+
+        //拒绝全部连麦申请
+        void onFinishLive();
+    }
+}

BIN
teacher/src/main/res/drawable-xhdpi/icon_live_barrage_buy_tag.png


BIN
teacher/src/main/res/drawable-xhdpi/icon_live_delay_high.png


BIN
teacher/src/main/res/drawable-xhdpi/icon_live_delay_middle.png


BIN
teacher/src/main/res/drawable-xhdpi/icon_live_delay_normal.png


BIN
teacher/src/main/res/drawable-xhdpi/icon_live_finish.png


BIN
teacher/src/main/res/drawable-xhdpi/icon_live_pause.png


BIN
teacher/src/main/res/drawable-xhdpi/icon_live_room_close_menu.png


BIN
teacher/src/main/res/drawable-xhdpi/icon_mic_contro.png


BIN
teacher/src/main/res/drawable-xxhdpi/icon_live_barrage_buy_tag.png


BIN
teacher/src/main/res/drawable-xxhdpi/icon_live_delay_high.png


BIN
teacher/src/main/res/drawable-xxhdpi/icon_live_delay_middle.png


BIN
teacher/src/main/res/drawable-xxhdpi/icon_live_delay_normal.png


BIN
teacher/src/main/res/drawable-xxhdpi/icon_live_finish.png


BIN
teacher/src/main/res/drawable-xxhdpi/icon_live_pause.png


BIN
teacher/src/main/res/drawable-xxhdpi/icon_live_room_close_menu.png


BIN
teacher/src/main/res/drawable-xxhdpi/icon_mic_contro.png


+ 7 - 0
teacher/src/main/res/drawable/shape_live_barrage_for_join_msg.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <gradient
+        android:endColor="#60FFF7"
+        android:startColor="#00BF85" />
+    <corners android:radius="12dp" />
+</shape>

+ 7 - 0
teacher/src/main/res/drawable/shape_live_barrage_for_snap_up_msg.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <gradient
+        android:endColor="#FF6500"
+        android:startColor="#FFB300" />
+    <corners android:radius="12dp" />
+</shape>

+ 5 - 0
teacher/src/main/res/drawable/shape_live_finish_bg.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#FFEEE3"/>
+    <corners android:radius="14dp"/>
+</shape>

+ 8 - 0
teacher/src/main/res/drawable/shape_live_mic_bt_bg.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/color_e4f8f7" />
+    <corners android:radius="8dp" />
+    <stroke
+        android:width="1dp"
+        android:color="@color/color_01c1b5" />
+</shape>

+ 11 - 0
teacher/src/main/res/drawable/shape_live_on_mic_tip_bg.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/color_ff4e19" />
+    <stroke
+        android:width="1dp"
+        android:color="@color/white" />
+    <corners
+        android:bottomRightRadius="8dp"
+        android:topLeftRadius="8dp"
+        android:topRightRadius="8dp" />
+</shape>

+ 5 - 0
teacher/src/main/res/drawable/shape_live_pause_bg.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#E4F8F7"/>
+    <corners android:radius="14dp"/>
+</shape>

+ 93 - 0
teacher/src/main/res/layout/dialog_live_manager_layout.xml

@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="226dp"
+    android:background="@drawable/bg_white_top_10dp">
+
+    <TextView
+        android:id="@+id/tv_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingTop="18dp"
+        android:text="选择暂停或结束直播!"
+        android:textColor="@color/color_333333"
+        android:textSize="@dimen/sp_16"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <View
+        android:id="@+id/view_pause_live"
+        android:layout_width="0dp"
+        android:layout_height="109dp"
+        android:layout_marginStart="14dp"
+        android:layout_marginTop="22dp"
+        android:layout_marginEnd="5dp"
+        android:background="@drawable/shape_live_pause_bg"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toLeftOf="@+id/view_pause_finish"
+        app:layout_constraintTop_toBottomOf="@+id/tv_title" />
+
+    <View
+        android:id="@+id/view_pause_finish"
+        android:layout_width="0dp"
+        android:layout_height="109dp"
+        android:layout_marginStart="5dp"
+        android:layout_marginEnd="14dp"
+        android:background="@drawable/shape_live_finish_bg"
+        app:layout_constraintLeft_toRightOf="@+id/view_pause_live"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="@+id/view_pause_live" />
+
+    <ImageView
+        android:id="@+id/iv_pause_live"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/icon_live_pause"
+        app:layout_constraintBottom_toTopOf="@+id/tv_live_pause"
+        app:layout_constraintLeft_toLeftOf="@+id/view_pause_live"
+        app:layout_constraintRight_toRightOf="@+id/view_pause_live"
+        app:layout_constraintTop_toTopOf="@+id/view_pause_live"
+        app:layout_constraintVertical_chainStyle="packed" />
+
+    <TextView
+        android:id="@+id/tv_live_pause"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:includeFontPadding="false"
+        android:text="@string/pause_live"
+        android:textColor="@color/color_333333"
+        android:textSize="@dimen/sp_14"
+        app:layout_constraintBottom_toBottomOf="@+id/view_pause_live"
+        app:layout_constraintLeft_toLeftOf="@+id/view_pause_live"
+        app:layout_constraintRight_toRightOf="@+id/view_pause_live"
+        app:layout_constraintTop_toBottomOf="@+id/iv_pause_live" />
+
+    <ImageView
+        android:id="@+id/iv_finish_live"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/icon_live_finish"
+        app:layout_constraintBottom_toTopOf="@+id/tv_finish_live"
+        app:layout_constraintLeft_toLeftOf="@+id/view_pause_finish"
+        app:layout_constraintRight_toRightOf="@+id/view_pause_finish"
+        app:layout_constraintTop_toTopOf="@+id/view_pause_finish"
+        app:layout_constraintVertical_chainStyle="packed" />
+
+    <TextView
+        android:id="@+id/tv_finish_live"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:includeFontPadding="false"
+        android:text="@string/live_finish_str"
+        android:textColor="@color/color_333333"
+        android:textSize="@dimen/sp_14"
+        app:layout_constraintBottom_toBottomOf="@+id/view_pause_finish"
+        app:layout_constraintLeft_toLeftOf="@+id/view_pause_finish"
+        app:layout_constraintRight_toRightOf="@+id/view_pause_finish"
+        app:layout_constraintTop_toBottomOf="@+id/iv_finish_live" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 48 - 0
teacher/src/main/res/layout/dialog_live_mic_manager_layout.xml

@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="400dp"
+    android:background="@drawable/bg_white_top_10dp">
+
+    <com.google.android.material.tabs.TabLayout
+        android:id="@+id/tab_layout"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:tabBackground="@color/transparent"
+        app:tabGravity="fill"
+        app:tabIndicator="@drawable/custom_indicator_drawable"
+        app:tabIndicatorColor="@color/color_01c1b5"
+        app:tabIndicatorFullWidth="false"
+        app:tabIndicatorHeight="3dp"
+        app:tabMode="fixed"
+        app:tabRippleColor="@color/transparent"
+        app:tabSelectedTextColor="@color/color_333333"
+        app:tabTextColor="@color/color_666666">
+
+        <com.google.android.material.tabs.TabItem
+            android:id="@+id/tabItem1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="B" />
+
+        <com.google.android.material.tabs.TabItem
+            android:id="@+id/tabItem2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="B" />
+    </com.google.android.material.tabs.TabLayout>
+
+    <androidx.viewpager2.widget.ViewPager2
+        android:id="@+id/viewPager"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:overScrollMode="never"
+        android:scrollbars="none"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tab_layout" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 50 - 0
teacher/src/main/res/layout/fragment_live_apply_mic_layout.xml

@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/tv_refuse_all"
+        android:layout_width="0dp"
+        android:layout_height="42dp"
+        android:layout_marginStart="14dp"
+        android:layout_marginTop="14dp"
+        android:layout_marginEnd="5dp"
+        android:background="@drawable/shape_live_mic_bt_bg"
+        android:gravity="center"
+        android:text="全部拒绝"
+        android:textColor="@color/color_01c1b5"
+        android:textSize="@dimen/dp_16"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toLeftOf="@+id/tv_enable_mic"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/tv_enable_mic"
+        android:layout_width="0dp"
+        android:layout_height="42dp"
+        android:layout_marginStart="5dp"
+        android:layout_marginEnd="14dp"
+        android:background="@drawable/shape_live_mic_bt_bg"
+        android:gravity="center"
+        android:text="禁止连麦"
+        android:textColor="@color/color_01c1b5"
+        android:textSize="@dimen/dp_16"
+        app:layout_constraintLeft_toRightOf="@+id/tv_refuse_all"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="@+id/tv_refuse_all" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/recyclerView"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_marginTop="14dp"
+        android:overScrollMode="never"
+        android:scrollbars="none"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_refuse_all" />
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 35 - 0
teacher/src/main/res/layout/fragment_live_on_mic_layout.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/tv_down_all_mic"
+        android:layout_width="0dp"
+        android:layout_height="42dp"
+        android:layout_marginStart="14dp"
+        android:layout_marginTop="14dp"
+        android:layout_marginEnd="14dp"
+        android:background="@drawable/shape_live_mic_bt_bg"
+        android:gravity="center"
+        android:text="全部下麦"
+        android:textColor="@color/color_01c1b5"
+        android:textSize="@dimen/dp_16"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/recyclerView"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_marginTop="14dp"
+        android:overScrollMode="never"
+        android:scrollbars="none"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_down_all_mic" />
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 58 - 0
teacher/src/main/res/layout/item_live_mic_manager_layout.xml

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginTop="10dp"
+    android:paddingStart="14dp"
+    android:paddingEnd="14dp">
+
+    <de.hdodenhof.circleimageview.CircleImageView
+        android:id="@+id/iv_avatar"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/tv_name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingStart="10dp"
+        android:textColor="@color/color_1a1a1a"
+        android:textSize="15sp"
+        app:layout_constraintBottom_toTopOf="@+id/tv_tip"
+        app:layout_constraintLeft_toRightOf="@+id/iv_avatar"
+        app:layout_constraintTop_toTopOf="@+id/iv_avatar"
+        app:layout_constraintVertical_chainStyle="packed"
+        tools:text="王欣欣" />
+
+    <TextView
+        android:id="@+id/tv_tip"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="5dp"
+        android:paddingStart="10dp"
+        android:text="申请连麦中"
+        android:textColor="@color/color_1a1a1a"
+        android:textSize="13sp"
+        app:layout_constraintBottom_toBottomOf="@+id/iv_avatar"
+        app:layout_constraintLeft_toRightOf="@+id/iv_avatar"
+        app:layout_constraintTop_toBottomOf="@+id/tv_name" />
+
+
+    <TextView
+        android:id="@+id/tv_handle"
+        android:layout_width="64dp"
+        android:layout_height="28dp"
+        android:background="@drawable/shape_8dp_01c1b5"
+        android:gravity="center"
+        android:includeFontPadding="false"
+        android:textColor="@color/white"
+        android:textSize="14sp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:text="上麦" />
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 117 - 14
teacher/src/main/res/layout/view_live_room_main_layout.xml

@@ -4,6 +4,7 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:paddingTop="17dp"
     tools:background="@color/color_25292e">
 
 
@@ -52,17 +53,6 @@
             app:layout_constraintTop_toTopOf="@+id/bg_avatar"
             tools:text="唐老唐老师唐老师师" />
 
-        <ImageView
-            android:id="@+id/iv_close"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="14dp"
-            android:padding="5dp"
-            android:src="@drawable/icon_close_gray"
-            app:layout_constraintBottom_toBottomOf="@+id/bg_avatar"
-            app:layout_constraintRight_toRightOf="parent"
-            app:layout_constraintTop_toTopOf="@+id/bg_avatar" />
-
         <LinearLayout
             android:id="@+id/ll_member_num_bg"
             android:layout_width="wrap_content"
@@ -75,7 +65,7 @@
             android:paddingEnd="10dp"
             android:paddingBottom="5dp"
             app:layout_constraintBottom_toBottomOf="@+id/bg_avatar"
-            app:layout_constraintRight_toLeftOf="@+id/iv_close"
+            app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintTop_toTopOf="@+id/bg_avatar">
 
             <ImageView
@@ -128,6 +118,47 @@
                 android:textSize="@dimen/sp_12"
                 tools:text="本场点赞1240000000" />
         </LinearLayout>
+
+
+        <LinearLayout
+            android:id="@+id/ll_live_delay"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="11dp"
+            android:layout_marginEnd="15dp"
+            android:background="@drawable/bg_gray_20dp_shape"
+            android:gravity="center"
+            android:orientation="horizontal"
+            android:paddingStart="7dp"
+            android:paddingTop="5dp"
+            android:paddingEnd="7dp"
+            android:paddingBottom="5dp"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/ll_member_num_bg">
+
+            <ImageView
+                android:id="@+id/iv_live_delay"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/icon_live_delay_normal"
+                app:layout_constraintRight_toRightOf="parent" />
+
+            <TextView
+                android:id="@+id/tv_live_delay"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:includeFontPadding="false"
+                android:paddingStart="3dp"
+                android:text="0ms"
+                android:textColor="@color/white"
+                android:textSize="@dimen/sp_12"
+                app:layout_constraintBottom_toBottomOf="@+id/iv_live_delay"
+                app:layout_constraintLeft_toRightOf="@+id/iv_live_delay"
+                app:layout_constraintTop_toTopOf="@+id/iv_live_delay"
+                tools:text="255ms" />
+
+        </LinearLayout>
+
     </androidx.constraintlayout.widget.ConstraintLayout>
 
 
@@ -168,7 +199,7 @@
         android:layout_height="wrap_content"
         android:layout_marginEnd="11dp"
         android:layout_marginBottom="30dp"
-        android:src="@drawable/icon_finish_live_exit"
+        android:src="@drawable/icon_live_room_close_menu"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintRight_toRightOf="parent" />
 
@@ -177,11 +208,31 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginEnd="11dp"
-        android:src="@drawable/icon_mic_connecting"
+        android:src="@drawable/icon_mic_contro"
+        android:visibility="gone"
         app:layout_constraintBottom_toBottomOf="@+id/icon_finish_live"
         app:layout_constraintRight_toLeftOf="@+id/icon_finish_live"
         app:layout_constraintTop_toTopOf="@+id/icon_finish_live" />
 
+
+    <TextView
+        android:id="@+id/tv_on_mic_num_tip"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@drawable/shape_live_on_mic_tip_bg"
+        android:includeFontPadding="false"
+        android:paddingStart="8dp"
+        android:paddingTop="2dp"
+        android:paddingEnd="8dp"
+        android:paddingBottom="2dp"
+        android:textColor="@color/white"
+        android:visibility="gone"
+        app:layout_constraintCircle="@+id/iv_mic"
+        app:layout_constraintCircleAngle="45"
+        app:layout_constraintCircleRadius="25dp"
+        tools:ignore="MissingConstraints"
+        tools:text="3" />
+
     <FrameLayout
         android:id="@+id/fl_recycler_container"
         android:layout_width="match_parent"
@@ -200,4 +251,56 @@
             android:overScrollMode="never"
             android:scrollbars="none" />
     </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/fl_join_barrage"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="11dp"
+        android:layout_marginBottom="10dp"
+        android:background="@drawable/shape_live_barrage_for_join_msg"
+        android:paddingStart="10dp"
+        android:paddingTop="3dp"
+        android:paddingEnd="10dp"
+        android:paddingBottom="3dp"
+        android:visibility="gone"
+        app:layout_constraintBottom_toTopOf="@+id/fl_recycler_container"
+        app:layout_constraintLeft_toLeftOf="parent">
+
+        <TextView
+            android:id="@+id/tv_join_barrage"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="@color/white"
+            android:textSize="@dimen/sp_13"
+            tools:text="新雷 进入直播间" />
+
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/fl_snap_up_barrage"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="11dp"
+        android:layout_marginBottom="10dp"
+        android:background="@drawable/shape_live_barrage_for_snap_up_msg"
+        android:paddingStart="10dp"
+        android:paddingTop="3dp"
+        android:paddingEnd="10dp"
+        android:paddingBottom="3dp"
+        android:visibility="gone"
+        app:layout_constraintBottom_toTopOf="@+id/fl_recycler_container"
+        app:layout_constraintLeft_toLeftOf="parent">
+
+        <TextView
+            android:id="@+id/tv_snap_up_barrage"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:drawableLeft="@drawable/icon_live_barrage_buy_tag"
+            android:drawablePadding="4dp"
+            android:textColor="@color/white"
+            android:textSize="@dimen/sp_13"
+            tools:text="张予锡 正在去购买" />
+
+    </FrameLayout>
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 9 - 0
teacher/src/main/res/values/strings.xml

@@ -30,4 +30,13 @@
     <string name="live_room_add_like_count_text_str">给主讲人点了%1$d个赞</string>
     <string name="reset_str">重置</string>
     <string name="no_teacher_introduce">暂无简介内容</string>
+    <string name="pause_live">暂停直播</string>
+    <string name="live_finish_str">结束直播</string>
+    <string name="live_room_add_like_count_str">本场点赞%1$d</string>
+    <string name="enter_live_tip_str">%1$s 进入直播间</string>
+    <string name="live_snap_up_tip_str">%1$s 正在抢购</string>
+    <string name="live_pause_tip_str">暂停后观众将无法看到视频画面</string>
+    <string name="finish_live_tip_str">结束直播后,不可再次开启</string>
+    <string name="net_error_tip">网络已断开</string>
+    <string name="live_delay_text">%1$dms</string>
 </resources>