honghengqiang 2 år sedan
förälder
incheckning
9faa235ded
47 ändrade filer med 1809 tillägg och 72 borttagningar
  1. 9 0
      baseswago/src/main/java/com/swago/baseswago/agora/AgoraManager.kt
  2. 2 0
      baseswago/src/main/java/com/swago/baseswago/baseroom/IRoomInfo.kt
  3. 4 0
      baseswago/src/main/java/com/swago/baseswago/baseroom/ui/AbsUserActivity.kt
  4. 10 0
      baseswago/src/main/java/com/swago/baseswago/cusview/SwagoImageView.kt
  5. 30 0
      baseswago/src/main/java/com/swago/baseswago/im/GroupMsgParser.kt
  6. 46 0
      baseswago/src/main/java/com/swago/baseswago/im/ImConstant.kt
  7. 89 3
      baseswago/src/main/java/com/swago/baseswago/inter/RoomApi.kt
  8. 11 0
      baseswago/src/main/java/com/swago/baseswago/model/MomentModel.java
  9. 53 0
      baseswago/src/main/java/com/swago/baseswago/model/live/audio/AudioSeatModel.kt
  10. 15 0
      baseswago/src/main/java/com/swago/baseswago/model/live/audio/IMAudioModel.kt
  11. 17 0
      baseswago/src/main/java/com/swago/baseswago/model/live/audio/IMAudioSeatUpdateModel.kt
  12. 9 0
      baseswago/src/main/java/com/swago/glide.kt
  13. 1 1
      baseswago/src/main/res/layout/view_avatar.xml
  14. BIN
      baseswago/src/main/res/mipmap-xxhdpi/ic_audio_integration.webp
  15. BIN
      baseswago/src/main/res/mipmap-xxhdpi/ic_audio_lock.webp
  16. BIN
      baseswago/src/main/res/mipmap-xxhdpi/ic_audio_seat.webp
  17. 1 0
      baseswago/src/main/res/values/colors.xml
  18. 6 0
      baseswago/src/main/res/values/strings.xml
  19. 68 2
      room/src/main/java/com/swago/room/anchor/AnchorRoomActivity.kt
  20. 6 1
      room/src/main/java/com/swago/room/anchor/AnchorRoomFragment.kt
  21. 22 0
      room/src/main/java/com/swago/room/audio/ApplyOnMicDialog.kt
  22. 114 0
      room/src/main/java/com/swago/room/audio/AudioActionDialog.kt
  23. 66 0
      room/src/main/java/com/swago/room/audio/AudioRoomManager.kt
  24. 37 0
      room/src/main/java/com/swago/room/audio/AudioSeatAdapter.kt
  25. 36 0
      room/src/main/java/com/swago/room/audio/IAudioRoomListener.kt
  26. 105 0
      room/src/main/java/com/swago/room/audio/UserByAnchorInviteDialog.kt
  27. 186 30
      room/src/main/java/com/swago/room/base/BaseComFragment.kt
  28. 20 0
      room/src/main/java/com/swago/room/bean/UserRoomModel.kt
  29. 7 0
      room/src/main/java/com/swago/room/enum/RoomType.kt
  30. 115 21
      room/src/main/java/com/swago/room/user/UserRoomActivity.kt
  31. 12 0
      room/src/main/java/com/swago/room/user/UserRoomFragment.kt
  32. 129 11
      room/src/main/java/com/swago/room/vm/MsgVm.kt
  33. 83 1
      room/src/main/java/com/swago/room/vm/RoomVm.kt
  34. 6 0
      room/src/main/java/com/swago/room/widget/AnchorFooterView.kt
  35. 31 0
      room/src/main/java/com/swago/room/widget/ChoiceViewPager.kt
  36. 59 1
      room/src/main/res/layout/activity_anchor_room.xml
  37. 59 0
      room/src/main/res/layout/dialog_apply_on_mic.xml
  38. 185 0
      room/src/main/res/layout/dialog_audio_action.xml
  39. 89 0
      room/src/main/res/layout/dialog_invited_by_anchor_mic.xml
  40. 9 0
      room/src/main/res/layout/fragment_base_com.xml
  41. 61 0
      room/src/main/res/layout/item_audio_seat.xml
  42. 1 1
      room/src/main/res/layout/layout_user_room.xml
  43. BIN
      room/src/main/res/mipmap-xxhdpi/ic_apply_on_mic.webp
  44. BIN
      room/src/main/res/mipmap-xxhdpi/ic_down_seat.png
  45. BIN
      room/src/main/res/mipmap-xxhdpi/ic_lock.png
  46. BIN
      room/src/main/res/mipmap-xxhdpi/ic_unlock.png
  47. BIN
      room/src/main/res/mipmap-xxhdpi/ic_yao_qiing_shangmai.png

+ 9 - 0
baseswago/src/main/java/com/swago/baseswago/agora/AgoraManager.kt

@@ -167,6 +167,15 @@ object AgoraManager {
         mRtcEngine?.setupLocalVideo(VideoCanvas(mLocalView, VideoCanvas.RENDER_MODE_HIDDEN, 0))
     }
 
+    /**
+     * 主播端切到语音房停止预览然后移除视频控件
+     */
+    fun stopPreviewAndRemoveLocalView(mLocalContainer: FrameLayout?){
+        mRtcEngine?.stopPreview()
+        mLocalContainer?.removeAllViews()
+    }
+
+
 
     /**
      * 观众拉取远端主播画面

+ 2 - 0
baseswago/src/main/java/com/swago/baseswago/baseroom/IRoomInfo.kt

@@ -29,4 +29,6 @@ interface IRoomInfo {
     fun getRoomSystemMsg():String
     fun getIsRobot():Boolean
     fun getRoomAdmin():Int //用户是否是直播间管理员
+
+    fun getRoomType():Int
 }

+ 4 - 0
baseswago/src/main/java/com/swago/baseswago/baseroom/ui/AbsUserActivity.kt

@@ -82,6 +82,10 @@ abstract class AbsUserActivity<T: ActivityAbsRoomUserBinding,E: IRoomInfo> : Bas
         SwagoRoomManager.clearListener()
     }
 
+    fun setCanVerticalScroll(isCanScroll:Boolean){
+        pagerLayoutManager.setCanScroll(isCanScroll)
+    }
+
     abstract fun initUserRoomView()
     abstract fun initLiveData()
 

+ 10 - 0
baseswago/src/main/java/com/swago/baseswago/cusview/SwagoImageView.kt

@@ -4,6 +4,7 @@ import android.content.Context
 import android.util.AttributeSet
 import android.view.LayoutInflater
 import android.widget.FrameLayout
+import androidx.annotation.DrawableRes
 import com.swago.baseswago.databinding.ViewAvatarBinding
 import com.swago.loadUrl
 
@@ -35,4 +36,13 @@ class SwagoImageView : FrameLayout {
         }
     }
 
+    fun loadImage(@DrawableRes resourceId: Int, picFrameUrl:String=""){
+        binding?.apply {
+            ivAvatar.loadUrl(context,resourceId)
+            if (picFrameUrl.isNotEmpty()){
+                ivFrame.loadUrl(context,picFrameUrl)
+            }
+        }
+    }
+
 }

+ 30 - 0
baseswago/src/main/java/com/swago/baseswago/im/GroupMsgParser.kt

@@ -18,7 +18,9 @@ import com.swago.baseswago.im.ImConstant.forbid_speak
 import com.swago.baseswago.im.ImConstant.force_close_live_room
 import com.swago.baseswago.im.ImConstant.fruit_game
 import com.swago.baseswago.im.ImConstant.game_win_big_prize
+import com.swago.baseswago.im.ImConstant.invite_user_on_mic
 import com.swago.baseswago.im.ImConstant.launch_mic
+import com.swago.baseswago.im.ImConstant.lock_un_lock_mic
 import com.swago.baseswago.im.ImConstant.lucky_gift
 import com.swago.baseswago.im.ImConstant.lucky_gift_prize
 import com.swago.baseswago.im.ImConstant.pk_process
@@ -33,14 +35,21 @@ import com.swago.baseswago.im.ImConstant.room_chat_text
 import com.swago.baseswago.im.ImConstant.set_room_admin
 import com.swago.baseswago.im.ImConstant.svg_gift
 import com.swago.baseswago.im.ImConstant.update_audience
+import com.swago.baseswago.im.ImConstant.update_mic_list_data
+import com.swago.baseswago.im.ImConstant.user_agree_invite_by_anchor
+import com.swago.baseswago.im.ImConstant.user_down_mic
 import com.swago.baseswago.im.ImConstant.user_exit_room
 import com.swago.baseswago.im.ImConstant.user_join_room
+import com.swago.baseswago.im.ImConstant.user_refuse_invite_by_anchor
 import com.swago.baseswago.model.RedEnvelope
 import com.swago.baseswago.model.im.*
 import com.swago.baseswago.model.live.ForceCloseModel
 import com.swago.baseswago.model.live.ReceiveModel
 import com.swago.baseswago.model.im.GamePrize
 import com.swago.baseswago.model.live.RoomUserChangeModel
+import com.swago.baseswago.model.live.audio.AudioSeatModel
+import com.swago.baseswago.model.live.audio.IMAudioModel
+import com.swago.baseswago.model.live.audio.IMAudioSeatUpdateModel
 import com.swago.baseswago.model.live.gift.IMGiftModel
 import com.swago.baseswago.model.live.mic.LianMaiIMModel
 import com.swago.baseswago.model.live.pk.*
@@ -247,6 +256,27 @@ class GroupMsgParser : IGroupNewMsgParser {
                     )
                     parserModel = gson.fromJson(resultString,parameterizedTypeImpl)
                 }
+
+                lock_un_lock_mic, invite_user_on_mic,
+                    user_refuse_invite_by_anchor,
+                user_agree_invite_by_anchor,
+                user_down_mic-> {
+                    parameterizedTypeImpl = ParameterizedTypeImpl(
+                        arrayOf<Type>(IMAudioModel::class.java),
+                        CusNewMsgBean::class.java,
+                        CusNewMsgBean::class.java
+                    )
+                    parserModel = gson.fromJson(resultString,parameterizedTypeImpl)
+                }
+
+                update_mic_list_data -> {
+                    parameterizedTypeImpl = ParameterizedTypeImpl(
+                        arrayOf<Type>(IMAudioSeatUpdateModel::class.java),
+                        CusNewMsgBean::class.java,
+                        CusNewMsgBean::class.java
+                    )
+                    parserModel = gson.fromJson(resultString,parameterizedTypeImpl)
+                }
             }
             parserModel?.v2TIMMessage = v2TIMMessage
         }catch (e:Exception){

+ 46 - 0
baseswago/src/main/java/com/swago/baseswago/im/ImConstant.kt

@@ -137,6 +137,52 @@ object ImConstant {
     const val set_room_admin = 221
     const val delete_room_admin = 222
 
+
+    /***************语音房****************/
+
+    /**
+     * 邀请用户上麦
+     */
+    const val invite_user_on_mic = 301
+
+    /**
+     *锁麦和解锁
+     */
+    const val lock_un_lock_mic = 302
+
+    /**
+     * 主播对用户开麦和闭麦
+     */
+    const val open_close_mic = 303
+
+    /**
+     * 主播下麦用户
+     */
+    const val user_down_mic = 304
+
+
+    /**
+     * 麦位列表刷新
+     */
+    const val update_mic_list_data = 305
+
+    /**
+     * 用户同意主播邀请上麦
+     */
+    const val user_agree_invite_by_anchor = 306
+
+    /**
+     * 用户拒绝主播邀请上麦
+     */
+    const val user_refuse_invite_by_anchor = 307
+
+
+    /**
+     * 用户送礼积分变更
+     */
+    const val jifen_change = 308
+
+
     /**********游戏相关IM********/
     const val fruit_game = 1001
     const val beauty_game = 1002

+ 89 - 3
baseswago/src/main/java/com/swago/baseswago/inter/RoomApi.kt

@@ -3,6 +3,8 @@ package com.swago.baseswago.inter
 import com.swago.baseswago.model.MomentModel
 import com.swago.baseswago.model.RedEnvelope
 import com.swago.baseswago.model.live.*
+import com.swago.baseswago.model.live.audio.AudioSeatList
+import com.swago.baseswago.model.live.audio.AudioSeatModel
 import com.swago.baseswago.model.live.game.GameListModel
 import com.swago.baseswago.model.live.gift.GiftAllModel
 import com.swago.baseswago.model.live.gift.GiftSendModel
