You need to enable JavaScript to run this app.
文档中心
实时音视频

实时音视频

复制全文
下载 pdf
游戏房
场景搭建(Android)
复制全文
下载 pdf
场景搭建(Android)

SDK集成

本场景需要集成火山引擎的RTC SDK 以及SUD MGP 互动小游戏接入平台,您需要在 RTC 的控制台开通服务,并下载对应的SUD MGP 的SDK,相应开通指南如下:

RTC SDK 接入

详细细节请参见 RTC服务开通指南

alt

小游戏 SDK 接入

整体实现流程

alt


核心功能实现

房主创建游戏房以及观众加入游戏房流程:

时序图

alt

示例代码

/**
     * 加入RTC房间并初始化参数 
     * @param token 加入 RTC 房间的 token
     * @param roomId 加入 RTC 房间的 id
     * @param userId 加入 RTC 房间的 用户id
     */
    public static void joinRoom(String token, String roomId, String uid) {
        MLog.d("joinChannel", "token:" + token + " roomId:" + roomId + " uid:" + uid);
        leaveRoom();
        if (mRTCVideo == null) {
            return;
        }
        mRTCRoom = mRTCVideo.createRTCRoom(roomId);
        mRTCRoom.setRTCRoomEventHandler(mRTCRoomEventHandler);
        UserInfo userInfo = new UserInfo(uid, null);
        RTCRoomConfig roomConfig = new RTCRoomConfig(ChannelProfile.CHANNEL_PROFILE_COMMUNICATION,
                true, true, true);
        mRTCRoom.joinRoom(token, userInfo, roomConfig);
}
    /**
     * 初始化SudMGP sdk
     *
     * @param activity 游戏所在页面
     * @param gameId   游戏id
     * @param code     令牌
     */
    private void initSdk(FragmentActivity activity, long gameId, String code) {
        String appId = getAppId();
        String appKey = getAppKey();
        // 初始化sdk
        SudMGP.initSDK(activity, appId, appKey, isTestEnv(), new ISudListenerInitSDK() {
            @Override
            public void onSuccess() {
                loadGame(activity, code, gameId);
            }

            @Override
            public void onFailure(int errCode, String errMsg) {
                if (isTestEnv()) {
                    Toast.makeText(activity, "initSDK onFailure:" + errMsg + "(" + errCode + ")", Toast.LENGTH_LONG).show();
                }

                delayLoadGame(activity, gameId);
            }
        });
    }

    /**
     * 加载游戏
     * APP和游戏的相互调用
     * ISudFSTAPP:APP调用游戏的接口
     * ISudFSMMG:游戏调APP的响应回调
     *
     * @param activity 游戏所在页面
     * @param code     登录令牌
     * @param gameId   游戏id
     */
    private void loadGame(FragmentActivity activity, String code, long gameId) {
        if (activity.isDestroyed() || !isRunning || gameId != playingGameId) {
            return;
        }

        // 给装饰类设置回调
        sudFSMMGDecorator.setSudFSMMGListener(this);

        // 调用游戏sdk加载游戏
        ISudFSTAPP iSudFSTAPP = SudMGP.loadMG(activity, getUserId(), gameRoomId, code, gameId, getLanguageCode(), sudFSMMGDecorator);

        // 如果返回空,则代表参数问题或者非主线程
        if (iSudFSTAPP == null) {
            Toast.makeText(activity, "loadMG params error", Toast.LENGTH_LONG).show();
            delayLoadGame(activity, gameId);
            return;
        }

        // APP调用游戏接口的装饰类设置
        sudFSTAPPDecorator.setISudFSTAPP(iSudFSTAPP);

        // 获取游戏视图,将其抛回Activity进行展示
        // Activity调用:gameContainer.addView(view, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
        gameView = iSudFSTAPP.getGameView();
        onAddGameView(gameView);
    }
    
    /**
     * 处理游戏视图信息(游戏安全区)
     * 文档:https://docs.sud.tech/zh-CN/app/Client/API/ISudFSMMG/onGetGameViewInfo.html
     */
    public void processOnGetGameViewInfo(View gameView, ISudFSMStateHandle handle) {
        //拿到游戏View的宽高
        int gameViewWidth = gameView.getMeasuredWidth();
        int gameViewHeight = gameView.getMeasuredHeight();
        if (gameViewWidth > 0 && gameViewHeight > 0) {
            notifyGameViewInfo(handle, gameViewWidth, gameViewHeight);
            return;
        }

        //如果游戏View未加载完成,则监听加载完成时回调
        gameView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                gameView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                int width = gameView.getMeasuredWidth();
                int height = gameView.getMeasuredHeight();
                notifyGameViewInfo(handle, width, height);
            }
        });
    }

    /** 通知游戏,游戏视图信息 */
    private void notifyGameViewInfo(ISudFSMStateHandle handle, int gameViewWidth, int gameViewHeight) {
        GameViewInfoModel gameViewInfoModel = new GameViewInfoModel();
        gameViewInfoModel.ret_code = 0;
        // 游戏View大小
        gameViewInfoModel.view_size.width = gameViewWidth;
        gameViewInfoModel.view_size.height = gameViewHeight;

        // 游戏安全操作区域
        getGameRect(gameViewInfoModel);

        // 给游戏侧进行返回
        String json = SudJsonUtils.toJson(gameViewInfoModel);
        handle.success(json);
    }

