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

实时音视频

复制全文
下载 pdf
双人合唱
场景搭建(iOS)
复制全文
下载 pdf
场景搭建(iOS)
SDK集成​
为了保证最佳体验效果,本场景需要集成火山引擎的 RTC SDK 以及 HIFIVE 音乐开放平台的SDK,您需要在 RTC、HIFIVE的控制台开通服务,相应开通指南如下:​
  1. RTC SDK总体接入流程,详细步骤请参看 RTC服务开通指南。​
​Image​​
  1. HIFIVE 音乐开放平台 SDK 接入流程,详细步骤请参看 HIFIVE 集成文档。​
整体实现流程​
整体业务流程图​
​Image​​
数据流向图​
​Image​​
核心功能实现​
当前仅提供了你已通过其他渠道获取音乐文件时,实现 KTV 场景的参考实现。RTC 也提供从曲库接入到 KTV 场景的完整能力,如果希望获取参考文档,请咨询技术支持。​
创建/加入房间​
时序图​
​Image​​
示例代码​
​
/**​
* 加入RTC房间并初始化参数​
* @param token: RTC Token​
* @param roomID: RTC room id​
* @param uid: RTC user id​
* @param isHost: YES 业务上主播 ; NO 业务上观众​
**/​
- (void)joinRTCRoomWithToken:(NSString *)token​
roomID:(NSString *)roomID​
uid:(NSString *)uid​
isHost:(BOOL)isHost {​
// 初始化 ByteRTCVideo 对象​
self.rtcEngineKit = [ByteRTCVideo createRTCVideo:APPID​
delegate:self​
parameters:@{}];​
​
// 初始化 ByteRTCRoom 对象​
self.rtcRoom = [self.rtcEngineKit createRTCRoom:roomID];​
self.rtcRoom.delegate = self;​
​
// 设置音频场景类型 Music​
[self.rtcEngineKit setAudioScenario:ByteRTCAudioScenarioMusic];​
​
// 设置音频双声道音乐音质​
[self.rtcEngineKit setAudioProfile:ByteRTCAudioProfileHD];​
​
// 设置主播为可见,观众为隐身​
[self.rtcRoom setUserVisibility:isHost];​
​
// 加入房间时主播需要开启麦克风,观众需要关闭麦克风​
if (isHost) {​
[self.rtcEngineKit startAudioCapture];​
} else {​
[self.rtcEngineKit stopAudioCapture];​
}​
​
// 设置音频路由模式​
[self.rtcEngineKit setDefaultAudioRoute:ByteRTCAudioRouteSpeakerphone];​
​
// 开启发言者音量监听​
ByteRTCAudioPropertiesConfig *audioPropertiesConfig = [[ByteRTCAudioPropertiesConfig alloc] init];​
audioPropertiesConfig.interval = 300;​
[self.rtcEngineKit enableAudioPropertiesReport:audioPropertiesConfig];​
​
// 加入房间,开始连麦,需要申请AppId和Token​
ByteRTCUserInfo *userInfo = [[ByteRTCUserInfo alloc] init];​
userInfo.userId = uid;​
ByteRTCRoomConfig *config = [[ByteRTCRoomConfig alloc] init];​
config.profile = ByteRTCRoomProfileKTV;​
config.isAutoPublish = YES;​
config.isAutoSubscribeAudio = YES;​
[self.rtcRoom joinRoom:token userInfo:userInfo roomConfig:config];​
}​
/** ​
* ByteRTCRoomDelegate 中的房间状态改变回调,加入房间、离开房间、发生房间相关的警告或错误时会收到此回调。​
* @param roomId 房间 ID。​
* @param uid 用户 ID。​
* @param state 房间状态码。​
* @param extraInfo 额外信息。​
*/​
- (void)rtcRoom:(ByteRTCRoom *)rtcRoom onRoomStateChanged:(NSString *)roomId​
withUid:(NSString *)uid​
state:(NSInteger)state​
extraInfo:(NSString *)extraInfo {​
// 收到 RTC 加入房间结果​
}​
​
/** ​
* ByteRTCVideoDelegate 中的用户音量信息回调​
* @param engine ByteRTCVideo 对象​
* @param audioPropertiesInfos 本地音频信息​
*/​
- (void)rtcEngine:(ByteRTCVideo *)engine onLocalAudioPropertiesReport:(NSArray<ByteRTCLocalAudioPropertiesInfo *> *)audioPropertiesInfos {​
// 本地用户音量回调 ​
}​
​
/** ​
* ByteRTCVideoDelegate 中的远端用户音量回调​
* @param engine ByteRTCVideo 对象​
* @param audioPropertiesInfos 远端音频信息,其中包含音频流属性、房间 ID、用户 ID。​
* @param totalRemoteVolume 订阅的所有远端流混音后的总音量,范围是 [0,255]。​
*/​
- (void)rtcEngine:(ByteRTCVideo *)engine onRemoteAudioPropertiesReport:(NSArray<ByteRTCRemoteAudioPropertiesInfo *> *)audioPropertiesInfos ​
totalRemoteVolume:(NSInteger)totalRemoteVolume {​
// 远端用户音量回调​
}​
​
双人合唱​
时序图​
​Image​​
示例代码​
状态变化​
​
/** ​
* 演唱者角色变化(上下麦)​
*/​
- (void)switchRoleBecomeSinger:(BOOL)isSinger {​
// 设置可见性​
[self.rtcRoom setUserVisibility:isSinger];​
// 开启/关闭 本地音频采集​
if (isSinger) {​
[self.rtcEngineKit startAudioCapture];​
} else {​
[self.rtcEngineKit stopAudioCapture];​
}​
}​
​
/**​
* 主唱、副唱和观众更新音频流订阅状态​
*/​
- (void)updateAudioSubscribe {​
if (!isChorusing) {​
return;​
}​
// 在合唱中​
// 如果自己是主唱,取消订阅副唱音频​
if (role == LeadSinger) {​
[self.rtcRoom unsubscribeStream:succentorUid mediaStreamType:ByteRTCMediaStreamTypeAudio];​
} ​
// 如果自己是观众,取消订阅主唱音频​
else if (role == Audience) {​
[self.rtcRoom unsubscribeStream:leadSingerUid mediaStreamType:ByteRTCMediaStreamTypeAudio];​
}​
}​
​
主唱​
​
/**​
* 开始演唱。在歌词/歌曲下载完成,收到开始演唱广播后执行。​
* @param filePath 歌曲的文件路径​
*/​
- (void)startStartSinging:(NSString *)filePath {​
ByteRTCMediaPlayer *mediaPlayer = [self.rtcEngineKit getMediaPlayer:0];​
​
ByteRTCMediaPlayerConfig *config = [[ByteRTCMediaPlayerConfig alloc]init];​
config.autoPlay = YES;​
// 设置歌曲本地播放和推送到远端​
config.type = ByteRTCAudioMixingTypePlayoutAndPublish;​
​
// 设置歌曲播放一次​
config.playCount = 1;​
​
// 开始播放歌曲​
[mediaPlayer open:filePath config:config];​
​
// 设置歌曲进度回调,100ms 间隔回调一次​
[mediaPlayer setProgressInterval:100];​
}​
​
/**​
* ByteRTCVideoDelegate 中收到本地歌曲播放进度回调​
* @param engine ByteRTCVideo 对象​
* @param mixId 混音ID​
* @param progress 歌曲播放进度,单位为毫秒​
*/​
- (void)rtcEngine:(ByteRTCVideo *)engine onAudioMixingPlayingProgress:(NSInteger)mixId progress:(int64_t)progress {​
// 主唱发送音频流同步信息​
NSString *millisecondStr = [NSString stringWithFormat:@"%ld", (long)(progress)];​
NSData *data = [millisecondStr dataUsingEncoding:NSUTF8StringEncoding];​
ByteRTCStreamSycnInfoConfig *config = [[ByteRTCStreamSycnInfoConfig alloc] init];​
[self.rtcEngineKit sendStreamSyncInfo:data config:config];​
​
// 刷新本地歌词进度​
[self reloadLocalLyrics:progress];​
}​
​
/**​
* ByteRTCVideoDelegate 中的音乐文件播放状态改变回调​
* @param engine 当前 RTC SDK 对象​
* @param mixId 混音 ID​
* @param state 混音状态 ​
* @param error 错误码 ​
*/​
- (void)rtcEngine:(ByteRTCVideo * _Nonnull)engine onAudioMixingStateChanged:(NSInteger)mixId state:(ByteRTCAudioMixingState)state error:(ByteRTCAudioMixingError)error {​
if (state == ByteRTCAudioMixingStateFinished) {​
// 歌曲播放结束​
}​
}​
​
副唱​
​
/**​
* 副唱开启混音​
*/​
- (void)startSuccentorAudioMixing {​
// 开启PCM混音​
ByteRTCMediaPlayer *mediaPlayer = [self.rtcEngineKit getMediaPlayer:0];​
ByteRTCMediaPlayerCustomSource *mdsSource = [[ByteRTCMediaPlayerCustomSource alloc] init];​
mdsSource.provider = (id<ByteRTCMediaPlayerCustomSourceProvider>)source;​
mdsSource.mode = ByteRTCMediaPlayerCustomSourceModePull;​
mdsSource.type = ByteRTCMediaPlayerCustomSourceStreamTypeEncoded;​
​
ByteRTCMediaPlayerConfig *config = [[ByteRTCMediaPlayerConfig alloc] init];​
config.type = ByteRTCAudioMixingTypePlayoutAndPublish;​
config.playCount = 1;​
config.startPos = startPos;​
config.callbackOnProgressInterval = self.ktvInfo.callbackOnProgressInterval;​
config.syncProgressToRecordFrame = YES;​
config.autoPlay = NO;​
​
[mediaPlayer openWithCustomSource:self.mdsSource config:config];​
​
// 监听远端用户音频数据​
[self.rtcEngineKit registerAudioFrameObserver:self];​
ByteRTCAudioFormat *format = [[ByteRTCAudioFormat alloc] init];​
format.sampleRate = ByteRTCAudioSampleRateAuto;​
format.channel = ByteRTCAudioChannelAuto;​
[self.rtcEngineKit enableAudioFrameCallback:ByteRTCAudioFrameCallbackRemoteUser format:format];​
}​
​
/**​
* 副唱停止合唱 ​
*/​
- (void)stopSuccentorAudioMixing {​
// 关闭监听远端用户音频数据​
[self.rtcEngineKit disableAudioFrameCallback:ByteRTCAudioFrameCallbackRemoteUser];​
// 关闭PCM混音​
ByteRTCMediaPlayer *mediaPlayer = [self.rtcEngineKit getMediaPlayer:0];​
[mediaPlayer stop];​
}​
​
/** ​
* ByteRTCAudioFrameObserver 中的音频数据回调​
* @param streamKey 远端流信息。​
* @param audioFrame 音频数据。​
*/​
- (void)onRemoteUserAudioFrame:(ByteRTCRemoteStreamKey * _Nonnull)streamKey audioFrame:(ByteRTCAudioFrame * _Nonnull)audioFrame {​
// 副唱转推房间内主唱的音频​
ByteRTCMediaPlayer *mediaPlayer = [self.rtcEngineKit getMediaPlayer:0];​
[mediaPlayer pushExternalAudioFrame:audioFrame];​
}​
​
/** ​
* ByteRTCVideoDelegate 中的音频流同步信息回调​
* @param engine 当前 ByteRTCVideo 实例。​
* @param remoteStreamKey 远端流信息。​
* @param streamType 媒体流类型。​
* @param data 消息内容。​
*/​
- (void)rtcEngine:(ByteRTCVideo *)engine onStreamSyncInfoReceived:(ByteRTCRemoteStreamKey *)remoteStreamKey streamType:(ByteRTCSyncInfoStreamType)streamType data:(NSData *)data {​
// 转发主唱的音频流同步信息​
ByteRTCStreamSycnInfoConfig *config = [[ByteRTCStreamSycnInfoConfig alloc] init];​
[self.rtcEngineKit sendStreamSyncInfo:data config:config];​
​
// 刷新本地歌词进度​
[self reloadLocalLyrics:data];​
}​
​
观众​
​
/** ​
* ByteRTCVideoDelegate 中的音频流同步信息回调​
* @param engine 当前 ByteRTCVideo 实例。​
* @param remoteStreamKey 远端流信息。​
* @param streamType 媒体流类型。​
* @param data 消息内容。​
*/​
- (void)rtcEngine:(ByteRTCVideo *)engine onStreamSyncInfoReceived:(ByteRTCRemoteStreamKey *)remoteStreamKey streamType:(ByteRTCSyncInfoStreamType)streamType data:(NSData *)data {​
// 刷新本地歌词进度​
[self reloadLocalLyrics:data];​
}​
​
歌曲控制台​
​Image​​
​Image​​
示例代码​
​
/**​
* 原唱/伴奏切换,需要音乐素材支持右声道伴奏,左声道原唱​
* @param isAccompaniment 是否为伴奏,YES 为伴奏,NO 为原唱​
*/​
- (void)setIsAccompaniment:(BOOL)isAccompaniment {​
ByteRTCMediaPlayer *mediaPlayer = [self.rtcEngineKit getMediaPlayer:0];​
if (isAccompaniment) {​
[mediaPlayer setAudioDualMonoMode:ByteRTCAudioMixingDualMonoModeR];​
} else {​
[mediaPlayer setAudioDualMonoMode:ByteRTCAudioMixingDualMonoModeL];​
}​
}​
​
/**​
* 暂停混音播放​
*/​
- (void)pauseSinging {​
ByteRTCMediaPlayer *mediaPlayer = [self.rtcEngineKit getMediaPlayer:0];​
[mediaPlayer pause];​
}​
​
/**​
* 恢复混音播放​
*/​
- (void)resumeSinging {​
ByteRTCMediaPlayer *mediaPlayer = [self.rtcEngineKit getMediaPlayer:0];​
[mediaPlayer resume];​
}​
​
/**​
* 开启/关闭耳返​
* @param isEnable YES 为开启耳返,NO 为关闭耳返​
*/​
- (void)enableEarMonitor:(BOOL)isEnable {​
[self.rtcEngineKit setEarMonitorMode:isEnable ? ByteRTCEarMonitorModeOn : ByteRTCEarMonitorModeOff];​
}​
​
/**​
* 设置耳返的音量​
* @param volume 耳返音量​
*/​
- (void)setEarMonitorVolume:(NSInteger)volume {​
[self.rtcEngineKit setEarMonitorVolume:volume];​
}​
​
/**​
* 调节本地播放和远端混音的音量大小​
* @param volume 混音音量​
*/​
- (void)setMusicVolume:(NSInteger)volume {​
ByteRTCMediaPlayer *mediaPlayer = [self.rtcEngineKit getMediaPlayer:0];​
[mediaPlayer setVolume:volume type:ByteRTCAudioMixingTypePlayoutAndPublish];​
}​
​
/**​
* 调节麦克风采集音量​
* @param volume 麦克风采集音量​
*/​
- (void)setRecordingVolume:(NSInteger)volume {​
[self.rtcEngineKit setCaptureVolume:ByteRTCStreamIndexMain volume:(int)volume];​
}​
​
/**​
* 设置混响特效类型​
* @param reverbType 特效类型​
*/​
- (void)setVoiceReverbType:(ByteRTCVoiceReverbType)reverbType {​
[self.rtcEngineKit setVoiceReverbType:reverbType];​
}​
​
核心功能对应 API 与回调​
API​
​
​
功能点​
API​
创建 RTCVideo 对象​
createRTCVideo:delegate:parameters:​
设置音频场景类型​
设置音质档位​
开启本地音频采集​
开启内部视频采集​
创建 RTC 房间​
设置用户可见性​
加入RTC 房间​
joinRoom:userInfo:roomConfig:​
开始播放音频文件​
设置混音时音频文件播放进度回调的间隔​
发送音频流同步信息​
订阅房间内指定的通过摄像头/麦克风采集的媒体流​
subscribeStream:mediaStreamType:​
取消订阅房间内指定的通过摄像头/麦克风采集的媒体流​
unSubscribeStream:mediaStreamType:​
启动 PCM 音频数据混音​
注册音频数据回调观察者。​
开启音频回调​
推送 PCM 音频帧数据用于混音​
启用音频信息提示。​
设置当前音频文件的声道模式​
暂停混音播放​
恢复混音播放​
打开/关闭耳返功能​
设置耳返音量​
调节音频采集音量​
setCaptureVolume:volume:​
设置混响特效类型​
离开 RTC 房间​
销毁 RTC 房间引擎​
关闭内部音频采集​
销毁 RTCVideo 对象​
destroyRTCVideo​
​
回调​
​
​
功能点​
回调​
本地用户加入 RTC 回调​
rtcRoom:onRoomStateChanged:uid:state:extraInfo​
音频流同步信息回调​
rtcEngine:onStreamSyncInfoReceived:streamType:data:​
返回远端单个用户的音频数据​
onRemoteUserAudioFrame:audioFrame:​
本地音频的相关信息回调​
订阅的远端用户的音频信息回调​
音频混音文件播放状态改变时回调​
音频播放路由变化回调​
混音音频文件播放进度回调​
远端视频流的状态改变回调​
rtcEngine:onRemoteVideoStateChanged:withVideoState:withVideoStateReason:​
​
​
最近更新时间:2026.09.22 14:41:50
这个页面对您有帮助吗?
有用
有用
无用
无用