客户端实现

更新时间: 2022/01/20 03:43:43

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

技术架构

如果示例项目中默认实现的 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

步骤二 初始化组件

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

示例代码:

objective-cNEEduKitOptions *option = [[NEEduKitOptions alloc] init];
option.authorization = [KeyCenter authorization];
option.baseURL = [KeyCenter baseURL];
[[EduManager shared] setupAppKey:[KeyCenter appKey] options:option];

步骤三 学生端进入课堂

学生端通过 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) {
        // 进入失败处理
}

步骤四 在线聊天室

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

师生调用 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. Recordplay 回放组件包含 NERecordPlay、NERecordPlayUI 2 个依赖模块,podfile 中添加依赖到自己的项目中:

    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)
  }
此文档是否对你有帮助?
有帮助
去反馈
  • 技术架构
  • 业务流程
  • 客户端实现方法
  • 步骤一 集成组件
  • 步骤二 初始化组件
  • 步骤三 学生端进入课堂
  • 步骤四 在线聊天室
  • 步骤五 录制回放
  • 步骤六 结束课堂