观众请求上麦和房主拉观众上麦

观众请求上麦时序图

alt

房主拉观众上麦时序图

alt

示例代码

/**
 * 观众举手
 */
public void onCSRaiseHandsMicEvent(RaiseHandsMicEvent event) {
    mChatRoomAdapter.updateRaiseHandStatus(event.userId);
    mIsSomeoneRaiseHand = true;
    updateUI();
}

/**
 * 主动邀请上麦
 */
public void onCSInviteMicEvent(InviteMicEvent event) {
    if (!GameRoomDataManger.isSelf(event.userId)) {
        return;
    }
    if (mDialog != null) {
        mDialog.dismiss();
    }
    if (TextUtils.equals(event.userId, mUserId)) {
        CommonDialog dialog = new CommonDialog(this);
        dialog.setMessage("主播邀请您上麦");
        dialog.setPositiveListener(v -> {
            GameRoomRtmClient rtmClient = GameRoomRtcManager.getRtmClient();
            if (rtmClient != null) {
                rtmClient.confirmBecomeSpeaker();
            }
            dialog.dismiss();
        });
        dialog.setNegativeListener(v -> dialog.dismiss());
        dialog.show();
        mDialog = dialog;
    }
}

/**
 * 收到上麦邀请
 */
public void onCSInviteMicEvent(InviteMicEvent event) {
    if (!GameRoomDataManger.isSelf(event.userId)) {
        return;
    }
    if (mDialog != null) {
        mDialog.dismiss();
    }
    if (TextUtils.equals(event.userId, mUserId)) {
        CommonDialog dialog = new CommonDialog(this);
        dialog.setMessage("主播邀请您上麦");
        dialog.setPositiveListener(v -> {
            GameRoomRtmClient rtmClient = GameRoomRtcManager.getRtmClient();
            if (rtmClient != null) {
                rtmClient.confirmBecomeSpeaker();
            }
            dialog.dismiss();
        });
        dialog.setNegativeListener(v -> dialog.dismiss());
        dialog.show();
        mDialog = dialog;
    }
}

/**
 * 成功上麦通知
 */
public void onCSMicOnEvent(MicOnEvent event) {
    if (TextUtils.equals(event.user.userId, mUserId)) {
        if (!hasAudioPermission()) {
            SafeToast.show("麦克风权限已关闭,请至设备设置页开启");
            requestPermissions(Manifest.permission.RECORD_AUDIO);
        }
        showToast("您已经成功上麦", true);
        mIsSpeaker = true;
        mIsRaiseHand = false;
        switchMic(true);
    }
    mChatRoomAdapter.onUserRoleChange(event.user.userId, true);
    updateUI();
}

/**
 * 下麦通知
 */
public void onCSMicOffEvent(MicOffEvent event) {
    if (TextUtils.equals(event.userId, mUserId)) {
        showToast("您已回到听众席", true);
        mIsSpeaker = false;
        switchMic(false);
    }
    mChatRoomAdapter.onUserRoleChange(event.userId, false);
    updateUI();
}

核心功能 API 与回调参考

API

功能点API
创建 RTCVideo 对象createRTCVideo
创建 RTCRoom 对象createRTCRoom
设置用户可见性setUserVisibility
开启本地音频采集startAudioCapture
加入RTC房间joinRoom
离开房间leaveRoom
关闭内部音频采集stopAudioCapture
销毁 RTCRoom 对象destroy

回调

功能点回调
本地用户加入 RTC 房间回调onRoomStateChanged
远端可见用户加入房间onUserJoined
最近更新时间:2025.10.16 10:06:07
这个页面对您有帮助吗?
有用
有用
无用
无用