@@ -28,9 +30,11 @@ interface RoomApi {
 
     /**
      * 开播
+     * broadcast_type 直播间类型(1视频2语音)
      */
-    @POST("/v2/rtc/start/broadcast")
-    suspend fun startLive(): RoomModel
+    @FormUrlEncoded
+    @POST("/v3/rtc/start/broadcast")
+    suspend fun startLive(@Field("broadcast_type")broadcast_type:Int): RoomModel
 
 
     /**
@@ -313,19 +317,101 @@ interface RoomApi {
 
 
 
+    /*************************语音房*******************************************/
 
+    /**
+     * 获取麦位列表
+     * type 1开播前 2开播中
+     */
+    @FormUrlEncoded
+    @POST("/v3/rtc/yuying/position/list")
+    suspend fun getAudioList(@Field("room_id") room_id: String,
+                             @Field("type") type: Int): AudioSeatList
 
+    /**
+     * 锁麦和解锁麦位
+     * type类型(1锁麦2解锁)
+     */
+    @FormUrlEncoded
+    @POST("/v3/rtc/yuying/position/lock")
+    suspend fun lockAndUnLockMic(@Field("room_id") room_id: String,
+                                 @Field("broadcast_log_id") broadcast_log_id: String,
+                                 @Field("position_id") position_id: Int,
+                                 @Field("type") type: Int):Any
 
+    /**
+     * 邀请用户上麦
+     */
+    @FormUrlEncoded
+    @POST("/v3/rtc/yuying/position/invite")
+    suspend fun inviteOnMic(@Field("room_id") room_id: String,
+                            @Field("broadcast_log_id") broadcast_log_id: String,
+                            @Field("position_id") position_id: Int,
+                            @Field("user_id") user_id: String):Any
 
 
+    /**
+     * 主播对用户开闭麦
+     * "type": 1, //类型(1闭麦2开麦)
+     */
+    @FormUrlEncoded
+    @POST("/v3/rtc/yuying/position/open")
+    suspend fun operateMicByAnchor(@Field("room_id") room_id: String,
+                                   @Field("broadcast_log_id") broadcast_log_id: String,
+                                   @Field("position_id") position_id: Int,
+                                   @Field("user_id") user_id: String,
+                                   @Field("type") type: Int):Any
 
+    /**
+     * 主播对用户下麦操作
+     */
+    @FormUrlEncoded
+    @POST("/v3/rtc/yuying/position/down")
+    suspend fun downMicByAnchor(@Field("room_id") room_id: String,
+                                   @Field("broadcast_log_id") broadcast_log_id: String,
+                                   @Field("position_id") position_id: Int,
+                                   @Field("user_id") user_id: String):Any
 
+    /**
+     * 主播同意用户上麦
+     * "type": 1, //类型(1闭麦2开麦)
+     */
+    @FormUrlEncoded
+    @POST("/v3/rtc/yuying/position/access")
+    suspend fun agreeUserOnMic(@Field("room_id") room_id: String,
+                                @Field("broadcast_log_id") broadcast_log_id: String,
+                                @Field("position_id") position_id: Int,
+                                @Field("user_id") user_id: String):Any
 
+    /**
+     * 用户上麦成功确认
+     */
+    @FormUrlEncoded
+    @POST("/v3/rtc/yuying/position/ack")
+    suspend fun userOnMicCallBack(@Field("room_id") room_id: String,
+                               @Field("broadcast_log_id") broadcast_log_id: String,
+                               @Field("apply_id") apply_id: String):Any
 
 
+    /**
+     * 用户申请上麦
+     */
+    @FormUrlEncoded
+    @POST("/v3/rtc/yuying/position/apply")
+    suspend fun userApplyOnMic(@Field("room_id") room_id: String,
+                               @Field("position_id") position_id: Int):Any
 
 
-
+    /**
+     * 观众同意主播的邀请上麦
+     * "type": 1 //操作类型(1同意 2拒绝)
+     */
+    @FormUrlEncoded
+    @POST("/v3/rtc/yuying/position/agree")
+    suspend fun userAgreeAnchorInvite(@Field("room_id") room_id: String,
+                                      @Field("broadcast_log_id") broadcast_log_id: String,
+                                      @Field("apply_id") apply_id: String,
+                                      @Field("type") type: Int):Any
 
 
 }

+ 11 - 0
baseswago/src/main/java/com/swago/baseswago/model/MomentModel.java

