客户端实现

更新时间: 2022/01/19 03:15:03

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

技术架构

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

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

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

业务流程

智慧云课堂的启动流程如下图所示。

当 App 客户端请求加入云课堂时:

  1. App 客户端向 App 服务端申请 查询房间信息。如果房间不存在,那么加入失败;如果房间已存在,那么加入房间。
  2. 加入课堂,先检测 IM 是否已经登录。未登录则需要登录,登录失败返回加入失败。向服务端发送加入课堂接口,成功后进入课程页面。
  3. 请求快照,获取聊天室 ID,加入聊天室。
  4. 开始初始化。更新本地流,开始拉流。

客户端实现方法

步骤一 集成到项目

  1. 新建 Android 工程。

    1. 运行 Android Sudio,在顶部菜单依次选择 File -> New -> New Project... 新建工程。
    2. 选择 Phone and Tablet -> Empty Activity ,并单击 Next
    3. 配置工程相关信息。

    Minimum API Level 为 API 21。

    1. 单击 Finish,完成工程创建。
  2. 添加依赖模块。

    1. 复制示例项目中的 Modulesconfig.gradleconfig.properties 等相关配置文件至当前目录。

    2. settings.gradle 引入 Modules

      implementation project(':edu-ui')
      implementation project(':recordplay-ui')
      implementation project(':viewbinding')
      
    3. 修改工程目录下的 app/build.gradle 文件,添加智慧云课堂 SDK 相关的依赖。

      allprojects {
          repositories {
              google()
              jcenter()
              maven{
                  url 'https://oss.sonatype.org/content/repositories/snapshots/'
              }
          }
      }
      
      // 若出现 More than one file was found with OS independent path 'lib/arm64-v8a/libc++_shared.so'.
      // 可以在主 module 的 build.gradle 文件中 android 闭包内追加如下 packageOptions 配置
      android{
          //......
          packagingOptions {
              pickFirst 'lib/arm64-v8a/libc++_shared.so'
              pickFirst 'lib/armeabi-v7a/libc++_shared.so'
          }
      }
      
      
      dependencies {
          //......
          // 添加EduUI依赖
          implementation project(':edu-ui')
      }
      
    4. 在顶部菜单单击 Build -> Make Project 构建工程,下载依赖。

      下载完成后即可在代码中引入云课堂组件中的类和方法。

  3. 权限配置。

    智慧云课堂 SDK 正常工作需要应用获取以下权限:

    <!-- 网络相关 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
    <!-- 多媒体 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.Manifest.permission.READ_PHONE_STATE"/>
    
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    

    以上权限已经在SDK内部进行声明,开发者无需在 AndroidManifest.xml文件中重新声明这些权限,但需要自己编码实现运行时的权限申请。运行时的权限可在应用首页中统一申请,详细信息请参考 Android 官方开发文档

步骤二 初始化组件

  1. 进行全局配置。

    首先创建 NEEduOptions 实例对 SDK 进行全局配置,然后调用 config 方法传入该实例。

    NEEduOptions 包含以下参数:

    | 配置项 | 说明 | |---|---| | APP_KEY | 应用的 AppKey。可以在网易云信控制台中查看。 | | BASE_URL | 应用服务器地址。私有化配置时需替换为私有化部署地址 | | AUTHORIZATION | 调用服务端接口时,请求头中的校验参数。 | | reuseIM | 配置是否复用底层NIM-SDK的长连接通道,默认关闭。仅当应用中同时还需独立接入和使用NIM-SDK,才需要开启该配置,其他情况下请忽略该配置。 |

    NEEduUiKit.config(
        this,
        NEEduOptions(
            BuildConfig.APP_KEY,
            BuildConfig.AUTHORIZATION,
            BuildConfig.API_BASE_URL,
            reuseIM
        )
    )
    
  2. 初始化

    配置完成后,创建 NEEduUiKit 实例,调用 init 方法进行初始化。包含以下参数:

    | 配置项 | 说明 | |---|---| | uuid | 用户鉴权userUuid。匿名登录时请设置为空字符串"" | | token | 用户鉴权userToken。匿名登录时请设置为空字符串"" |

    示例代码:

    NEEduUiKit.init(uuid, token).observeOnce(viewLifecycleOwner, initObserver)
    

步骤三 学生加入课堂

学生加入课堂时,会使用 NEEduClassOptions 的实例创建课堂并且加入,如果对应课堂号的课堂已经存在就直接加入。NEEduClassOptions 包含以下参数:

配置项 说明
classId 课程号,课堂唯一标识
className 课程名称
nickName 用户在课堂中的昵称
sceneType 课堂类型,有4种类型: 一对一教学、多人小班课、互动大班课、直播大班课
roleType 角色类型:host:教育场景中映射为老师,broadcaster: 教育场景中映射为学生

示例代码:

