# 3\_5-云课堂场景-连麦

* [1 功能概述](#_1-功能概述)
* [2 使用演示](#_2-使用演示)
* [3 实现介绍](#_3-实现介绍)
  * [3.1 PLVLinkMicPresenter](#_31-plvlinkmicpresenter)
  * [3.2 PLVLCLinkMicControlBar](#_32-plvlclinkmiccontrolbar)
    * [3.2.1 初始化方法](#_321-初始化方法)
    * [3.2.2 PLVLCLinkMicControlBarDelegate](#_322-plvlclinkmiccontrolbardelegate)
  * [3.3 PLVLCLinkMicWindowsView](#_33-plvlclinkmicwindowsview)

#### 1 功能概述

保利威云课堂sdk支持连麦功能，举手连麦、音频连麦、视频连麦可自由选择，并支持多人连麦，丰富课堂内容。

连麦流程：讲师端发起连麦->学员举手申请连麦->讲师端允许学员连麦->学员正式加入连麦。

#### 2 使用演示

在demo项目中`PLVLCCloudClassViewController` 演示了如何创建连麦布局，以及如何调用初始化方法。

```objective-c
self.linkMicAreaView = [[PLVLCLinkMicAreaView alloc] init];
self.linkMicAreaView.delegate = self;
```

其中`PLVLCLinkMicAreaView`负责管理`PLVLinkMicPresenter`连麦管理器，`PLVLCLinkMicControlBar`连麦悬浮控制栏以及`PLVLCLinkMicWindowsView`连麦窗口列表视图。因此可`PLVLCLinkMicAreaView`作为连麦模块集成使用。

同时 `PLVLCCloudClassViewController` 需遵循协议 `PLVLCLinkMicAreaViewDelegate`。该协议提供第一画面切换回调、连麦状态变更回调等相关的回调，用于视图的更新和切换。该协议提供以下代理方法：

```objective-c
@protocol PLVLCLinkMicAreaViewDelegate <NSObject>

/// RTC画面窗口 需外部展示 ‘第一画面连麦窗口’
///
/// @param linkMicAreaView 连麦区域视图
/// @param canvasView 第一画面连麦窗口视图 (需外部进行添加展示)
- (void)plvLCLinkMicAreaView:(PLVLCLinkMicAreaView *)linkMicAreaView showFirstSiteCanvasViewOnExternal:(UIView *)canvasView;

/// RTC画面窗口被点击 (表示用户希望视图位置交换)
///
/// @note 当接收到此回调时，表示用户希望 某个Rtc画布视图(即canvasView) 在外部位置中显示，可对 canvasView 作相应布局处理
///
/// @param linkMicAreaView 连麦区域视图
/// @param canvasView Rtc画布视图
- (UIView *)plvLCLinkMicAreaView:(PLVLCLinkMicAreaView *)linkMicAreaView rtcWindowDidClickedCanvasView:(UIView *)canvasView;

/// 恢复外部视图位置
///
/// @note 当外部视图需要回归原位时，此回调将被触发；接收到此回调后，可将 externalView 重新布局在原位上
///
/// @param linkMicAreaView 连麦区域视图
/// @param externalView 被添加在连麦区域视图上的外部视图
- (void)plvLCLinkMicAreaView:(PLVLCLinkMicAreaView *)linkMicAreaView rollbackExternalView:(UIView *)externalView;

/// ‘是否在RTC房间中’ 状态值发生改变
///
/// @param linkMicAreaView 连麦区域视图
/// @param inRTCRoom 当前 是否在RTC房间中
- (void)plvLCLinkMicAreaView:(PLVLCLinkMicAreaView *)linkMicAreaView inRTCRoomChanged:(BOOL)inRTCRoom;

/// ‘RTC房间在线用户数’ 发生改变
///
/// @param linkMicAreaView 连麦区域视图
/// @param currentRTCRoomUserCount 当前 RTC房间在线用户数
- (void)plvLCLinkMicAreaView:(PLVLCLinkMicAreaView *)linkMicAreaView currentRTCRoomUserCountChanged:(NSInteger)currentRTCRoomUserCount;

/// ‘是否正在连麦’ 状态值改变
///
/// @param linkMicAreaView 连麦区域视图
/// @param inLinkMic 当前是否正在连麦 (YES:正在连麦中 NO:不在连麦中)
- (void)plvLCLinkMicAreaView:(PLVLCLinkMicAreaView *)linkMicAreaView inLinkMicChanged:(BOOL)inLinkMic;

/// 需获知 ‘当前频道是否直播中’
///
/// @note 此回调不保证在主线程触发
///
/// @param linkMicAreaView 连麦区域视图
- (BOOL)plvLCLinkMicAreaViewGetChannelInLive:(PLVLCLinkMicAreaView *)linkMicAreaView;

/// 需获知 ‘主讲的PPT 当前是否在主屏’
///
/// @note 此回调不保证在主线程触发
///
/// @param linkMicAreaView 连麦区域视图
- (BOOL)plvLCLinkMicAreaViewGetMainSpeakerPPTOnMain:(PLVLCLinkMicAreaView *)linkMicAreaView;

@end
```

并在 `-viewWillLayoutSubviews` 方法中，对 `PLVLCLinkMicAreaView` 进行布局，具体可参考demo项目中`PLVLCCloudClassViewController`的实现。

#### 3 实现介绍

**3.1 PLVLinkMicPresenter**

`PLVLinkMicPresenter`连麦管理器在demo项目中已由`PLVLCLinkMicAreaView`进行管理，可查看以下说明，了解如何自行使用`PLVLinkMicPresenter`。

连麦功能模块使用了mvp模式，因此在实现时需要先初始化Presenter。

```objective-c
self.presenter = [[PLVLinkMicPresenter alloc] init];

self.presenter.delegate = self;

self.presenter.preRenderContainer = self;
```

同时需要配置默认值，以连麦悬浮控制栏中声明的为准，详见demo项目中`PLVLCLinkMicControlBarProtocol.h`。 若业务改变时，可直接修改 `PLVLCLinkMicControlBarProtocol.h` 的默认值，则连麦管理器 中同时生效。

```objective-c
self.presenter.micDefaultOpen = PLVLCLinkMicControlBarMicDefaultOpen;

self.presenter.cameraDefaultOpen = PLVLCLinkMicControlBarCameraDefaultOpen;

self.presenter.cameraDefaultFront = PLVLCLinkMicControlBarSwitchCameraDefaultFront;
```

同时使用 `PLVLinkMicPresenter` 可遵循协议 `PLVLinkMicPresenterDelegate`，并按需求实现其中代理方法。更多内容可以参考demo项目中`PLVLCLinkMicAreaView` 的演示。

**3.2 PLVLCLinkMicControlBar**

`PLVLCLinkMicControlBar`连麦悬浮控制栏在demo项目中已由`PLVLCLinkMicAreaView`进行管理，可查看以下说明，可了解如何自行使用`PLVLCLinkMicControlBar`对其进行轻度修改或模仿重写实现业务场景。

`PLVLCLinkMicControlBar` 在`PLVLCLinkMicAreaView` 中初始化，由连麦悬浮控制条的点击事件以及刷新连麦控制条的UI状态。主要的逻辑集中在动画、点击事件响应、和横竖屏两套UI保持同步。

**3.2.1 初始化方法**

`PLVLCLinkMicLandscapeControlBar`和`PLVLCLinkMicPortraitControlBar` 分别是连麦悬浮控制条`PLVLCLinkMicControlBar`的竖屏和横屏的实现。

```objective-c
_portraitControlBar = [[PLVLCLinkMicPortraitControlBar alloc] init];
_portraitControlBar.delegate = self;
_landscapeControlBar = [[PLVLCLinkMicLandscapeControlBar alloc] init];
_landscapeControlBar.delegate = self;
```

`PLVLCLinkMicControlBarProtocol`是连麦控制栏对象抽象协议，在`PLVLCLinkMicAreaView`中用于控制当前连麦悬浮控制栏currentControlBar。实现\[setCurrentControlBar]可以参考demo项目中`PLVLCLinkMicAreaView` 的演示。

```objective-c
 self.currentControlBar = self.landscapeControlBar; //设置当前悬浮控制条为竖屏样式
```

在`PLVLCCloudClassViewController`中合适时机中需要插入currentControlBar，具体实现可以参考demo项目中`PLVLCCloudClassViewController` 的演示。

**3.2.2 PLVLCLinkMicControlBarDelegate**

`PLVLCLinkMicAreaView` 需遵循协议 `PLVLCLinkMicControlBarDelegate`，并实现其中代理方法。以连麦开关按钮被点击为例，通过不同的状态调用PLVLinkMicPresenter的申请连麦、取消申请连麦、退出连麦：

```objective-c
- (void)plvLCLinkMicControlBar:(id<PLVLCLinkMicControlBarProtocol>)bar onOffButtonClickedCurrentStatus:(PLVLCLinkMicControlBarStatus)status{
    __weak typeof(self) weakSelf = self;
    if (status == PLVLCLinkMicControlBarStatus_Open) {
        // Bar 处于显示 ‘申请连麦’，点击表示希望申请连麦
        [self.presenter requestJoinLinkMic];
    }else if (status == PLVLCLinkMicControlBarStatus_Waiting){
        // Bar 处于显示 ‘请求中...’，点击表示希望取消申请连麦
        [PLVFdUtil showAlertWithTitle:@"确认取消申请连麦吗？" message:nil viewController:[PLVFdUtil getCurrentViewController] cancelActionTitle:@"按错了" cancelActionStyle:UIAlertActionStyleDefault cancelActionBlock:nil confirmActionTitle:@"取消申请连麦" confirmActionStyle:UIAlertActionStyleDestructive confirmActionBlock:^(UIAlertAction * _Nonnull action) {
            [weakSelf.presenter cancelRequestJoinLinkMic];
        }];
    }else if (status == PLVLCLinkMicControlBarStatus_Joined){
        // Bar 处于已连麦，点击表示希望取消申请连麦
        [PLVFdUtil showAlertWithTitle:@"确认挂断连麦吗？" message:nil viewController:[PLVFdUtil getCurrentViewController] cancelActionTitle:@"按错了" cancelActionStyle:UIAlertActionStyleDefault cancelActionBlock:nil confirmActionTitle:@"挂断" confirmActionStyle:UIAlertActionStyleDestructive confirmActionBlock:^(UIAlertAction * _Nonnull action) {
            [weakSelf.presenter leaveLinkMic];
        }];
    }
}
```

更多内容可以参考demo项目中`PLVLCLinkMicAreaView` 的演示。

**3.3 PLVLCLinkMicWindowsView**

`PLVLCLinkMicWindowsView`是连麦功能模块的主体，负责展示多个连麦成员RTC画面窗口，该视图支持左右滑动浏览。初始化方法参考如下：

```objective-c
_windowsView = [[PLVLCLinkMicWindowsView alloc] init];
_windowsView.delegate = self;
```

同时 `PLVLCLinkMicAreaView` 需遵循协议 `PLVLCLinkMicWindowsViewDelegate`，并实现其中代理方法，与`PLVLinkMicPresenter`连麦管理器实现数据交换。示例如下：

```objective-c
#pragma mark PLVLCLinkMicWindowsViewDelegate
/// 连麦窗口列表视图 需获知 ‘当前频道连麦场景类型’
- (PLVChannelLinkMicSceneType)plvLCLinkMicWindowsViewGetCurrentLinkMicSceneType:(PLVLCLinkMicWindowsView *)windowsView{
    return self.presenter.linkMicSceneType;//获取连麦管理当前频道连麦场景类型
}
/// 连麦窗口被点击事件 (表示用户希望某个窗口成为‘第一画面’)
- (void)plvLCLinkMicWindowsView:(PLVLCLinkMicWindowsView *)windowsView linkMicUserWantToBecomeFirstSite:(NSInteger)index{
    [self.presenter changeMainSpeakerInLocalWithLinkMicUserIndex:index];//连麦管理器请求变更‘第一画面’
}

/// 连麦窗口列表视图 需要获取当前用户数组
- (NSArray *)plvLCLinkMicWindowsViewGetCurrentUserModelArray:(PLVLCLinkMicWindowsView *)windowsView{
    return self.presenter.onlineUserArray;//获取连麦管理器当前RTC房间在线用户数组
}
```

更多内容可以参考demo项目中`PLVLCLinkMicAreaView` 的演示。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://polyv.gitbook.io/document/docs/live/ios/35-yun-ke-tang-chang-jing-lian-mai.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