@@ -31,6 +31,7 @@ public class MomentModel implements Parcelable {
     private int is_official;
     private int is_crown;
     private int is_cup;
+    private int user_broadcast_type; //直播间类型(1视频2语音)
 
     protected MomentModel(Parcel in) {
         user_account = in.readString();
@@ -47,6 +48,7 @@ public class MomentModel implements Parcelable {
         is_robot = in.readInt();
         is_crown = in.readInt();
         is_cup = in.readInt();
+        user_broadcast_type = in.readInt();
     }
 
     @Override
@@ -65,6 +67,7 @@ public class MomentModel implements Parcelable {
         dest.writeInt(is_robot);
         dest.writeInt(is_crown);
         dest.writeInt(is_cup);
+        dest.writeInt(user_broadcast_type);
     }
 
     @Override
@@ -211,4 +214,12 @@ public class MomentModel implements Parcelable {
     public void setIs_cup(int is_cup) {
         this.is_cup = is_cup;
     }
+
+    public int getUser_broadcast_type() {
+        return user_broadcast_type;
+    }
+
+    public void setUser_broadcast_type(int user_broadcast_type) {
+        this.user_broadcast_type = user_broadcast_type;
+    }
 }

+ 53 - 0
baseswago/src/main/java/com/swago/baseswago/model/live/audio/AudioSeatModel.kt

@@ -0,0 +1,53 @@
+package com.swago.baseswago.model.live.audio
+
+import android.os.Parcel
+import android.os.Parcelable
+
+data class AudioSeatModel(
+    val user_name:String?, //用户昵称
+    val user_head_img_url: String?, //用户头像
+    val user_id:String?, //用户ID
+    val voice_status:Int, //麦位语音状态(1正常2禁言)
+    var lock_status:Int, //锁麦状态(1正常2锁定)
+    val voice_jifen:String?,//积分
+    val maiIndex:Int//积分
+) : Parcelable {
+    constructor(parcel: Parcel) : this(
+        parcel.readString(),
+        parcel.readString(),
+        parcel.readString(),
+        parcel.readInt(),
+        parcel.readInt(),
+        parcel.readString(),
+        parcel.readInt()
+    ) {
+    }
+
+    override fun writeToParcel(parcel: Parcel, flags: Int) {
+        parcel.writeString(user_name)
+        parcel.writeString(user_head_img_url)
+        parcel.writeString(user_id)
+        parcel.writeInt(voice_status)
+        parcel.writeInt(lock_status)
+        parcel.writeString(voice_jifen)
+        parcel.writeInt(maiIndex)
+    }
+
+    override fun describeContents(): Int {
+        return 0
+    }
+
+    companion object CREATOR : Parcelable.Creator<AudioSeatModel> {
+        override fun createFromParcel(parcel: Parcel): AudioSeatModel {
+            return AudioSeatModel(parcel)
+        }
+
+        override fun newArray(size: Int): Array<AudioSeatModel?> {
+            return arrayOfNulls(size)
+        }
+    }
+}
+
+data class AudioSeatList(
+    val list:List<AudioSeatModel>?
+)

+ 15 - 0
baseswago/src/main/java/com/swago/baseswago/model/live/audio/IMAudioModel.kt

@@ -0,0 +1,15 @@
+package com.swago.baseswago.model.live.audio
+
+/**
+ * 语音房IM消息
+ */
+data class IMAudioModel(
+    val roomId:String,
+    val roomSessionId:String,
+    val maiIndex:Int,
+    val receiverId:String,
+    val action:Int, //1锁麦 0解锁
+    val inviteName:String,
+    val inviteAvatar:String,
+    val applyId:String
+)

+ 17 - 0
baseswago/src/main/java/com/swago/baseswago/model/live/audio/IMAudioSeatUpdateModel.kt

@@ -0,0 +1,17 @@
+package com.swago.baseswago.model.live.audio
+
+data class IMAudioSeatUpdateModel(
+    val roomId:String,
+    val roomSessionId:String,
+    val maiSeatInfo:IMAudioSeat
+)
+
+data class IMAudioSeat(
+    val integration:String,
+    val lock:Int,
+    val maiIndex:Int,
+    val maiStatus:Int,
+    val userAvatar:String,
+    val userId:String,
+    val userName:String
+)

+ 9 - 0
baseswago/src/main/java/com/swago/glide.kt

@@ -35,6 +35,15 @@ fun ImageView.loadUrl(context: Context,url:String){
         .into(this)
 }
 
+fun ImageView.loadUrl(context: Context,@DrawableRes resourceId: Int){
+    Glide.with(context)
+        .load(resourceId)
+        .centerCrop()
+        .placeholder(R.mipmap.default_avatar)
+        .error(R.mipmap.default_avatar)
+        .into(this)
+}
+
 fun ImageView.loadBurlImage(context: Context, url: String) {
     Glide.with(context)
         .load(url)

+ 1 - 1
baseswago/src/main/res/layout/view_avatar.xml

@@ -15,7 +15,7 @@
         android:id="@+id/ivAvatar"
         android:layout_width="match_parent"
         android:layout_height="0dp"
-        android:layout_margin="7dp"
+        android:layout_margin="9dp"
         app:layout_constraintDimensionRatio="h,1:1"
         app:layout_constraintTop_toTopOf="parent"/>
 

BIN
baseswago/src/main/res/mipmap-xxhdpi/ic_audio_integration.webp


BIN
baseswago/src/main/res/mipmap-xxhdpi/ic_audio_lock.webp


BIN
baseswago/src/main/res/mipmap-xxhdpi/ic_audio_seat.webp


+ 1 - 0
baseswago/src/main/res/values/colors.xml

@@ -3,6 +3,7 @@
     <color name="_ff9300">#ff9300</color>
     <color name="_000000">#000000</color>
     <color name="_ffffff">#ffffff</color>
+    <color name="_d4ffffff">#D4FFFFFF</color>
     <color name="_868686">#868686</color>
 
     <color name="startColor">#ff56b7</color>

+ 6 - 0
baseswago/src/main/res/values/strings.xml

@@ -230,5 +230,11 @@
     <string name="become_room_manager">%s becomes the room administrator</string>
     <string name="ban_live_reason">Reason for banning:%s</string>
     <string name="ban_live_time">Block time:%s</string>
+    <string name="apply_to_connect_a_mic">申请上麦?</string>
+    <string name="invited_on_mic">收到来自主播的上麦邀请</string>
+    <string name="lock_success">锁麦成功</string>
+    <string name="unlock_success">解锁成功</string>
+    <string name="reject_time">拒绝(%ss)</string>
+    <string name="down_mic_success">下麦成功</string>
 
 </resources>

+ 68 - 2
room/src/main/java/com/swago/room/anchor/AnchorRoomActivity.kt

@@ -8,6 +8,7 @@ import android.view.ViewGroup
 import android.view.WindowManager
 import androidx.activity.viewModels
 import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.content.ContextCompat
 import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
@@ -22,6 +23,8 @@ import com.swago.baseswago.baseroom.SwagoRoomManager
 import com.swago.baseswago.baseroom.ui.AbsAnchorActivity
 import com.swago.baseswago.constant.ARouteConstant
 import com.swago.baseswago.dialog.ChoiceDialogFragment
+import com.swago.baseswago.model.live.audio.AudioSeatModel
+import com.swago.baseswago.model.live.audio.IMAudioModel
 import com.swago.baseswago.model.live.pk.ProcessPKModel
 import com.swago.baseswago.model.live.pk.PunishPKModel
 import com.swago.baseswago.model.live.pk.StartPKModel
@@ -32,12 +35,15 @@ import com.swago.baseswago.util.NoDoubleClickListener
 import com.swago.baseswago.util.UserInfo
 import com.swago.room.R
 import com.swago.room.adapter.GameAdapter
+import com.swago.room.audio.AudioRoomManager
+import com.swago.room.audio.IAudioRoomListener
 import com.swago.room.base.NoContentFragment
 import com.swago.room.bean.UserRoomModel
 import com.swago.room.databinding.ActivityAnchorRoomBinding
 import com.swago.room.dialog.AnchorCloseDialog
 import com.swago.room.dialog.CanStartLiveDialog
 import com.swago.room.dialog.ForceCloseRoomDialog
+import com.swago.room.enum.RoomType
 import com.swago.room.lianmai.LianMaiManager
 import com.swago.room.lianmai.LianMaiVm
 import com.swago.room.pk.IPKListener
@@ -56,7 +62,7 @@ import com.swago.room.vm.RoomVm
  */
 @Route(path = ARouteConstant.Room.anchor)
 class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInfo>(),
-    ISwagoIRtcEngineEventHandler, IPKListener {
+    ISwagoIRtcEngineEventHandler, IPKListener, IAudioRoomListener {
 
     private val roomVm by viewModels<RoomVm>()
     private val roomOtherVm by viewModels<RoomOtherVm>()
@@ -73,6 +79,9 @@ class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInf
 
     private var anchorRoomFragment: AnchorRoomFragment? = null
 
+    //开播类型  0视频房 1语音房
+    private var roomType = RoomType.VIDEO
+
     override fun initLiveData() {
         PKStateManager.resetData()
         roomVm.init()
@@ -80,6 +89,7 @@ class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInf
         pkVm.init()
         lianMaiVm.init()
         PKStateManager.addPKListener(this)
+        AudioRoomManager.addListener(this)
         initPeerAnchorLayoutParams()
         window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
         agoraService = Intent(this, AgoraForegroundService::class.java)
@@ -105,11 +115,48 @@ class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInf
                 anchorCloseRoom()
             }
         })
+
+        binding.llVideo.setOnClickListener(object:NoDoubleClickListener(){
+            override fun onClick() {
+                if (roomType == RoomType.VIDEO) return
+                AgoraManager.setVideoAudio(pullVideo = true, pullAudio = true, pushVideo = true, pushAudio = true)
+                roomType = RoomType.VIDEO
+                binding.viewAudio.visibility = View.INVISIBLE
+                binding.viewVideo.visibility = View.VISIBLE
+                binding.tvVideo.setTextColor(ContextCompat.getColor(AppContext.getContext(),R.color._ffffff))
+                binding.tvAudio.setTextColor(ContextCompat.getColor(AppContext.getContext(),R.color._d4ffffff))
+                AgoraManager.setupLocalVideo(this@AnchorRoomActivity, binding.flLocal)
+                anchorRoomFragment?.setAudioRvState(false)
+                binding.viewPager.currentItem = 0
+                binding.ivPrepareCamera.visibility = View.VISIBLE
+            }
+        })
+
+        binding.llAudio.setOnClickListener(object:NoDoubleClickListener(){
+            override fun onClick() {
+                if (roomType == RoomType.AUDIO) return
+                AgoraManager.setVideoAudio(pullVideo = false, pullAudio = true, pushVideo = false, pushAudio = true)
+                roomType = RoomType.AUDIO
+                binding.viewAudio.visibility = View.VISIBLE
+                binding.viewVideo.visibility = View.INVISIBLE
+                binding.tvVideo.setTextColor(ContextCompat.getColor(AppContext.getContext(),R.color._d4ffffff))
+                binding.tvAudio.setTextColor(ContextCompat.getColor(AppContext.getContext(),R.color._ffffff))
+                AgoraManager.stopPreviewAndRemoveLocalView(binding.flLocal)
+                anchorRoomFragment?.setAudioRvState(true)
+                binding.viewPager.currentItem = 1
+                binding.ivPrepareCamera.visibility = View.GONE
+            }
+        })
+
         binding.tvStartLive.setOnClickListener(object : NoDoubleClickListener() {
             override fun onClick() {
                 binding.tvStartLive.isEnabled = false
                 val userModel = UserRoomModel()
+                userModel.roomType = roomType
                 SwagoRoomManager.changeRoom(userModel)
+                if (roomType == RoomType.VIDEO){
+                    anchorRoomFragment?.setAudioRvState(false)
+                }
             }
         })
         binding.ivClose.setOnClickListener(object : NoDoubleClickListener() {
@@ -224,6 +271,7 @@ class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInf
 
     override fun onDestroy() {
         PKStateManager.removePKListener(this)
+        AudioRoomManager.removeListener(this)
         agoraService?.let { stopService(it) }
         super.onDestroy()
     }
@@ -320,6 +368,24 @@ class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInf
         binding.peerFl.layoutParams = params
     }
 
-    /************************************************************/
+    /*************************语音房***********************************/
+
+    override fun lockOrUnlockSeat(imAudioModel: IMAudioModel) {
+    }
+
+    override fun openOrMuteSeatMic() {
+    }
+
+    override fun onSeatMic() {
+    }
+
+    override fun downSeatMic() {
+    }
+
+    override fun updateData(audioSeatModel: AudioSeatModel) {
+    }
+
+    override fun changeJiFen() {
+    }
 
 }

+ 6 - 1
room/src/main/java/com/swago/room/anchor/AnchorRoomFragment.kt

@@ -10,6 +10,7 @@ import com.swago.baseswago.model.live.pk.PunishPKModel
 import com.swago.baseswago.model.live.pk.StartPKModel
 import com.swago.baseswago.model.live.pk.StopPKModel
 import com.swago.baseswago.util.AppContext
+import com.swago.baseswago.util.UserInfo
 import com.swago.room.R
 import com.swago.room.base.BaseComFragment
 import com.swago.room.databinding.FragmentBaseComBinding
@@ -19,7 +20,6 @@ import com.swago.room.hongbao.RedEnvelopeDialog
 import com.swago.room.inter.IFooter
 import com.swago.room.inter.IHeader
 import com.swago.room.lianmai.AnchorLianMaiDialog
-import com.swago.room.lianmai.UserLianMaiDialog
 import com.swago.room.pk.PKAcceptDialog
 import com.swago.room.pk.PKInviteDialog
 import com.swago.room.pk.PKSearchLisDialog
@@ -38,6 +38,11 @@ class AnchorRoomFragment : BaseComFragment<FragmentBaseComBinding>() {
 
     override fun initOther() {
         super.initOther()
+        //语音列表
+        UserInfo.getUserInfo()?.let {
+            roomVm.getAudioList(it.id,1)
+        }
+
     }
 
     override fun initLiveData() {

+ 22 - 0
room/src/main/java/com/swago/room/audio/ApplyOnMicDialog.kt

@@ -0,0 +1,22 @@
+package com.swago.room.audio
+
+import android.view.Gravity
+import com.swago.baseswago.dialog.BaseXDFragment
+import com.swago.room.databinding.DialogApplyOnMicBinding
+
+class ApplyOnMicDialog : BaseXDFragment<DialogApplyOnMicBinding>()  {
+
+    init {
+        setGravity(Gravity.BOTTOM)
+        setCanCancel(true)
+        setDimAmount(0f)
+    }
+
+    override fun initOther() {
+        TODO("Not yet implemented")
+    }
+
+    override fun initLiveData() {
+        TODO("Not yet implemented")
+    }
+}

+ 114 - 0
room/src/main/java/com/swago/room/audio/AudioActionDialog.kt

@@ -0,0 +1,114 @@
+package com.swago.room.audio
+
+import android.os.Bundle
+import android.view.Gravity
+import android.view.View
+import androidx.fragment.app.activityViewModels
+import com.swago.baseswago.baseroom.RoleType
+import com.swago.baseswago.baseroom.SwagoRoomManager
+import com.swago.baseswago.dialog.BaseXDFragment
+import com.swago.baseswago.model.live.audio.AudioSeatModel
+import com.swago.baseswago.util.NoDoubleClickListener
+import com.swago.baseswago.util.UserInfo
+import com.swago.room.databinding.DialogAudioActionBinding
+import com.swago.room.vm.RoomVm
+
+class AudioActionDialog : BaseXDFragment<DialogAudioActionBinding>()  {
+
+    private val roomVm by activityViewModels<RoomVm>()
+
+    init {
+        setGravity(Gravity.BOTTOM)
+        setCanCancel(true)
+        setDimAmount(0f)
+    }
+
+    companion object{
+        fun newInstance(audioSeatModel: AudioSeatModel): AudioActionDialog {
+            val args = Bundle()
+            args.putParcelable("model",audioSeatModel)
+            val fragment = AudioActionDialog()
+            fragment.arguments = args
+            return fragment
+        }
+    }
+
+    override fun initOther() {
+        arguments?.let {
+            val audioSeatModel = it.getParcelable<AudioSeatModel>("model")
+            audioSeatModel?.let {
+                if (SwagoRoomManager.roleType == RoleType.anchor){
+                    //主播
+                    if (audioSeatModel.lock_status==2){
+                        binding.llUnlock.visibility = View.VISIBLE
+                    }else{
+                        if (audioSeatModel.user_id == "0"){
+                            binding.llLock.visibility = View.VISIBLE
+                        }
+                    }
+                    if (audioSeatModel.user_id == "0"){
+                        if (audioSeatModel.lock_status==1){
+                            binding.llYaoQingShangMic.visibility = View.VISIBLE
+                        }
+                    }else{
+                        UserInfo.getUserInfo()?.let { userInfoModel ->
+                            if (userInfoModel.id == it.user_id){
+                                binding.llDownSeatMic.visibility = View.VISIBLE
+                                if (audioSeatModel.voice_status==2){
+                                    binding.llUnMuteMic.visibility = View.VISIBLE
+                                }else{
+                                    binding.llMuteMic.visibility = View.VISIBLE
+                                }
+                            }else{
+                                binding.llDownSeatMic.visibility = View.VISIBLE
+                            }
+                        }
+                    }
+                }else{
+                    binding.llLock.visibility = View.GONE
+                    binding.llUnlock.visibility = View.GONE
+                    UserInfo.getUserInfo()?.let { userInfoModel ->
+                        if (userInfoModel.id == it.user_id){
+                            binding.llDownSeatMic.visibility = View.VISIBLE
+                            if (audioSeatModel.voice_status==2){
+                                binding.llUnMuteMic.visibility = View.VISIBLE
+                            }else{
+                                binding.llMuteMic.visibility = View.VISIBLE
+                            }
+                        }
+                    }
+                }
+                binding.llLock.setOnClickListener(object:NoDoubleClickListener(){
+                    override fun onClick() {
+                        roomVm.lockAndUnLockMic(it.maiIndex,1)
+                        dismissAllowingStateLoss()
+                    }
+                })
+                binding.llUnlock.setOnClickListener(object:NoDoubleClickListener(){
+                    override fun onClick() {
+                        roomVm.lockAndUnLockMic(it.maiIndex,2)
+                        dismissAllowingStateLoss()
+                    }
+                })
+                binding.llYaoQingShangMic.setOnClickListener(object:NoDoubleClickListener(){
+                    override fun onClick() {
+                        roomVm.inviteUserOnMic("20000018",it.maiIndex)
+                        dismissAllowingStateLoss()
+                    }
+                })
+                binding.llDownSeatMic.setOnClickListener(object:NoDoubleClickListener(){
+                    override fun onClick() {
+                        roomVm.downMicByAnchor(it.maiIndex,it.user_id?:"")
+                        dismissAllowingStateLoss()
+                    }
+                })
+
+            }
+
+
+        }
+    }
+
+    override fun initLiveData() {
+    }
+}

+ 66 - 0
room/src/main/java/com/swago/room/audio/AudioRoomManager.kt

@@ -0,0 +1,66 @@
+package com.swago.room.audio
+
+import com.swago.baseswago.model.live.audio.AudioSeatModel
+import com.swago.baseswago.model.live.audio.IMAudioModel
+
+object AudioRoomManager {
+
+    private val list = ArrayList<IAudioRoomListener>()
+
+    fun addListener(iAudioRoomListener: IAudioRoomListener){
+        list.add(iAudioRoomListener)
+    }
+
+    fun removeListener(iAudioRoomListener: IAudioRoomListener){
+        list.remove(iAudioRoomListener)
+    }
+
+    /**
+     * 锁和解锁麦位
+     */
+    fun dispatchLockOrUnlockSeat(imAudioModel: IMAudioModel){
+        list.forEach {
+            it.lockOrUnlockSeat(imAudioModel)
+        }
+    }
+
+    /**
+     * 开麦和闭麦
+     */
+    fun dispatchOpenOrMuteSeatMic(){
+        list.forEach {
+            it.openOrMuteSeatMic()
+        }
+    }
+
+    /**
+     * 上麦和下麦
+     */
+    fun dispatchOnSeatMic(){
+        list.forEach {
+            it.onSeatMic()
+        }
+    }
+
+    fun dispatchDownSeatMic(){
+        list.forEach {
+            it.downSeatMic()
+        }
+    }
+
+    /**
+     * 改变积分
+     */
+    fun dispatchChangeJiFen(){
+        list.forEach {
+            it.changeJiFen()
+        }
+    }
+
+    fun dispatchUpdateData(audioSeatModel: AudioSeatModel){
+        list.forEach {
+            it.updateData(audioSeatModel)
+        }
+    }
+
+}

+ 37 - 0
room/src/main/java/com/swago/room/audio/AudioSeatAdapter.kt

@@ -0,0 +1,37 @@
+package com.swago.room.audio
+
+import com.chad.library.adapter.base.BaseQuickAdapter
+import com.chad.library.adapter.base.BaseViewHolder
+import com.swago.baseswago.cusview.SwagoImageView
+import com.swago.baseswago.model.live.audio.AudioSeatModel
+import com.swago.room.R
+
+class AudioSeatAdapter : BaseQuickAdapter<AudioSeatModel, BaseViewHolder>(R.layout.item_audio_seat, arrayListOf()) {
+
+    override fun convert(helper: BaseViewHolder?, item: AudioSeatModel?) {
+        helper?.apply {
+            item?.let {
+                if (it.user_id == "0"){
+                    setVisible(R.id.tvIntegration,false)
+                    setText(R.id.tvName,"No.${layoutPosition+1}")
+                    if (it.lock_status==2){
+                        itemView.findViewById<SwagoImageView>(R.id.ivImageView).loadImage(R.mipmap.ic_audio_lock)
+                    }else{
+                        itemView.findViewById<SwagoImageView>(R.id.ivImageView).loadImage(R.mipmap.ic_audio_seat)
+                    }
+                }else{
+                    itemView.findViewById<SwagoImageView>(R.id.ivImageView).loadImage(it.user_head_img_url?:"")
+                    setText(R.id.tvName,it.user_name)
+
+                    setVisible(R.id.tvIntegration,true)
+                    if (it.voice_jifen.isNullOrEmpty()){
+                        setText(R.id.tvIntegration,"0")
+                    }else{
+                        setText(R.id.tvIntegration,it.voice_jifen)
+                    }
+                }
+            }
+        }
+
+    }
+}

+ 36 - 0
room/src/main/java/com/swago/room/audio/IAudioRoomListener.kt

@@ -0,0 +1,36 @@
+package com.swago.room.audio
+
+import com.swago.baseswago.model.live.audio.AudioSeatModel
+import com.swago.baseswago.model.live.audio.IMAudioModel
+
+interface IAudioRoomListener {
+
+    /**
+     * 锁麦和解锁
+     */
+    fun lockOrUnlockSeat(imAudioModel: IMAudioModel)
+
+
+    /**
+     * 闭麦和开麦
+     */
+    fun openOrMuteSeatMic()
+
+
+    /**
+     * 上麦和下麦
+     */
+    fun onSeatMic()
+    fun downSeatMic()
+
+
+    /**
+     * 数据更新
+     */
+    fun updateData(audioSeatModel: AudioSeatModel)
+
+    /**
+     * 积分变更
+     */
+    fun changeJiFen()
+}

+ 105 - 0
room/src/main/java/com/swago/room/audio/UserByAnchorInviteDialog.kt

@@ -0,0 +1,105 @@
+package com.swago.room.audio
+
+import android.Manifest
+import android.os.Bundle
+import android.view.Gravity
+import android.widget.Toast
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.lifecycleScope
+import com.alibaba.android.arouter.launcher.ARouter
+import com.permissionx.guolindev.PermissionX
+import com.swago.baseswago.constant.ARouteConstant
+import com.swago.baseswago.dialog.BaseXDFragment
+import com.swago.baseswago.model.live.audio.IMAudioModel
+import com.swago.baseswago.util.AppContext
+import com.swago.baseswago.util.NoDoubleClickListener
+import com.swago.room.R
+import com.swago.room.databinding.DialogInvitedByAnchorMicBinding
+import com.swago.room.vm.RoomVm
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+class UserByAnchorInviteDialog  : BaseXDFragment<DialogInvitedByAnchorMicBinding>()  {
+
+    private val roomVm by activityViewModels<RoomVm>()
+
+
+    init {
+        setGravity(Gravity.BOTTOM)
+        setCanCancel(true)
+        setDimAmount(0f)
+    }
+
+    companion object {
+        fun newInstance(name:String,avatar:String,maiIndex:Int,applyId:String): UserByAnchorInviteDialog {
+            val args = Bundle()
+            args.putString("name",name)
+            args.putString("avatar",avatar)
+            args.putString("applyId",applyId)
+            args.putInt("maiIndex",maiIndex)
+            val fragment = UserByAnchorInviteDialog()
+            fragment.arguments = args
+            return fragment
+        }
+    }
+
+    override fun initOther() {
+        arguments?.let {
+            val name = it.getString("name","")
+            val avatar = it.getString("avatar","")
+            val maiIndex = it.getInt("maiIndex",-1)
+            val applyId = it.getString("applyId","")
+            binding.ivAvatar.loadImage(avatar)
+            binding.tvName.text = name
+            val time = 20
+            binding.tvReject.text = AppContext.getContext().resources.getString(R.string.reject_time).format(time)
+            lifecycleScope.launch {
+                for (time in 20 downTo 0){
+                    delay(1000)
+                    if (time==0){
+                        roomVm.userAgreeAnchorInvite(applyId,2)
+                        dismissAllowingStateLoss()
+                    }else{
+                        binding.tvReject.text = AppContext.getContext().resources.getString(R.string.reject_time).format(time)
+                    }
+                }
+            }
+            binding.tvReject.setOnClickListener(object:NoDoubleClickListener(){
+                override fun onClick() {
+                    //拒绝
+                    binding.tvReject.isEnabled = false
+                    roomVm.userAgreeAnchorInvite(applyId,2)
+                    dismissAllowingStateLoss()
+                }
+            })
+
+            binding.tvAgree.setOnClickListener(object:NoDoubleClickListener(){
+                override fun onClick() {
+                    //同意
+                    activity?.let {
+                        PermissionX.init(it)
+                            .permissions(
+                                Manifest.permission.RECORD_AUDIO,
+                                Manifest.permission.CAMERA,
+                                Manifest.permission.READ_EXTERNAL_STORAGE)
+                            .request { allGranted, grantedList, deniedList ->
+                                if (allGranted) {
+                                    roomVm.userAgreeAnchorInvite(applyId,1)
+                                    dismissAllowingStateLoss()
+                                } else {
+                                    Toast.makeText(
+                                        AppContext.getContext(),
+                                        "These permissions are denied: $deniedList",
+                                        Toast.LENGTH_LONG
+                                    ).show()
+                                }
+                            }
+                    }
+                }
+            })
+        }
+    }
+
+    override fun initLiveData() {
+    }
+}

+ 186 - 30
room/src/main/java/com/swago/room/base/BaseComFragment.kt

@@ -4,10 +4,12 @@ import android.graphics.Rect
 import android.text.TextUtils
 import android.view.View
 import android.view.ViewGroup
+import android.widget.TextView
 import android.widget.Toast
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.fragment.app.activityViewModels
 import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.GridLayoutManager
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.alibaba.android.arouter.launcher.ARouter
@@ -19,24 +21,33 @@ import com.liulishuo.okdownload.core.cause.EndCause
 import com.liulishuo.okdownload.core.cause.ResumeFailedCause
 import com.swago.baseswago.PersonDataDFragment
 import com.swago.baseswago.UserVm
+import com.swago.baseswago.agora.AgoraManager
 import com.swago.baseswago.baseroom.*
 import com.swago.baseswago.constant.ARouteConstant
 import com.swago.baseswago.constant.UrlConstant
+import com.swago.baseswago.cusview.SwagoImageView
 import com.swago.baseswago.fragment.BaseXFragment
 import com.swago.baseswago.im.IRoomChat
 import com.swago.baseswago.model.im.GamePrize
 import com.swago.baseswago.model.im.RoomSystemMsgBean
 import com.swago.baseswago.model.live.RoomConfig
 import com.swago.baseswago.model.live.RoomUserModel
+import com.swago.baseswago.model.live.audio.AudioSeatModel
+import com.swago.baseswago.model.live.audio.IMAudioModel
 import com.swago.baseswago.model.live.game.GameModel
 import com.swago.baseswago.util.*
 import com.swago.room.R
 import com.swago.room.adapter.RoomChatAdapter
+import com.swago.room.audio.AudioActionDialog
+import com.swago.room.audio.AudioRoomManager
+import com.swago.room.audio.AudioSeatAdapter
+import com.swago.room.audio.IAudioRoomListener
 import com.swago.room.bean.UserRoomModel
 import com.swago.room.databinding.FragmentBaseComBinding
 import com.swago.room.dialog.AudienceListDialog
 import com.swago.room.dialog.MessageListDialog
 import com.swago.room.dialog.SendMsgDialog
+import com.swago.room.enum.RoomType
 import com.swago.room.game.GamePlayDialog
 import com.swago.room.gift.GiftDialog
 import com.swago.room.gift.GiftVm
@@ -70,8 +81,8 @@ import java.util.concurrent.CopyOnWriteArrayList
  *description:
  */
 abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
-    IRoomActiveListener,IPKListener,
-    RoomTimer.TimeTickListener {
+    IRoomActiveListener, IPKListener,
+    RoomTimer.TimeTickListener, IAudioRoomListener {
 
     val giftVm by activityViewModels<GiftVm>()
     val pkVm by activityViewModels<PkVm>()
@@ -94,13 +105,13 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
     abstract val iHeader: IHeader
     abstract val iFooter: IFooter
 
-    var roomConfig:RoomConfig? = null
+    var roomConfig: RoomConfig? = null
 
     var dialog: SendMsgDialog? = null
     var gameDialog: GamePlayDialog? = null
     var msgListDialog: MessageListDialog? = null
 
-    val gameList  by lazy {
+    val gameList by lazy {
         ArrayList<GameModel>()
     }
 
@@ -128,6 +139,7 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
         RoomTimer.timeTickList.add(this)
         PKStateManager.addPKListener(this)
         SwagoRoomManager.addListener(this)
+        AudioRoomManager.addListener(this)
         binding.headFl.addView(iHeader.getHeaderView())
         binding.footerFl.addView(iFooter.getFooterView())
         setHeaderViewPosition()
@@ -135,6 +147,8 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
         giftVm.getGiftList()
         //获取直播间配置
         roomVm.getRoomConfig()
+        //初始话语音列表
+        initAudioRvList()
         //飘条
         waftManager.init()
         waftManager.waftViewList.add(binding.waftView)
@@ -145,7 +159,7 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
         danDaoManager.giftDanDaoViewList.add(binding.danDaoView2)
         danDaoManager.giftDanDaoViewList.add(binding.danDaoView3)
         //进场特效
-        msgVm.joinRoomManager.initViewStub(binding.joinRoomViewStub,activity)
+        msgVm.joinRoomManager.initViewStub(binding.joinRoomViewStub, activity)
 
         val layoutManager = LinearLayoutManager(context)
         layoutManager.stackFromEnd = true
@@ -168,6 +182,46 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
         }
     }
 
+    private fun initAudioRvList() {
+        activity?.let {
+            binding.rvAudio.addItemDecoration(GridItemDecoration())
+            binding.rvAudio.layoutManager = GridLayoutManager(it, 4)
+            binding.rvAudio.adapter = audioSeatAdapter
+            audioSeatAdapter.setOnItemClickListener { _, _, position ->
+                val audioSeatModel = audioSeatAdapter.data[position]
+                if (audioSeatModel.user_id == "0") {
+                    //麦位没有人
+                    if (SwagoRoomManager.roleType == RoleType.anchor) {
+                        //主播点击麦位
+                        AudioActionDialog.newInstance(audioSeatModel)
+                            .show(childFragmentManager, "AudioActionDialog")
+                    } else {
+                        //用户点击了空位麦
+                        if (audioSeatModel.lock_status == 2) {
+                            Toast.makeText(AppContext.getContext(), "当前麦位已被锁", Toast.LENGTH_SHORT)
+                                .show()
+                        }
+                    }
+                } else {
+                    //麦位有人
+                    if (SwagoRoomManager.roleType == RoleType.anchor) {
+                        //主播点击麦位
+                        AudioActionDialog.newInstance(audioSeatModel)
+                            .show(childFragmentManager, "AudioActionDialog")
+                    } else {
+                        //用户点击了有人的麦位
+                        //如果点击的麦位不是自己弹资料卡  如果是自己弹操作弹窗
+                        SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
+                            audioSeatModel.user_id?.let {
+                                PersonDataDFragment.newInstance(it,false,true,iRoomInfo.getRoomId()).show(childFragmentManager,"PersonDataDFragment")
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     var listener = KeyboardUtils.OnSoftInputChangedListener {
         if (it == 0) {
             setChatRvPop(false, it)
@@ -188,14 +242,14 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
             it?.let {
                 roomUserList.clear()
                 roomUserList.addAll(it.list)
-                (iHeader as ComHeaderView).updateRoomUser(roomUserList,it.count)
+                (iHeader as ComHeaderView).updateRoomUser(roomUserList, it.count)
             }
         }
 
-        msgVm.updateUserRoom = { data,count ->
+        msgVm.updateUserRoom = { data, count ->
             roomUserList.clear()
             roomUserList.addAll(data)
-            (iHeader as ComHeaderView).updateRoomUser(roomUserList,count)
+            (iHeader as ComHeaderView).updateRoomUser(roomUserList, count)
         }
 
         chatAdapter.showUserInfoDialog = {
@@ -203,7 +257,12 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
             SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
                 isAnchor = iRoomInfo.getAnchorId() == UserInfo.getUserInfo()?.id
             }
-            PersonDataDFragment.newInstance(it.getSenderId(), isAnchor = isAnchor, inRoom = true,SwagoRoomManager.iRoomInfo?.getRoomId()?:"")
+            PersonDataDFragment.newInstance(
+                it.getSenderId(),
+                isAnchor = isAnchor,
+                inRoom = true,
+                SwagoRoomManager.iRoomInfo?.getRoomId() ?: ""
+            )
                 .apply {
                     this.openGiftDialog = { nickName, userId ->
                         openGiftDialog(nickName, userId)
@@ -211,9 +270,11 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
                     this.sendMsgInRoom = {
                         if (isForbid) {
                             Toast.makeText(
-                                AppContext.getContext(), AppContext.getContext().resources.getString(
+                                AppContext.getContext(),
+                                AppContext.getContext().resources.getString(
                                     R.string.you_are_been_forbid
-                                ), Toast.LENGTH_SHORT
+                                ),
+                                Toast.LENGTH_SHORT
                             ).show()
                         } else {
                             openSendMessageDialog("@${it} ")
@@ -233,11 +294,11 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
         //飘条
         msgVm.waftFun = {
             //如果是游戏飘条 要判断游戏列表是否有数据有则展示游戏飘条
-            if (it is GamePrize){
-                if (gameList.isNotEmpty()){
+            if (it is GamePrize) {
+                if (gameList.isNotEmpty()) {
                     waftManager.addNewMessage(it)
                 }
-            }else{
+            } else {
                 waftManager.addNewMessage(it)
             }
         }
@@ -255,16 +316,16 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
 
         (iHeader as ComHeaderView).followFun = {
             SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
-                userVm.followUser(it, 0,iRoomInfo.getBroadcastId())
+                userVm.followUser(it, 0, iRoomInfo.getBroadcastId())
             }
         }
 
         (iHeader as ComHeaderView).openAudienceListDialog = {
-            AudienceListDialog.newInstance().show(childFragmentManager,"AudienceListDialog")
+            AudienceListDialog.newInstance().show(childFragmentManager, "AudienceListDialog")
         }
 
         //游戏列表
-        roomVm.gameListModelLiveData.observe(this){
+        roomVm.gameListModelLiveData.observe(this) {
             it.game?.let { gameData ->
                 iFooter.setGameIcon(gameData.isNotEmpty())
                 gameList.addAll(gameData)
@@ -272,7 +333,7 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
         }
 
         //直播间配置
-        roomVm.roomConfigLiveData.observe(this){
+        roomVm.roomConfigLiveData.observe(this) {
             this.roomConfig = it
             //轮播图
             binding.bannerView.setData(it.banners)
@@ -283,8 +344,15 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
             }
         }
 
+        //语音房麦位列表数据
+        roomVm.audioSeatListLiveData.observe(this) {
+            if (it != null) {
+                audioSeatAdapter.setNewData(it)
+            }
+        }
+
         //红包列表
-        roomOtherVm.redEnvelopeListLiveData.observe(this){
+        roomOtherVm.redEnvelopeListLiveData.observe(this) {
             binding.ivRedEnvelopeView.addRedEnvelopList(it)
         }
 
@@ -295,16 +363,16 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
 
         //打开红包
         binding.ivRedEnvelopeView.openRedEnvelope = {
-            RedEnvelopResultDialog.newInstance(it.id,it.senderAvatar,it.senderName).apply {
+            RedEnvelopResultDialog.newInstance(it.id, it.senderAvatar, it.senderName).apply {
                 this.openGiftDialog = {
                     SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
-                        openGiftDialog( iRoomInfo.getAnchorName(), iRoomInfo.getAnchorId())
+                        openGiftDialog(iRoomInfo.getAnchorName(), iRoomInfo.getAnchorId())
                     }
                 }
                 this.addSenderMsgToRoomChatList = {
                     addChatMsgToRv(it)
                 }
-            }.show(childFragmentManager,"RedEnvelopResultDialog")
+            }.show(childFragmentManager, "RedEnvelopResultDialog")
         }
     }
 
@@ -372,10 +440,11 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
         activity?.let {
             KeyboardUtils.unregisterSoftInputChangedListener(it.window)
         }
+        AudioRoomManager.removeListener(this)
         SwagoRoomManager.removeListener(this)
     }
 
-    fun openSendMessageDialog(atName:String="") {
+    fun openSendMessageDialog(atName: String = "") {
         dialog = SendMsgDialog.newInstance(atName)
         dialog?.addSenderMsgToRoomChatList = {
             addChatMsgToRv(it)
@@ -408,6 +477,9 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
     private var isFirst = true
     override fun joinedRoom(iRoomInfo: IRoomInfo) {
         roomOtherVm.getRedEnvelopeList()
+        if (iRoomInfo.getRoomType() == RoomType.AUDIO.type) {
+            roomVm.getAudioList(iRoomInfo.getAnchorId(), 2)
+        }
         if (iRoomInfo.getRoomSystemMsg().isNotEmpty()) {
             val roomSystemMsgBean = RoomSystemMsgBean()
             roomSystemMsgBean.broadcast_notice_content = iRoomInfo.getRoomSystemMsg()
@@ -416,14 +488,14 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
         }
 
         //默认是否自动弹出游戏
-        lifecycleScope.launch(Dispatchers.Main){
+        lifecycleScope.launch(Dispatchers.Main) {
             delay(2000)
             roomConfig?.let {
-                if (gameList.isNotEmpty()&&it.auto_show_game==1){
-                    if (it.is_repeat_game==1){
+                if (gameList.isNotEmpty() && it.auto_show_game == 1) {
+                    if (it.is_repeat_game == 1) {
                         //多次弹出游戏
                         setGameDefaultData(0)
-                    }else{
+                    } else {
                         if (isFirst) {
                             //只弹出一次
                             setGameDefaultData(0)
@@ -434,7 +506,7 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
             }
         }
 
-        if (SwagoRoomManager.roleType == RoleType.user){
+        if (SwagoRoomManager.roleType == RoleType.user) {
             UserInfo.getUserInfo()?.let {
                 if (it.id.isNotEmpty()) {
                     SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
@@ -451,9 +523,9 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
         }
     }
 
-    fun setGameDefaultData(index:Int) {
+    fun setGameDefaultData(index: Int) {
         SwagoRoomManager.iRoomInfo?.let {
-            if (it is UserRoomModel && gameList.size>index) {
+            if (it is UserRoomModel && gameList.size > index) {
                 it.roomModel?.game_api_url = gameList[index].game_api_url
                 it.roomModel?.game_down_url = gameList[index].game_down_url
                 it.roomModel?.game_type = gameList[index].game_type
@@ -605,4 +677,88 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
         })
     }
 
+    private val audioSeatAdapter by lazy {
+        AudioSeatAdapter()
+    }
+
+    fun setAudioRvState(isVisible: Boolean) {
+        binding.rvAudio.visibility = if (isVisible) View.VISIBLE else View.GONE
+    }
+
+    inner class GridItemDecoration : RecyclerView.ItemDecoration() {
+        override fun getItemOffsets(
+            outRect: Rect,
+            view: View,
+            parent: RecyclerView,
+            state: RecyclerView.State
+        ) {
+            val margin = DpPxUtil.dip2px(14f)
+            val middle = DpPxUtil.dip2px(10f)
+
+            val itemPosition = parent.getChildAdapterPosition(view)
+            when (itemPosition % 4) {
+                0 -> {
+                    outRect.set(margin, 0, middle, 0)
+                }
+
+                1 -> {
+                    outRect.set(middle, 0, middle, 0)
+                }
+
+                2 -> {
+                    outRect.set(middle, 0, middle, 0)
+                }
+
+                3 -> {
+                    outRect.set(middle, 0, margin, 0)
+                }
+            }
+        }
+    }
+
+
+    /***************语音房*******************/
+    override fun lockOrUnlockSeat(imAudioModel: IMAudioModel) {
+        if (audioSeatAdapter.data.size > imAudioModel.maiIndex - 1) {
+            //会偶现空指针
+            val view = audioSeatAdapter.getViewByPosition(
+                binding.rvAudio,
+                imAudioModel.maiIndex - 1,
+                R.id.ivImageView
+            )
+            if (view != null && view is SwagoImageView) {
+                if (imAudioModel.action == 1){
+                    view.loadImage(R.mipmap.ic_audio_lock)
+                }else{
+                    view.loadImage(R.mipmap.ic_audio_seat)
+                }
+
+            }
+            if (imAudioModel.action == 1) {
+                audioSeatAdapter.data[imAudioModel.maiIndex - 1].lock_status = 2
+            } else {
+                audioSeatAdapter.data[imAudioModel.maiIndex - 1].lock_status = 1
+            }
+        }
+    }
+
+    override fun openOrMuteSeatMic() {
+    }
+
+    override fun onSeatMic() {
+
+    }
+    override fun downSeatMic() {
+
+    }
+    override fun changeJiFen() {
+
+    }
+    override fun updateData(audioSeatModel: AudioSeatModel) {
+        if (audioSeatAdapter.data.size > audioSeatModel.maiIndex - 1) {
+            audioSeatAdapter.data[audioSeatModel.maiIndex-1] = audioSeatModel
+            audioSeatAdapter.notifyItemChanged(audioSeatModel.maiIndex-1)
+        }
+    }
+
 }

+ 20 - 0
room/src/main/java/com/swago/room/bean/UserRoomModel.kt

@@ -5,6 +5,7 @@ import com.swago.baseswago.baseroom.RoleType
 import com.swago.baseswago.baseroom.SwagoRoomManager
 import com.swago.baseswago.model.MomentModel
 import com.swago.baseswago.model.live.RoomModel
+import com.swago.room.enum.RoomType
 
 /**
  *@date 2021/10/11 14:29
@@ -18,6 +19,8 @@ class UserRoomModel :  IRoomInfo{
 
     var userInRoomIsAdmin:Int = 0//用户自己是否是直播间管理员
 
+    var roomType = RoomType.VIDEO
+
     override fun getAnchorName(): String {
         return roomModel?.user_name?:""
     }
@@ -121,4 +124,21 @@ class UserRoomModel :  IRoomInfo{
     override fun getRoomAdmin(): Int {
         return userInRoomIsAdmin
     }
+
+    override fun getRoomType(): Int {
+        momentModel?.let {
+            roomType = when (it.user_broadcast_type) {
+                1 -> {
+                    RoomType.VIDEO
+                }
+                2 -> {
+                    RoomType.AUDIO
+                }
+                else -> {
+                    RoomType.NULL
+                }
+            }
+        }
+        return roomType.type
+    }
 }

+ 7 - 0
room/src/main/java/com/swago/room/enum/RoomType.kt

@@ -0,0 +1,7 @@
+package com.swago.room.enum
+
+enum class RoomType(val type: Int) {
+    VIDEO(1),
+    AUDIO(2),
+    NULL(0)
+}

+ 115 - 21
room/src/main/java/com/swago/room/user/UserRoomActivity.kt

@@ -30,6 +30,8 @@ import com.swago.baseswago.constant.ARouteConstant
 import com.swago.baseswago.databinding.ActivityAbsRoomUserBinding
 import com.swago.baseswago.dialog.ChoiceDialogFragment
 import com.swago.baseswago.model.MomentModel
+import com.swago.baseswago.model.live.audio.AudioSeatModel
+import com.swago.baseswago.model.live.audio.IMAudioModel
 import com.swago.baseswago.model.live.mic.LianMaiIMModel
 import com.swago.baseswago.model.live.pk.ProcessPKModel
 import com.swago.baseswago.model.live.pk.PunishPKModel
@@ -37,9 +39,12 @@ import com.swago.baseswago.model.live.pk.StartPKModel
 import com.swago.baseswago.model.live.pk.StopPKModel
 import com.swago.baseswago.util.*
 import com.swago.room.R
+import com.swago.room.audio.AudioRoomManager
+import com.swago.room.audio.IAudioRoomListener
 import com.swago.room.base.NoContentFragment
 import com.swago.room.bean.UserRoomModel
 import com.swago.room.data.RoomDataManager
+import com.swago.room.enum.RoomType
 import com.swago.room.lianmai.ILianMaiListener
 import com.swago.room.lianmai.LianMaiManager
 import com.swago.room.lianmai.LianMaiView
@@ -50,6 +55,7 @@ import com.swago.room.pk.PkVm
 import com.swago.room.vm.MsgVm
 import com.swago.room.vm.RoomOtherVm
 import com.swago.room.vm.RoomVm
+import com.swago.room.widget.ChoiceViewPager
 import com.swago.room.widget.UserShowAnchorCloseView
 import jp.wasabeef.glide.transformations.BlurTransformation
 import kotlinx.coroutines.Dispatchers
@@ -63,7 +69,7 @@ import java.util.concurrent.CopyOnWriteArrayList
  */
 @Route(path = ARouteConstant.Room.user)
 class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomModel>(),
-    ISwagoIRtcEngineEventHandler,IPKListener,ILianMaiListener {
+    ISwagoIRtcEngineEventHandler,IPKListener,ILianMaiListener, IAudioRoomListener {
 
     private val roomVm by viewModels<RoomVm>()
     private val msgVm by viewModels<MsgVm>()
@@ -86,6 +92,8 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
     @JvmField
     var data: ArrayList<MomentModel>? = null
 
+    //TODO  关闭直播间 RoomType判断
+
     private var userRoomFragment: UserRoomFragment? = null
 
     private var ivClose: ImageView? = null
@@ -94,18 +102,19 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
     private var flRoot: FrameLayout? = null
     private var peerFl: FrameLayout? = null
     private var lianMaiView: LianMaiView? = null
+    private var choiceViewPager:ChoiceViewPager? = null
 
     override val roomCoverView: ViewGroup by lazy {
         val userRoomView = layoutInflater.inflate(R.layout.layout_user_room, null) as ViewGroup
-        val viewPager = userRoomView.findViewById<ViewPager>(R.id.viewPager)
+        choiceViewPager = userRoomView.findViewById<ChoiceViewPager>(R.id.viewPager)
         lianMaiView = userRoomView.findViewById(R.id.lianMaiView)
         ivClose = userRoomView.findViewById(R.id.ivClose)
         userShowAnchorCloseView = userRoomView.findViewById(R.id.userShowAnchorCloseView)
         ivCover = userRoomView.findViewById(R.id.ivCover)
         flRoot = userRoomView.findViewById(R.id.flRoot)
         peerFl = userRoomView.findViewById(R.id.peerFl)
-        viewPager.adapter = SwagoAdapter(fragments, supportFragmentManager)
-        viewPager.currentItem = 1
+        choiceViewPager?.adapter = SwagoAdapter(fragments, supportFragmentManager)
+        choiceViewPager?.currentItem = 1
         userRoomView
     }
 
@@ -118,6 +127,7 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
         PKStateManager.resetData()
         PKStateManager.addPKListener(this)
         LianMaiManager.addLianMaiListener(this)
+        AudioRoomManager.addListener(this)
         AgoraManager.initializeEngine(this, this)
         mCurrentPosition = position
         RoomDataManager.initData(data)
@@ -216,6 +226,30 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
         }
         ivCover?.visibility = View.VISIBLE
         userShowAnchorCloseView?.visibility = View.INVISIBLE
+
+        when(iRoomInfo.getRoomType()){
+            RoomType.VIDEO.type -> {
+                choiceViewPager?.setCanScroll(true)
+                AgoraManager.setVideoAudio(
+                    pullVideo = true,
+                    pullAudio = true,
+                    pushVideo = false,
+                    pushAudio = false
+                )
+            }
+
+            RoomType.AUDIO.type -> {
+                choiceViewPager?.setCanScroll(false)
+                AgoraManager.setVideoAudio(
+                    pullVideo = false,
+                    pullAudio = true,
+                    pushVideo = false,
+                    pushAudio = false
+                )
+            }
+
+            RoomType.NULL.type -> {}
+        }
     }
 
     override fun leaveRoom(iRoomInfo: IRoomInfo) {
@@ -237,27 +271,56 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
             pkVm.getPKInfo(iRoomInfo.getRoomId())
             lianMaiVm.getRoomLianMaiInfo()
         }
-        UserInfo.getUserInfo()?.let { userInfoModel ->
-            lifecycleScope.launch(Dispatchers.Main) {
-                AgoraManager.joinChannel(
-                    iRoomInfo.getChannelName(),
-                    userInfoModel.id.toInt(),
-                    iRoomInfo.getAgoraToken()
-                )
-                if (!isRobot) {
-                    flRoot?.let {
-                        //这里加个延迟是因为第一次进入直播间的时候布局未完全加载成功导致部分布局无法显示
-                        if (isFirstJoinRoom){
-                            isFirstJoinRoom = false
-                            delay(2000)
+        when (iRoomInfo.getRoomType()){
+            RoomType.VIDEO.type -> {
+                UserInfo.getUserInfo()?.let { userInfoModel ->
+                    lifecycleScope.launch(Dispatchers.Main) {
+                        AgoraManager.joinChannel(
+                            iRoomInfo.getChannelName(),
+                            userInfoModel.id.toInt(),
+                            iRoomInfo.getAgoraToken()
+                        )
+                        if (!isRobot) {
+                            flRoot?.let {
+                                //这里加个延迟是因为第一次进入直播间的时候布局未完全加载成功导致部分布局无法显示
+                                if (isFirstJoinRoom){
+                                    isFirstJoinRoom = false
+                                    delay(2000)
+                                }
+                                AgoraManager.setupRemoteVideo(
+                                    this@UserRoomActivity,
+                                    iRoomInfo.getAnchorId().toInt(), it
+                                )
+                            }
                         }
-                        AgoraManager.setupRemoteVideo(
-                            this@UserRoomActivity,
-                            iRoomInfo.getAnchorId().toInt(), it
+                    }
+                }
+            }
+            RoomType.AUDIO.type -> {
+                UserInfo.getUserInfo()?.let { userInfoModel ->
+                    lifecycleScope.launch(Dispatchers.Main) {
+                        AgoraManager.joinChannel(
+                            iRoomInfo.getChannelName(),
+                            userInfoModel.id.toInt(),
+                            iRoomInfo.getAgoraToken()
                         )
                     }
                 }
             }
+            RoomType.NULL.type -> {}
+        }
+    }
+
+    override fun receiveStopLive() {
+        SwagoRoomManager.iRoomInfo?.let {
+            if (it.getRoomType() == RoomType.AUDIO.type){
+                AgoraManager.setVideoAudio(
+                    pullVideo = false,
+                    pullAudio = false,
+                    pushVideo = false,
+                    pushAudio = false
+                )
+            }
         }
     }
 
@@ -274,6 +337,7 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
     }
 
     override fun onDestroy() {
+        AudioRoomManager.removeListener(this)
         LianMaiManager.removeLianMaiListener(this)
         PKStateManager.removePKListener(this)
         super.onDestroy()
@@ -292,7 +356,14 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
 
     override fun onChannelMediaRelayStateChanged(state: Int, code: Int) {}
     override fun onFirstLocalAudioFramePublished(elapsed: Int) {
-        lianMaiVm.lianMaiCallback()
+        SwagoRoomManager.iRoomInfo?.let {
+            if (it.getRoomType() == RoomType.VIDEO.type){
+                lianMaiVm.lianMaiCallback()
+            }else if(it.getRoomType() == RoomType.AUDIO.type){
+                //TODO
+            }
+        }
+
     }
 
     override fun onError(err: Int) {
@@ -392,5 +463,28 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
         }
     }
 
+    override fun lockOrUnlockSeat(imAudioModel: IMAudioModel) {
+    }
+
+    override fun openOrMuteSeatMic() {
+    }
+
+    override fun onSeatMic() {
+        AgoraManager.setVideoAudio(pullVideo = false, pullAudio = true, pushVideo = false, pushAudio = true)
+        setCanVerticalScroll(false)
+    }
+
+    override fun downSeatMic() {
+        AgoraManager.setVideoAudio(pullVideo = false, pullAudio = true, pushVideo = false, pushAudio = false)
+        setCanVerticalScroll(true)
+    }
+
+    override fun updateData(audioSeatModel: AudioSeatModel) {
+
+    }
+
+    override fun changeJiFen() {
+    }
+
 
 }

+ 12 - 0
room/src/main/java/com/swago/room/user/UserRoomFragment.kt

@@ -4,13 +4,16 @@ import android.view.View
 import android.widget.Toast
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.lifecycleScope
 import com.swago.baseswago.PersonDataDFragment
+import com.swago.baseswago.agora.AgoraManager
 import com.swago.baseswago.baseroom.IRoomInfo
 import com.swago.baseswago.baseroom.SwagoRoomManager
 import com.swago.baseswago.dialog.BenefitBagDialog
 import com.swago.baseswago.dialog.ReportDialog
 import com.swago.baseswago.model.UserInfoModel
 import com.swago.baseswago.model.im.UserJoinRoomBean
+import com.swago.baseswago.model.live.audio.AudioSeatModel
 import com.swago.baseswago.model.live.pk.ProcessPKModel
 import com.swago.baseswago.model.live.pk.PunishPKModel
 import com.swago.baseswago.model.live.pk.StartPKModel
@@ -19,10 +22,12 @@ import com.swago.baseswago.util.AppContext
 import com.swago.baseswago.util.NoDoubleClickListener
 import com.swago.baseswago.util.UserInfo
 import com.swago.room.R
+import com.swago.room.audio.UserByAnchorInviteDialog
 import com.swago.room.base.BaseComFragment
 import com.swago.room.bean.UserRoomModel
 import com.swago.room.databinding.FragmentBaseComBinding
 import com.swago.room.dialog.ShareDialog
+import com.swago.room.enum.RoomType
 import com.swago.room.game.GameListDialog
 import com.swago.room.gift.GiftDialog
 import com.swago.room.hongbao.RedEnvelopBroadcastDialog
@@ -33,6 +38,9 @@ import com.swago.room.lianmai.UserLianMaiDialog
 import com.swago.room.vm.RoomOtherVm
 import com.swago.room.widget.ComHeaderView
 import com.swago.room.widget.UserFooterView
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
 
 /**
  *@date 2021/10/11 14:24
@@ -170,6 +178,10 @@ class UserRoomFragment : BaseComFragment<FragmentBaseComBinding>() {
             }
         }
 
+        msgVm.openInviteByAnchorFun = {
+            UserByAnchorInviteDialog.newInstance(it.inviteName,it.inviteAvatar,it.maiIndex,it.applyId).show(childFragmentManager,"UserByAnchorInviteDialog")
+        }
+
 
         (iHeader as ComHeaderView).showUserInfo = {
             PersonDataDFragment.newInstance(it, isAnchor = false, inRoom = true,SwagoRoomManager.iRoomInfo?.getRoomId()?:"")

+ 129 - 11
room/src/main/java/com/swago/room/vm/MsgVm.kt

@@ -1,6 +1,7 @@
 package com.swago.room.vm
 
 import android.app.Application
+import android.widget.Toast
 import com.swago.baseswago.baseroom.IRoomInfo
 import com.swago.baseswago.baseroom.RoleType
 import com.swago.baseswago.baseroom.SwagoRoomManager
@@ -13,6 +14,8 @@ import com.swago.baseswago.im.ImConstant.follow_anchor_success
 import com.swago.baseswago.im.ImConstant.forbid_speak
 import com.swago.baseswago.im.ImConstant.force_close_live_room
 import com.swago.baseswago.im.ImConstant.game_win_big_prize
+import com.swago.baseswago.im.ImConstant.invite_user_on_mic
+import com.swago.baseswago.im.ImConstant.lock_un_lock_mic
 import com.swago.baseswago.im.ImConstant.lucky_gift
 import com.swago.baseswago.im.ImConstant.lucky_gift_prize
 import com.swago.baseswago.im.ImConstant.red_envelope
@@ -22,8 +25,12 @@ import com.swago.baseswago.im.ImConstant.room_chat_text
 import com.swago.baseswago.im.ImConstant.set_room_admin
 import com.swago.baseswago.im.ImConstant.svg_gift
 import com.swago.baseswago.im.ImConstant.update_audience
+import com.swago.baseswago.im.ImConstant.update_mic_list_data
+import com.swago.baseswago.im.ImConstant.user_agree_invite_by_anchor
+import com.swago.baseswago.im.ImConstant.user_down_mic
 import com.swago.baseswago.im.ImConstant.user_exit_room
 import com.swago.baseswago.im.ImConstant.user_join_room
+import com.swago.baseswago.im.ImConstant.user_refuse_invite_by_anchor
 import com.swago.baseswago.model.RedEnvelope
 import com.swago.baseswago.model.im.*
 import com.swago.baseswago.model.live.ForceCloseModel
@@ -31,8 +38,14 @@ import com.swago.baseswago.model.live.ReceiveModel
 import com.swago.baseswago.model.im.GamePrize
 import com.swago.baseswago.model.live.RoomUserChangeModel
 import com.swago.baseswago.model.live.RoomUserModel
+import com.swago.baseswago.model.live.audio.AudioSeatModel
+import com.swago.baseswago.model.live.audio.IMAudioModel
+import com.swago.baseswago.model.live.audio.IMAudioSeatUpdateModel
 import com.swago.baseswago.model.live.gift.IMGiftModel
+import com.swago.baseswago.util.AppContext
 import com.swago.baseswago.util.UserInfo
+import com.swago.room.audio.AudioRoomManager
+import com.swago.room.audio.IAudioRoomListener
 import com.swago.room.manager.JoinRoomManager
 
 /**
@@ -83,6 +96,11 @@ class MsgVm(application: Application) : AbsMsgVm(application) {
      */
     var showGiftDanDao: ((data: IMGiftModel) -> Unit)? = null
 
+    /**
+     * 被邀请的用户展示被邀请弹窗
+     */
+    var openInviteByAnchorFun: ((imAudioModel: IMAudioModel) -> Unit)? = null
+
     val joinRoomManager by lazy {
         JoinRoomManager()
     }
@@ -280,7 +298,7 @@ class MsgVm(application: Application) : AbsMsgVm(application) {
                 UserInfo.getUserInfo()?.let { userInfo ->
                     it.data?.let {
                         if (it.roomId == iRoomInfo.getRoomId()) {
-                            if ( it.receiverId == userInfo.id){
+                            if (it.receiverId == userInfo.id) {
                                 setOrDeleteRoomAdmin?.invoke(1)
                             }
                             newChatMsgFun?.invoke(it)
@@ -302,25 +320,125 @@ class MsgVm(application: Application) : AbsMsgVm(application) {
             }
         }
 
+        imGroupNewMsgListener.handleMsgType<CusNewMsgBean<IMAudioModel>>(lock_un_lock_mic) {
+            SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
+                it.data?.let {
+                    if (it.roomId == iRoomInfo.getRoomId() && it.roomSessionId == iRoomInfo.getBroadcastId()) {
+                        AudioRoomManager.dispatchLockOrUnlockSeat(it)
+                    }
+                }
+            }
+        }
 
-    }
+        //邀请用户上麦
+        imGroupNewMsgListener.handleMsgType<CusNewMsgBean<IMAudioModel>>(invite_user_on_mic) {
+            SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
+                it.data?.let {
+                    if (it.roomId == iRoomInfo.getRoomId() && it.roomSessionId == iRoomInfo.getBroadcastId()) {
+                        UserInfo.getUserInfo()?.let { userInfoModel ->
+                            if (userInfoModel.id == it.receiverId) {
+                                //被邀请的用户弹窗
+                                openInviteByAnchorFun?.invoke(it)
+                            }
+                        }
+                    }
+                }
+            }
+        }
 
-    override fun changeRoom(iRoomInfo: IRoomInfo) {
 
-    }
+        //用户同意主播邀请
+        imGroupNewMsgListener.handleMsgType<CusNewMsgBean<IMAudioModel>>(user_agree_invite_by_anchor) {
+            SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
+                it.data?.let {
+                    if (it.roomId == iRoomInfo.getRoomId() && it.roomSessionId == iRoomInfo.getBroadcastId()) {
+                        UserInfo.getUserInfo()?.let { userInfoModel ->
+                            if (userInfoModel.id == it.receiverId) {
+                                Toast.makeText(
+                                    AppContext.getContext(),
+                                    "用户同意了您的邀请",
+                                    Toast.LENGTH_SHORT
+                                ).show()
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        //用户拒绝主播邀请
+        imGroupNewMsgListener.handleMsgType<CusNewMsgBean<IMAudioModel>>(
+            user_refuse_invite_by_anchor
+        ) {
+            SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
+                it.data?.let {
+                    if (it.roomId == iRoomInfo.getRoomId() && it.roomSessionId == iRoomInfo.getBroadcastId()) {
+                        UserInfo.getUserInfo()?.let { userInfoModel ->
+                            if (userInfoModel.id == it.receiverId) {
+                                //被邀请的用户弹窗
+                                Toast.makeText(
+                                    AppContext.getContext(),
+                                    "用户拒绝了您的邀请",
+                                    Toast.LENGTH_SHORT
+                                ).show()
+                            }
+                        }
+                    }
+                }
+            }
+        }
 
-    override fun leaveRoom(iRoomInfo: IRoomInfo) {
+        //麦位数据更新
+        imGroupNewMsgListener.handleMsgType<CusNewMsgBean<IMAudioSeatUpdateModel>>(
+            update_mic_list_data
+        ) {
+            SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
+                it.data?.let {
+                    if (it.roomId == iRoomInfo.getRoomId() && it.roomSessionId == iRoomInfo.getBroadcastId()) {
+                        //列表有数据更新
+                        val audioSeatModel = AudioSeatModel(it.maiSeatInfo.userName,it.maiSeatInfo.userAvatar,it.maiSeatInfo.userId,it.maiSeatInfo.maiStatus,it.maiSeatInfo.lock,it.maiSeatInfo.integration,it.maiSeatInfo.maiIndex)
+                        AudioRoomManager.dispatchUpdateData(audioSeatModel)
+                    }
+                }
+            }
+        }
 
-    }
+        //用户被主播下麦
+        imGroupNewMsgListener.handleMsgType<CusNewMsgBean<IMAudioModel>>(
+            user_down_mic
+        ) {
+            SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
+                it.data?.let {
+                    if (it.roomId == iRoomInfo.getRoomId() && it.roomSessionId == iRoomInfo.getBroadcastId()) {
+                        UserInfo.getUserInfo()?.let { userInfoModel ->
+                            if (userInfoModel.id == it.receiverId) {
+                                AudioRoomManager.dispatchDownSeatMic()
+                            }
+                        }
+                    }
+                }
+            }
+        }
 
-    override fun joinedRoom(iRoomInfo: IRoomInfo) {
     }
 
-    override fun endRoom(iRoomInfo: IRoomInfo?) {
 
-    }
+override fun changeRoom(iRoomInfo: IRoomInfo) {
 
-    override fun closeRoomed() {
+}
 
-    }
+override fun leaveRoom(iRoomInfo: IRoomInfo) {
+
+}
+
+override fun joinedRoom(iRoomInfo: IRoomInfo) {
+}
+
+override fun endRoom(iRoomInfo: IRoomInfo?) {
+
+}
+
+override fun closeRoomed() {
+
+}
 }

+ 83 - 1
room/src/main/java/com/swago/room/vm/RoomVm.kt

@@ -13,8 +13,11 @@ import com.swago.baseswago.model.MomentModel
 import com.swago.baseswago.model.RedEnvelope
 import com.swago.baseswago.model.im.AnchorRoomClosedBean
 import com.swago.baseswago.model.live.*
+import com.swago.baseswago.model.live.audio.AudioSeatModel
 import com.swago.baseswago.model.live.game.GameListModel
 import com.swago.baseswago.util.*
+import com.swago.room.R
+import com.swago.room.audio.AudioRoomManager
 import com.swago.room.bean.UserRoomModel
 import com.swago.room.user.UserRoomActivity
 
@@ -102,7 +105,7 @@ class RoomVm(application: Application) : AbsRoomVm(application) {
             requestData {
                 SwagoLoading.showLoadingDialog(ActivityManagerUtil.get().currentActivity())
                 val roomInfo = iRoomInfo as UserRoomModel
-                val roomModel = ApiManager.roomApi.startLive()
+                val roomModel = ApiManager.roomApi.startLive(roomInfo.roomType.type)
                 roomInfo.roomModel = roomModel
                 callback.invoke(true)
                 SwagoLoading.cancelLoadingDialog()
@@ -278,4 +281,83 @@ class RoomVm(application: Application) : AbsRoomVm(application) {
         }
     }
 
+
+
+    /*********************************************语音房接口***********************************************/
+
+
+    /**
+     * 语音房列表
+     */
+    val audioSeatListLiveData by lazy {
+        MutableLiveData<List<AudioSeatModel>?>()
+    }
+    fun getAudioList(userId: String,type:Int) {
+        requestData2(false) {
+            requestData {
+                val data = ApiManager.roomApi.getAudioList(userId,type)
+                audioSeatListLiveData.value = data.list
+            }
+
+            requestError {
+                audioSeatListLiveData.value = null
+            }
+        }
+    }
+
+    /**
+     * 锁麦和解锁
+     */
+    fun lockAndUnLockMic(position_id:Int,type:Int){
+        requestData {
+            SwagoRoomManager.iRoomInfo?.let {
+                ApiManager.roomApi.lockAndUnLockMic(it.getRoomId(),it.getBroadcastId(),position_id,type)
+                if (type==1){
+                    Toast.makeText(AppContext.getContext(), AppContext.getContext().resources.getString(
+                        R.string.lock_success), Toast.LENGTH_SHORT).show()
+                }else if(type==2){
+                    Toast.makeText(AppContext.getContext(), AppContext.getContext().resources.getString(
+                        R.string.unlock_success), Toast.LENGTH_SHORT).show()
+                }
+            }
+        }
+    }
+
+    /**
+     * 邀请用户上麦
+     */
+    fun inviteUserOnMic(userId:String,maiIndex:Int){
+        requestData {
+            SwagoRoomManager.iRoomInfo?.let {
+                ApiManager.roomApi.inviteOnMic(it.getRoomId(),it.getBroadcastId(),maiIndex,userId)
+            }
+        }
+    }
+
+    /**
+     * 用户同意上麦和拒绝上麦
+     */
+    fun userAgreeAnchorInvite(applyId:String,type:Int){
+        requestData {
+            SwagoRoomManager.iRoomInfo?.let {
+                ApiManager.roomApi.userAgreeAnchorInvite(it.getRoomId(),it.getBroadcastId(),applyId,type)
+                if (type==1){
+                    AudioRoomManager.dispatchOnSeatMic()
+                }
+            }
+        }
+    }
+
+    /**
+     * 主播对用户下麦
+     */
+    fun downMicByAnchor(maiIndex: Int,usrId:String){
+        requestData {
+            SwagoRoomManager.iRoomInfo?.let {
+                ApiManager.roomApi.downMicByAnchor(it.getRoomId(),it.getBroadcastId(),maiIndex,usrId)
+                Toast.makeText(AppContext.getContext(), AppContext.getContext().resources.getString(R.string.down_mic_success), Toast.LENGTH_SHORT).show()
+            }
+        }
+    }
+
 }

+ 6 - 0
room/src/main/java/com/swago/room/widget/AnchorFooterView.kt

@@ -15,6 +15,7 @@ import com.swago.baseswago.util.NoDoubleClickListener
 import com.swago.baseswago.util.UserInfo
 import com.swago.room.R
 import com.swago.room.databinding.LayoutAnchorFooterViewBinding
+import com.swago.room.enum.RoomType
 import com.swago.room.inter.IFooter
 import com.swago.room.lianmai.LianMaiManager
 import com.swago.room.pk.PKStateManager
@@ -133,6 +134,11 @@ class AnchorFooterView : ConstraintLayout, IFooter, IRoomActiveListener {
     }
 
     override fun joinedRoom(iRoomInfo: IRoomInfo) {
+        if (iRoomInfo.getRoomType() == RoomType.AUDIO.type){
+            binding.ivSwitchCamera.visibility = View.GONE
+            binding.ivPK.visibility = View.GONE
+            binding.ivLianMai.visibility = View.GONE
+        }
         visibility = View.VISIBLE
     }
 

+ 31 - 0
room/src/main/java/com/swago/room/widget/ChoiceViewPager.kt

@@ -0,0 +1,31 @@
+package com.swago.room.widget
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.MotionEvent
+import com.duolingo.open.rtlviewpager.RtlViewPager
+
+
+/**
+ * 可设置是否左右滚动
+ */
+class ChoiceViewPager : RtlViewPager {
+
+    constructor(context: Context) : super(context)
+    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+    private var isCanScroll = false
+
+    fun setCanScroll(isCanScroll:Boolean){
+        this.isCanScroll = isCanScroll
+    }
+
+    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
+        return isCanScroll && super.onInterceptTouchEvent(ev)
+    }
+
+    override fun onTouchEvent(ev: MotionEvent?): Boolean {
+        return isCanScroll && super.onTouchEvent(ev)
+    }
+
+}

+ 59 - 1
room/src/main/res/layout/activity_anchor_room.xml

@@ -94,10 +94,68 @@
             app:layout_constraintEnd_toEndOf="parent"
             android:layout_marginStart="20dp"
             android:layout_marginEnd="20dp"
-            android:layout_marginBottom="20dp"
+            android:layout_marginBottom="73dp"
             android:layout_width="match_parent"
             android:layout_height="44dp"/>
 
+
+        <LinearLayout
+            android:id="@+id/llVideo"
+            android:orientation="vertical"
+            app:layout_constraintBottom_toBottomOf="parent"
+            android:layout_marginBottom="20dp"
+            app:layout_constraintHorizontal_chainStyle="packed"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/llAudio"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+
+            <com.swago.baseswago.cusview.BoldTextView
+                android:id="@+id/tvVideo"
+                android:textSize="16dp"
+                android:textColor="#fff"
+                android:text="Live"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+            <View
+                android:id="@+id/viewVideo"
+                android:layout_marginTop="3dp"
+                android:layout_gravity="center"
+                android:background="@drawable/shape_white_5"
+                android:layout_width="10dp"
+                android:layout_height="2dp"/>
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/llAudio"
+            android:orientation="vertical"
+            android:layout_marginStart="40dp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            android:layout_marginBottom="20dp"
+            app:layout_constraintStart_toEndOf="@+id/llVideo"
+            app:layout_constraintEnd_toEndOf="parent"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+
+            <com.swago.baseswago.cusview.BoldTextView
+                android:id="@+id/tvAudio"
+                android:textSize="16dp"
+                android:textColor="@color/_d4ffffff"
+                android:text="Audio"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+            <View
+                android:id="@+id/viewAudio"
+                android:layout_marginTop="3dp"
+                android:layout_gravity="center"
+                android:visibility="invisible"
+                android:background="@drawable/shape_white_5"
+                android:layout_width="10dp"
+                android:layout_height="2dp"/>
+
+        </LinearLayout>
+
     </androidx.constraintlayout.widget.ConstraintLayout>
 
 

+ 59 - 0
room/src/main/res/layout/dialog_apply_on_mic.xml

@@ -0,0 +1,59 @@
+<?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:background="@drawable/shape_161722_top_20"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <ImageView
+        android:id="@+id/iv"
+        android:layout_marginTop="24dp"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        android:src="@mipmap/ic_apply_on_mic"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <com.swago.baseswago.cusview.BoldTextView
+        android:textSize="20dp"
+        android:textColor="#fff"
+        android:id="@+id/tv"
+        android:layout_marginTop="16dp"
+        android:text="@string/apply_to_connect_a_mic"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/iv"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+
+    <com.swago.baseswago.cusview.MediumTextView
+        android:textSize="14dp"
+        android:textColor="#fff"
+        android:id="@+id/tv2"
+        android:layout_marginTop="16dp"
+        android:text="主播同意后可自动上麦"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <com.swago.baseswago.cusview.BoldTextView
+        android:id="@+id/tvApply"
+        android:text="Apply"
+        android:textSize="16dp"
+        android:gravity="center"
+        android:textColor="#fff"
+        app:layout_constraintTop_toBottomOf="@+id/tv2"
+        android:layout_marginTop="24dp"
+        android:layout_marginStart="16dp"
+        android:layout_marginEnd="16dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        android:layout_marginBottom="24dp"
+        android:background="@drawable/shape_ff56b7_37"
+        android:layout_width="match_parent"
+        android:layout_height="48dp"/>
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 185 - 0
room/src/main/res/layout/dialog_audio_action.xml

@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:background="@drawable/shape_161722_top_20"
+    android:layout_height="120dp">
+
+    <LinearLayout
+        android:id="@+id/llYaoQingShangMic"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/llDownSeatMic"
+        android:visibility="gone"
+        tools:visibility="visible"
+        android:orientation="vertical"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <ImageView
+            android:id="@+id/ivYaoQingShangMic"
+            android:padding="10dp"
+            android:src="@mipmap/ic_yao_qiing_shangmai"
+            android:layout_width="50dp"
+            android:layout_height="50dp"/>
+        <TextView
+            android:id="@+id/tvYaoQingShangMic"
+            android:textColor="#fff"
+            android:textSize="12dp"
+            android:text="上麦"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/llDownSeatMic"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/llYaoQingShangMic"
+        app:layout_constraintEnd_toStartOf="@+id/llLock"
+        android:orientation="vertical"
+        android:visibility="gone"
+        tools:visibility="visible"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <ImageView
+            android:id="@+id/ivDownSeatMic"
+            android:padding="10dp"
+            android:src="@mipmap/ic_down_seat"
+            android:layout_width="50dp"
+            android:layout_height="50dp"/>
+        <TextView
+            android:id="@+id/tvDownSeatMic"
+            android:textColor="#fff"
+            android:textSize="12dp"
+            android:text="下麦"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/llLock"
+        app:layout_constraintStart_toEndOf="@+id/llDownSeatMic"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/llUnlock"
+        android:orientation="vertical"
+        android:visibility="gone"
+        tools:visibility="visible"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <ImageView
+            android:id="@+id/ivLock"
+            android:padding="10dp"
+            android:src="@mipmap/ic_lock"
+            android:layout_width="50dp"
+            android:layout_height="50dp"/>
+        <TextView
+            android:id="@+id/tvLock"
+            android:textColor="#fff"
+            android:textSize="12dp"
+            android:text="Lock"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/llUnlock"
+        app:layout_constraintStart_toEndOf="@+id/llLock"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/llMuteMic"
+        android:orientation="vertical"
+        android:visibility="gone"
+        tools:visibility="visible"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <ImageView
+            android:id="@+id/ivUnlock"
+            android:padding="10dp"
+            android:src="@mipmap/ic_unlock"
+            android:layout_width="50dp"
+            android:layout_height="50dp"/>
+        <TextView
+            android:id="@+id/tvUnlock"
+            android:textColor="#fff"
+            android:textSize="12dp"
+            android:text="Unlock"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+
+    <LinearLayout
+        android:id="@+id/llMuteMic"
+        app:layout_constraintStart_toEndOf="@+id/llUnlock"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/llUnMuteMic"
+        android:orientation="vertical"
+        android:visibility="gone"
+        tools:visibility="visible"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <ImageView
+            android:id="@+id/ivMuteMic"
+            android:padding="10dp"
+            android:src="@mipmap/live_mute"
+            android:layout_width="50dp"
+            android:layout_height="50dp"/>
+        <TextView
+            android:id="@+id/tvMuteMic"
+            android:textColor="#fff"
+            android:textSize="12dp"
+            android:text="闭麦"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/llUnMuteMic"
+        app:layout_constraintStart_toEndOf="@+id/llMuteMic"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:orientation="vertical"
+        android:visibility="gone"
+        tools:visibility="visible"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <ImageView
+            android:id="@+id/ivUnMuteMic"
+            android:padding="10dp"
+            android:src="@mipmap/live_unmute"
+            android:layout_width="50dp"
+            android:layout_height="50dp"/>
+        <TextView
+            android:id="@+id/tvUnMuteMic"
+            android:textColor="#fff"
+            android:textSize="12dp"
+            android:text="开麦"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 89 - 0
room/src/main/res/layout/dialog_invited_by_anchor_mic.xml

@@ -0,0 +1,89 @@
+<?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="wrap_content"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <com.swago.baseswago.cusview.SwagoImageView
+        android:id="@+id/ivAvatar"
+        android:layout_width="72dp"
+        android:layout_height="72dp"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="36dp"
+        android:background="@drawable/shape_161722_top_20"
+        app:layout_constraintTop_toTopOf="parent">
+
+        <com.swago.baseswago.cusview.MediumTextView
+            android:id="@+id/tvReject"
+            android:layout_marginTop="16dp"
+            android:layout_marginEnd="16dp"
+            tools:text="Reject(10s)"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            android:textColor="@color/_d4ffffff"
+            android:textSize="12dp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+        <com.swago.baseswago.cusview.BoldTextView
+            android:id="@+id/tvName"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="50dp"
+            tools:text="Swago"
+            android:textColor="#fff"
+            android:textSize="16dp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+
+        <com.swago.baseswago.cusview.MediumTextView
+            android:id="@+id/tv2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="16dp"
+            android:text="@string/invited_on_mic"
+            android:textColor="#fff"
+            android:textSize="14dp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/tvName" />
+
+
+        <FrameLayout
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/tv2"
+            android:layout_width="match_parent"
+            android:layout_height="48dp"
+            android:background="@drawable/shape_ff56b7_37"
+            android:layout_marginStart="16dp"
+            android:layout_marginTop="24dp"
+            android:layout_marginEnd="16dp"
+            android:layout_marginBottom="24dp">
+
+            <com.swago.baseswago.cusview.BoldTextView
+                android:id="@+id/tvAgree"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:drawableStart="@mipmap/live_unmute"
+                android:gravity="center"
+                android:drawablePadding="5dp"
+                android:layout_gravity="center"
+                android:text="@string/accept"
+                android:textColor="#fff"
+                android:textSize="16dp" />
+
+        </FrameLayout>
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 9 - 0
room/src/main/res/layout/fragment_base_com.xml

@@ -20,6 +20,15 @@
         android:layout_marginBottom="10dp"
         app:layout_constraintBottom_toBottomOf="parent" />
 
+
+    <androidx.recyclerview.widget.RecyclerView
+        app:layout_constraintTop_toTopOf="parent"
+        android:layout_marginTop="120dp"
+        android:id="@+id/rvAudio"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+
+
     <com.swago.room.pk.PKLayoutView
         android:id="@+id/pkLayoutView"
         android:layout_marginTop="14dp"

+ 61 - 0
room/src/main/res/layout/item_audio_seat.xml

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="68dp"
+    android:layout_height="wrap_content"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:background="#000"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <com.swago.baseswago.cusview.SwagoImageView
+        android:id="@+id/ivImageView"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        android:layout_width="68dp"
+        android:layout_height="68dp"/>
+
+    <ImageView
+        android:id="@+id/ivAudioState"
+        app:layout_constraintEnd_toEndOf="@+id/ivImageView"
+        app:layout_constraintBottom_toBottomOf="@+id/ivImageView"
+        android:src="@mipmap/live_mute"
+        android:visibility="invisible"
+        tools:visibility="visible"
+        android:layout_width="10dp"
+        android:layout_height="wrap_content"/>
+
+    <com.swago.baseswago.cusview.MediumTextView
+        android:id="@+id/tvName"
+        android:textSize="12dp"
+        android:textColor="#fff"
+        android:maxLines="1"
+        android:maxWidth="68dp"
+        tools:text="Swago"
+        android:ellipsize="end"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/ivImageView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <com.swago.baseswago.cusview.MediumTextView
+        android:id="@+id/tvIntegration"
+        android:textColor="#fff"
+        android:maxLines="1"
+        android:maxWidth="68dp"
+        tools:text="100"
+        android:textSize="10dp"
+        android:layout_marginTop="2dp"
+        android:drawablePadding="2dp"
+        android:visibility="invisible"
+        tools:visibility="visible"
+        android:drawableStart="@mipmap/ic_audio_integration"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tvName"
+        app:layout_constraintBottom_toBottomOf="parent"
+        android:layout_marginBottom="8dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 1 - 1
room/src/main/res/layout/layout_user_room.xml

@@ -22,7 +22,7 @@
     </FrameLayout>
 
 
-    <com.duolingo.open.rtlviewpager.RtlViewPager
+    <com.swago.room.widget.ChoiceViewPager
         android:id="@+id/viewPager"
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>

BIN
room/src/main/res/mipmap-xxhdpi/ic_apply_on_mic.webp


BIN
room/src/main/res/mipmap-xxhdpi/ic_down_seat.png


BIN
room/src/main/res/mipmap-xxhdpi/ic_lock.png


BIN
room/src/main/res/mipmap-xxhdpi/ic_unlock.png


BIN
room/src/main/res/mipmap-xxhdpi/ic_yao_qiing_shangmai.png