honghengqiang 2 rokov pred
rodič
commit
8f76434b81
66 zmenil súbory, kde vykonal 2738 pridanie a 118 odobranie
  1. 6 2
      baseswago/src/main/java/com/swago/baseswago/PersonDataDFragment.kt
  2. 62 11
      baseswago/src/main/java/com/swago/baseswago/agora/AgoraManager.kt
  3. 8 0
      baseswago/src/main/java/com/swago/baseswago/agora/ISwagoIRtcEngineEventHandler.kt
  4. 2 0
      baseswago/src/main/java/com/swago/baseswago/baseroom/IRoomInfo.kt
  5. 4 0
      baseswago/src/main/java/com/swago/baseswago/baseroom/ui/AbsUserActivity.kt
  6. 10 0
      baseswago/src/main/java/com/swago/baseswago/cusview/SwagoImageView.kt
  7. 14 3
      baseswago/src/main/java/com/swago/baseswago/dialog/HandleDialogFragment.kt
  8. 33 0
      baseswago/src/main/java/com/swago/baseswago/im/GroupMsgParser.kt
  9. 51 0
      baseswago/src/main/java/com/swago/baseswago/im/ImConstant.kt
  10. 109 3
      baseswago/src/main/java/com/swago/baseswago/inter/RoomApi.kt
  11. 11 0
      baseswago/src/main/java/com/swago/baseswago/model/MomentModel.java
  12. 9 0
      baseswago/src/main/java/com/swago/baseswago/model/live/audio/AudioInviteUserModel.kt
  13. 59 0
      baseswago/src/main/java/com/swago/baseswago/model/live/audio/AudioSeatModel.kt
  14. 16 0
      baseswago/src/main/java/com/swago/baseswago/model/live/audio/IMAudioModel.kt
  15. 18 0
      baseswago/src/main/java/com/swago/baseswago/model/live/audio/IMAudioSeatUpdateModel.kt
  16. 9 0
      baseswago/src/main/java/com/swago/glide.kt
  17. 4 1
      baseswago/src/main/res/layout/dialog_choice.xml
  18. 1 1
      baseswago/src/main/res/layout/view_avatar.xml
  19. BIN
      baseswago/src/main/res/mipmap-xxhdpi/ic_audio_integration.webp
  20. BIN
      baseswago/src/main/res/mipmap-xxhdpi/ic_audio_lock.webp
  21. BIN
      baseswago/src/main/res/mipmap-xxhdpi/ic_audio_seat.webp
  22. BIN
      baseswago/src/main/res/mipmap-xxhdpi/icon_audioing.webp
  23. 14 0
      baseswago/src/main/res/values-ar/strings.xml
  24. 14 0
      baseswago/src/main/res/values-in/strings.xml
  25. 15 0
      baseswago/src/main/res/values-ms/strings.xml
  26. 15 0
      baseswago/src/main/res/values-zh/strings.xml
  27. 1 0
      baseswago/src/main/res/values/colors.xml
  28. 14 0
      baseswago/src/main/res/values/strings.xml
  29. 7 1
      home/src/main/java/com/swago/home/innerhome/HomeAdapter.kt
  30. 2 1
      home/src/main/res/layout/item_home.xml
  31. 1 1
      room/src/main/java/com/swago/room/adapter/AudienceAdapter.kt
  32. 122 9
      room/src/main/java/com/swago/room/anchor/AnchorRoomActivity.kt
  33. 32 1
      room/src/main/java/com/swago/room/anchor/AnchorRoomFragment.kt
  34. 176 0
      room/src/main/java/com/swago/room/audio/AudioActionDialog.kt
  35. 91 0
      room/src/main/java/com/swago/room/audio/AudioCanInviteDialog.kt
  36. 20 0
      room/src/main/java/com/swago/room/audio/AudioInviteAdapter.kt
  37. 101 0
      room/src/main/java/com/swago/room/audio/AudioRoomManager.kt
  38. 56 0
      room/src/main/java/com/swago/room/audio/AudioSeatAdapter.kt
  39. 48 0
      room/src/main/java/com/swago/room/audio/IAudioRoomListener.kt
  40. 105 0
      room/src/main/java/com/swago/room/audio/UserByAnchorInviteDialog.kt
  41. 342 30
      room/src/main/java/com/swago/room/base/BaseComFragment.kt
  42. 20 0
      room/src/main/java/com/swago/room/bean/UserRoomModel.kt
  43. 7 0
      room/src/main/java/com/swago/room/enum/RoomType.kt
  44. 18 3
      room/src/main/java/com/swago/room/lianmai/LianMaiView.kt
  45. 185 34
      room/src/main/java/com/swago/room/user/UserRoomActivity.kt
  46. 6 5
      room/src/main/java/com/swago/room/user/UserRoomFragment.kt
  47. 192 1
      room/src/main/java/com/swago/room/vm/MsgVm.kt
  48. 141 2
      room/src/main/java/com/swago/room/vm/RoomVm.kt
  49. 16 1
      room/src/main/java/com/swago/room/widget/AnchorFooterView.kt
  50. 31 0
      room/src/main/java/com/swago/room/widget/ChoiceViewPager.kt
  51. 5 0
      room/src/main/java/com/swago/room/widget/UserFooterView.kt
  52. 61 7
      room/src/main/res/layout/activity_anchor_room.xml
  53. 197 0
      room/src/main/res/layout/dialog_audio_action.xml
  54. 14 0
      room/src/main/res/layout/dialog_audio_can_invite.xml
  55. 90 0
      room/src/main/res/layout/dialog_invited_by_anchor_mic.xml
  56. 9 0
      room/src/main/res/layout/fragment_base_com.xml
  57. 59 0
      room/src/main/res/layout/item_audio_invite.xml
  58. 62 0
      room/src/main/res/layout/item_audio_seat.xml
  59. 13 0
      room/src/main/res/layout/layout_anchor_footer_view.xml
  60. 10 1
      room/src/main/res/layout/layout_user_room.xml
  61. BIN
      room/src/main/res/mipmap-xxhdpi/ic_apply_on_mic.webp
  62. BIN
      room/src/main/res/mipmap-xxhdpi/ic_clear_jifen.png
  63. BIN
      room/src/main/res/mipmap-xxhdpi/ic_down_seat.png
  64. BIN
      room/src/main/res/mipmap-xxhdpi/ic_lock.png
  65. BIN
      room/src/main/res/mipmap-xxhdpi/ic_unlock.png
  66. BIN
      room/src/main/res/mipmap-xxhdpi/ic_yao_qiing_shangmai.png

+ 6 - 2
baseswago/src/main/java/com/swago/baseswago/PersonDataDFragment.kt