eduManager.enterClass(neEduClassOptions).map {
    if (it.success()) {
        when {
            NEEduUiKit.instance?.neEduManager == null -> {
                NEEduUiKit.destroy()
                ALog.w("eduManager not initialized!")
            }
            neEduClassOptions.roleType == NEEduRoleType.HOST -> {
                when (neEduClassOptions.sceneType) {
                    NEEduSceneType.ONE_TO_ONE -> {
                        OneToOneTeacherActivity.start(context)
                    }
                    NEEduSceneType.SMALL -> {
                        SmallClazzTeacherActivity.start(context)
                    }
                    NEEduSceneType.BIG -> {
                        BigClazzTeacherActivity.start(context)
                    }
                }
            }
            else -> {
                when (neEduClassOptions.sceneType) {
                    NEEduSceneType.ONE_TO_ONE -> {
                        OneToOneStudentActivity.start(context)
                    }
                    NEEduSceneType.SMALL -> {
                        SmallClazzStudentActivity.start(context)
                    }
                    NEEduSceneType.BIG -> {
                        BigClazzStudentActivity.start(context)
                    }
                    // 学生进入直播大班课
                    NEEduSceneType.LIVE_SIMPLE -> {
                        LiveClassActivity.start(context)
                    }
                }
            }
        }
    }
    it
}

步骤四 在线聊天室

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

师生调用 enterChatRoom 加入聊天室,并通过 sendMessage 发送文字和图片消息。

示例代码:

// 发起加入聊天室
// 首先创建EnterChatRoomData实例
val data = EnterChatRoomData(activity.eduRoom?.chatRoomId())
// 接着使用EnterChatRoomData实例进入聊天室
imService.enterChatRoom(data).observe(this, { it ->
    // 最后处理结果回调
    if (it.success()) roomInfo = it.data!!.roomInfo
    it
}

// 发送文本消息
// 首先创建文本消息
val chatMessage = ChatRoomMessageBuilder.createChatRoomTextMessage(it.roomId, text)
// 接着发送消息
imService.sendMessage(chatMessage)


// 发送图片消息
// 首先创建图片消息
val chatMessage =
    ChatRoomMessageBuilder.createChatRoomImageMessage(it.roomId, file, file?.name)
// 接着发送消息
imService.sendMessage(chatMessage)

步骤五 录制回放

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

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

  1. Recordplay 回放组件包含 recordplay-logicrecordplay-modelrecordplay-ui 3 个依赖模块。复制示例项目中的 recordplay-logicrecordplay-modelrecordplay-ui 这 3 个模块至当前项目目录。

  2. 添加模块依赖。

    示例代码:

    implementation project(':recordplay-ui')
    
  3. 课程结束后,回放观看端调用 fetchRecord 获取上一次的回放记录,并创建回放播放器实例。

    示例代码:

    RecordPlayRepository.appKey = BuildConfig.APP_KEY
    RecordPlayRepository.baseUrl = BuildConfig.API_BASE_URL
    // 根据roomUuid和rtcCid查询回放记录,并创建回放播放器实例
    NERecordPlayUiKit.fetchRecord(roomUuid, rtcCid)
        .observeOnce(viewLifecycleOwner, initRecordObserver)
        
    
    // 回放记录查询结果回调
    private val initRecordObserver = { t: NEResult<NERecordPlayer> ->
        when {
            t.success() -> {
                // 调用成功后进入回放观看界面
                enterRecordPlay()
            }
            // 音视频未完成转码,需要等待服务端20分钟左右进行转码
            t.code == NEEduHttpCode.NO_CONTENT.code -> {
                ALog.i("init record failed, result $t")
                ToastUtil.showLong(getString(R.string.course_playback_file_is_being_transcoded))
            }
            else -> {
                // 获取回放记录失败
                ALog.i("init record failed, result $t")
                val tip = context?.let { NEEduErrorCode.tipsWithErrorCode(it, t.code) }
                if (!TextUtils.isEmpty(tip)) {
                    ToastUtil.showLong(tip!!)
                } else {
                    ToastUtil.showLong(getString(R.string.open_recordplay_fail_try_again))
                }
            }
        }
    }
    
  4. 如果成功,那么跳转到 Recordplay 模块中的 NERecordActivity 回放界面。

    示例代码:

    NERecordActivity.start(requireActivity())
    
     <!-- 回放播放界面 -->
    <activity
       android:name=".NERecordActivity"
       android:configChanges="keyboardHidden|screenSize|orientation"
       android:launchMode="singleTop"
       android:screenOrientation="sensorLandscape"
       android:theme="@style/Theme.EduApp.Landscape" />
    
  5. 初始化播放器。

    示例代码:

    var recordPlayer = NERecordPlayer.instance
    recordPlayer.init(application, this)
    
  6. 开始播放。

    示例代码:

    // 判断播放状态
    when (recordPlayer.getState()) {
       // 处于播放就绪状态,开始播放
       NERecordPlayState.PREPARED, NERecordPlayState.PAUSED -> recordPlayer.start()
        ...
    }
    
  7. 暂停播放。

    示例代码:

    // 判断播放状态
    when (recordPlayer.getState()) {
        // 处于播放暂停状态,暂停播放
        NERecordPlayState.PLAYING -> recordPlayer.pause()
        ...
    }
    
  8. 拖动进度。

    示例代码:

    // 根据progress改变播放进度,progress介于 0 ~ 100 之间
    recordPlayer.seek(recordPlayer.getDuration() * progress / 100)
    

步骤六 结束课堂

调用 NEEduUiKit.destroy() 结束课程。

示例代码:

releasePlayer() // 释放视频播放器相关资源
NEEduUiKit.destroy() // 结束课程
此文档是否对你有帮助?
有帮助
去反馈
  • 技术架构
  • 业务流程
  • 客户端实现方法
  • 步骤一 集成到项目
  • 步骤二 初始化组件
  • 步骤三 学生加入课堂
  • 步骤四 在线聊天室
  • 步骤五 录制回放
  • 步骤六 结束课堂