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



/**
* Join the RTC room and initialize the parameters
* @param token: RTC Token
* @param roomID: RTC room id
* @param uid: RTC user id
**/
- (void)joinChannelWithToken:(NSString *)token roomID:(NSString *)roomID uid:(NSString *)uid {
//设置订阅的音视频流回退选项
[self.rtcEngineKit setSubscribeFallbackOption:ByteRTCSubscribeFallbackOptionAudioOnly];
//关闭 本地音频/视频采集
[self.rtcEngineKit stopAudioCapture];
[self.rtcEngineKit stopVideoCapture];
//设置音频路由模式,YES 扬声器/NO 听筒
[self.rtcEngineKit setDefaultAudioRoute:ByteRTCAudioRouteSpeakerphone];
//开启/关闭发言者音量键控
ByteRTCAudioPropertiesConfig *audioPropertiesConfig = [[ByteRTCAudioPropertiesConfig alloc] init];
audioPropertiesConfig.interval = 200;
[self.rtcEngineKit enableAudioPropertiesReport:audioPropertiesConfig];
//加入房间,开始连麦,需要申请AppId和Token
ByteRTCUserInfo *userInfo = [[ByteRTCUserInfo alloc] init];
userInfo.userId = uid;
ByteRTCRoomConfig *config = [[ByteRTCRoomConfig alloc] init];
config.profile = ByteRTCRoomProfileCommunication;
config.isAutoPublish = YES;
config.isAutoSubscribeAudio = YES;
self.rtcRoom = [self.rtcEngineKit createRTCRoom:roomID];
self.rtcRoom.delegate = self;
[self.rtcRoom joinRoom:token userInfo:userInfo roomConfig:config];
//设置用户为隐身状态
[self.rtcRoom setUserVisibility:NO];
}
/**
* 初始化游戏SDK
* @param appId: 游戏SDK所需的appId
* @param appKey: 游戏SDK所需的appKey
* @param callback: 初始化游戏SDK回调
**/
- (void)initSudMGPSDKWithAppId:(NSString *)appId appKey:(NSString *)appKey callback:(void(^)(BOOL success))resultCallback {
if (self.isInitSDK) {
if (resultCallback) {
resultCallback(YES);
}
return;
}
__weak __typeof(self) wself = self;
[SudMGP initSDK:appId appKey:appKey isTestEnv:YES listener:^(int retCode, const NSString * _Nonnull retMsg) {
wself.isInitSDK = retCode == 0;
if (resultCallback) {
resultCallback(wself.isInitSDK);
}
}];
}
/**
* 小游戏游戏界面加载
**/
- (void)initSudMGP {
__weak __typeof(self) wself = self;
[[GameSudMGPManager shareManager] requestSudMGPCode:NO resultCallback:^(NSString * _Nullable code) {
if (!code) {
[[ToastComponent shareToastComponent] showWithMessage:@"登陆小游戏失败" view:self.view];
return;
}
[wself.iSudAPP destroyMG];
wself.iSudAPP = nil;
wself.iSudAPP = [SudMGP loadMG:[LocalUserComponent userModel].uid roomId:self.roomModel.room_id code:[GameSudMGPManager shareManager].sudMGPCode mgId:self.gameId language:@"zh-CN" fsmMG:self rootView:self.gameRootView];
}];
}
/**
* 游戏游戏界面UI适配
* @param handle 回调句柄,APP接入方需要调用handle.success或handle.fail
* @param dataJson {}
*/
-(void)onGetGameViewInfo:(id<ISudFSMStateHandle>)handle dataJson:(NSString*)dataJson {
CGRect rect = self.gameRootView.frame;
CGFloat scale = [[UIScreen mainScreen] nativeScale];
CGFloat height = rect.size.height;
CGFloat width = 1.0 / 1.4 * height; //游戏区域宽高比建议1:1.4
width = MIN(width, rect.size.width);
CGFloat left = 0.5 * (rect.size.width - width) * scale;
NSDictionary *rectDict = [NSDictionary dictionaryWithObjectsAndKeys:@(0), @"top", @(left), @"left", @(0), @"bottom", @(left), @"right", nil];
NSDictionary *viewDict = [NSDictionary dictionaryWithObjectsAndKeys:@(rect.size.width * scale), @"width", @(rect.size.height * scale), @"height", nil];
NSDictionary *dataDict = [NSDictionary dictionaryWithObjectsAndKeys:@(0), @"ret_code", @"return form APP onGetGameViewInfo", @"ret_msg", viewDict, @"view_size", rectDict, @"view_game_rect", nil];
/// 回调
[handle success:[GameUtils dictionaryToJson:dataDict]];
}
objectivec