@@ -35,7 +35,7 @@ class PersonDataDFragment : BaseXDFragment<DialogPersonDataBinding>() {
     var nickName = ""
     var account = ""
     var roomId:String = ""
-    var isAnchor = false //在直播间是不是打开资料卡
+    var isAnchor = false //是否是主播点击了资料卡
     var isAdmin = false
     private var inRoom = false
     private var isForbid = 0 //0没有被禁言  1已被禁言
@@ -141,7 +141,11 @@ class PersonDataDFragment : BaseXDFragment<DialogPersonDataBinding>() {
 
             binding.ivMore.setOnClickListener(object:NoDoubleClickListener(){
                 override fun onClick() {
-                    HandleDialogFragment.newInstance(uid,account,isForbid,isAnchor,inRoom,isAdmin).show(parentFragmentManager,"HandleDialogFragment")
+                    HandleDialogFragment.newInstance(uid,account,isForbid,isAnchor,inRoom,isAdmin){
+                        if (!TextUtils.isEmpty(uid)){
+                            userVm.getOtherUserInfo(uid,roomId)
+                        }
+                    }.show(parentFragmentManager,"HandleDialogFragment")
                 }
             })
 

+ 62 - 11
baseswago/src/main/java/com/swago/baseswago/agora/AgoraManager.kt

@@ -42,6 +42,7 @@ object AgoraManager {
 
                     override fun onError(err: Int) {
                         super.onError(err)
+                        iSwagoIRtcEngineEventHandler?.onError(err)
                         LogUtil.d("声网错误码-$err")
                     }
 
@@ -77,6 +78,19 @@ object AgoraManager {
                         iSwagoIRtcEngineEventHandler?.onFirstRemoteVideoDecoded(uid, width, height, elapsed)
                     }
 
+                    override fun onFirstLocalVideoFramePublished(elapsed: Int) {
+                        super.onFirstLocalVideoFramePublished(elapsed)
+                        LogUtil.d("首帧视频推出")
+                    }
+
+                    override fun onAudioVolumeIndication(
+                        speakers: Array<out AudioVolumeInfo>?,
+                        totalVolume: Int
+                    ) {
+                        super.onAudioVolumeIndication(speakers, totalVolume)
+                        iSwagoIRtcEngineEventHandler?.onAudioVolumeIndication(speakers,totalVolume)
+                    }
+
                     override fun onConnectionStateChanged(state: Int, reason: Int) {
                         super.onConnectionStateChanged(state, reason)
                         iSwagoIRtcEngineEventHandler?.onConnectionStateChanged(state, reason)
@@ -107,10 +121,44 @@ object AgoraManager {
 
     private fun setChannelProfile() {
         mRtcEngine?.setChannelProfile(CHANNEL_PROFILE_LIVE_BROADCASTING)
+        mRtcEngine?.enableAudio()
+        mRtcEngine?.enableVideo()
     }
 
 
-    fun setClientRole(userType: Int,isNeedVideo:Boolean,isNeedVoice:Boolean) {
+    fun setVideoAudio(pullVideo:Boolean,pullAudio:Boolean,pushVideo:Boolean,pushAudio:Boolean){
+        if (pullVideo){
+            mRtcEngine?.muteAllRemoteVideoStreams(false)
+        }else{
+            mRtcEngine?.muteAllRemoteVideoStreams(true)
+        }
+        if (pullAudio){
+            mRtcEngine?.muteAllRemoteAudioStreams(false)
+        }else{
+            mRtcEngine?.muteAllRemoteAudioStreams(true)
+        }
+        if (pushAudio){
+            mRtcEngine?.enableLocalAudio(true)
+            mRtcEngine?.muteLocalAudioStream(false)
+        }else{
+            mRtcEngine?.enableLocalAudio(false)
+            mRtcEngine?.muteLocalAudioStream(true)
+        }
+        if (pushVideo){
+            mRtcEngine?.enableLocalVideo(true)
+            mRtcEngine?.muteLocalVideoStream(false)
+        }else{
+            mRtcEngine?.enableLocalVideo(false)
+            mRtcEngine?.muteLocalVideoStream(true)
+        }
+        if (pushVideo || pushAudio){
+            setClientRole(RoleType.anchor)
+        }else{
+            setClientRole(RoleType.user)
+        }
+    }
+
+    private fun setClientRole(userType: Int) {
         this.userType = userType
         if (userType == RoleType.anchor) {
             mRtcEngine?.setClientRole(CLIENT_ROLE_BROADCASTER)
@@ -119,16 +167,6 @@ object AgoraManager {
             clientRoleOptions.audienceLatencyLevel = AUDIENCE_LATENCY_LEVEL_LOW_LATENCY
             mRtcEngine?.setClientRole(CLIENT_ROLE_AUDIENCE, clientRoleOptions)
         }
-        if(isNeedVideo){
-            mRtcEngine?.enableVideo()
-        }else{
-            mRtcEngine?.disableVideo()
-        }
-        if(isNeedVoice){
-            mRtcEngine?.enableAudio()
-        }else{
-            mRtcEngine?.disableAudio()
-        }
     }
 
     /**
@@ -151,6 +189,15 @@ object AgoraManager {
 
     }
 
+    /**
+     * 主播端切到语音房停止预览然后移除视频控件
+     */
+    fun stopPreviewAndRemoveLocalView(mLocalContainer: FrameLayout?){
+        mRtcEngine?.stopPreview()
+        mLocalContainer?.removeAllViews()
+    }
+
+
 
     /**
      * 观众拉取远端主播画面
@@ -301,4 +348,8 @@ object AgoraManager {
     }
 
 
+    fun enableAudioVolumeIndication(){
+        mRtcEngine?.enableAudioVolumeIndication(2000,3,true)
+    }
+
 }

+ 8 - 0
baseswago/src/main/java/com/swago/baseswago/agora/ISwagoIRtcEngineEventHandler.kt

@@ -1,5 +1,7 @@
 package com.swago.baseswago.agora
 
+import io.agora.rtc.IRtcEngineEventHandler
+
 /**
  *@date 2022/2/28 15:53
  *description:
@@ -19,4 +21,10 @@ interface ISwagoIRtcEngineEventHandler {
 
     fun onFirstLocalAudioFramePublished(elapsed:Int)
 
+    fun onError(err: Int)
+
+    fun onAudioVolumeIndication(
+        speakers: Array<out IRtcEngineEventHandler.AudioVolumeInfo>?,
+        totalVolume: Int
+    )
 }

+ 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)
+            }
+        }
+    }
+
 }

+ 14 - 3
baseswago/src/main/java/com/swago/baseswago/dialog/HandleDialogFragment.kt

@@ -38,7 +38,9 @@ class HandleDialogFragment : BaseXDFragment<DialogHandleBinding>() {
 
 
     companion object{
-        fun newInstance(userId:String,account:String,isForbid:Int,isAnchor:Boolean,inRoom:Boolean=false,isRoomAdmin:Boolean=false): HandleDialogFragment {
+        private var refreshCallBack:(()->Unit)? = null
+        fun newInstance(userId:String,account:String,isForbid:Int,isAnchor:Boolean,inRoom:Boolean=false,isRoomAdmin:Boolean=false,refreshCallBack:(()->Unit)? = null): HandleDialogFragment {
+            this.refreshCallBack = refreshCallBack
             val args = Bundle()
             args.putString("userId",userId)
             args.putString("account",account)
@@ -79,8 +81,16 @@ class HandleDialogFragment : BaseXDFragment<DialogHandleBinding>() {
                     //用户
                     SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
                         if (iRoomInfo.getRoomAdmin()==1){
-                            binding.tvKick.visibility = View.VISIBLE
-                            binding.tvMute.visibility = View.VISIBLE
+                            //如果操作的人是管理员  被点击的不是主播显示下面两个按钮
+                            SwagoRoomManager.iRoomInfo?.let {
+                                if (it.getAnchorId()!=userId){
+                                    binding.tvKick.visibility = View.VISIBLE
+                                    binding.tvMute.visibility = View.VISIBLE
+                                }else{
+                                    binding.tvKick.visibility = View.GONE
+                                    binding.tvMute.visibility = View.GONE
+                                }
+                            }
                         }else{
                             binding.tvKick.visibility = View.GONE
                             binding.tvMute.visibility = View.GONE
@@ -212,6 +222,7 @@ class HandleDialogFragment : BaseXDFragment<DialogHandleBinding>() {
         }
 
         userVm.setRoomAdminLiveData.observe(this){
+            refreshCallBack?.invoke()
             if (it==1){
                 binding.tvSetRoomAdmin.visibility = View.GONE
                 binding.tvDeleteRoomAdmin.visibility = View.VISIBLE

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

@@ -18,9 +18,14 @@ 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.jifen_change
+import com.swago.baseswago.im.ImConstant.jifen_clear
 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.open_close_mic
 import com.swago.baseswago.im.ImConstant.pk_process
 import com.swago.baseswago.im.ImConstant.pk_punish
 import com.swago.baseswago.im.ImConstant.pk_send
@@ -33,14 +38,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 +259,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,open_close_mic,jifen_clear, jifen_change-> {
+                    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){

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

@@ -137,6 +137,57 @@ 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
+
+    /**
+     * 积分清零
+     */
+    const val jifen_clear = 309
+
+
     /**********游戏相关IM********/
     const val fruit_game = 1001
     const val beauty_game = 1002

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

@@ -3,6 +3,9 @@ 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.AudioInviteUserModel
+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 +31,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
 
 
     /**
@@ -90,7 +95,7 @@ interface RoomApi {
      * 赠送礼物
      */
     @FormUrlEncoded
-    @POST("/v1/rtc/buy/gift")
+    @POST("/v3/rtc/buy/gift")
     suspend fun sendGift(
         @Field("room_id") room_id: String,
         @Field("gift_id") gift_id: String,
@@ -313,19 +318,120 @@ 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("broadcast_log_id") broadcast_log_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
 
 
+    /**
+     * 积分清零
+     */
+    @FormUrlEncoded
+    @POST("/v3/rtc/yuying/position/jifen/reset")
+    suspend fun clearJiFen(@Field("room_id") room_id: String,
+                           @Field("broadcast_log_id") broadcast_log_id: String):Any
+
+
+    /**
+     * 语音房被邀请用户列表
+     */
+    @FormUrlEncoded
+    @POST("/v3/rtc/yuying/user/list")
+    suspend fun getCanAudioInviteUserList(@Field("room_id") room_id: String,
+                           @Field("broadcast_log_id") broadcast_log_id: String): List<AudioInviteUserModel>
+
 
 }

+ 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;
+    }
 }

+ 9 - 0
baseswago/src/main/java/com/swago/baseswago/model/live/audio/AudioInviteUserModel.kt

@@ -0,0 +1,9 @@
+package com.swago.baseswago.model.live.audio
+
+data class AudioInviteUserModel(
+    val id:String,
+    val user_id:String,
+    val user_name:String,
+    val user_head_img_url:String,
+    val user_wealth_level:Int
+)

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

@@ -0,0 +1,59 @@
+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锁定)
+    var voice_jifen:String?,//积分
+    var voice_user_id:String?,//被谁给闭麦
+    val maiIndex:Int,//积分
+    var showVoice:Int //说话闪烁 1显示 0隐藏
+) : Parcelable {
+    constructor(parcel: Parcel) : this(
+        parcel.readString(),
+        parcel.readString(),
+        parcel.readString(),
+        parcel.readInt(),
+        parcel.readInt(),
+        parcel.readString(),
+        parcel.readString(),
+        parcel.readInt(),
+        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.writeString(voice_user_id)
+        parcel.writeInt(maiIndex)
+        parcel.writeInt(showVoice)
+    }
+
+    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>?
+)

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

@@ -0,0 +1,16 @@
+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,
+    val voice_jifen:String
+)

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

@@ -0,0 +1,18 @@
+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,
+    val voiceUserId: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)

+ 4 - 1
baseswago/src/main/res/layout/dialog_choice.xml

@@ -10,6 +10,7 @@
         app:layout_constraintTop_toTopOf="parent"
         android:layout_marginStart="40dp"
         android:layout_marginEnd="40dp"
+        app:layout_constraintBottom_toBottomOf="parent"
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
 
@@ -34,7 +35,7 @@
             android:textColor="#131B23"
             android:textSize="14dp"
             android:gravity="center"
-            tools:text="Titledfsdfdsfdsfsdfdsfdsfdsfsdsaddsds"
+            tools:text="Titledfsdfdsfdsfsdfdsfdsfdsfsdsaddsds递四方速递佛挡杀佛fdsfs dsfdsfdsfdsfsdf sdfdsfdsdsfdsffdsfsfsd"
             android:layout_marginStart="20dp"
             android:layout_marginEnd="20dp"
             app:layout_constraintTop_toBottomOf="@+id/tvTitle"
@@ -58,6 +59,7 @@
             android:textColor="#828C9D"
             android:text="@string/cancel"
             android:gravity="center"
+            app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintTop_toBottomOf="@+id/view"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintEnd_toStartOf="@+id/tvSure"
@@ -70,6 +72,7 @@
             android:textColor="#fff"
             android:text="@string/confirm"
             android:gravity="center"
+            app:layout_constraintBottom_toBottomOf="parent"
             android:background="@drawable/shape_ff56b7_right_bottom_20"
             app:layout_constraintTop_toBottomOf="@+id/view"
             app:layout_constraintStart_toEndOf="@+id/tvCancel"

+ 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


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


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

@@ -228,4 +228,18 @@
     <string name="become_room_manager">%s يصبح مشرف الغرفة</string>
     <string name="ban_live_reason">سبب الحظر: %s</string>
     <string name="ban_live_time">مدة الحظر: %s</string>
+    <string name="invited_on_mic">تسليم دعوة لاتصال MIC من المضيف</string>
+    <string name="lock_success">قفل الميكروفون بنجاح</string>
+    <string name="unlock_success">تم فتح  الميكروفون بنجاح</string>
+    <string name="reject_time">رفض(%ss)</string>
+    <string name="down_mic_success">نزل من الميكروفون بالنجاح</string>
+    <string name="invite_on_mic">دعوة للجيست</string>
+    <string name="you_be_mute_anchor">تم كتمك من المضيف</string>
+    <string name="on_mic">صعود الجيست</string>
+    <string name="down_mic">نزل من الجيست</string>
+    <string name="lock_mic">قفل الجيست</string>
+    <string name="unlock_mic">فتح الجيست</string>
+    <string name="close_mic">كتم الجيست</string>
+    <string name="open_mic">إلغاء الكتم</string>
+    <string name="ji_fen_to_zero">هل تتأكد من إعادة احتساب جميع نقاط مستخدم الميكروفون في الغرفة؟</string>
 </resources>

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

@@ -240,4 +240,18 @@
     <string name="become_room_manager">%s menjadi admin ruangan ini</string>
     <string name="ban_live_reason">Alasan Banned Live:%s</string>
     <string name="ban_live_time">Durasi Banned Live:%s</string>
+    <string name="invited_on_mic">Anda menerima undangan naik kursi dari host</string>
+    <string name="lock_success">Sukses mengunci kursi</string>
+    <string name="unlock_success">Sukses membuka kunci kursi</string>
+    <string name="reject_time">Menolak(%ss)</string>
+    <string name="down_mic_success">Sukses menurun  kursi</string>
+    <string name="invite_on_mic">Mengundang naik kursi</string>
+    <string name="you_be_mute_anchor">Mikropon Anda telah terkunci oleh host</string>
+    <string name="on_mic">Naik kursi</string>
+    <string name="down_mic">Menurun kursi</string>
+    <string name="lock_mic">Kunci Kursi</string>
+    <string name="unlock_mic">Membuka kursi</string>
+    <string name="close_mic">Tutup Mikropon</string>
+    <string name="open_mic">Membuka Mikropon</string>
+    <string name="ji_fen_to_zero">Apakah Anda ingin mengatur kembali semua poin pengguna di kursi menjadi nol</string>
 </resources>

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

@@ -240,4 +240,19 @@
     <string name="become_room_manager">%s menjadi Pentadbir Bilik</string>
     <string name="ban_live_reason">Sebab Penyiaran Terlarang:%s</string>
     <string name="ban_live_time">Masa Terlarang:%s</string>
+    <string name="invited_on_mic">Terima jemputan dari tempat duduk dari sauh</string>
+    <string name="lock_success">Berjaya menutup tempat duduk</string>
+    <string name="unlock_success">Berjaya membuka kunci</string>
+    <string name="reject_time">menolak(%ss)</string>
+    <string name="down_mic_success">Berjaya mengakhiri suara</string>
+    <string name="invite_on_mic">Jemput ke tempat duduk</string>
+    <string name="you_be_mute_anchor">Anda telah dilarang bercakap dengan tuan rumah.</string>
+    <string name="on_mic">Masukkan tempat duduk</string>
+    <string name="down_mic">Meninggalkan kedudukan</string>
+    <string name="lock_mic">Tutup kedudukan mikrofon</string>
+    <string name="unlock_mic">Buka kedudukan mikrofon</string>
+    <string name="close_mic">Matikan suara</string>
+    <string name="open_mic">Buka bunyi</string>
+    <string name="ji_fen_to_zero">Adakah anda perlu menetapkan semula semua skor tempat duduk di bilik semasa hingga sifar?</string>
+
 </resources>

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

@@ -228,4 +228,19 @@
     <string name="become_room_manager">%s成为该房间管理员</string>
     <string name="ban_live_reason">禁播原因:%s</string>
     <string name="ban_live_time">禁播时长:%s</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>
+    <string name="invite_on_mic">邀请上麦</string>
+    <string name="you_be_mute_anchor">你已被主播闭麦</string>
+    <string name="on_mic">上麦</string>
+    <string name="down_mic">下麦</string>
+    <string name="lock_mic">锁麦</string>
+    <string name="unlock_mic">解锁</string>
+    <string name="close_mic">闭麦</string>
+    <string name="open_mic">开麦</string>
+    <string name="ji_fen_to_zero">您是否需要将当前房间的所有麦位用户积分值重置为零?</string>
+
 </resources>

+ 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>

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

@@ -260,5 +260,19 @@
     <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="invited_on_mic">Receive an invite for MIC-connection from the anchor</string>
+    <string name="lock_success">Lock the microphone successfully</string>
+    <string name="unlock_success">successfully unlocked</string>
+    <string name="reject_time">reject(%ss)</string>
+    <string name="down_mic_success">off the microphone successfully</string>
+    <string name="invite_on_mic">invite to mic</string>
+    <string name="you_be_mute_anchor">You have been blocked by the anchor</string>
+    <string name="on_mic">connect the mic</string>
+    <string name="down_mic">off the mic</string>
+    <string name="lock_mic">lock the mic</string>
+    <string name="unlock_mic">unlock the mic</string>
+    <string name="close_mic">mute the mic</string>
+    <string name="open_mic">on the mic</string>
+    <string name="ji_fen_to_zero">Do you need to reset all microphone user point in the room?</string>
 
 </resources>

+ 7 - 1
home/src/main/java/com/swago/home/innerhome/HomeAdapter.kt

@@ -33,7 +33,13 @@ class HomeAdapter  : BaseQuickAdapter<MomentModel, BaseViewHolder>(R.layout.item
             val imageView = itemView.findViewById<ShapeableImageView>(R.id.ivAvatar)
             imageView.loadUrl(itemView.context,item.user_head_img_url)
             if (item.user_broadcast_status == 1){
-                itemView.findViewById<ImageView>(R.id.ivLive).loadWebp(mContext,R.mipmap.icon_living)
+                if (item.user_broadcast_type==1){
+                    itemView.findViewById<ImageView>(R.id.ivLive).loadWebp(mContext,R.mipmap.icon_living)
+                    setText(R.id.tvType,"Live")
+                }else if(item.user_broadcast_type==2){
+                    itemView.findViewById<ImageView>(R.id.ivLive).loadWebp(mContext,R.mipmap.icon_audioing)
+                    setText(R.id.tvType,"Audio")
+                }
                 setVisible(R.id.llLive,true)
             }else{
                 setVisible(R.id.llLive,false)

+ 2 - 1
home/src/main/res/layout/item_home.xml

@@ -31,9 +31,10 @@
         <ImageView
             android:id="@+id/ivLive"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"/>
+            android:layout_height="15dp"/>
 
         <TextView
+            android:id="@+id/tvType"
             android:textSize="10dp"
             android:textColor="#fff"
             android:text="Live"

+ 1 - 1
room/src/main/java/com/swago/room/adapter/AudienceAdapter.kt

@@ -7,7 +7,7 @@ import com.swago.baseswago.cusview.SwagoLevelView
 import com.swago.baseswago.model.live.RoomUserModel
 import com.swago.loadUrl
 import com.swago.room.R
-import com.tencent.qcloud.tim.uikit.component.CircleImageView
+import de.hdodenhof.circleimageview.CircleImageView
 
 /**
  *@date 2022/3/29 20:33

+ 122 - 9
room/src/main/java/com/swago/room/anchor/AnchorRoomActivity.kt

@@ -3,11 +3,13 @@ package com.swago.room.anchor
 import android.content.Intent
 import android.os.Bundle
 import android.util.Log
+import android.view.SurfaceView
 import android.view.View
 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
@@ -27,6 +29,8 @@ import com.swago.baseswago.util.UserInfo
 import com.swago.lib_beauty.FuBeautyManager
 import com.swago.lib_beautyui.BeautyDialogFragment
 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
@@ -34,12 +38,15 @@ import com.swago.baseswago.model.live.pk.StopPKModel
 import com.swago.baseswago.util.DpPxUtil
 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
@@ -54,6 +61,10 @@ import com.swago.room.vm.RoomVm
 import io.agora.capture.video.camera.CameraVideoManager
 import io.agora.capture.video.camera.Constant
 import java.util.*
+import io.agora.rtc.IRtcEngineEventHandler
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
 
 /**
  *@date 2021/10/6 10:35
@@ -61,7 +72,7 @@ import java.util.*
  */
 @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>()
@@ -81,6 +92,9 @@ class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInf
         mVideoManager.preprocessor as PreprocessorFaceUnity
     }
 
+    private val localSurfaceView by lazy {
+        SurfaceView(this)
+    }
 
     private var agoraService: Intent? = null
 
@@ -90,7 +104,6 @@ class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInf
 
     private var anchorRoomFragment: AnchorRoomFragment? = null
 
-
     private fun initPushView() {
         mVideoManager.setCameraStateListener(object :
             io.agora.capture.video.camera.VideoCapture.VideoCaptureStateListener {
@@ -108,18 +121,21 @@ class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInf
         preprocessor.setRenderEnable(true)
         mVideoManager.setLocalPreviewMirror(Constant.MIRROR_MODE_AUTO)
         mVideoManager.setFrameRate(15)
-        mVideoManager.setLocalPreview(binding.localSurfaceView)
-
         AgoraManager.initializeEngine(this, this)
         AgoraManager.setVideoConfiguration()
-        AgoraManager.setClientRole(RoleType.anchor, isNeedVideo = true, isNeedVoice = true)
+        AgoraManager.enableAudioVolumeIndication()
         UserInfo.getUserInfo()?.let {
             AgoraManager.setupLocalVideo(this, binding.flLocal, it.id.toInt(), true) {
-                AgoraManager.getRtcEngine()?.enableVideo()
+                AgoraManager.setVideoAudio(pullVideo = true, pullAudio = true, pushVideo = true, pushAudio = true)
+                mVideoManager.setLocalPreview(localSurfaceView)
+                binding.flLocal.addView(localSurfaceView)
             }
         }
     }
 
+    //开播类型  0视频房 1语音房
+    private var roomType = RoomType.VIDEO
+
     override fun initLiveData() {
         PKStateManager.resetData()
         roomVm.init()
@@ -127,6 +143,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)
@@ -149,16 +166,64 @@ class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInf
                 anchorCloseRoom()
             }
         })
+
         binding.ivBeauty.setOnClickListener(object : NoDoubleClickListener() {
             override fun onClick() {
                 BeautyDialogFragment().show(supportFragmentManager, "BeautyDialogFragment")
             }
         })
+
+        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.ivBeauty.visibility = View.VISIBLE
+                binding.tvVideo.setTextColor(ContextCompat.getColor(AppContext.getContext(),R.color._ffffff))
+                binding.tvAudio.setTextColor(ContextCompat.getColor(AppContext.getContext(),R.color._d4ffffff))
+                UserInfo.getUserInfo()?.let {
+                    AgoraManager.setupLocalVideo(this@AnchorRoomActivity,binding.flLocal,it.id.toInt(),true){
+                        AgoraManager.setVideoAudio(pullVideo = true, pullAudio = true, pushVideo = true, pushAudio = true)
+                        mVideoManager.setLocalPreview(localSurfaceView)
+                        binding.flLocal.addView(localSurfaceView)
+                    }
+                }
+                anchorRoomFragment?.setAudioRvState(false)
+                mVideoManager.startCapture()
+                binding.viewPager.currentItem = 0
+                binding.ivPrepareCamera.visibility = View.VISIBLE
+            }
+        })
+
+        binding.llAudio.setOnClickListener(object:NoDoubleClickListener(){
+            override fun onClick() {
+                if (roomType == RoomType.AUDIO) return
+                mVideoManager.stopCapture()
+                AgoraManager.setVideoAudio(pullVideo = false, pullAudio = true, pushVideo = false, pushAudio = true)
+                roomType = RoomType.AUDIO
+                binding.viewAudio.visibility = View.VISIBLE
+                binding.viewVideo.visibility = View.INVISIBLE
+                binding.ivBeauty.visibility = View.GONE
+                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() {
@@ -259,10 +324,13 @@ class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInf
         finish()
     }
 
-
+    private var isFirstEnter = true
     override fun onResume() {
         super.onResume()
-        mVideoManager.startCapture()
+        if (isFirstEnter){
+            isFirstEnter = false
+            mVideoManager.startCapture()
+        }
         agoraService?.let {
             it.action = ACTION_STOP_FOREGROUND_SERVICE
             startService(it)
@@ -279,6 +347,7 @@ class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInf
 
     override fun onDestroy() {
         PKStateManager.removePKListener(this)
+        AudioRoomManager.removeListener(this)
         agoraService?.let { stopService(it) }
         mVideoManager.stopCapture()
         mVideoManager.setCameraStateListener(null)
@@ -304,6 +373,23 @@ class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInf
 
     }
 
+    override fun onError(err: Int) {
+
+    }
+
+    override fun onAudioVolumeIndication(
+        speakers: Array<out IRtcEngineEventHandler.AudioVolumeInfo>?,
+        totalVolume: Int
+    ) {
+        lifecycleScope.launch(Dispatchers.Main) {
+            SwagoRoomManager.iRoomInfo?.let {
+                if (it.getRoomType() == RoomType.AUDIO.type) {
+                    AudioRoomManager.dispatchOnAudioVolumeIndication(speakers)
+                }
+            }
+        }
+    }
+
     /**************************PK******************************/
     private val marginTopValue by lazy {
         ImmersionBar.getStatusBarHeight(this) + DpPxUtil.dip2px(78f)
@@ -373,6 +459,33 @@ class AnchorRoomActivity : AbsAnchorActivity<ActivityAnchorRoomBinding, IRoomInf
         binding.peerFl.layoutParams = params
     }
 
-    /************************************************************/
+    /*************************语音房***********************************/
+
+    override fun lockOrUnlockSeat(imAudioModel: IMAudioModel) {
+    }
+
+    override fun openSeatMic() {
+        AgoraManager.setMute(false)
+    }
+
+    override fun muteSeatMic() {
+        AgoraManager.setMute(true)
+    }
+
+    override fun onSeatMic() {
+    }
+
+    override fun downSeatMic() {
+    }
+
+    override fun updateData(audioSeatModel: AudioSeatModel) {
+    }
+
+    override fun changeJiFen(imAudioModel: IMAudioModel) {
+    }
+
+    override fun clearJiFen() {
+
+    }
 
 }

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

@@ -6,11 +6,13 @@ import com.swago.baseswago.agora.AgoraManager
 import com.swago.baseswago.baseroom.IRoomInfo
 import com.swago.lib_beautyui.BeautyDialogFragment
 import com.swago.baseswago.baseroom.SwagoRoomManager
+import com.swago.baseswago.dialog.ChoiceDialogFragment
 import com.swago.baseswago.model.live.pk.ProcessPKModel
 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
@@ -20,7 +22,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
@@ -39,6 +40,11 @@ class AnchorRoomFragment : BaseComFragment<FragmentBaseComBinding>() {
 
     override fun initOther() {
         super.initOther()
+        //语音列表
+        UserInfo.getUserInfo()?.let {
+            roomVm.getAudioList(it.id,1)
+        }
+
     }
 
     override fun initLiveData() {
@@ -86,6 +92,14 @@ class AnchorRoomFragment : BaseComFragment<FragmentBaseComBinding>() {
             openLianMaiListDialog()
         }
 
+        footerView?.clearJiFen = {
+            ChoiceDialogFragment.newInstance(AppContext.getContext().resources.getString(R.string.ji_fen_to_zero)).apply {
+                this.sureFun = {
+                    roomVm.clearJiFen()
+                }
+            }.show(childFragmentManager,"ChoiceDialogFragment")
+        }
+
         (iHeader as ComHeaderView).showUserInfo = {
             PersonDataDFragment.newInstance(it, isAnchor = true, inRoom = true,SwagoRoomManager.iRoomInfo?.getRoomId()?:"")
                 .apply {
@@ -138,6 +152,7 @@ class AnchorRoomFragment : BaseComFragment<FragmentBaseComBinding>() {
 
 
     override fun changeRoom(iRoomInfo: IRoomInfo) {
+        super.changeRoom(iRoomInfo)
     }
 
     override fun leaveRoom(iRoomInfo: IRoomInfo) {
@@ -166,6 +181,22 @@ class AnchorRoomFragment : BaseComFragment<FragmentBaseComBinding>() {
     }
     /*********************PK**************************/
 
+
+    override fun openSeatMic() {
+        super.openSeatMic()
+        footerView?.let {
+            it.isMute = !it.isMute
+        }
+    }
+
+    override fun muteSeatMic() {
+        super.muteSeatMic()
+        footerView?.let {
+            it.isMute = !it.isMute
+        }
+    }
+
+
     override fun closeRoomed() {
         super.closeRoomed()
     }

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

@@ -0,0 +1,176 @@
+package com.swago.room.audio
+
+import android.os.Bundle
+import android.view.Gravity
+import android.view.View
+import android.widget.Toast
+import androidx.fragment.app.activityViewModels
+import com.swago.baseswago.baseroom.IRoomActiveListener
+import com.swago.baseswago.baseroom.IRoomInfo
+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.AppContext
+import com.swago.baseswago.util.NoDoubleClickListener
+import com.swago.baseswago.util.UserInfo
+import com.swago.room.R
+import com.swago.room.databinding.DialogAudioActionBinding
+import com.swago.room.vm.RoomVm
+
+class AudioActionDialog : BaseXDFragment<DialogAudioActionBinding>(),IRoomActiveListener  {
+
+    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() {
+        SwagoRoomManager.addListener(this)
+        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){
+                                //闭麦的情况下  如果是被主播闭麦 那么主播端开麦按钮   否则不展示
+                                if (userInfoModel.id == audioSeatModel.voice_user_id){
+                                    binding.llUnMuteMic.visibility = View.VISIBLE
+                                }
+                            }else{
+                                binding.llMuteMic.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() {
+                        AudioCanInviteDialog.newInstance(it.maiIndex).show(parentFragmentManager,"AudioCanInviteDialog")
+                        dismissAllowingStateLoss()
+                    }
+                })
+                binding.llDownSeatMic.setOnClickListener(object:NoDoubleClickListener(){
+                    override fun onClick() {
+                        roomVm.downMicByAnchor(it.maiIndex,it.user_id?:"")
+                        dismissAllowingStateLoss()
+                    }
+                })
+                //闭麦
+                binding.llMuteMic.setOnClickListener(object:NoDoubleClickListener(){
+                    override fun onClick() {
+                        roomVm.operateMicByAnchor(it.maiIndex,it.user_id?:"",1)
+                        dismissAllowingStateLoss()
+                    }
+                })
+                //开麦
+                binding.llUnMuteMic.setOnClickListener(object:NoDoubleClickListener(){
+                    override fun onClick() {
+                        if (it.user_id == it.voice_user_id){
+                            //被自己闭麦后开麦
+                            roomVm.operateMicByAnchor(it.maiIndex,it.user_id?:"",2)
+                            dismissAllowingStateLoss()
+                        }else{
+                            //被主播闭麦 如果是主播操作
+                            if (SwagoRoomManager.roleType == RoleType.anchor){
+                                roomVm.operateMicByAnchor(it.maiIndex,it.user_id?:"",2)
+                                dismissAllowingStateLoss()
+                            }else{
+                                Toast.makeText(
+                                    AppContext.getContext(),
+                                    AppContext.getContext().resources.getString(R.string.you_be_mute_anchor),
+                                    Toast.LENGTH_SHORT
+                                )
+                                    .show()
+                            }
+                        }
+
+                    }
+                })
+
+            }
+
+
+        }
+    }
+
+    override fun initLiveData() {
+    }
+
+    override fun changeRoom(iRoomInfo: IRoomInfo) {
+    }
+
+    override fun leaveRoom(iRoomInfo: IRoomInfo) {
+    }
+
+    override fun joinedRoom(iRoomInfo: IRoomInfo) {
+    }
+
+    override fun endRoom(iRoomInfo: IRoomInfo?) {
+    }
+
+    override fun closeRoomed() {
+    }
+
+    override fun onDestroyView() {
+        SwagoRoomManager.removeListener(this)
+        super.onDestroyView()
+    }
+
+    override fun receiveStopLive() {
+        dismissAllowingStateLoss()
+    }
+}

+ 91 - 0
room/src/main/java/com/swago/room/audio/AudioCanInviteDialog.kt

@@ -0,0 +1,91 @@
+package com.swago.room.audio
+
+import android.graphics.Rect
+import android.os.Bundle
+import android.view.Gravity
+import android.view.View
+import androidx.fragment.app.activityViewModels
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.chad.library.adapter.base.BaseQuickAdapter
+import com.swago.baseswago.cusview.SwagoRecyclerView
+import com.swago.baseswago.dialog.BaseListDialogFragment
+import com.swago.baseswago.model.live.audio.AudioInviteUserModel
+import com.swago.baseswago.util.DpPxUtil
+import com.swago.room.databinding.DialogAudioCanInviteBinding
+import com.swago.room.vm.RoomVm
+
+class AudioCanInviteDialog : BaseListDialogFragment<DialogAudioCanInviteBinding, AudioInviteUserModel>() {
+
+    private val roomVm by activityViewModels<RoomVm>()
+
+    init {
+        setGravity(Gravity.BOTTOM)
+        setCanCancel(true)
+        setDimAmount(0f)
+    }
+
+    override val smartRecyclerView: SwagoRecyclerView<AudioInviteUserModel> by lazy {
+        binding.swagoRv as SwagoRecyclerView<AudioInviteUserModel>
+    }
+    override val adapter: BaseQuickAdapter<AudioInviteUserModel, *> by lazy {
+        AudioInviteAdapter()
+    }
+    override val layoutManager: RecyclerView.LayoutManager by lazy {
+        LinearLayoutManager(context)
+    }
+    override val loadData: (page: Int) -> Unit = {
+        roomVm.getCanAudioInviteUserList()
+    }
+
+    companion object{
+        fun newInstance(maiIndex:Int): AudioCanInviteDialog {
+            val args = Bundle()
+            args.putInt("maiIndex",maiIndex)
+            val fragment = AudioCanInviteDialog()
+            fragment.arguments = args
+            return fragment
+        }
+    }
+
+    override fun initViewData() {
+        arguments?.let {
+            val maiIndex = it.getInt("maiIndex",0)
+            smartRecyclerView.recyclerView?.addItemDecoration(ListItemDecoration())
+            adapter.setOnItemChildClickListener { _, _, position ->
+                if (adapter.data.size>position){
+                    roomVm.inviteUserOnMic(adapter.data[position].user_id,maiIndex)
+                    dismissAllowingStateLoss()
+                }
+            }
+        }
+    }
+
+    override fun initLiveData() {
+        roomVm.audioInvitedUserListLiveData.observe(this){
+            if (it == null){
+                smartRecyclerView.onFetchDataError()
+            }else{
+                smartRecyclerView.onFetchDataFinish(it,true)
+            }
+        }
+    }
+
+    override fun loadMoreNeed(): Boolean {
+        return false
+    }
+
+
+    inner class ListItemDecoration : RecyclerView.ItemDecoration() {
+        override fun getItemOffsets(
+            outRect: Rect,
+            view: View,
+            parent: RecyclerView,
+            state: RecyclerView.State
+        ) {
+            val margin = DpPxUtil.dip2px(8f)
+            outRect.set(0, 0, 0, margin)
+        }
+    }
+
+}

+ 20 - 0
room/src/main/java/com/swago/room/audio/AudioInviteAdapter.kt

@@ -0,0 +1,20 @@
+package com.swago.room.audio
+
+import com.chad.library.adapter.base.BaseQuickAdapter
+import com.chad.library.adapter.base.BaseViewHolder
+import com.swago.baseswago.cusview.SwagoLevelView
+import com.swago.baseswago.model.live.audio.AudioInviteUserModel
+import com.swago.loadUrl
+import com.swago.room.R
+import de.hdodenhof.circleimageview.CircleImageView
+
+class AudioInviteAdapter : BaseQuickAdapter<AudioInviteUserModel, BaseViewHolder>(R.layout.item_audio_invite, arrayListOf()) {
+    override fun convert(helper: BaseViewHolder, item: AudioInviteUserModel) {
+        helper.apply {
+            setText(R.id.tvName,item.user_name)
+            itemView.findViewById<CircleImageView>(R.id.ivAvatar).loadUrl(mContext,item.user_head_img_url)
+            itemView.findViewById<SwagoLevelView>(R.id.tvLevel).setUserLevel(item.user_wealth_level)
+            addOnClickListener(R.id.tvInvite)
+        }
+    }
+}

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

@@ -0,0 +1,101 @@
+package com.swago.room.audio
+
+import com.swago.baseswago.model.live.audio.AudioSeatModel
+import com.swago.baseswago.model.live.audio.IMAudioModel
+import io.agora.rtc.IRtcEngineEventHandler
+
+object AudioRoomManager {
+
+    //两个字段用户端使用
+    var isOnMic = false
+    var maiIndex = -1
+
+    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 dispatchOpenSeatMic(){
+        list.forEach {
+            it.openSeatMic()
+        }
+    }
+
+    fun dispatchMuteSeatMic(){
+        list.forEach {
+            it.muteSeatMic()
+        }
+    }
+
+    /**
+     * 上麦和下麦
+     */
+    fun dispatchOnSeatMic(){
+        list.forEach {
+            it.onSeatMic()
+        }
+    }
+
+    fun dispatchDownSeatMic(){
+        list.forEach {
+            it.downSeatMic()
+        }
+    }
+
+    /**
+     * 改变积分
+     */
+    fun dispatchChangeJiFen(imAudioModel: IMAudioModel){
+        list.forEach {
+            it.changeJiFen(imAudioModel)
+        }
+    }
+
+    fun dispatchUpdateData(audioSeatModel: AudioSeatModel){
+        list.forEach {
+            it.updateData(audioSeatModel)
+        }
+    }
+
+    /**
+     * 积分清零
+     */
+    fun dispatchClearJiFen(){
+        list.forEach {
+            it.clearJiFen()
+        }
+    }
+
+    /**
+     * 用户说话回调
+     */
+    fun dispatchOnAudioVolumeIndication(speakers: Array<out IRtcEngineEventHandler.AudioVolumeInfo>?){
+        list.forEach {
+            it.onAudioVolumeIndication(speakers)
+        }
+    }
+
+
+    fun resetData(){
+        isOnMic = false
+        maiIndex = -1
+    }
+
+}

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

@@ -0,0 +1,56 @@
+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)
+                    setVisible(R.id.ivAudioState, 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)
+                    }
+
+
+                    if (it.voice_status == 2) {
+                        setVisible(R.id.ivAudioState, true)
+                        setImageResource(R.id.ivAudioState, R.mipmap.live_mute)
+                    } else {
+                        if (it.showVoice==1){
+                            setImageResource(R.id.ivAudioState, R.mipmap.live_unmute)
+                            setVisible(R.id.ivAudioState, true)
+                        }else{
+                            setVisible(R.id.ivAudioState, false)
+                        }
+
+                    }
+                }
+            }
+        }
+
+    }
+}

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

