客户端实现

更新时间: 2022/01/20 03:45:29

本文档为您展示智慧云课堂在互动大班课场景下的常见功能,您可以参考智慧云课堂方案实现互动大班课教学场景,也可以在此基础上实现业务功能的灵活扩展。

技术架构

如果示例项目中默认实现的 UI 不符合您的预期,您可以按需实现自己的用户界面,即只使用我们封装好的组件所提供的音视频能力,自行实现 UI 部分。

教育组件的架构如下图所示。

技术架构-iOS.png

  • EduUI:教育组件的UI配置,包括一对一教学、多人小班课、互动大班课、直播大班课等场景的 ViewController、View 以及 model 部分。
  • EduLogic:基于云信 NERTC SDK、IM SDK 定制的,针对教育场景的逻辑实现,包括如下2个服务:
    • NEEduRtcService 是音视频服务,提供可供 App 调用的音视频相关方法。
    • NEEduIMService 是 IM 服务,提供可供 App 调用的即时通信、聊天室相关方法。
  • NEWhiteBoard:云信的互动白板服务,提供可供 App 调用的互动白板相关方法。

业务流程

下图展示了启动智慧云课堂的基本流程:

当 App 客户端请求加入云课堂时,业务流程如下:

  1. App 客户端向 App 服务端申请创建场景。根据创建场景的配置参数,查询房间信息,如果房间不存在,则生成房间信息;如果房间已存在,提示已存在。
  2. 加入课堂,先检测 IM 是否已经登录,没登录需要登录,登录失败返回加入失败。向服务端发送加入课堂接口,成功后进入课程页面, 根据状态加入音视频房间。
  3. 请求快照,获取聊天室 ID,加入聊天室。
  4. 初始化组件。加入白板房间,白板服务器会进行 IM 账号鉴权。更新本地流,开始拉流。

客户端实现方法

步骤一 集成组件

  1. 新建 iOS 工程。

    1. 运行 XCode,单击 Create a new Xcode project
    2. 选择 Single View App,单击 Next
    3. 配置工程相关信息,单击 Next
    4. 选择合适的工程本地路径,并单击 Create 创建工程。
  2. 集成 SDK。

    1. 复制示例项目中的 Modules 文件夹到项目目录下。

    2. 进入工程目录,创建 Podfile 文件。

      podpod init
      
    3. 添加 pod 本地依赖,复制以下代码到 Podfile 文件。

      podplatform :ios, '10.0'
      target '工程名' do
      use_frameworks!
      pod 'EduLogic', :path => 'Modules/EduLogic/EduLogic.podspec'
      pod 'NEWhiteBoard', :path => 'Modules/NEWhiteBoard/NEWhiteBoard.podspec'
      pod 'NEScreenShareBroadcaster', '~> 0.1.0'
      
    4. 执行以下命令安装组件。

      podpod install
      
  3. 添加摄像头和麦克风的权限。

    智慧云课堂 SDK 正常工作需要摄像头、麦克风权限。

    1. 在工程中的 Info.list 文件中配置相关的权限信息。

      Privacy - Microphone Usage Description
      Privacy - Camera Usage Description
      
    2. 在工程的 Signing&Capabilities 添加 Background Modes,并勾选 Audio、Airplay、and Picture in Picture

步骤二 初始化组件

  1. 在使用组件其他功能之前,首先需要通过 setupAppKey 方法完成组件初始化。

示例代码:

objective-cNEEduKitOptions *option = [[NEEduKitOptions alloc] init];
option.authorization = [KeyCenter authorization];
option.baseURL = [KeyCenter baseURL];
[[EduManager shared] setupAppKey:[KeyCenter appKey] options:option];
  1. (可选)私有云场景的初始化配置。

    当部署场景为私有云时,您需要对云课堂用到的IM、RTC、互动白板和应用服务器,增加私有云相关配置。公有云请忽略该配置

    V1.9.2及之后的智慧云课堂版本,才支持私有云的配置。

    • 应用服务器的私有云配置。

      KeyCenter类中,将baseUrl的值改为私有云中应用服务的URL地址。

      | 配置项 | 说明 | |---|---| | baseUrl | 应用服务在私有云中的URL地址 |

    • IM的私有云配置。

      1. 联系网易云信技术支持获取 IM 私有云的配置文件,并将文件名改为server.conf
      2. server.conf拷贝到项目的根目录。
    • RTC的私有云配置。

      1. 联系网易云信技术支持获取 RTC 私有云的配置文件,并将文件名改为rtc_server.conf

      2. rtc_server.conf拷贝到项目的根目录。

      3. 在云课堂初始化时,打开 RTC 私有云配置的开关。示例代码如下:

        Objective-C
        NEEduKitOptions *option = [[NEEduKitOptions alloc] init];
        option.authorization = [KeyCenter authorization];
        option.baseURL = [KeyCenter baseURL];
        // 读取私有云文件开关
        option.configRead = YES;
        [[EduManager shared] setupAppKey:[KeyCenter appKey] options:option];
        
        
    • 互动白板的私有云配置。

      1. 联系网易云信技术支持获取互动白板私有云的配置文件,并将文件名改为wb_server.conf

      2. wb_server.conf拷贝到项目的根目录。

      3. 在云课堂初始化时,打开互动白板私有云配置的开关。示例代码如下:

        Objective-C
        [NMCWhiteboardManager sharedManager].configRead = YES;
        
      4. 修改互动白板webView的URL地址。即在NMCWhiteboardManager类的.m文件中,将NMCWhiteboardUrl的值设置为您的私有云地址。示例代码如下:

        Objective-C
        NSString *const NMCWhiteboardUrl = @”您的私有云地址“;
        
        
      5. 修改互动白板录像回放webView的URL地址。即在NEWBRecordPlayer类的.m文件中,将NMCWhiteboardRecordUrl的值设置为您的私有云地址,示例代码如下:

        Objective-C
        NSString *const NMCWhiteboardRecordUrl = @”您的私有云地址“;
        

步骤三 教师端开启课堂

  1. 教师端登录智慧云课堂。

    调用 login 登录课堂,登录课堂成功后,自动创建对应课堂。

    示例代码:

    objective-c__weak typeof(self)weakSelf = self;
    [[EduManager shared] login:nil success:^(NEEduUser * _Nonnull user) {
    __strong typeof(self)strongSelf = weakSelf;
    //登录成功,创建房间
    [strongSelf createRoom];
    } failure:^(NSError * _Nonnull error) {
            //登录失败处理逻辑
    }];
    
  2. 选择课堂类型。

    课堂类型分为 1 对 1 教学、多人小班课、互动大班课和直播大班课,您可以在开课的逻辑中自定义相关 UI 显示、菜单、行为等,并配置课堂最大容纳人数。

    示例代码:

    objective-cNEEduRoom *room = [[NEEduRoom alloc] init];
        room.roomName = [NSString stringWithFormat:@"%@的课堂",self.nicknameView.text];
        room.sceneType = self.lessonType;
        switch (room.sceneType) {
            case NEEduSceneType1V1:
            {
                room.configId = 5;
            }
                break;
            case NEEduSceneTypeSmall:
            {
                room.configId = 6;
            }
                break;
            case NEEduSceneTypeBig:
            {
                room.configId = 7;
            }
                break;
            default:
                break;
        }
        room.roomUuid = [NSString stringWithFormat:@"%@%d",self.lessonIdView.text,room.configId];
        __weak typeof(self)weakSelf = self;
        [[EduManager shared].roomService createRoom:room completion:^(NEEduCreateRoomRequest *result,NSError * _Nonnull error) {
        // 创建结果处理
        }];
    

步骤四 学生端进入课堂

学生端通过 enterClassroom 加入已创建的课堂。示例代码如下:

objective-cNEEduEnterRoomParam *room = [[NEEduEnterRoomParam alloc] init];
    room.autoPublish = YES;
    room.autoSubscribeVideo = YES;
    room.autoSubscribeAudio = YES;
    room.roomUuid = resRoom.roomUuid;
    room.roomName = resRoom.roomName;
    room.sceneType = self.lessonType;
    room.role = NEEduRoleTypeStudent;
    room.userName = @"";
    __weak typeof(self)weakSelf = self;
    [[EduManager shared] enterClassroom:room success:^(NEEduRoomProfile * _Nonnull roomProfile) {
        // 进入成功处理
    } failure:^(NSError * _Nonnull error) {
        // 进入失败处理
}

步骤五 课堂互动

教学双方加入教室后,开启课程,可以进行课堂互动。智慧云课堂提供了丰富的课堂功能,如:互动白板、屏幕共享、举手、视频、语音等。

  1. 开始上课。

    教师端开始上课。

    示例代码:

    objective-c[[NEEduManager shared].roomService startLesson:state completion:^(NSError * _Nonnull error, NEEduPropertyItem * _Nonnull item) {
            button.userInteractionEnabled = YES;
            if (error) {
            [weakSelf.view makeToast:error.localizedDescription];
            }else {
            [weakSelf.maskView selectButton:!selected];
            }
        }];
    
  2. 学生管理。

    1. 教师端调用 remoteUserVideoEnable:userID:result:remoteUserAudioEnable:userID:result: 方法控制学生端的摄像头和麦克风。如果需要和学生互动,可以开启对方的麦克风。

      示例代码:

      objective-c[[NEEduManager shared].userService remoteUserAudioEnable:!member.streams.audio.value userID:member.userUuid result:^(NSError * _Nonnull error) {
          if (error) {
              [weakSelf.view makeToast:error.description];
          }else {
              [weakSelf.view makeToast:@"操作成功"];
          }
          }];
      
    2. 教师端调用 whiteboardDrawable:userID:result:screenShareAuthorization:userID:result: 方法授权学生使用白板或屏幕共享。

      示例代码:

      objective-c__weak typeof(self)weakSelf = self;
      [[NEEduManager shared].userService localShareScreenEnable:NO result:^(NSError * _Nonnull error) {
          if (error) {
          [self.view makeToast:error.localizedDescription];
          }else {
          weakSelf.isSharing = NO;
          weakSelf.shareScreenMask.hidden = YES;
          [weakSelf updateShareItemWithSelected:NO];
          }
      }];
      
  3. 屏幕共享。

    教师端或学生端调用 localShareScreenEnable:result: 发起屏幕共享,共享本端屏幕给其他人观看。

    示例代码:

    objective-c//这里只是同步共享消息,前置条件:发起 NERtcEngine 屏幕共享,详细参考项目源码。
    __weak typeof(self)weakSelf = self;
        [[NEEduManager shared].userService localShareScreenEnable:NO result:^(NSError * _Nonnull error) {
        if (error) {
            [self.view makeToast:error.localizedDescription];
        }else {
            weakSelf.isSharing = NO;
            weakSelf.shareScreenMask.hidden = YES;
            [weakSelf updateShareItemWithSelected:NO];
        }
        }];
    
  4. 在线聊天室。

在多人小班课、互动大班课、直播大班课中,可以通过聊天室实现消息收发,学生和学生、学生和老师之间通过聊天室发送文字或图片消息,教师端可以禁言或解禁聊天室。

教师和学生调用 enterChatRoomWithParam:success:failed: 加入聊天室,并通过 sendChatroomTextMessage:error:sendChatroomImageMessage:error:发送文字和图片消息。

示例代码:

- (void)addChatroom:(NEEduHttpRoom *)room {
  __weak typeof(self) weakSelf = self;
  NEEduChatRoomParam *chatparam = [[NEEduChatRoomParam alloc] init];
  chatparam.chatRoomID = room.properties.chatRoom.chatRoomId;
  chatparam.nickname = [NSString stringWithFormat:@"%@(学生)",[NEEduManager shared].localUser.userName];
  [[NEEduManager shared].imService enterChatRoomWithParam:chatparam success:^(NEEduChatRoomResponse * _Nonnull response) {
    __strong typeof(self)strongSelf = weakSelf;
    [strongSelf addChatMenue];
  } failed:^(NSError * _Nonnull error) {
    __strong typeof(self)strongSelf = weakSelf;
    [strongSelf.view makeToast:error.localizedDescription];
  }];
}

步骤六 录制回放

在线教育场景中,可实现上课过程中录制老师和学生的音视频、白板、屏幕共享,还原真实上课场景,供学生和教师回放复习。目前所有课堂模式都支持录制回放。录制功能包含在云端录制服务中,用户端只需要接入Recordplay 回放组件,回放功能依赖的代码包含在组件里面。

教师开始上课时,服务器会自动开始录制。课程结束时,需要等待服务端进行转码,预计 20 分钟左右。转码完成后,用户可以通过 Recordplay 回放组件观看录制内容。在示例项目中,展示了如何快速接入 Recordplay 回放组件。

接入步骤如下:

  1. 在 podfile 中,将 Recordplay 回放组件所依赖的 NERecordPlay、NERecordPlayUI 模块,添加到自己的项目中。 示例代码:

    podpod 'NERecordPlay', :path => 'Modules/NERecordPlay/NERecordPlay.podspec'
    pod 'NERecordPlayUI', :path => 'Modules/NERecordPlayUI/NERecordPlayUI.podspec'
    
  2. 课程结束后,回放观看端调 getRecordListWithRoomUuid:rtcCid:success:failure: 获取上一次的回放记录,并创建回放播放器实例。

    示例代码:

    objective-c- (void)recordPlayEvent:(UIButton *)button {
    NSString *lastRoomUuid = [[NSUserDefaults standardUserDefaults] objectForKey:kLastRoomUuid];
    NSString *lastRtcCid = [[NSUserDefaults standardUserDefaults] objectForKey:kLastRtcCid];
    NSString *lastUserUuid = [[NSUserDefaults standardUserDefaults] objectForKey:kLastUserUuid];
    NSString *lastUserToken = [[NSUserDefaults standardUserDefaults] objectForKey:kLastUserToken];
    NERecordRequest *request = [[NERecordRequest alloc] initWithAppKey:[KeyCenter appKey] authorization:[KeyCenter authorization] baseUrl:[KeyCenter baseURL] userUuid:lastUserUuid token:lastUserToken];
    [request getRecordListWithRoomUuid:lastRoomUuid rtcCid:lastRtcCid success:^(id _Nonnull data) {
        if (!data) {
        [self.view makeToast:@"课程结束后,需进行文件转码,预计20分钟后可观看回放"];
        return;
        }
        NERecordViewController *vc = [[NERecordViewController alloc] init];
        vc.modalPresentationStyle = UIModalPresentationOverFullScreen;
        vc.recordData = data;
        [self presentViewController:vc animated:YES completion:nil];
    } failure:^(NSError * _Nonnull error) {
        [self.view makeToast:error.localizedDescription];
    }];
    }
    
  3. 如果成功,那么跳转到 Recordplay 模块中的 NERecordViewController 回放界面。

    示例代码:

    objective-cNERecordViewController *vc = [[NERecordViewController alloc] init];
    vc.modalPresentationStyle = UIModalPresentationOverFullScreen;
    vc.recordData = data;
    [self presentViewController:vc animated:YES completion:nil];
    
  4. 初始化播放器。

    示例代码:

    objective-cfunc createPlayer() {
        guard let data = recordData else {
        print("error:recordData = nil")
        return
        }
        player = NEEduRecorderPlayerManager(data: data, view: contentView)
        player?.delegate = self
        recordList = player?.playingRecordItems
        player?.prepareToPlay() 
    }
    
    func addNetListen() {
        NetworkReachabilityManager.default?.startListening(onUpdatePerforming: { state in
        print("state:\(state)")
        if state == .notReachable {
            self.navView.netState.image = UIImage.ne_imageName(name: "net_0")
        }else {
            self.navView.netState.image = UIImage.ne_imageName(name: "net_3")
        }
        })
    }
    
  5. 开始播放。

    示例代码:

    objective-c@objc func playButtonEvent(button: UIButton) {
        print(#function,button)
        button.isSelected = !button.isSelected
        button.isSelected ? player?.play() : player?.pause()
    }
    
  6. 暂停播放。

    示例代码:

    objective-c@objc func playButtonEvent(button: UIButton) {
        print(#function,button)
        button.isSelected = !button.isSelected
        button.isSelected ? player?.play() : player?.pause()
    }
    
  7. 拖动进度。

    示例代码:

    objective-c@objc func sliderEvent(slider: UISlider, event: UIEvent) {
        guard let touch: UITouch = event.allTouches?.first else {
        return
        }
        switch touch.phase {
        case .began,.moved:
        seeking = true
        case .ended,.cancelled:
        seeking = false
        player?.seekTo(time: Double(slider.value) * player!.duration)
        default:
        return
        }
    }
    

步骤七 结束课堂

调用 player?.stop() 结束课堂。

示例代码:

objective-c@objc func backButtonEvent(button: UIButton) {
    player?.stop()
    self.dismiss(animated: true, completion: nil)
  }
此文档是否对你有帮助?
有帮助
去反馈
  • 技术架构
  • 业务流程
  • 客户端实现方法
  • 步骤一 集成组件
  • 步骤二 初始化组件
  • 步骤三 教师端开启课堂
  • 步骤四 学生端进入课堂
  • 步骤五 课堂互动
  • 步骤六 录制回放
  • 步骤七 结束课堂