iOS
功能介绍
观众连麦功能是一种实时互动交流方式,通过观众连麦功能,主播可以与多达9个观众进行实时互动,无论是解答问题、分享经验还是进行娱乐互动,都能极大地提升观众的参与感和满意度。这种直接的互动和交流为商业化运营提供了更加便捷和高效的渠道,同时也为观众提供了更加个性化和定制化的购物体验。观众连麦功能适用于多个场景,包括电商直播、娱乐直播、在线教学等。
单人连麦 | 多人连麦 |
| |
使用说明
观众发起连麦申请
点击连麦请求按钮 | 选择连麦方式 | 发送连麦请求,等待主播同意 | 主播同意后,连麦成功 |
| | | |
主播处理观众连麦请求
收到观众的连麦请求 | 点击连麦用户,打开连麦面板 | 点击同意后,连麦成功 |
| | |
功能定制
自定义主播端连麦管理面板视图
如您需要自定义主播端连麦管理面板视图 ,请参考以下路径更改。
// 文件位置:TUILiveKit/Source/View/LiveRoom/
View/Anchor/LivingViewPanel // 主播连麦相关视图目录└── AnchorLinkControlPanel.swift // 连麦管理面板:可接受观众连麦、拒绝观众连麦、挂断连麦
自定义观众端连麦申请面板视图
如您需要自定义观众端申请连麦面板视图 ,请参考以下路径更改。
// 文件位置:TUILiveKit/Source/View/LiveRoom/
View/Audience/LivingView
Panel // 观众连麦相关的视图目录├── LinkMicTypePanel.swift // 观众连麦弹出的选择语音连麦还是视频连麦的视图└── VideoLinkSettingPanel.swift // 视频连麦时相关参数设置面板视图
关键代码
观众连麦
TUILiveKit 观众连麦功能 主要是通过 SeatService 实现,在 SeatService 中,您可通过 takeSeat 接口,实现观众连麦功能。以观众 B 申请和主播 A 连麦为例,具体交互时序可参考下图:
观众发送连麦请求
// 文件位置:TUILiveKit/iOS/TUILiveKit/Source/Service/SeatService.swiftfunc takeSeat(index: Int?, requestCallback:@escaping RequestClosure) -> AnyPublisher<TakeSeatResult, InternalError> {return Future<TakeSeatResult, InternalError> { [weak self] promise inguard let self = self else { return }let request = roomEngine.takeSeat(index ?? kRandomSeatIndex , timeout: kTimeoutValue) { requestId, operateUserId in// 主播同意连麦请求的回调} onRejected: { requestId, operateUserId, message in// 主播拒绝连麦请求的回调} onCancelled: { requestId, operateUserId in// 观众自己主动取消连麦请求的回调} onTimeout: { requestId, operateUserId in// 观众请求连麦请求超时回调} onError: { requestId, operateUserId, err, message in// 发送连麦请求失败回调}requestCallback(request)}.eraseToAnyPublisher()}
主播端收到连麦请求
// 文件位置:TUILiveKit/iOS/TUILiveKit/Source/Service/EngineServiceCenter.swiftfunc onRequestReceived(request: TUIRequest) {guard let store = self.store else { return }switch request.requestAction {case .takeSeat:let seatApplication = SeatApplication(request: request)store.dispatch(action: SeatActions.addSeatApplication(payload: seatApplication))let actions: [ActionTemplate<User>] = [SeatActions.addSeatApplicationUser]let param = generateActionTemplateParamTuple(param: request.userId, actions: actions)store.dispatch(action: UserActions.fetchUserInfo(payload: param))case .remoteUserOnSeat:store.dispatch(action: SeatActions.updateReceivedSeatInvitation(payload: SeatInvitation(request: request)))default:break}}
观众取消连麦请求
// 文件位置:TUILiveKit/iOS/TUILiveKit/Source/Service/SeatService.swiftfunc cancelRequest(requestId: String) -> AnyPublisher<Void, InternalError> {return Future { [weak self] promise inguard let self = self else { return }roomEngine.cancelRequest(requestId) {promise(.success(()))} onError: { err, message inlet error = InternalError(error: err, message: message)promise(.failure(error))}}.eraseToAnyPublisher()}
主播端收到取消连麦请求
// 文件位置:TUILiveKit/iOS/TUILiveKit/Source/Service/EngineServiceCenter.swiftfunc onRequestCancelled(requestId: String, userId: String) {guard let store = self.store else { return }let isContainApplicationRequest = store.selectCurrent(SeatSelectors.getSeatApplications).contains { $0.id == requestId }if isContainApplicationRequest {store.dispatch(action: SeatActions.removeSeatApplication(payload: requestId))}if store.selectCurrent(SeatSelectors.getReceivedSeatInvitation).id == requestId {store.dispatch(action: SeatActions.updateReceivedSeatInvitation(payload: SeatInvitation()))store.dispatch(action: ViewActions.toastEvent(payload: ToastInfo(message: .inviteCancelText)))}}
主播处理连麦请求
// 文件位置:TUILiveKit/iOS/TUILiveKit/Source/Service/SeatService.swiftfunc responseRemoteRequest(isAgree: Bool, requestId: String) -> AnyPublisher <Void, InternalError> {return Future { [weak self] promise inguard let self = self else { return }roomEngine.responseRemoteRequest(requestId, agree: isAgree) {promise(.success(()))} onError: { err, message inlet error = InternalError(error: err, message: message)promise(.failure(error))}}.eraseToAnyPublisher()}
观众连麦成功后,主播挂断观众的连麦
// 文件位置:TUILiveKit/iOS/TUILiveKit/Source/Service/SeatService.swiftfunc kickSeat(seat: SeatInfo) -> AnyPublisher<Void, InternalError> {return Future<Void, InternalError> { [weak self] promise inguard let self = self else { return }roomEngine.kickUserOffSeatByAdmin(seat.index, userId: seat.userId) {promise(.success(()))} onError: { err, message inlet error = InternalError(error: err, message: message)promise(.failure(error))}}.eraseToAnyPublisher()}
观众连麦成功后,观众结束连麦
// 文件位置:TUILiveKit/iOS/TUILiveKit/Source/Service/SeatService.swiftfunc leaveSeat() -> AnyPublisher<Void, InternalError> {return Future<Void, InternalError> { [weak self] promise inguard let self = self else { return }roomEngine.leaveSeat {promise(.success(()))} onError: { err, message inlet error = InternalError(error: err, message: message)promise(.failure(error))}}.eraseToAnyPublisher()}