@@ -0,0 +1,48 @@
+package com.swago.room.audio
+
+import com.swago.baseswago.model.live.audio.AudioSeatModel
+import com.swago.baseswago.model.live.audio.IMAudioModel
+import io.agora.rtc.IRtcEngineEventHandler
+
+interface IAudioRoomListener {
+
+    /**
+     * 锁麦和解锁
+     */
+    fun lockOrUnlockSeat(imAudioModel: IMAudioModel)
+
+
+    /**
+     * 闭麦和开麦
+     */
+    fun openSeatMic()
+    fun muteSeatMic()
+
+
+    /**
+     * 上麦和下麦
+     */
+    fun onSeatMic()
+    fun downSeatMic()
+
+
+    /**
+     * 数据更新
+     */
+    fun updateData(audioSeatModel: AudioSeatModel)
+
+    /**
+     * 积分变更
+     */
+    fun changeJiFen(imAudioModel: IMAudioModel)
+
+    /**
+     * 积分清零
+     */
+    fun clearJiFen()
+
+    /**
+     * 用户说话回调
+     */
+    fun onAudioVolumeIndication(speakers: Array<out IRtcEngineEventHandler.AudioVolumeInfo>?){}
+}

+ 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(false)
+        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.llAgree.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() {
+    }
+}

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

