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

实时音视频

复制全文
下载 pdf
游戏房
场景搭建(iOS)
复制全文
下载 pdf
场景搭建(iOS)
SDK集成​
本场景需要集成火山引擎的RTC SDK 以及SUD MGP 互动小游戏接入平台,您需要在 RTC 的控制台开通服务,并下载对应的SUD MGP 的SDK,相应开通指南如下:​
RTC SDK 接入​
详细细节请参见 RTC服务开通指南​
​Image​​
小游戏 SDK 接入​
整体实现流程​
​Image​​
核心功能实现​
房主创建游戏房与观众加入游戏房​
时序图​
​Image​​
示例代码​
​
/**​
* 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]];​
}​
​
观众请求上麦与房主拉观众上麦​
观众请求上麦时序图​
​Image​​
房主拉观众上麦时序图​
​Image​​
示例代码​
​
/**​
* 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];​
}​
}​
​
核心功能 API 与回调参考​
API​
​
​
功能点​
API​
创建 RTCVideo 对象​
createRTCVideo:delegate:parameters:​
创建 RTCRoom 对象​
设置用户可见性​
开启本地音频采集​
加入RTC房间​
joinRoom:userInfo:roomConfig:​
离开房间​
关闭内部音频采集​
销毁 RTCRoom 对象​
​
回调​
​
​
功能点​
回调​
本地用户加入 RTC 房间回调​
rtcRoom:onRoomStateChanged:uid:state:extraInfo​
远端可见用户加入房间​
rtcRoom:onUserJoined:elapsed:​
​
​
最近更新时间:2026.09.22 14:41:50
这个页面对您有帮助吗?
有用
有用
无用
无用