diff --git a/app/src/main/java/com/shayu/phonelive/AppContext.java b/app/src/main/java/com/shayu/phonelive/AppContext.java index 499fa2607..8d2e7884e 100644 --- a/app/src/main/java/com/shayu/phonelive/AppContext.java +++ b/app/src/main/java/com/shayu/phonelive/AppContext.java @@ -23,6 +23,7 @@ import com.alibaba.fastjson.JSONObject; import com.blankj.utilcode.util.Utils; import com.facebook.appevents.AppEventsLogger; import com.fm.openinstall.OpenInstall; +import com.google.gson.Gson; import com.shayu.phonelive.utils.LogUtils; import com.tencent.imsdk.v2.V2TIMGroupMemberInfo; import com.tencent.imsdk.v2.V2TIMManager; @@ -36,12 +37,14 @@ import com.yunbao.common.CommonAppContext; import com.yunbao.common.Constants; import com.yunbao.common.bean.AnchorStartLiveBean; import com.yunbao.common.bean.CrashSaveBean; +import com.yunbao.common.event.SudGameSocketImEvent; import com.yunbao.common.manager.imrongcloud.InstructorSendReward; import com.yunbao.common.manager.imrongcloud.InstructorSendRewardProvider; import com.yunbao.common.manager.imrongcloud.MessageIMManager; import com.yunbao.common.manager.imrongcloud.RecommendLiveRoom; import com.yunbao.common.manager.imrongcloud.RongcloudIMManager; import com.yunbao.common.utils.AppManager; +import com.yunbao.common.utils.Bus; import com.yunbao.common.utils.GoogleUtils; import com.yunbao.common.utils.L; import com.yunbao.common.utils.SpUtil; @@ -210,6 +213,11 @@ public class AppContext extends CommonAppContext { SocketReceiveBean received = JSON.parseObject(content.getContent(), SocketReceiveBean.class); JSONObject map = received.getMsg().getJSONObject(0); sendStartAnchorLive(map); + } else if (message.getTargetId().contains("v")) { + String contentJson = ((TextMessage) message.getContent()).getContent(); + Log.e("wewe", contentJson); + SudGameSocketImEvent sudGameSocketImEvent = new Gson().fromJson(contentJson, SudGameSocketImEvent.class); + Bus.get().post(sudGameSocketImEvent); } //主播页面 if (TextUtils.isEmpty(PortraitLiveManager.liveID) && SocketRyClient.mSocketHandler != null) { diff --git a/common/src/main/assets/chat_message_bg.png b/common/src/main/assets/chat_message_bg.png new file mode 100644 index 000000000..4138e7e12 Binary files /dev/null and b/common/src/main/assets/chat_message_bg.png differ diff --git a/common/src/main/java/com/yunbao/common/activity/SudGameActivity.java b/common/src/main/java/com/yunbao/common/activity/SudGameActivity.java index 93544495f..f059a0103 100644 --- a/common/src/main/java/com/yunbao/common/activity/SudGameActivity.java +++ b/common/src/main/java/com/yunbao/common/activity/SudGameActivity.java @@ -3,29 +3,40 @@ package com.yunbao.common.activity; import android.app.Activity; import android.view.View; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.TextView; import androidx.lifecycle.Observer; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import com.google.gson.Gson; import com.lxj.xpopup.XPopup; -import com.makeramen.roundedimageview.RoundedImageView; import com.yunbao.common.R; +import com.yunbao.common.adapter.SudGameChatAdapter; +import com.yunbao.common.adapter.SudGameUserListAdapter; import com.yunbao.common.bean.CheckRemainingBalance; import com.yunbao.common.bean.CreateSudRoomModel; import com.yunbao.common.bean.CustomSidebarChildModel; import com.yunbao.common.bean.CustomSidebarInfoModel; +import com.yunbao.common.bean.SudGameChatImModel; +import com.yunbao.common.dialog.SudGameInputPopupWindow; import com.yunbao.common.event.CheckRemainingBalanceEvent; +import com.yunbao.common.event.SudGameSocketImEvent; import com.yunbao.common.glide.ImgLoader; import com.yunbao.common.http.base.HttpCallback; import com.yunbao.common.http.live.LiveNetManager; import com.yunbao.common.manager.IMLoginManager; +import com.yunbao.common.manager.imrongcloud.GameMicManager; import com.yunbao.common.sud.QuickStartGameViewModel; import com.yunbao.common.sud.model.GameConfigModel; +import com.yunbao.common.sud.model.GameViewInfoModel; import com.yunbao.common.sud.state.SudMGPMGState; import com.yunbao.common.utils.Bus; +import com.yunbao.common.utils.DpUtil; import com.yunbao.common.utils.ToastUtil; import com.yunbao.common.views.LiveSudGameHistoryPopup; +import com.yunbao.common.views.TopGradual; import com.yunbao.common.views.weight.ViewClicksAntiShake; import org.greenrobot.eventbus.Subscribe; @@ -35,15 +46,28 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; -public class SudGameActivity extends AbsActivity { +import cn.rongcloud.rtc.api.RCRTCEngine; +import cn.rongcloud.rtc.api.RCRTCRemoteUser; +import cn.rongcloud.rtc.api.RCRTCRoom; +import cn.rongcloud.rtc.api.stream.RCRTCInputStream; +import cn.rongcloud.rtc.base.RTCErrorCode; + +public class SudGameActivity extends AbsActivity implements GameMicManager.MeetingCallback { private FrameLayout gameContainer; private long mInteractionID; private String mLiveUid; private final QuickStartGameViewModel gameViewModel = new QuickStartGameViewModel(); // 创建ViewModel private CreateSudRoomModel mCreateSudRoomModel; - private TextView gameTitle, roomName, roomNumber; - private RoundedImageView mAvatar; + private TextView roomName, roomNumber; + private GameMicManager gameMicManager; + private ImageView gameCloseWheat, gameSeat; + private boolean disable = true, publishDefault = false; + + private RecyclerView chatList, userList; + private SudGameChatAdapter mLiveChatAdapter; + private SudGameUserListAdapter sudGameUserListAdapter; + @Override protected int getLayoutId() { return R.layout.activity_sud_game; @@ -56,7 +80,9 @@ public class SudGameActivity extends AbsActivity { initView(); initDate(); } + private List customSidebarChildModels = new ArrayList<>(); + private void initDate() { LiveNetManager.get(mContext) .getCustomSidebarInfo("1", new HttpCallback>() { @@ -75,10 +101,21 @@ public class SudGameActivity extends AbsActivity { } }); + gameMicManager = new GameMicManager(); + gameMicManager.attachView(this); + gameMicManager.config(this); + gameMicManager.joinRoom(mLiveUid); + // 设置禁用麦克风采集 + RCRTCEngine.getInstance().getDefaultAudioStream().setMicrophoneDisable(disable); + ImgLoader.display(mContext, R.mipmap.icon_game_close_wheat, gameCloseWheat); + gameCloseWheat.setVisibility(View.INVISIBLE); } + @Override protected void onDestroy() { Bus.getOff(this); + gameMicManager.leaveRoom(); + gameMicManager.detachView(); super.onDestroy(); } @@ -89,15 +126,33 @@ public class SudGameActivity extends AbsActivity { mLiveUid = mCreateSudRoomModel.getSudGameRoomId(); gameContainer = findViewById(R.id.game_container); - gameTitle = findViewById(R.id.game_title); roomName = findViewById(R.id.room_name); roomNumber = findViewById(R.id.room_number); - mAvatar = findViewById(R.id.avatar); + gameCloseWheat = findViewById(R.id.game_close_wheat); + gameSeat = findViewById(R.id.game_seat); + chatList = findViewById(R.id.chat_list); + userList = findViewById(R.id.user_list); + //聊天栏 + FrameLayout.LayoutParams params1 = (FrameLayout.LayoutParams) + chatList.getLayoutParams(); + params1.topMargin = DpUtil.dp2px(65); + chatList.setLayoutParams(params1); + + chatList.setHasFixedSize(true); + LinearLayoutManager layoutManager = new LinearLayoutManager(mContext); + layoutManager.setOrientation(RecyclerView.VERTICAL); + layoutManager.setStackFromEnd(true); + chatList.setLayoutManager(layoutManager); + chatList.addItemDecoration(new TopGradual()); + chatList.setItemViewCacheSize(10); + mLiveChatAdapter = new SudGameChatAdapter(mContext); + chatList.setAdapter(mLiveChatAdapter); + sudGameUserListAdapter = new SudGameUserListAdapter(new ArrayList<>()); + userList.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false)); + userList.setAdapter(sudGameUserListAdapter); if (mCreateSudRoomModel != null) { - gameTitle.setText(mCreateSudRoomModel.getSudGameName()); roomName.setText(mCreateSudRoomModel.getRoomName()); roomNumber.setText(mCreateSudRoomModel.getSudGameRoomId()); - ImgLoader.display(mContext, mCreateSudRoomModel.getAvatar(), mAvatar); } ViewClicksAntiShake.clicksAntiShake(findViewById(R.id.exit), new ViewClicksAntiShake.ViewClicksCallBack() { @Override @@ -115,6 +170,52 @@ public class SudGameActivity extends AbsActivity { .asCustom(new LiveSudGameHistoryPopup(mContext, customSidebarChildModels)).show(); } }); + ViewClicksAntiShake.clicksAntiShake(findViewById(R.id.game_seat), new ViewClicksAntiShake.ViewClicksCallBack() { + @Override + public void onViewClicks() { + if (publishDefault) { + disable = true; + // 设置禁用麦克风采集 + RCRTCEngine.getInstance().getDefaultAudioStream().setMicrophoneDisable(disable); + ImgLoader.display(mContext, R.mipmap.icon_game_close_wheat, gameCloseWheat); + gameMicManager.unPublishStreams(); + } else { + gameMicManager.publishDefaultAVStream(); + } + + } + }); + ViewClicksAntiShake.clicksAntiShake(gameCloseWheat, new ViewClicksAntiShake.ViewClicksCallBack() { + @Override + public void onViewClicks() { + if (disable) { + disable = false; + // 设置禁用麦克风采集 + RCRTCEngine.getInstance().getDefaultAudioStream().setMicrophoneDisable(disable); + ImgLoader.display(mContext, R.mipmap.icon_game_open_wheat, gameCloseWheat); + } else { + disable = true; + // 设置禁用麦克风采集 + RCRTCEngine.getInstance().getDefaultAudioStream().setMicrophoneDisable(disable); + ImgLoader.display(mContext, R.mipmap.icon_game_close_wheat, gameCloseWheat); + } + } + }); + ViewClicksAntiShake.clicksAntiShake(findViewById(R.id.game_review_input), new ViewClicksAntiShake.ViewClicksCallBack() { + @Override + public void onViewClicks() { + new XPopup.Builder(mContext) + .enableDrag(false) + .asCustom(new SudGameInputPopupWindow(mContext, new SudGameInputPopupWindow.SudGameInputCallBack() { + @Override + public void sendMessage(String textMessage) { + gameMicManager.sendMessage(textMessage); + } + })) + .show(); + } + }); + gameViewModel.gameViewLiveData.observe(this, new Observer() { @Override public void onChanged(View view) { @@ -122,7 +223,9 @@ public class SudGameActivity extends AbsActivity { gameContainer.removeAllViews(); } else { // 把游戏View添加到容器内 gameContainer.addView(view, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); + } + } }); // 加载游戏,参数定义可查看BaseGameViewModel.switchGame()方法注释 @@ -137,6 +240,7 @@ public class SudGameActivity extends AbsActivity { gameConfigModel.ui.game_settle_again_btn.custom = true; gameConfigModel.ui.start_btn.custom = true; + // SudMGP平台64bit游戏ID gameViewModel.switchGame((Activity) mContext, mLiveUid, mInteractionID); // gameViewModel.sudFSTAPPDecorator.notifyAPPCommonSelfIn(true, -1, true, 1); @@ -147,6 +251,13 @@ public class SudGameActivity extends AbsActivity { // // } // }); + // 设置游戏安全操作区域 + GameViewInfoModel.GameViewRectModel gameViewRectModel = new GameViewInfoModel.GameViewRectModel(); + gameViewRectModel.left = 0; + gameViewRectModel.top = DpUtil.dp2px(155); + gameViewRectModel.right = 0; + gameViewRectModel.bottom = DpUtil.dp2px(155); + gameViewModel.gameViewRectModel = gameViewRectModel; } @@ -156,6 +267,7 @@ public class SudGameActivity extends AbsActivity { switch (event.getSudMGPMGState()) { case SudMGPMGState.MG_COMMON_SELF_CLICK_JOIN_BTN: case SudMGPMGState.MG_COMMON_SELF_CLICK_GAME_SETTLE_AGAIN_BTN: + LiveNetManager.get(mContext).checkRemainingBalance(mCreateSudRoomModel.getSudGameRoomId(), new HttpCallback() { @Override public void onSuccess(CheckRemainingBalance data) { @@ -190,9 +302,9 @@ public class SudGameActivity extends AbsActivity { HttpCallback() { @Override public void onSuccess(CheckRemainingBalance data) { - if (data.getStatus()==1){ + if (data.getStatus() == 1) { gameViewModel.sudFSTAPPDecorator.notifyAPPCommonSelfPlaying(true); - }else { + } else { } @@ -205,10 +317,91 @@ public class SudGameActivity extends AbsActivity { }); break; case SudMGPMGState.MG_COMMON_GAME_STATE: - LiveNetManager.get(mContext).deductMoney( mCreateSudRoomModel.getSudGameRoomId()); + LiveNetManager.get(mContext).deductMoney(mCreateSudRoomModel.getSudGameRoomId()); break; } } + @Override + public void onJoinRoomSuccess(RCRTCRoom rcrtcRoom) { + + // 主动订阅远端用户发布的资源 + gameMicManager.subscribeAVStream(); + } + + @Override + public void onJoinRoomFailed(RTCErrorCode rtcErrorCode) { + ToastUtil.show("加入失败 "); + } + + @Override + public void onPublishSuccess() { + runOnUiThread(new Runnable() { + @Override + public void run() { + ImgLoader.display(mContext, R.mipmap.icon_game_hang_up, gameSeat); + publishDefault = true; + gameCloseWheat.setVisibility(View.VISIBLE); + disable = false; + // 设置禁用麦克风采集 + RCRTCEngine.getInstance().getDefaultAudioStream().setMicrophoneDisable(disable); + ImgLoader.display(mContext, R.mipmap.icon_game_open_wheat, gameCloseWheat); + } + }); + + } + + @Override + public void onPublishFailed() { + ToastUtil.show("发布失败 "); + } + + @Override + public void onSubscribeSuccess(List inputStreamList) { + ToastUtil.show("订阅成功 "); + } + + @Override + public void onSubscribeFailed() { + ToastUtil.show("订阅失败 "); + } + + @Override + public void onUserJoined(RCRTCRemoteUser rcrtcRemoteUser) { + + } + + @Override + public void onUserLeft(RCRTCRemoteUser rcrtcRemoteUser) { + + } + + @Override + public void insertItem(SudGameChatImModel sudGameChatImModel) { + mLiveChatAdapter.insertItem(sudGameChatImModel); + } + + @Override + public void onUnPublishStreamsSuccess() { + runOnUiThread(new Runnable() { + @Override + public void run() { + ImgLoader.display(mContext, R.mipmap.icon_game_seat, gameSeat); + publishDefault = false; + gameCloseWheat.setVisibility(View.INVISIBLE); + } + }); + + } + + @Override + public void onUnPublishStreamsFailed() { + + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onSudGameSocketImEvent(SudGameSocketImEvent event) { + gameMicManager.processingMessage(event); + } } diff --git a/common/src/main/java/com/yunbao/common/adapter/SudGameChatAdapter.java b/common/src/main/java/com/yunbao/common/adapter/SudGameChatAdapter.java new file mode 100644 index 000000000..0cc916894 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/adapter/SudGameChatAdapter.java @@ -0,0 +1,122 @@ +package com.yunbao.common.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.yunbao.common.R; +import com.yunbao.common.bean.SudGameChatImModel; +import com.yunbao.common.views.SudGameChatViewHolder; + +import java.util.ArrayList; +import java.util.List; + +public class SudGameChatAdapter extends RecyclerView.Adapter { + private boolean isBottom = false; + List sudGameChatImModels = new ArrayList<>(); + private RecyclerView mRecyclerView; + private LinearLayoutManager mLayoutManager; + private int mRecyclerViewScrolledDy; + private Context mContext; + + public SudGameChatAdapter(Context mContext) { + this.mContext = mContext; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View herdView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_sud_game_chat_item_holder, parent, false); + return new SudGameChatViewHolder(herdView); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (holder instanceof SudGameChatViewHolder) { + SudGameChatViewHolder itemViewHolder = (SudGameChatViewHolder) holder; + itemViewHolder.sudGameChat(sudGameChatImModels.get(position)); + + } + } + + @Override + public int getItemCount() { + return sudGameChatImModels.size(); + } + + @Override + public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { + mRecyclerView = recyclerView; + mLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + if (isBottom && dy >= 0) return; + mRecyclerViewScrolledDy = dy; + isBottom = false; + + } + + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (newState == 0 && isSlideToBottom(recyclerView)) { + mRecyclerViewScrolledDy = 0; + scrollToBottom(); + isBottom = true; + } else if (newState == 0) { + isBottom = false; + } + } + }); + } + + public synchronized void insertItem(SudGameChatImModel bean) { + if (bean == null) { + return; + } + int size = sudGameChatImModels.size(); + //设置最大展示99条消息 + if (size >= 100 && (isBottom || mRecyclerViewScrolledDy == 0)) { + + sudGameChatImModels.subList(0, 50).clear(); + notifyItemRangeRemoved(0, 50); + } + sudGameChatImModels.add(bean); + if (getItemCount() == 1) { + notifyDataSetChanged(); + } else { + notifyItemInserted(getItemCount()); + } + if (isBottom || mRecyclerViewScrolledDy == 0) { + scrollToBottom(); + } + } + + /** + * 判断是否滚到底部 + * + * @param recyclerView + * @return + */ + public boolean isSlideToBottom(RecyclerView recyclerView) { + if (recyclerView == null) return false; + if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange()) + return true; + return false; + } + + public void scrollToBottom() { + if (sudGameChatImModels.size() > 0) { + mRecyclerView.smoothScrollToPosition(getItemCount()); + } + mRecyclerViewScrolledDy = 0; + } + +} diff --git a/common/src/main/java/com/yunbao/common/adapter/SudGameUserListAdapter.java b/common/src/main/java/com/yunbao/common/adapter/SudGameUserListAdapter.java new file mode 100644 index 000000000..3c7afd853 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/adapter/SudGameUserListAdapter.java @@ -0,0 +1,61 @@ +package com.yunbao.common.adapter; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.yunbao.common.R; +import com.yunbao.common.bean.SudGameUserModel; +import com.yunbao.common.views.SudGameChatViewHolder; +import com.yunbao.common.views.SudGameUserListViewHolder; + +import java.util.ArrayList; +import java.util.List; + +public class SudGameUserListAdapter extends RecyclerView.Adapter { + private List gameUserModels = new ArrayList<>(); + + public SudGameUserListAdapter(List gameUserModels) { + + if (gameUserModels.size() < 7) { + this.gameUserModels.addAll(gameUserModels); + for (int i = 0; i < this.gameUserModels.size(); i++) { + this.gameUserModels.get(i).setNullUser(false); + } + int size = 7 - gameUserModels.size(); + for (int i = 0; i < size; i++) { + this.gameUserModels.add(new SudGameUserModel().setNullUser(true)); + } + } else if (gameUserModels.size() == 7) { + this.gameUserModels.addAll(gameUserModels); + for (int i = 0; i < this.gameUserModels.size(); i++) { + this.gameUserModels.get(i).setNullUser(false); + } + } else { + for (int i = 0; i < 7; i++) { + this.gameUserModels.add(gameUserModels.get(i).setNullUser(false)); + } + } + + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View herdView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_sud_game_user_list_holder, parent, false); + return new SudGameUserListViewHolder(herdView); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + + } + + @Override + public int getItemCount() { + return gameUserModels.size(); + } +} diff --git a/common/src/main/java/com/yunbao/common/bean/SudGameChatImModel.java b/common/src/main/java/com/yunbao/common/bean/SudGameChatImModel.java new file mode 100644 index 000000000..e55ee691d --- /dev/null +++ b/common/src/main/java/com/yunbao/common/bean/SudGameChatImModel.java @@ -0,0 +1,26 @@ +package com.yunbao.common.bean; + +public class SudGameChatImModel extends BaseModel { + //昵称 + private String nickname; + //文字消息 + private String textMessage; + + public String getNickname() { + return nickname; + } + + public SudGameChatImModel setNickname(String nickname) { + this.nickname = nickname; + return this; + } + + public String getTextMessage() { + return textMessage; + } + + public SudGameChatImModel setTextMessage(String textMessage) { + this.textMessage = textMessage; + return this; + } +} diff --git a/common/src/main/java/com/yunbao/common/bean/SudGameUserModel.java b/common/src/main/java/com/yunbao/common/bean/SudGameUserModel.java new file mode 100644 index 000000000..e7b45af68 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/bean/SudGameUserModel.java @@ -0,0 +1,14 @@ +package com.yunbao.common.bean; + +public class SudGameUserModel extends BaseModel { + private boolean nullUser; + + public boolean isNullUser() { + return nullUser; + } + + public SudGameUserModel setNullUser(boolean nullUser) { + this.nullUser = nullUser; + return this; + } +} diff --git a/common/src/main/java/com/yunbao/common/dialog/SudGameInputPopupWindow.java b/common/src/main/java/com/yunbao/common/dialog/SudGameInputPopupWindow.java new file mode 100644 index 000000000..6cac0cc25 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/dialog/SudGameInputPopupWindow.java @@ -0,0 +1,73 @@ +package com.yunbao.common.dialog; + +import android.content.Context; +import android.text.TextUtils; +import android.widget.EditText; + +import androidx.annotation.NonNull; + +import com.lxj.xpopup.core.BottomPopupView; +import com.yunbao.common.R; +import com.yunbao.common.utils.ToastUtil; +import com.yunbao.common.utils.WordUtil; +import com.yunbao.common.views.weight.ViewClicksAntiShake; + +/*** + * 游戏房字体输入 + */ +public class SudGameInputPopupWindow extends BottomPopupView { + private EditText textMessage; + private SudGameInputCallBack sudGameInputCallBack; + + public SudGameInputPopupWindow(@NonNull Context context, SudGameInputCallBack sudGameInputCallBack) { + super(context); + this.sudGameInputCallBack = sudGameInputCallBack; + } + + // 返回自定义弹窗的布局 + @Override + protected int getImplLayoutId() { + return R.layout.dialog_sud_game_input; + } + + // 执行初始化操作,比如:findView,设置点击,或者任何你弹窗内的业务逻辑 + @Override + protected void onCreate() { + super.onCreate(); + initView(); + initDate(); + + } + + private void initView() { + textMessage = findViewById(R.id.text_message); + ViewClicksAntiShake.clicksAntiShake(findViewById(R.id.send), new ViewClicksAntiShake.ViewClicksCallBack() { + @Override + public void onViewClicks() { + dialog.dismiss(); + if (sudGameInputCallBack != null) { + String textMessageStr = textMessage.getText().toString(); + if (!TextUtils.isEmpty(textMessageStr)) { + if (textMessageStr.length() > 100) { + ToastUtil.show(WordUtil.isNewZh() ? "超出字數限制" : "Exceed word limit"); + } else { + sudGameInputCallBack.sendMessage(textMessageStr); + } + } else { + ToastUtil.show(WordUtil.getNewString(R.string.cannot_be_empty)); + } + + } + } + }); + + } + + private void initDate() { + + } + + public interface SudGameInputCallBack { + void sendMessage(String textMessage); + } +} diff --git a/common/src/main/java/com/yunbao/common/event/SudGameSocketImEvent.java b/common/src/main/java/com/yunbao/common/event/SudGameSocketImEvent.java new file mode 100644 index 000000000..31d9ec28e --- /dev/null +++ b/common/src/main/java/com/yunbao/common/event/SudGameSocketImEvent.java @@ -0,0 +1,120 @@ +package com.yunbao.common.event; + +import com.google.gson.annotations.SerializedName; +import com.yunbao.common.bean.BaseModel; + +import java.util.List; + +public class SudGameSocketImEvent extends BaseModel { + + @SerializedName("msg") + private List msg; + @SerializedName("retcode") + private String retcode; + @SerializedName("retmsg") + private String retmsg; + + public List getMsg() { + return msg; + } + + public void setMsg(List msg) { + this.msg = msg; + } + + public String getRetcode() { + return retcode; + } + + public void setRetcode(String retcode) { + this.retcode = retcode; + } + + public String getRetmsg() { + return retmsg; + } + + public void setRetmsg(String retmsg) { + this.retmsg = retmsg; + } + + public static class MsgDTO { + @SerializedName("action") + private String action; + @SerializedName("uid") + private String uid; + @SerializedName("roomnum") + private String roomnum; + @SerializedName("ct") + private String ct; + @SerializedName("uname") + private String uname; + @SerializedName("_method_") + private String method; + @SerializedName("equipment") + private String equipment; + + public String getAction() { + return action; + } + + public MsgDTO setAction(String action) { + this.action = action; + return this; + } + + public String getUid() { + return uid; + } + + public MsgDTO setUid(String uid) { + this.uid = uid; + return this; + } + + public String getRoomnum() { + return roomnum; + } + + public MsgDTO setRoomnum(String roomnum) { + this.roomnum = roomnum; + return this; + } + + public String getCt() { + return ct; + } + + public MsgDTO setCt(String ct) { + this.ct = ct; + return this; + } + + public String getUname() { + return uname; + } + + public MsgDTO setUname(String uname) { + this.uname = uname; + return this; + } + + public String getMethod() { + return method; + } + + public MsgDTO setMethod(String method) { + this.method = method; + return this; + } + + public String getEquipment() { + return equipment; + } + + public MsgDTO setEquipment(String equipment) { + this.equipment = equipment; + return this; + } + } +} diff --git a/common/src/main/java/com/yunbao/common/manager/imrongcloud/GameMicManager.java b/common/src/main/java/com/yunbao/common/manager/imrongcloud/GameMicManager.java new file mode 100644 index 000000000..abd8b6d7f --- /dev/null +++ b/common/src/main/java/com/yunbao/common/manager/imrongcloud/GameMicManager.java @@ -0,0 +1,429 @@ +package com.yunbao.common.manager.imrongcloud; + +import android.content.Context; +import android.text.TextUtils; +import android.util.Log; + +import com.google.gson.Gson; +import com.yunbao.common.CommonAppContext; +import com.yunbao.common.bean.IMLoginModel; +import com.yunbao.common.bean.SudGameChatImModel; +import com.yunbao.common.event.SudGameSocketImEvent; +import com.yunbao.common.manager.IMLoginManager; +import com.yunbao.common.utils.ToastUtil; +import com.yunbao.common.utils.WordUtil; + +import java.util.ArrayList; +import java.util.List; + +import cn.rongcloud.rtc.api.RCRTCEngine; +import cn.rongcloud.rtc.api.RCRTCRemoteUser; +import cn.rongcloud.rtc.api.RCRTCRoom; +import cn.rongcloud.rtc.api.RCRTCRoomConfig; +import cn.rongcloud.rtc.api.callback.IRCRTCResultCallback; +import cn.rongcloud.rtc.api.callback.IRCRTCResultDataCallback; +import cn.rongcloud.rtc.api.callback.IRCRTCRoomEventsListener; +import cn.rongcloud.rtc.api.stream.RCRTCInputStream; +import cn.rongcloud.rtc.base.RCRTCRoomType; +import cn.rongcloud.rtc.base.RTCErrorCode; +import io.rong.imlib.IRongCallback; +import io.rong.imlib.IRongCoreCallback; +import io.rong.imlib.IRongCoreEnum; +import io.rong.imlib.RongIMClient; +import io.rong.imlib.chatroom.base.RongChatRoomClient; +import io.rong.imlib.model.Conversation; +import io.rong.imlib.model.Message; +import io.rong.message.TextMessage; + +public class GameMicManager { + MeetingCallback mMeetingCallback = null; + private RCRTCRoom mRtcRoom = null; + private String mRoomID = ""; + + + private final IRCRTCRoomEventsListener roomEventsListener = new IRCRTCRoomEventsListener() { + /** + * 房间内用户发布资源 + * + * @param rcrtcRemoteUser 远端用户 + * @param list 发布的资源 + */ + @Override + public void onRemoteUserPublishResource(RCRTCRemoteUser rcrtcRemoteUser, final List list) { + subscribeAVStream(); + } + + @Override + public void onRemoteUserMuteAudio(RCRTCRemoteUser rcrtcRemoteUser, RCRTCInputStream rcrtcInputStream, boolean b) { + + } + + @Override + public void onRemoteUserMuteVideo(RCRTCRemoteUser rcrtcRemoteUser, RCRTCInputStream rcrtcInputStream, boolean b) { + } + + + @Override + public void onRemoteUserUnpublishResource(RCRTCRemoteUser rcrtcRemoteUser, List list) { + } + + /** + * 用户加入房间 + * + * @param rcrtcRemoteUser 远端用户 + */ + @Override + public void onUserJoined(final RCRTCRemoteUser rcrtcRemoteUser) { + try { + getView().onUserJoined(rcrtcRemoteUser); + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } + + /** + * 用户离开房间 + * + * @param rcrtcRemoteUser 远端用户 + */ + @Override + public void onUserLeft(RCRTCRemoteUser rcrtcRemoteUser) { + try { + getView().onUserLeft(rcrtcRemoteUser); + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } + + @Override + public void onUserOffline(RCRTCRemoteUser rcrtcRemoteUser) { + } + + @Override + public void onPublishLiveStreams(List list) { + } + + @Override + public void onUnpublishLiveStreams(List list) { + } + + /** + * 自己退出房间。 例如断网退出等 + * @param i 状态码 + */ + @Override + public void onLeaveRoom(int i) { + } + }; + + protected MeetingCallback getView() { + if (mMeetingCallback == null) { + throw new IllegalStateException("view is not attached"); + } else { + return mMeetingCallback; + } + } + + public void attachView(MeetingCallback callback) { + mMeetingCallback = callback; + } + + public void detachView() { + mMeetingCallback = null; + } + + /** + * 主动订阅远端用户发布的流 + * 视频流需要用户设置用于显示载体的videoview + */ + public void subscribeAVStream() { + if (mRtcRoom == null || mRtcRoom.getRemoteUsers() == null) { + return; + } + final List inputStreams = new ArrayList<>(); + for (final RCRTCRemoteUser remoteUser : mRtcRoom.getRemoteUsers()) { + if (remoteUser.getStreams().size() == 0) { + continue; + } + + inputStreams.addAll(remoteUser.getStreams()); + } + + if (inputStreams.size() == 0) { + return; + } + mRtcRoom.getLocalUser().subscribeStreams(inputStreams, new IRCRTCResultCallback() { + @Override + public void onSuccess() { + + + try { + getView().onSubscribeSuccess(inputStreams); + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } + + @Override + public void onFailed(RTCErrorCode errorCode) { + try { + getView().onSubscribeFailed(); + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } + }); + } + + public void unPublishStreams() { + if (mRtcRoom == null) { + return; + } + mRtcRoom.getLocalUser().unpublishStream(RCRTCEngine.getInstance().getDefaultAudioStream(), new IRCRTCResultCallback() { + @Override + public void onSuccess() { + try { + getView().onUnPublishStreamsSuccess(); + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } + + @Override + public void onFailed(RTCErrorCode errorCode) { + try { + getView().onUnPublishStreamsFailed(); + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } + }); + } + + /** + * 发布默认流 + */ + public void publishDefaultAVStream() { + if (mRtcRoom == null) { + return; + } + mRtcRoom.getLocalUser().publishStream(RCRTCEngine.getInstance().getDefaultAudioStream(), new IRCRTCResultCallback() { + @Override + public void onSuccess() { + try { + getView().onPublishSuccess(); + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } + + @Override + public void onFailed(RTCErrorCode rtcErrorCode) { + try { + getView().onPublishFailed(); + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } + }); + } + + + /** + * 配置rtc sdk + */ + public void config(Context context) { + +// RCRTCConfig.Builder configBuilder = RCRTCConfig.Builder.create(); +// // 是否硬解码 +// configBuilder.enableHardwareDecoder(true); +// // 是否硬编码 +// configBuilder.enableHardwareEncoder(true); +// +// // init 需结合 uninit 使用,否则有些配置无法重新初始化 +// RCRTCEngine.getInstance().unInit(); +// RCRTCEngine.getInstance().init(context, configBuilder.build()); + +// RCRTCVideoStreamConfig.Builder videoConfigBuilder = RCRTCVideoStreamConfig.Builder.create(); +// // 设置分辨率 +// videoConfigBuilder.setVideoResolution(RCRTCParamsType.RCRTCVideoResolution.RESOLUTION_720_1280); +// // 设置帧率 +// videoConfigBuilder.setVideoFps(RCRTCParamsType.RCRTCVideoFps.Fps_30); +// /** +// * 设置最小码率,可根据分辨率RCRTCVideoResolution设置 +// * {@link RCRTCParamsType.RCRTCVideoResolution)} +// */ +// videoConfigBuilder.setMinRate(250); +// /** +// * 设置最大码率,可根据分辨率RCRTCVideoResolution设置 +// * {@link RCRTCParamsType.RCRTCVideoResolution)} +// */ +// videoConfigBuilder.setMaxRate(2200); +// RCRTCEngine.getInstance().getDefaultVideoStream().setVideoConfig(videoConfigBuilder.build()); + //打开扬声器。 + RCRTCEngine.getInstance().enableSpeaker(true); + // 启用耳返功能 +// RCRTCEngine.getInstance().getDefaultAudioStream().enableEarMonitoring(true); + RCRTCEngine.getInstance().getDefaultAudioStream().setMicrophoneDisable(false); + } + + public void joinRoom(String roomId) { + mRoomID = roomId; + RCRTCRoomConfig roomConfig = RCRTCRoomConfig.Builder.create() + // 根据实际场景,选择音视频直播:LIVE_AUDIO_VIDEO 或音频直播:LIVE_AUDIO + .setRoomType(RCRTCRoomType.MEETING) + .build(); + RCRTCEngine.getInstance().joinRoom("v" + roomId, roomConfig, new IRCRTCResultDataCallback() { + @Override + public void onSuccess(final RCRTCRoom rcrtcRoom) { + GameMicManager.this.mRtcRoom = rcrtcRoom; + // 注册房间回调 + rcrtcRoom.registerRoomListener(roomEventsListener); + try { + getView().onJoinRoomSuccess(rcrtcRoom); + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } + + @Override + public void onFailed(RTCErrorCode rtcErrorCode) { + try { + getView().onJoinRoomFailed(rtcErrorCode); + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } + }); + RongChatRoomClient.getInstance().joinChatRoom("v" + roomId, -1, new IRongCoreCallback.OperationCallback() { + @Override + public void onSuccess() { + Log.i("tx", "加入成功"); + + } + + @Override + public void onError(IRongCoreEnum.CoreErrorCode coreErrorCode) { + Log.i("tx", "加入" + "失败" + coreErrorCode); + if (WordUtil.isNewZh()) { + ToastUtil.show("網絡不佳無法連接,請重新進入"); + } else { + ToastUtil.show("The network is not connected, please re-enter"); + } + } + }); + } + + public void leaveRoom() { + RCRTCEngine.getInstance().leaveRoom(new IRCRTCResultCallback() { + @Override + public void onFailed(RTCErrorCode rtcErrorCode) { + } + + @Override + public void onSuccess() { + } + }); + RongChatRoomClient.getInstance().quitChatRoom("v" + mRoomID, new IRongCoreCallback.OperationCallback() { + @Override + public void onSuccess() { + Log.i("tx", "退出成功"); + } + + @Override + public void onError(IRongCoreEnum.CoreErrorCode coreErrorCode) { + Log.i("tx", "退出" + "" + coreErrorCode); + } + }); + } + + /** + * 处理游戏房Im消息 + */ + public void processingMessage(SudGameSocketImEvent socketImModel) { + + List msgDTOS = socketImModel.getMsg(); + if (msgDTOS.isEmpty()) return; + SudGameSocketImEvent.MsgDTO msgDTO = msgDTOS.get(0); + //正常文字消息 + if (TextUtils.equals(msgDTO.getMethod(), "SendMsg")) { + getView().insertItem(new SudGameChatImModel().setNickname(msgDTO.getUname()).setTextMessage(msgDTO.getCt())); + } + } + + /** + * 发送聊天信息 + * + * @param textMessage + */ + public void sendMessage(String textMessage) { + IMLoginModel loginModel = IMLoginManager.get(CommonAppContext.sInstance.getApplicationContext()).getUserInfo(); + SudGameSocketImEvent sudGameSocketImEvent = new SudGameSocketImEvent(); + sudGameSocketImEvent.setRetcode("000000"); + sudGameSocketImEvent.setRetmsg("ok"); + + SudGameSocketImEvent.MsgDTO msgDTO = new SudGameSocketImEvent.MsgDTO(); + msgDTO.setAction("0") + .setCt(textMessage) + .setEquipment("app") + .setUid(String.valueOf(loginModel.getId())) + .setMethod("SendMsg") + .setUname(loginModel.getUserNicename()) + .setRoomnum(mRoomID); + + List msgDTOS = new ArrayList<>(); + msgDTOS.add(msgDTO); + sudGameSocketImEvent.setMsg(msgDTOS); + Conversation.ConversationType conversationType = Conversation.ConversationType.CHATROOM; + TextMessage messageContent = TextMessage.obtain(new Gson().toJson(sudGameSocketImEvent)); + Message message = Message.obtain("v" + mRoomID, conversationType, messageContent); + RongIMClient.getInstance().sendMessage(message, null, null, new IRongCallback.ISendMessageCallback() { + @Override + public void onAttached(Message message) { + + } + + @Override + public void onSuccess(Message message) { + Log.i("tx", "发送成功"); + String contentJson = ((TextMessage) message.getContent()).getContent(); + Log.e("wewe", contentJson); + SudGameSocketImEvent sudGameSocketImEvent = new Gson().fromJson(contentJson, SudGameSocketImEvent.class); + processingMessage(sudGameSocketImEvent); + } + + @Override + public void onError(Message message, RongIMClient.ErrorCode errorCode) { + + } + }); + } + + /** + * activity相关回调 + */ + public interface MeetingCallback { + void onJoinRoomSuccess(RCRTCRoom rcrtcRoom); + + void onJoinRoomFailed(RTCErrorCode rtcErrorCode); + + void onPublishSuccess(); + + + void onPublishFailed(); + + void onUnPublishStreamsSuccess(); + + void onUnPublishStreamsFailed(); + + void onSubscribeSuccess(List inputStreamList); + + void onSubscribeFailed(); + + void onUserJoined(RCRTCRemoteUser rcrtcRemoteUser); + + void onUserLeft(RCRTCRemoteUser rcrtcRemoteUser); + + void insertItem(SudGameChatImModel sudGameChatImModel); + } +} diff --git a/common/src/main/java/com/yunbao/common/sud/QuickStartGameViewModel.java b/common/src/main/java/com/yunbao/common/sud/QuickStartGameViewModel.java index d0dd12dc1..4a98859bd 100644 --- a/common/src/main/java/com/yunbao/common/sud/QuickStartGameViewModel.java +++ b/common/src/main/java/com/yunbao/common/sud/QuickStartGameViewModel.java @@ -52,6 +52,10 @@ public class QuickStartGameViewModel extends BaseGameViewModel { */ public GameViewInfoModel.GameViewRectModel gameViewRectModel; + public GameViewInfoModel.GameViewRectModel getGameViewRectModel() { + return gameViewRectModel; + } + /** * 游戏的语言代码 */ diff --git a/common/src/main/java/com/yunbao/common/sud/audio/AudioEngineUpdateType.java b/common/src/main/java/com/yunbao/common/sud/audio/AudioEngineUpdateType.java new file mode 100644 index 000000000..11b5f8fda --- /dev/null +++ b/common/src/main/java/com/yunbao/common/sud/audio/AudioEngineUpdateType.java @@ -0,0 +1,6 @@ +package com.yunbao.common.sud.audio; + +public enum AudioEngineUpdateType { + ADD, + DELETE +} diff --git a/common/src/main/java/com/yunbao/common/sud/audio/AudioPCMData.java b/common/src/main/java/com/yunbao/common/sud/audio/AudioPCMData.java new file mode 100644 index 000000000..2873dceb4 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/sud/audio/AudioPCMData.java @@ -0,0 +1,8 @@ +package com.yunbao.common.sud.audio; + +import java.nio.ByteBuffer; + +public class AudioPCMData { + public ByteBuffer data; + public int dataLength; +} diff --git a/common/src/main/java/com/yunbao/common/sud/audio/AudioRoomState.java b/common/src/main/java/com/yunbao/common/sud/audio/AudioRoomState.java new file mode 100644 index 000000000..d6c0da466 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/sud/audio/AudioRoomState.java @@ -0,0 +1,34 @@ +package com.yunbao.common.sud.audio; + +/** + * 语聊房房间状态 + */ +public enum AudioRoomState { + DISCONNECTED(0), + CONNECTING(1), + CONNECTED(2); + + private int value; + + private AudioRoomState(int value) { + this.value = value; + } + + public int value() { + return this.value; + } + + public static AudioRoomState getZegoRoomState(int value) { + try { + if (DISCONNECTED.value == value) { + return DISCONNECTED; + } else if (CONNECTING.value == value) { + return CONNECTING; + } else { + return CONNECTED.value == value ? CONNECTED : null; + } + } catch (Exception var2) { + throw new RuntimeException("The enumeration cannot be found"); + } + } +} diff --git a/common/src/main/java/com/yunbao/common/sud/audio/AudioStream.java b/common/src/main/java/com/yunbao/common/sud/audio/AudioStream.java new file mode 100644 index 000000000..af265e8ee --- /dev/null +++ b/common/src/main/java/com/yunbao/common/sud/audio/AudioStream.java @@ -0,0 +1,7 @@ +package com.yunbao.common.sud.audio; + +public class AudioStream { + public String userID; + public String streamID; + public String extraInfo; +} diff --git a/common/src/main/java/com/yunbao/common/sud/audio/ISudAudioEngine.java b/common/src/main/java/com/yunbao/common/sud/audio/ISudAudioEngine.java new file mode 100644 index 000000000..5653c8a57 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/sud/audio/ISudAudioEngine.java @@ -0,0 +1,121 @@ +package com.yunbao.common.sud.audio; + +import android.view.View; + +import com.yunbao.common.sud.model.AudioJoinRoomModel; + +public interface ISudAudioEngine { + // region 1. 初始化、销毁SDK, 设置IAudioEventHandler回调 + + /** + * 设置事件处理器 + * + * @param listener 事件处理实例 + */ + void setEventListener(ISudAudioEventListener listener); + + + /** + * 销毁引擎SDK + */ + void destroy(); + // endregion + + // region 2. 登录房间、退出房间 + + /** + * 加入房间, 登录成功后, 默认不推流, 默认拉流 + * + * @param model roomId + */ + void joinRoom(AudioJoinRoomModel model); + + /** + * 离开房间 + */ + void leaveRoom(); + // endregion + + // region 3. 开启推流、停止推流 + + /** + * 开启推流 + */ + void startPublishStream(); + + /** + * 停止推流 + */ + void stopPublishStream(); + // endregion + + // region 4. 开启拉流、停止拉流 + + /** + * 开启拉流,进入房间,默认订阅拉流 + */ + void startSubscribingStream(); + + /** + * 停止拉流 + */ + void stopSubscribingStream(); + // endregion + + // region 5. 开始音频流监听、关闭音频流监听 + + /** + * 开始音频流监听 + */ + void startPCMCapture(); + + /** + * 关闭音频流监听 + */ + void stopPCMCapture(); + // endregion + + // region 6. 是否使用扬声器作为音频通道 + + /** + * 切换扬声器作为音频通道 + */ + void setAudioRouteToSpeaker(boolean enabled); + // endregion + + // region 7. 发送信令 + + /** + * 发送信令 + * + * @param command 信令内容 + * @param listener 回调 + */ + void sendCommand(String command, SendCommandListener listener); + + /** + * 发送指令回调接口 + */ + interface SendCommandListener { + void onResult(int value); + } + // endregion + + // region 8. 直播接口 + + /** + * 观众开始拉流 + * + * @param streamID + * @param view + * @param mediaViewMode 图像拉伸 + */ + void startPlayingStream(String streamID, MediaViewMode mediaViewMode, View view); + + /** + * 观众停止拉流 + * + * @param streamID + */ + void stopPlayingStream(String streamID); +} diff --git a/common/src/main/java/com/yunbao/common/sud/audio/ISudAudioEventListener.java b/common/src/main/java/com/yunbao/common/sud/audio/ISudAudioEventListener.java new file mode 100644 index 000000000..e68a17a47 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/sud/audio/ISudAudioEventListener.java @@ -0,0 +1,95 @@ +package com.yunbao.common.sud.audio; + +import com.alibaba.fastjson.JSONObject; + +import java.util.HashMap; +import java.util.List; + +public interface ISudAudioEventListener { + /** + * 捕获本地音量变化, 可用于展示自己说话音浪大小 + * + * @param soundLevel 本地音量级别,取值范围[0, 100] + */ + void onCapturedSoundLevelUpdate(float soundLevel); + + /** + * 捕获远程音流音量变化, 可用于展示远端说话音浪大小 + * + * @param soundLevels [userId: 音量],音量取值范围[0, 100] + */ + void onRemoteSoundLevelUpdate(HashMap soundLevels); + + /** + * 房间流更新 增、减。可用于知道当前推流人数 + * + * @param roomId 房间id + * @param type 流更新类型 增,减 + * @param streamList 变动流列表 + * @param extendedData 扩展信息 + */ + void onRoomStreamUpdate(String roomId, AudioEngineUpdateType type, List streamList, JSONObject extendedData); + + /** + * 接收自定义指令信息回调 + * + * @param fromUserID 用户 + * @param command 指令内容 + */ + void onRecvCommand(String fromUserID, String command); + + /** + * 接收跨房指令信息回调 + * + * @param fromRoomID 消息的房间 ID + * @param fromUserID 消息的用户 ID + * @param command 指令内容 + */ + void onRecvXRoomCommand(String fromRoomID, String fromUserID, String command); + + /** + * 房间内当前在线用户数量回调 + * + * @param count 人数 + */ + void onRoomOnlineUserCountUpdate(int count); + + /** + * 房间状态变化 + * + * @param state 状态 + * @param errorCode 错误码 + * @param extendedData 扩展信息 + */ + void onRoomStateUpdate(AudioRoomState state, int errorCode, JSONObject extendedData); + + /** + * 监听音频PCM流回调 + * + * @param audioPCMData 音频流数据 + */ + void onCapturedPCMData(AudioPCMData audioPCMData); + + /** + * 观众拉流成功通知 + * + * @param streamID + */ + void onPlayingStreamingAdd(String streamID); + + /** + * 观众拉流结束通知 + * + * @param streamID + */ + void onPlayingStreamingDelete(String streamID); + + /** + * 拉流分辨率变更通知。 + * + * @param streamID 流id + * @param width 宽 + * @param height 高 + */ + void onPlayerVideoSizeChanged(String streamID, int width, int height); +} diff --git a/common/src/main/java/com/yunbao/common/sud/audio/MediaViewMode.java b/common/src/main/java/com/yunbao/common/sud/audio/MediaViewMode.java new file mode 100644 index 000000000..f28264417 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/sud/audio/MediaViewMode.java @@ -0,0 +1,7 @@ +package com.yunbao.common.sud.audio; + +public enum MediaViewMode { + ASPECT_FIT, // 等比缩放,可能有黑边 + ASPECT_FILL, // 等比缩放填充整个 View,可能有部分被裁减 + SCALE_TO_FILL; // 填充整个 View,图像可能被拉伸 +} diff --git a/common/src/main/java/com/yunbao/common/sud/model/AudioJoinRoomModel.java b/common/src/main/java/com/yunbao/common/sud/model/AudioJoinRoomModel.java new file mode 100644 index 000000000..4407efe35 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/sud/model/AudioJoinRoomModel.java @@ -0,0 +1,16 @@ +package com.yunbao.common.sud.model; + +public class AudioJoinRoomModel { + + public String userID; + + public String userName; + + public String roomID; + + public String token; + + public long timestamp; + + public String appId; +} diff --git a/common/src/main/java/com/yunbao/common/utils/LoadDian9TuUtilSud.java b/common/src/main/java/com/yunbao/common/utils/LoadDian9TuUtilSud.java new file mode 100644 index 000000000..cad240b93 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/utils/LoadDian9TuUtilSud.java @@ -0,0 +1,108 @@ +package com.yunbao.common.utils; + +import android.app.Activity; +import android.content.Context; +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.NinePatch; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.NinePatchDrawable; +import android.os.Build; +import android.text.TextUtils; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.target.CustomTarget; +import com.bumptech.glide.request.transition.Transition; +import com.yunbao.common.manager.IMLoginManager; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +public class LoadDian9TuUtilSud { + private static final List BITMAP_CACHE = new ArrayList<>();//.9图Bitmap缓存 + + public void loadDian9TuAssets(Context context, View imageView, int position) { + if (TextUtils.isEmpty(IMLoginManager.get(context).getKeyDefaultBubbleUrl())) { + Bitmap bitmap = getImageFromAssetsFile(context, "chat_message_bg.png"); + BITMAP_CACHE.add(bitmap); + setNinePathImage(context, imageView, bitmap, position); + } else { + String url = IMLoginManager.get(context).getKeyDefaultBubbleUrl(); + LoadDian9Tu(context, imageView, url, 1); + } + + } + + public void setNinePathImage(Context context, View imageView, Bitmap bitmap, int position) { + if (bitmap == null) + return; + byte[] chunk = bitmap.getNinePatchChunk(); + if (NinePatch.isNinePatchChunk(chunk)) { + NinePatchDrawable patchy = new NinePatchDrawable(context.getResources(), bitmap, chunk, NinePatchChunk.deserialize(chunk, position).mPaddings, null); + imageView.setBackground(patchy); + } + } + + public void LoadDian9Tu(Context context, View imageView, String imgUrl, int position) { + if (context == null) { + return; + } + if (context instanceof Activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + if (((Activity) context).isDestroyed()) { + return; + } + } + } + Glide.with(context) + .asFile() + .load(imgUrl) + .into(new CustomTarget() { + @Override + public void onResourceReady(@NonNull File resource, @Nullable Transition transition) { + try { + FileInputStream is = new FileInputStream(resource); + Bitmap bitmap = BitmapFactory.decodeStream(is); + BITMAP_CACHE.add(bitmap); + setNinePathImage(context, imageView, bitmap, position); + is.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + + } + }); + } + + /** + * 从Assets中读取图片 + * + * @param fileName + * @return + */ + private Bitmap getImageFromAssetsFile(Context context, String fileName) { + Bitmap image = null; + AssetManager am = context.getResources().getAssets(); + try { + InputStream is = am.open(fileName); + image = BitmapFactory.decodeStream(is); + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return image; + } +} diff --git a/live/src/main/java/com/yunbao/live/utils/NinePatchChunk.java b/common/src/main/java/com/yunbao/common/utils/NinePatchChunk.java similarity index 98% rename from live/src/main/java/com/yunbao/live/utils/NinePatchChunk.java rename to common/src/main/java/com/yunbao/common/utils/NinePatchChunk.java index 1a275d321..6ebd8c7e4 100644 --- a/live/src/main/java/com/yunbao/live/utils/NinePatchChunk.java +++ b/common/src/main/java/com/yunbao/common/utils/NinePatchChunk.java @@ -1,4 +1,4 @@ -package com.yunbao.live.utils; +package com.yunbao.common.utils; import android.graphics.Rect; diff --git a/common/src/main/java/com/yunbao/common/views/SudGameChatViewHolder.java b/common/src/main/java/com/yunbao/common/views/SudGameChatViewHolder.java new file mode 100644 index 000000000..a76cbc058 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/views/SudGameChatViewHolder.java @@ -0,0 +1,49 @@ +package com.yunbao.common.views; + +import android.graphics.Color; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.yunbao.common.R; +import com.yunbao.common.bean.SudGameChatImModel; +import com.yunbao.common.utils.LoadDian9TuUtilSud; + +public class SudGameChatViewHolder extends RecyclerView.ViewHolder { + private LinearLayout mBg; + private TextView chatMessage; + + public SudGameChatViewHolder(@NonNull View itemView) { + super(itemView); + mBg = (LinearLayout) itemView.findViewById(R.id.bg); + chatMessage = itemView.findViewById(R.id.chat_message); + + } + + /** + * 幸运100%活动 + */ + public void sudGameChat(SudGameChatImModel msgModel) { + new LoadDian9TuUtilSud().loadDian9TuAssets(itemView.getContext(), mBg, 1); + StringBuffer buffer = new StringBuffer(); + String userName = msgModel.getNickname() + ":"; + buffer.append(userName) + .append(" ") + .append(msgModel.getTextMessage()); + + String msg = buffer.toString(); + + int unameIndexOf = msg.indexOf(userName); + int unameSize = userName.length(); + SpannableStringBuilder builder = new SpannableStringBuilder(); + builder.append(msg); + builder.setSpan(new ForegroundColorSpan(Color.parseColor("#FFBD0D")), unameIndexOf, unameIndexOf + unameSize, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + chatMessage.setText(builder); + } +} diff --git a/common/src/main/java/com/yunbao/common/views/SudGameUserListViewHolder.java b/common/src/main/java/com/yunbao/common/views/SudGameUserListViewHolder.java new file mode 100644 index 000000000..4a8511d0e --- /dev/null +++ b/common/src/main/java/com/yunbao/common/views/SudGameUserListViewHolder.java @@ -0,0 +1,12 @@ +package com.yunbao.common.views; + +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +public class SudGameUserListViewHolder extends RecyclerView.ViewHolder { + public SudGameUserListViewHolder(@NonNull View itemView) { + super(itemView); + } +} diff --git a/live/src/main/java/com/yunbao/live/custom/TopGradual.java b/common/src/main/java/com/yunbao/common/views/TopGradual.java similarity index 97% rename from live/src/main/java/com/yunbao/live/custom/TopGradual.java rename to common/src/main/java/com/yunbao/common/views/TopGradual.java index 7cc8d818f..8e1d3d422 100644 --- a/live/src/main/java/com/yunbao/live/custom/TopGradual.java +++ b/common/src/main/java/com/yunbao/common/views/TopGradual.java @@ -1,4 +1,4 @@ -package com.yunbao.live.custom; +package com.yunbao.common.views; import android.graphics.Canvas; import android.graphics.Color; diff --git a/common/src/main/res/drawable/background_sud_game_input.xml b/common/src/main/res/drawable/background_sud_game_input.xml new file mode 100644 index 000000000..bdbe71942 --- /dev/null +++ b/common/src/main/res/drawable/background_sud_game_input.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/common/src/main/res/drawable/background_sud_game_input_edit_text.xml b/common/src/main/res/drawable/background_sud_game_input_edit_text.xml new file mode 100644 index 000000000..de7f97453 --- /dev/null +++ b/common/src/main/res/drawable/background_sud_game_input_edit_text.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/common/src/main/res/drawable/bg_live_sud_game_back_new.png b/common/src/main/res/drawable/bg_live_sud_game_back_new.png new file mode 100644 index 000000000..217fffa49 Binary files /dev/null and b/common/src/main/res/drawable/bg_live_sud_game_back_new.png differ diff --git a/common/src/main/res/drawable/bg_live_sud_game_bottom_input.xml b/common/src/main/res/drawable/bg_live_sud_game_bottom_input.xml new file mode 100644 index 000000000..4f5623992 --- /dev/null +++ b/common/src/main/res/drawable/bg_live_sud_game_bottom_input.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/common/src/main/res/drawable/bg_live_sud_game_bottom_input_right.xml b/common/src/main/res/drawable/bg_live_sud_game_bottom_input_right.xml new file mode 100644 index 000000000..75e3be568 --- /dev/null +++ b/common/src/main/res/drawable/bg_live_sud_game_bottom_input_right.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/common/src/main/res/drawable/bg_live_sud_game_top_new.xml b/common/src/main/res/drawable/bg_live_sud_game_top_new.xml new file mode 100644 index 000000000..6f5dd06ca --- /dev/null +++ b/common/src/main/res/drawable/bg_live_sud_game_top_new.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/common/src/main/res/layout/activity_sud_game.xml b/common/src/main/res/layout/activity_sud_game.xml index 6f6ae2637..ddf4fbc31 100644 --- a/common/src/main/res/layout/activity_sud_game.xml +++ b/common/src/main/res/layout/activity_sud_game.xml @@ -1,57 +1,10 @@ - - - - - - - - - - - - - - @@ -61,73 +14,142 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/common/src/main/res/layout/dialog_sud_game_input.xml b/common/src/main/res/layout/dialog_sud_game_input.xml new file mode 100644 index 000000000..32515abd5 --- /dev/null +++ b/common/src/main/res/layout/dialog_sud_game_input.xml @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/common/src/main/res/layout/view_sud_game_chat_item_holder.xml b/common/src/main/res/layout/view_sud_game_chat_item_holder.xml new file mode 100644 index 000000000..d697f53ab --- /dev/null +++ b/common/src/main/res/layout/view_sud_game_chat_item_holder.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/common/src/main/res/layout/view_sud_game_user_list_holder.xml b/common/src/main/res/layout/view_sud_game_user_list_holder.xml new file mode 100644 index 000000000..197037ea2 --- /dev/null +++ b/common/src/main/res/layout/view_sud_game_user_list_holder.xml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/common/src/main/res/mipmap-xxhdpi/icon_game_close_wheat.png b/common/src/main/res/mipmap-xxhdpi/icon_game_close_wheat.png new file mode 100644 index 000000000..363e0e380 Binary files /dev/null and b/common/src/main/res/mipmap-xxhdpi/icon_game_close_wheat.png differ diff --git a/common/src/main/res/mipmap-xxhdpi/icon_game_hang_up.png b/common/src/main/res/mipmap-xxhdpi/icon_game_hang_up.png new file mode 100644 index 000000000..ab9ffbdf7 Binary files /dev/null and b/common/src/main/res/mipmap-xxhdpi/icon_game_hang_up.png differ diff --git a/common/src/main/res/mipmap-xxhdpi/icon_game_open_wheat.png b/common/src/main/res/mipmap-xxhdpi/icon_game_open_wheat.png new file mode 100644 index 000000000..19a8c1b97 Binary files /dev/null and b/common/src/main/res/mipmap-xxhdpi/icon_game_open_wheat.png differ diff --git a/common/src/main/res/mipmap-xxhdpi/icon_game_seat.png b/common/src/main/res/mipmap-xxhdpi/icon_game_seat.png new file mode 100644 index 000000000..f3dca07f2 Binary files /dev/null and b/common/src/main/res/mipmap-xxhdpi/icon_game_seat.png differ diff --git a/common/src/main/res/mipmap-xxhdpi/icon_send_game.png b/common/src/main/res/mipmap-xxhdpi/icon_send_game.png new file mode 100644 index 000000000..13b06a190 Binary files /dev/null and b/common/src/main/res/mipmap-xxhdpi/icon_send_game.png differ diff --git a/common/src/main/res/mipmap-xxhdpi/icon_sud_history_live_new.png b/common/src/main/res/mipmap-xxhdpi/icon_sud_history_live_new.png new file mode 100644 index 000000000..f9c550e28 Binary files /dev/null and b/common/src/main/res/mipmap-xxhdpi/icon_sud_history_live_new.png differ diff --git a/common/src/main/res/mipmap-xxhdpi/icon_vacancy_sud_game.png b/common/src/main/res/mipmap-xxhdpi/icon_vacancy_sud_game.png new file mode 100644 index 000000000..d2475e35d Binary files /dev/null and b/common/src/main/res/mipmap-xxhdpi/icon_vacancy_sud_game.png differ diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index 6eedc57e5..584af597c 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -1428,4 +1428,5 @@ Limited ride And limited avatar frame The quantity of goods exchanged has reached the upper limit Successfully opened You have purchased the BattlePass + 評論 diff --git a/live/src/main/java/com/yunbao/live/dialog/LiveGiveHotDialogFragment.java b/live/src/main/java/com/yunbao/live/dialog/LiveGiveHotDialogFragment.java index 84b75209c..0e748b6e6 100644 --- a/live/src/main/java/com/yunbao/live/dialog/LiveGiveHotDialogFragment.java +++ b/live/src/main/java/com/yunbao/live/dialog/LiveGiveHotDialogFragment.java @@ -24,9 +24,7 @@ import com.opensource.svgaplayer.SVGADrawable; import com.opensource.svgaplayer.SVGAImageView; import com.opensource.svgaplayer.SVGAParser; import com.opensource.svgaplayer.SVGAVideoEntity; -import com.yunbao.common.CommonAppConfig; import com.yunbao.common.Constants; -import com.yunbao.common.bean.LevelBean; import com.yunbao.common.dialog.AbsDialogFragment; import com.yunbao.common.glide.ImgLoader; import com.yunbao.common.http.HttpCallback; @@ -36,7 +34,7 @@ import com.yunbao.common.utils.SVGAViewUtils; import com.yunbao.live.R; import com.yunbao.live.activity.LiveActivity; import com.yunbao.live.bean.HotBean; -import com.yunbao.live.custom.TopGradual; +import com.yunbao.common.views.TopGradual; import com.yunbao.common.http.LiveHttpUtil; import com.yunbao.live.utils.LiveTextRender; diff --git a/live/src/main/java/com/yunbao/live/utils/LoadDian9TuUtil.java b/live/src/main/java/com/yunbao/live/utils/LoadDian9TuUtil.java index 634f805c9..90c95bb03 100644 --- a/live/src/main/java/com/yunbao/live/utils/LoadDian9TuUtil.java +++ b/live/src/main/java/com/yunbao/live/utils/LoadDian9TuUtil.java @@ -19,6 +19,7 @@ import com.bumptech.glide.Glide; import com.bumptech.glide.request.target.CustomTarget; import com.bumptech.glide.request.transition.Transition; import com.yunbao.common.manager.IMLoginManager; +import com.yunbao.common.utils.NinePatchChunk; import com.yunbao.live.activity.LiveActivity; import java.io.File; diff --git a/live/src/main/java/com/yunbao/live/views/LiveRoomViewHolder.java b/live/src/main/java/com/yunbao/live/views/LiveRoomViewHolder.java index ae325bc80..1b5c91314 100644 --- a/live/src/main/java/com/yunbao/live/views/LiveRoomViewHolder.java +++ b/live/src/main/java/com/yunbao/live/views/LiveRoomViewHolder.java @@ -160,7 +160,7 @@ import com.yunbao.live.bean.LiveWishlistBean; import com.yunbao.live.bean.WishlistItemModel; import com.yunbao.live.custom.LiveLightView; import com.yunbao.live.custom.RightGradual; -import com.yunbao.live.custom.TopGradual; +import com.yunbao.common.views.TopGradual; import com.yunbao.live.dialog.GiftWallDialog; import com.yunbao.live.dialog.LiveContactDetailsSendGiftDialog; import com.yunbao.live.dialog.LiveFaceUnityDialogFragment; diff --git a/live/src/main/java/com/yunbao/live/views/SystemMessageViewHolder.java b/live/src/main/java/com/yunbao/live/views/SystemMessageViewHolder.java index 4a0f83171..f77180201 100644 --- a/live/src/main/java/com/yunbao/live/views/SystemMessageViewHolder.java +++ b/live/src/main/java/com/yunbao/live/views/SystemMessageViewHolder.java @@ -67,7 +67,7 @@ import com.yunbao.live.adapter.YouLikeMessageAdapter; import com.yunbao.live.bean.SearchUserBean; import com.yunbao.live.bean.SystemMessageBean; import com.yunbao.live.bean.YouLikeBean; -import com.yunbao.live.custom.TopGradual; +import com.yunbao.common.views.TopGradual; import com.yunbao.live.http.ImHttpConsts; import com.yunbao.live.http.ImHttpUtil;