@@ -1,13 +1,17 @@
 package com.swago.room.base
 
+import android.Manifest
 import android.graphics.Rect
 import android.text.TextUtils
 import android.view.View
 import android.view.ViewGroup
+import android.widget.ImageView
+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
@@ -17,26 +21,38 @@ import com.liulishuo.okdownload.DownloadTask
 import com.liulishuo.okdownload.core.breakpoint.BreakpointInfo
 import com.liulishuo.okdownload.core.cause.EndCause
 import com.liulishuo.okdownload.core.cause.ResumeFailedCause
+import com.permissionx.guolindev.PermissionX
 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.MediumTextView
+import com.swago.baseswago.cusview.SwagoImageView
+import com.swago.baseswago.dialog.ChoiceDialogFragment
 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
@@ -57,6 +73,7 @@ import com.swago.room.vm.RoomVm
 import com.swago.room.widget.AnchorFooterView
 import com.swago.room.widget.ComHeaderView
 import com.swago.room.widget.UserFooterView
+import io.agora.rtc.IRtcEngineEventHandler
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.delay
@@ -70,8 +87,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 +111,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 +145,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 +153,8 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
         giftVm.getGiftList()
         //获取直播间配置
         roomVm.getRoomConfig()
+        //初始话语音列表
+        initAudioRvList()
         //飘条
         waftManager.init()
         waftManager.waftViewList.add(binding.waftView)