/**
* tab按钮状态变化回调
* @param itemButton: 点击的button
* @param status: button状态
**/
- (void)gameRoomBottomView:(GameRoomBottomView *_Nonnull)gameRoomBottomView
itemButton:(GameRoomItemButton *_Nullable)itemButton
didSelectStatus:(GameRoomBottomStatus)status {
if (status == GameRoomBottomStatusList ||
status == GameRoomBottomStatusListRed) {
__weak __typeof(self) wself = self;
[self.userListComponents show:^{
[wself restoreBottomViewMenuStatus];
}];
} else if (status == GameRoomBottomStatusRaiseHand) { //点击举手
__weak __typeof(self) wself = self;
[GameRTSManager raiseHandsMicWithBlock:^(RTMACKModel * _Nonnull model) {
if (model.result) {
[[ToastComponent shareToastComponent] showWithMessage:@"上麦请求已发出,请耐心等待"];
[wself.bottomView updateButtonStatus:GameRoomBottomStatusRaiseHand close:YES];
[wself checkMicrophoneSystemAuthority];
}else {
[[ToastComponent shareToastComponent] showWithMessage:@"操作失败,请重试"];
}
}];
} else if (status == GameRoomBottomStatusMic) {
[SystemAuthority authorizationStatusWithType:AuthorizationTypeAudio block:^(BOOL isAuthorize) {
if (itemButton.status == ButtonStatusNone) {
//mute
[GameRTSManager muteMic];
[[GameRTCManager shareRtc] muteLocalAudioStream:YES];
} else {
//unmute
[GameRTSManager unmuteMic];
[[GameRTCManager shareRtc] muteLocalAudioStream:NO];
}
itemButton.status = itemButton.status == ButtonStatusNone ? ButtonStatusActive : ButtonStatusNone;
}];
} else if (status == GameRoomBottomStatusVolume) {
[self.volumeComponents show];
} else if (status == GameRoomBottomStatusData) {
[self.paramComponents show];
} else if (status == GameRoomBottomStatusDownHand) { //点击下麦
AlertActionModel *alertModel = [[AlertActionModel alloc] init];
alertModel.title = @"确定";
AlertActionModel *cancelModel = [[AlertActionModel alloc] init];
cancelModel.title = @"取消";
__weak __typeof(self) wself = self;
[[AlertActionManager shareAlertActionManager] showWithMessage:@"是否确认下麦?" actions:@[cancelModel, alertModel]];
alertModel.alertModelClickBlock = ^(UIAlertAction * _Nonnull action) {
if ([action.title isEqualToString:@"确定"]) {
[GameRTSManager offSelfMicWithBlock:^(RTMACKModel * _Nonnull model) {
if (model.result) {
[wself sendDownloadHand];
}else {
[[ToastComponent shareToastComponent] showWithMessage:@"操作失败,请重试"];
}
}];
}
};
} else {
}
}
/**
* 房主对观众和嘉宾操作
* @param userModel: 选中user的model
* @param dataLists: 对应的用户列表
**/
- (void)updateTableViewWithModel:(GameControlUserModel *)userModel dataLists:(NSArray<GameControlUserModel *> *)dataLists {
if (userModel.user_status == 0) {
// 邀请上麦
[GameRTSManager inviteMic:userModel.user_id block:^(RTMACKModel * _Nonnull model) {
if (!model.result) {
[[ToastComponent shareToastComponent] showWithMessage:@"操作失败,请重试"];
}
}];
} else if (userModel.user_status == 1) {
// 举手 - 同意
__weak __typeof(self)wself = self;
[GameRTSManager agreeMic:userModel.user_id block:^(RTMACKModel * _Nonnull model) {
if (model.result) {
userModel.user_status = 2;
[wself updateDataLists:dataLists model:userModel];
} else {
[[ToastComponent shareToastComponent] showWithMessage:@"操作失败,请重试"];
}
}];
} else if (userModel.user_status == 2) {
// 上麦 - 下麦
AlertActionModel *alertModel = [[AlertActionModel alloc] init];
alertModel.title = @"确定";
AlertActionModel *cancelModel = [[AlertActionModel alloc] init];
cancelModel.title = @"取消";
[[AlertActionManager shareAlertActionManager] showWithMessage:@"是否将该用户下麦?" actions:@[cancelModel, alertModel]];
__weak __typeof(self) wself = self;
alertModel.alertModelClickBlock = ^(UIAlertAction * _Nonnull action) {
if ([action.title isEqualToString:@"确定"]) {
[GameRTSManager offMic:userModel.user_id block:^(RTMACKModel * _Nonnull model) {
if (model.result) {
[wself removeDataLists:dataLists model:userModel];
} else {
[[ToastComponent shareToastComponent] showWithMessage:@"操作失败,请重试"];
}
}];
}
};
}
}
/**
* 房间内观众上麦通知
* @param userModel: 对应user的model
**/
- (void)receivedRaiseHandSucceedWithUser:(GameControlUserModel *)userModel {
[self.roomView audienceRaisedHandsSuccess:userModel];
[self.userListComponents update];
if ([userModel.user_id isEqualToString:[LocalUserComponent userModel].uid]) {
GameControlUserModel *localUser = [self currentLoginuserModel];
localUser.user_status = 2;
localUser.is_mic_on = YES;
[self.bottomView updateBottomLists:[self getBottomListsWithModel:localUser]];
[[ToastComponent shareToastComponent] showWithMessage:@"您已成功上麦"];
[[GameRTCManager shareRtc] makeCoHost:YES];
[[GameRTCManager shareRtc] muteLocalAudioStream:NO];
[self checkMicrophoneSystemAuthority];
}
}
objectivec| 功能点 | API |
|---|---|
| 创建 RTCVideo 对象 | createRTCVideo:delegate:parameters: |
| 创建 RTCRoom 对象 | createRTCRoom: |
| 设置用户可见性 | setUserVisibility: |
| 开启本地音频采集 | startAudioCapture |
| 加入RTC房间 | joinRoom:userInfo:roomConfig: |
| 离开房间 | leaveRoom |
| 关闭内部音频采集 | stopAudioCapture |
| 销毁 RTCRoom 对象 | destroy |
| 功能点 | 回调 |
|---|---|
| 本地用户加入 RTC 房间回调 | rtcRoom:onRoomStateChanged:uid:state:extraInfo |
| 远端可见用户加入房间 | rtcRoom:onUserJoined:elapsed: |