@@ -145,7 +165,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 +188,98 @@ 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 (AudioRoomManager.isOnMic){
+                                Toast.makeText(AppContext.getContext(), "您已经在麦位上", Toast.LENGTH_SHORT)
+                                    .show()
+                            }else{
+                                ChoiceDialogFragment.newInstance("您想要上麦么?").apply {
+                                    this.sureFun = {
+                                        PermissionX.init(it)
+                                            .permissions(
+                                                Manifest.permission.RECORD_AUDIO,
+                                                Manifest.permission.CAMERA,
+                                                Manifest.permission.READ_EXTERNAL_STORAGE)
+                                            .request { allGranted, grantedList, deniedList ->
+                                                if (allGranted) {
+                                                    roomVm.userApplyOnMic(audioSeatModel.maiIndex)
+                                                } else {
+                                                    Toast.makeText(
+                                                        AppContext.getContext(),
+                                                        "These permissions are denied: $deniedList",
+                                                        Toast.LENGTH_LONG
+                                                    ).show()
+                                                }
+                                            }
+                                    }
+                                }.show(childFragmentManager,"ChoiceDialogFragment")
+                            }
+                        }
+                    }
+                } else {
+                    //麦位有人
+                    if (SwagoRoomManager.roleType == RoleType.anchor) {
+                        //主播点击麦位
+                        AudioActionDialog.newInstance(audioSeatModel)
+                            .show(childFragmentManager, "AudioActionDialog")
+                    } else {
+                        //用户点击了有人的麦位
+                        //如果点击的麦位不是自己弹资料卡  如果是自己弹操作弹窗
+                        SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
+                            audioSeatModel.user_id?.let {
+                                UserInfo.getUserInfo()?.let { userInfoModel ->
+                                    if (userInfoModel.id == it){
+                                        AudioActionDialog.newInstance(audioSeatModel)
+                                            .show(childFragmentManager, "AudioActionDialog")
+                                    }else{
+                                        PersonDataDFragment.newInstance(it,
+                                            SwagoRoomManager.roleType==RoleType.anchor,true,iRoomInfo.getRoomId()).apply {
+                                            this.openGiftDialog = { nickName, userId ->
+                                                openGiftDialog(nickName, userId)
+                                            }
+                                            this.sendMsgInRoom = {
+                                                if (isForbid) {
+                                                    Toast.makeText(
+                                                        AppContext.getContext(),
+                                                        AppContext.getContext().resources.getString(
+                                                            R.string.you_are_been_forbid
+                                                        ),
+                                                        Toast.LENGTH_SHORT
+                                                    ).show()
+                                                } else {
+                                                    openSendMessageDialog("@${it} ")
+                                                }
+                                            }
+                                        }.show(childFragmentManager,"PersonDataDFragment")
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     var listener = KeyboardUtils.OnSoftInputChangedListener {
         if (it == 0) {
             setChatRvPop(false, it)
@@ -188,14 +300,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 +315,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 +328,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 +352,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 +374,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 +391,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 +402,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 +421,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 +498,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 +535,12 @@ 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)
+            binding.rvAudio.visibility = View.VISIBLE
+        }else{
+            binding.rvAudio.visibility = View.GONE
+        }
         if (iRoomInfo.getRoomSystemMsg().isNotEmpty()) {
             val roomSystemMsgBean = RoomSystemMsgBean()
             roomSystemMsgBean.broadcast_notice_content = iRoomInfo.getRoomSystemMsg()
@@ -416,14 +549,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 +567,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 +584,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
@@ -464,9 +597,17 @@ abstract class BaseComFragment<T : FragmentBaseComBinding> : BaseXFragment<T>(),
         }
     }
 
+    override fun changeRoom(iRoomInfo: IRoomInfo) {
+       binding?.rvAudio?.visibility = View.GONE
+    }
+
     override fun leaveRoom(iRoomInfo: IRoomInfo) {
         dataChatList.clear()
         chatAdapter.notifyDataSetChanged()
+        if (iRoomInfo.getRoomType() == RoomType.AUDIO.type){
+            val data = ArrayList<AudioSeatModel>()
+            audioSeatAdapter.setNewData(data)
+        }
 
     }
 
@@ -605,4 +746,175 @@ 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 openSeatMic() {
+
+    }
+
+    override fun muteSeatMic() {
+
+    }
+
+    override fun onSeatMic() {
+
+    }
+    override fun downSeatMic() {
+
+    }
+    override fun changeJiFen(imAudioModel: IMAudioModel) {
+        if (audioSeatAdapter.data.size > imAudioModel.maiIndex - 1) {
+            audioSeatAdapter.data[imAudioModel.maiIndex-1].voice_jifen = imAudioModel.voice_jifen
+            val view = audioSeatAdapter.getViewByPosition(
+                binding.rvAudio,
+                imAudioModel.maiIndex - 1,
+                R.id.tvIntegration
+            )
+            if (view != null && view is MediumTextView) {
+                view.text = imAudioModel.voice_jifen
+            }
+        }
+    }
+    override fun clearJiFen() {
+        audioSeatAdapter.data.forEach {
+            it.voice_jifen = "0"
+        }
+        audioSeatAdapter.notifyDataSetChanged()
+    }
+    override fun updateData(audioSeatModel: AudioSeatModel) {
+        if (audioSeatAdapter.data.size > audioSeatModel.maiIndex - 1) {
+            audioSeatAdapter.data[audioSeatModel.maiIndex-1] = audioSeatModel
+            audioSeatAdapter.notifyItemChanged(audioSeatModel.maiIndex-1)
+        }
+    }
+
+    override fun onAudioVolumeIndication(speakers: Array<out IRtcEngineEventHandler.AudioVolumeInfo>?) {
+        super.onAudioVolumeIndication(speakers)
+        speakers?.let { data ->
+            audioSeatAdapter.data.forEachIndexed { index, audioSeatModel ->
+                if (speakers.isEmpty()){
+                    if (audioSeatModel.showVoice == 1){
+                        audioSeatModel.showVoice = 0
+                        val view = audioSeatAdapter.getViewByPosition(
+                            binding.rvAudio,
+                            audioSeatModel.maiIndex - 1,
+                            R.id.ivAudioState
+                        )
+                        if (view != null) {
+                            if (audioSeatModel.voice_status==1){
+                                view.visibility = View.GONE
+                            }else{
+                                view.visibility = View.VISIBLE
+                            }
+                        }
+                    }
+                }else{
+                    speakers.forEach {
+                        if (it.uid == 0){
+                            UserInfo.getUserInfo()?.let { userInfo ->
+                                if (userInfo.id == audioSeatModel.user_id && it.vad==1){
+                                    audioSeatModel.showVoice = 1
+                                    val view = audioSeatAdapter.getViewByPosition(
+                                        binding.rvAudio,
+                                        audioSeatModel.maiIndex - 1,
+                                        R.id.ivAudioState
+                                    )
+                                    if (view != null && view is ImageView) {
+                                        view.visibility = View.VISIBLE
+                                        view.setImageResource(R.mipmap.live_unmute)
+                                    }
+                                }
+                            }
+                        }else{
+                            val view = audioSeatAdapter.getViewByPosition(
+                                binding.rvAudio,
+                                audioSeatModel.maiIndex - 1,
+                                R.id.ivAudioState
+                            )
+                            if (it.uid.toString() == audioSeatModel.user_id){
+                                audioSeatModel.showVoice = 1
+                                if (view != null && view is ImageView) {
+                                    view.visibility = View.VISIBLE
+                                    view.setImageResource(R.mipmap.live_unmute)
+                                }
+                            }else{
+                                audioSeatModel.showVoice = 0
+                                if (view != null && view is ImageView ) {
+                                    if (audioSeatModel.voice_status==1){
+                                        view.visibility = View.GONE
+                                    }else{
+                                        view.visibility = View.VISIBLE
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+    }
+
 }

+ 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)
+}

+ 18 - 3
room/src/main/java/com/swago/room/lianmai/LianMaiView.kt

@@ -95,7 +95,12 @@ class LianMaiView : ConstraintLayout, IRoomActiveListener, ILianMaiListener {
                             UserInfo.getUserInfo()?.let { userInfo ->
                                 if (SwagoRoomManager.roleType == RoleType.user && userInfo.id == lianMaiIMModel.senderId) {
                                     //正在连麦的用户
-                                    AgoraManager.setClientRole(RoleType.anchor,true, isNeedVoice = true)
+                                    AgoraManager.setVideoAudio(
+                                        pullVideo = true,
+                                        pullAudio = true,
+                                        pushVideo = false,
+                                        pushAudio = true
+                                    )
                                     AgoraManager.renewToken(token)
                                 }
                             }
@@ -113,7 +118,12 @@ class LianMaiView : ConstraintLayout, IRoomActiveListener, ILianMaiListener {
                 UserInfo.getUserInfo()?.let {
                     if (SwagoRoomManager.roleType == RoleType.user && it.id == lianMaiIMModel.senderId) {
                         //正在连麦用户
-                        AgoraManager.setClientRole(RoleType.user,true, isNeedVoice = true)
+                        AgoraManager.setVideoAudio(
+                            pullVideo = true,
+                            pullAudio = true,
+                            pushVideo = false,
+                            pushAudio = false
+                        )
                         lianMaiIMModel.linkMicToken?.let {
                             AgoraManager.renewToken(it)
                         }
@@ -129,7 +139,12 @@ class LianMaiView : ConstraintLayout, IRoomActiveListener, ILianMaiListener {
         visibility = View.INVISIBLE
         if (!isAnchor) {
             //如果不是主播还是把角色切换成用户
-            AgoraManager.setClientRole(RoleType.user, isNeedVideo = true, isNeedVoice = true)
+            AgoraManager.setVideoAudio(
+                pullVideo = true,
+                pullAudio = true,
+                pushVideo = false,
+                pushAudio = false
+            )
         }
     }
 }

+ 185 - 34
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,7 +55,9 @@ 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 io.agora.rtc.IRtcEngineEventHandler
 import jp.wasabeef.glide.transformations.BlurTransformation
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.delay
@@ -63,7 +70,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>()
@@ -90,22 +97,25 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
 
     private var ivClose: ImageView? = null
     private var ivCover: ImageView? = null
+    private var ivAudioBg: ImageView? = null
     private var userShowAnchorCloseView: UserShowAnchorCloseView? = null
     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)
+        ivAudioBg = userRoomView.findViewById(R.id.ivAudioBg)
         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 +128,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)
@@ -131,27 +142,55 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
         window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
 
         AgoraManager.setVideoConfiguration()
-        AgoraManager.setClientRole(RoleType.user, isNeedVideo = true, isNeedVoice = true)
+        AgoraManager.setVideoAudio(
+            pullVideo = true,
+            pullAudio = true,
+            pushVideo = false,
+            pushAudio = false
+        )
+        AgoraManager.enableAudioVolumeIndication()
 
         ivClose?.setOnClickListener(object : NoDoubleClickListener() {
             override fun onClick() {
-                if (LianMaiManager.lianMaiState == 1){
-                    ChoiceDialogFragment.newInstance(AppContext.getContext().resources.getString(R.string.lian_mai_ing_sure_close),AppContext.getContext().resources.getString(
-                        R.string.tips)).apply {
-                        this.sureFun = {
-                            lianMaiVm.closeLianMai(){
-                                lianMaiView?.closeLianMai(false)
+                if (SwagoRoomManager.iRoomInfo == null){
+                    SwagoRoomManager.closeRoom()
+                }else{
+                    SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
+                        if (iRoomInfo.getRoomType() == RoomType.VIDEO.type){
+                            if (LianMaiManager.lianMaiState == 1){
+                                ChoiceDialogFragment.newInstance(AppContext.getContext().resources.getString(R.string.lian_mai_ing_sure_close),AppContext.getContext().resources.getString(
+                                    R.string.tips)).apply {
+                                    this.sureFun = {
+                                        lianMaiVm.closeLianMai(){
+                                            lianMaiView?.closeLianMai(false)
+                                            SwagoRoomManager.closeRoom()
+                                        }
+                                    }
+                                }.show(supportFragmentManager,"ChoiceDialogFragment")
+                            }else if(LianMaiManager.lianMaiState == 3 || LianMaiManager.lianMaiState == 4){
+                                lianMaiVm.cancelApplyLianMai(LianMaiManager.lianMaiId){
+                                    SwagoRoomManager.closeRoom()
+                                }
+                            }else{
+                                SwagoRoomManager.closeRoom()
+                            }
+                        }else if (iRoomInfo.getRoomType() == RoomType.AUDIO.type){
+                            if (AudioRoomManager.isOnMic){
+                                UserInfo.getUserInfo()?.let { userInfoModel ->
+                                    roomVm.downMicByAnchor(AudioRoomManager.maiIndex,userInfoModel.id){
+                                        SwagoRoomManager.closeRoom()
+                                    }
+                                }
+
+                            }else{
                                 SwagoRoomManager.closeRoom()
                             }
+                        }else {
+                            SwagoRoomManager.closeRoom()
                         }
-                    }.show(supportFragmentManager,"ChoiceDialogFragment")
-                }else if(LianMaiManager.lianMaiState == 3 || LianMaiManager.lianMaiState == 4){
-                    lianMaiVm.cancelApplyLianMai(LianMaiManager.lianMaiId){
-                        SwagoRoomManager.closeRoom()
                     }
-                }else{
-                    SwagoRoomManager.closeRoom()
                 }
+
             }
         })
 
@@ -211,6 +250,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) {
@@ -223,6 +286,7 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
         }
         PKStateManager.resetData()
         LianMaiManager.clearData()
+        AudioRoomManager.resetData()
     }
 
     override fun joinedRoom(iRoomInfo: IRoomInfo) {
@@ -232,27 +296,59 @@ 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 -> {
+                ivAudioBg?.visibility = View.GONE
+                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 -> {
+                ivAudioBg?.visibility = View.VISIBLE
+                UserInfo.getUserInfo()?.let { userInfoModel ->
+                    lifecycleScope.launch(Dispatchers.Main) {
+                        AgoraManager.joinChannel(
+                            iRoomInfo.getChannelName(),
+                            userInfoModel.id.toInt(),
+                            iRoomInfo.getAgoraToken()
                         )
                     }
                 }
             }
+            RoomType.NULL.type -> {}
+        }
+    }
+
+    override fun receiveStopLive() {
+        AudioRoomManager.resetData()
+        SwagoRoomManager.iRoomInfo?.let {
+            if (it.getRoomType() == RoomType.AUDIO.type){
+                AgoraManager.setVideoAudio(
+                    pullVideo = false,
+                    pullAudio = false,
+                    pushVideo = false,
+                    pushAudio = false
+                )
+            }
         }
     }
 
@@ -261,6 +357,7 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
 
     override fun closeRoomed() {
         LianMaiManager.clearData()
+        AudioRoomManager.resetData()
         AgoraManager.closedRoom()
     }
 
@@ -269,6 +366,7 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
     }
 
     override fun onDestroy() {
+        AudioRoomManager.removeListener(this)
         LianMaiManager.removeLianMaiListener(this)
         PKStateManager.removePKListener(this)
         super.onDestroy()
@@ -287,7 +385,29 @@ 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()
+            }
+        }
+
+    }
+
+    override fun onError(err: Int) {
+
+    }
+
+    override fun onAudioVolumeIndication(
+        speakers: Array<out IRtcEngineEventHandler.AudioVolumeInfo>?,
+        totalVolume: Int
+    ) {
+        lifecycleScope.launch(Dispatchers.Main) {
+            SwagoRoomManager.iRoomInfo?.let {
+                if (it.getRoomType() == RoomType.AUDIO.type) {
+                    AudioRoomManager.dispatchOnAudioVolumeIndication(speakers)
+                }
+            }
+        }
     }
 
     fun gotoTargetRoom(anchorId: String) {
@@ -383,5 +503,36 @@ class UserRoomActivity : AbsUserActivity<ActivityAbsRoomUserBinding, UserRoomMod
         }
     }
 
+    override fun lockOrUnlockSeat(imAudioModel: IMAudioModel) {
+    }
+
+    override fun openSeatMic() {
+        AgoraManager.setMute(false)
+    }
+
+    override fun muteSeatMic() {
+        AgoraManager.setMute(true)
+    }
+
+    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(imAudioModel: IMAudioModel) {
+    }
+
+    override fun clearJiFen() {
+
+    }
 
 }

+ 6 - 5
room/src/main/java/com/swago/room/user/UserRoomFragment.kt

@@ -3,16 +3,12 @@ package com.swago.room.user
 import android.view.View
 import android.widget.Toast
 import androidx.constraintlayout.widget.ConstraintLayout
-import androidx.fragment.app.activityViewModels
-import com.bumptech.glide.Glide
 import com.google.gson.Gson
 import com.swago.baseswago.PersonDataDFragment
 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.pk.ProcessPKModel
 import com.swago.baseswago.model.live.pk.PunishPKModel
 import com.swago.baseswago.model.live.pk.StartPKModel
@@ -22,6 +18,7 @@ import com.swago.baseswago.util.NoDoubleClickListener
 import com.swago.baseswago.util.SpUtil
 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
@@ -33,7 +30,6 @@ import com.swago.room.hongbao.RedEnvelopeDialog
 import com.swago.room.inter.IFooter
 import com.swago.room.inter.IHeader
 import com.swago.room.lianmai.UserLianMaiDialog
-import com.swago.room.vm.RoomOtherVm
 import com.swago.room.widget.ComHeaderView
 import com.swago.room.widget.UserFooterView
 
@@ -173,6 +169,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()?:"")
@@ -231,6 +231,7 @@ class UserRoomFragment : BaseComFragment<FragmentBaseComBinding>() {
     }
 
     override fun changeRoom(iRoomInfo: IRoomInfo) {
+        super.changeRoom(iRoomInfo)
     }
 
     override fun leaveRoom(iRoomInfo: IRoomInfo) {

+ 192 - 1
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,8 +14,13 @@ 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.jifen_change
+import com.swago.baseswago.im.ImConstant.jifen_clear
+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.open_close_mic
 import com.swago.baseswago.im.ImConstant.red_envelope
 import com.swago.baseswago.im.ImConstant.red_envelope_broadcast
 import com.swago.baseswago.im.ImConstant.remove_room
@@ -22,8 +28,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 +41,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 +99,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 +301,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,9 +323,179 @@ 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)
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+
+        //用户同意主播邀请
+        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()
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        //麦位数据更新
+        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.voiceUserId,
+                            it.maiSeatInfo.maiIndex,
+                            0
+                        )
+                        AudioRoomManager.dispatchUpdateData(audioSeatModel)
+                        UserInfo.getUserInfo()?.let { userInfoModel ->
+                            if (userInfoModel.id == it.maiSeatInfo.userId) {
+                                AudioRoomManager.isOnMic = true
+                                AudioRoomManager.maiIndex = it.maiSeatInfo.maiIndex
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        //用户被主播下麦
+        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.resetData()
+                                AudioRoomManager.dispatchDownSeatMic()
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        //闭麦和开麦
+        imGroupNewMsgListener.handleMsgType<CusNewMsgBean<IMAudioModel>>(
+            open_close_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) {
+                                if (it.action == 1) {
+                                    AudioRoomManager.dispatchOpenSeatMic()
+                                } else if (it.action == 2) {
+                                    AudioRoomManager.dispatchMuteSeatMic()
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+
+        /**
+         * 积分清零
+         */
+        imGroupNewMsgListener.handleMsgType<CusNewMsgBean<IMAudioModel>>(
+            jifen_clear
+        ) {
+            SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
+                it.data?.let {
+                    if (it.roomId == iRoomInfo.getRoomId() && it.roomSessionId == iRoomInfo.getBroadcastId()) {
+                        AudioRoomManager.dispatchClearJiFen()
+                    }
+                }
+            }
+        }
+
+        /**
+         * 积分变更
+         */
+        imGroupNewMsgListener.handleMsgType<CusNewMsgBean<IMAudioModel>>(
+            jifen_change
+        ) {
+            SwagoRoomManager.iRoomInfo?.let { iRoomInfo ->
+                it.data?.let {
+                    if (it.roomId == iRoomInfo.getRoomId() && it.roomSessionId == iRoomInfo.getBroadcastId()) {
+                        AudioRoomManager.dispatchChangeJiFen(it)
+                    }
+                }
+            }
+        }
+
 
     }
 
+
     override fun changeRoom(iRoomInfo: IRoomInfo) {
 
     }

+ 141 - 2
room/src/main/java/com/swago/room/vm/RoomVm.kt

@@ -10,11 +10,14 @@ import com.swago.baseswago.baseroom.viewmodel.AbsRoomVm
 import com.swago.baseswago.http.SwagoException
 import com.swago.baseswago.inter.ApiManager
 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.AudioInviteUserModel
+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,140 @@ 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,callback: (() -> Unit)?=null){
+        requestData {
+            SwagoRoomManager.iRoomInfo?.let {
+                ApiManager.roomApi.downMicByAnchor(it.getRoomId(),it.getBroadcastId(),maiIndex,usrId)
+                callback?.invoke()
+                Toast.makeText(AppContext.getContext(), AppContext.getContext().resources.getString(R.string.down_mic_success), Toast.LENGTH_SHORT).show()
+            }
+        }
+    }
+
+    /**
+     * 闭麦和开麦
+     * 1闭麦2开麦
+     */
+    fun operateMicByAnchor(maiIndex: Int,usrId:String,type:Int){
+        requestData {
+            SwagoRoomManager.iRoomInfo?.let {
+                ApiManager.roomApi.operateMicByAnchor(it.getRoomId(),it.getBroadcastId(),maiIndex,usrId,type)
+            }
+        }
+    }
+
+    /**
+     * 用户主动上麦
+     */
+    fun userApplyOnMic(maiIndex: Int){
+        requestData {
+            SwagoRoomManager.iRoomInfo?.let {
+                ApiManager.roomApi.userApplyOnMic(it.getRoomId(),it.getBroadcastId(),maiIndex)
+                AudioRoomManager.dispatchOnSeatMic()
+            }
+        }
+    }
+
+    /**
+     * 积分清零
+     */
+    fun clearJiFen(){
+        requestData {
+            SwagoRoomManager.iRoomInfo?.let {
+                ApiManager.roomApi.clearJiFen(it.getRoomId(),it.getBroadcastId())
+            }
+        }
+    }
+
+    /**
+     * 获取可以被邀请上麦的用户列表
+     */
+    val audioInvitedUserListLiveData by lazy {
+        MutableLiveData<List<AudioInviteUserModel>>()
+    }
+    fun getCanAudioInviteUserList(){
+        requestData2(false) {
+            requestData {
+                SwagoRoomManager.iRoomInfo?.let {
+                    val data = ApiManager.roomApi.getCanAudioInviteUserList(it.getRoomId(),it.getBroadcastId())
+                    audioInvitedUserListLiveData.value = data
+                }
+            }
+
+            requestError {
+                audioInvitedUserListLiveData.value = null
+            }
+        }
+    }
+
 }

+ 16 - 1
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
@@ -34,8 +35,9 @@ class AnchorFooterView : ConstraintLayout, IFooter, IRoomActiveListener {
     var switchCameraFun:(()->Unit)? = null
     var openPKFun:(()->Unit)? = null
     var openLianMaiFun:(()->Unit)? = null
+    var clearJiFen:(()->Unit)? = null
 
-    private var isMute = false
+    var isMute = false
 
     constructor(context: Context) : this(context, null)
     constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
@@ -121,6 +123,12 @@ class AnchorFooterView : ConstraintLayout, IFooter, IRoomActiveListener {
                 isMute = !isMute
             }
         })
+
+        binding.ivClearJifen.setOnClickListener(object : NoDoubleClickListener() {
+            override fun onClick() {
+                clearJiFen?.invoke()
+            }
+        })
     }
 
     override fun getFooterView(): View {
@@ -141,6 +149,13 @@ 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
+            binding.ivMute.visibility = View.GONE
+            binding.ivClearJifen.visibility = View.VISIBLE
+        }
         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)
+    }
+
+}

+ 5 - 0
room/src/main/java/com/swago/room/widget/UserFooterView.kt

@@ -15,6 +15,7 @@ import com.swago.baseswago.util.NoDoubleClickListener
 import com.swago.baseswago.util.UserInfo
 import com.swago.room.databinding.LayoutUserFooterViewBinding
 import com.swago.room.databinding.LayoutUserHeaderViewBinding
+import com.swago.room.enum.RoomType
 import com.swago.room.inter.IFooter
 import com.swago.room.pk.PKStateManager
 
@@ -107,6 +108,10 @@ class UserFooterView : ConstraintLayout, IFooter,IRoomActiveListener {
 
     override fun joinedRoom(iRoomInfo: IRoomInfo) {
         visibility = View.VISIBLE
+        if (iRoomInfo.getRoomType() == RoomType.AUDIO.type){
+            binding.ivLianMai.visibility = View.GONE
+            binding.ivShare.visibility = View.GONE
+        }
     }
 
     override fun endRoom(iRoomInfo: IRoomInfo?) {

+ 61 - 7
room/src/main/res/layout/activity_anchor_room.xml

@@ -14,11 +14,6 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
-        <SurfaceView
-            android:id="@+id/localSurfaceView"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" />
-
     </FrameLayout>
 
 
@@ -100,7 +95,8 @@
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintEnd_toStartOf="@+id/ivBeauty"
             android:layout_marginStart="20dp"
-            android:layout_marginBottom="20dp"
+            android:layout_marginEnd="20dp"
+            android:layout_marginBottom="73dp"
             android:layout_width="0dp"
             android:layout_height="44dp"/>
 
@@ -110,14 +106,72 @@
             app:layout_constraintTop_toTopOf="@+id/tvStartLive"
             app:layout_constraintBottom_toBottomOf="@+id/tvStartLive"
             app:layout_constraintEnd_toEndOf="parent"
-            android:layout_marginStart="20dp"
             android:layout_marginEnd="24dp"
             android:background="@drawable/shape_20000000_41"
             android:padding="10dp"
+            android:visibility="visible"
             android:src="@mipmap/icon_beauty"
             android:layout_width="44dp"
             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>
 
 

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

@@ -0,0 +1,197 @@
+<?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="wrap_content">
+
+    <LinearLayout
+        android:id="@+id/llYaoQingShangMic"
+        android:layout_marginTop="10dp"
+        android:layout_marginBottom="15dp"
+        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="@string/on_mic"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/llDownSeatMic"
+        android:layout_marginTop="10dp"
+        android:layout_marginBottom="15dp"
+        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="@string/down_mic"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/llLock"
+        android:layout_marginTop="10dp"
+        android:layout_marginBottom="15dp"
+        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="@string/lock_mic"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/llUnlock"
+        android:layout_marginTop="10dp"
+        android:layout_marginBottom="15dp"
+        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="@string/unlock_mic"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+
+    <LinearLayout
+        android:id="@+id/llMuteMic"
+        android:layout_marginTop="10dp"
+        android:layout_marginBottom="15dp"
+        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="@string/close_mic"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/llUnMuteMic"
+        android:layout_marginTop="10dp"
+        android:layout_marginBottom="15dp"
+        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="@string/open_mic"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 14 - 0
room/src/main/res/layout/dialog_audio_can_invite.xml

@@ -0,0 +1,14 @@
+<?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"
+    android:layout_height="match_parent"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <com.swago.baseswago.cusview.SwagoRecyclerView
+        app:layout_constraintTop_toTopOf="parent"
+        android:id="@+id/swagoRv"
+        android:background="@drawable/shape_161722_top_20"
+        android:layout_width="match_parent"
+        android:layout_height="250dp"/>
+
+</androidx.constraintlayout.widget.ConstraintLayout>

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

@@ -0,0 +1,90 @@
+<?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">
+
+    <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
+            android:id="@+id/llAgree"
+            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>
+
+    <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>

+ 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"

+ 59 - 0
room/src/main/res/layout/item_audio_invite.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"
+    android:layout_width="match_parent"
+    android:layout_height="64dp"
+    xmlns:tools="http://schemas.android.com/tools"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <de.hdodenhof.circleimageview.CircleImageView
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        android:layout_marginStart="16dp"
+        android:id="@+id/ivAvatar"
+        android:layout_width="50dp"
+        android:layout_height="50dp"/>
+
+    <com.swago.baseswago.cusview.MediumTextView
+        android:id="@+id/tvName"
+        app:layout_constraintStart_toEndOf="@+id/ivAvatar"
+        android:layout_marginStart="8dp"
+        android:layout_marginTop="4dp"
+        android:textSize="18dp"
+        android:textColor="#fff"
+        tools:text="Chridfsfdsfdfs"
+        android:maxLines="1"
+        android:maxWidth="150dp"
+        app:layout_constraintTop_toTopOf="@+id/ivAvatar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <com.swago.baseswago.cusview.SwagoLevelView
+        android:id="@+id/tvLevel"
+        android:layout_marginStart="8dp"
+        app:layout_constraintStart_toEndOf="@+id/ivAvatar"
+        app:layout_constraintBottom_toBottomOf="@+id/ivAvatar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+
+    <TextView
+        android:id="@+id/tvInvite"
+        android:gravity="center"
+        android:text="@string/invite_on_mic"
+        android:paddingStart="15dp"
+        android:paddingEnd="15dp"
+        android:paddingTop="10dp"
+        android:paddingBottom="10dp"
+        android:layout_marginEnd="10dp"
+        android:textSize="10dp"
+        android:textColor="#fff"
+        android:background="@drawable/shape_ff56b7_37"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>

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

@@ -0,0 +1,62 @@
+<?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="15dp"
+        android:layout_marginEnd="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>

+ 13 - 0
room/src/main/res/layout/layout_anchor_footer_view.xml

@@ -86,6 +86,19 @@
         android:layout_width="10dp"
         android:layout_height="10dp"/>
 
+    <ImageView
+        android:id="@+id/ivClearJifen"
+        android:layout_marginEnd="10dp"
+        android:background="@drawable/shape_80000000_20"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/ivMute"
+        android:src="@mipmap/ic_clear_jifen"
+        android:padding="7dp"
+        android:visibility="gone"
+        tools:visibility="visible"
+        android:layout_width="40dp"
+        android:layout_height="40dp"/>
+
     <ImageView
         android:id="@+id/ivMute"
         android:layout_marginEnd="10dp"

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

@@ -7,6 +7,15 @@
     android:id="@+id/rootUserView"
     xmlns:app="http://schemas.android.com/apk/res-auto">
 
+    <ImageView
+        android:id="@+id/ivAudioBg"
+        android:visibility="gone"
+        android:background="@mipmap/bg_room"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"/>
+
     <FrameLayout
         android:id="@+id/flRoot"
         android:layoutDirection="ltr"
@@ -22,7 +31,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_clear_jifen.png


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