直播问答模式是用户在指定时间内登陆直播间,在主持人引导下进行线上答题,答对12道题目即可冲顶奖金,瓜分每期设定的奖金。从2018年伊始,互联网圈就刮起了一阵“大佬狂撒币,网友喜答题”的热潮,那么如何在自己的业务中增加这样强互动的方式,促成用户活跃的提升呢?下面以阿里视频云提供的方案为例,描述如何搭建直播答题功能。

  • 如果业务中还没有直播的服务,请 注册阿里云账号开通视频直播服务
  • 目前我们提供的方式是在直播流中通过APPServer调用openAPI来插入SEI信号,使用阿里云答题播放器解析SEI信号。

实现方案

步骤一:流程说明
  1. 主持人提出问题,此时准备推送题目。
  2. 现场人员发出信息,通过接入方的AppServer,调用阿里云的OpenAPI,在直播视频流当前位置中插入若干SEI帧,帧内容可由业务自定义。
  3. 播放SDK接收到视频流后,解析出SEI帧,并回调给APP。此时APP立即向AppServer请求问题信息,然后显示在APP上,完成整个出题过程。
    说明 在这个方案中,由于推流会产生固定的延时,而现场人员是通过云端服务插入SEI信号,有可能插入SEI的画面比真实插入时间早一点。因此现场人员在出题前需要做好校准,在插入SEI信号时加入一个固定延迟。

    举例:现场主持人在12:00:00时提出问题,假设现场到阿里云的推流延时有1秒,那么现场工作人员应在12:00:01时调用添加SEI的OpenAPI(或者在12:00:00时调用,但是OpenAPI里面的delay参数设置为1000),这样正好保证SEI插入的是12:00:00主持人提出问题时的画面。

    说明
    • 客户端在收到SEI信号后,需要向服务器获取问题,这会产生一定的通信耗时。因此实际答题系统中,可酌情延长答题时间,比如在原有答题时间上+1秒。
    • 用户答题后,客户端需要上报答案,这会产生一定的通信耗时。因此实际答题系统中,AppServer在接收到答案时,答题超时时间允许有一个宽限值,比如原有的答题时限+1秒之内的均认为及时答题。

    详见如下直播问答服务的架构图:



步骤二:配置与开通
  • 首先需要开通阿里云视频直播服务。
  • 提出工单,要求开通视频云添加SEI功能(提交域名和appname信息)。
  • 在推流时,需要增加一个推流参数wm=1
步骤三:服务端API调用

如前流程介绍,在接入方的appserver完成视频流中添加SEI信号时需要调用以下接口。

说明 除了通过服务端api方式插入SEI信号完成题目下发,还可以通过我们提供的 定制OBS工具完成推题
  1. 添加SEI的OpenAPI
    • 请求参数
      参数 类型 是否必须 描述
      Action String 操作接口名,系统规定参数,取值:AddTrancodeSEI
      DomainName String 您的加速域名。
      AppName String 直播流所属应用名称。
      StreamName String 流名(SEI将会被添加到该流以及该流所产生的所有转码流上)。
      Text String SEI文本,长度限制: 4000 字节。
      Pattern String 追加到每一个关键帧 、每一帧。

      取值:keyframe 、frame。

      Repeat Integer 重复次数,-1 代表无限。
      Delay Integer 接收到命令后的 delay 时间(毫秒)。
    • 返回参数
      名称 类型 描述
      RequestId String 该条任务请求ID
    • 特殊错误码
      错误代码 描述 Http 状态码 语义
      InvalidDomain.NotFound The domain provided does not exist in our records. 404 当前账户下未查到域名
      IllegalOperation Illegal domain operate is not permitted. 403 不支持当前操作,如:非直播类域名
      InvalidParams Invalid parameters 400 参数不合法
      InternalError The request processing has failed due to some unknown error. 500 后台发生未知错误
  2. 调用示例
    https://live.aliyuncs.com?Action=AddTrancodeSEI&Domain=test101.cdnpe.com&App=xxx&Stream=xxx&Text=hahaha&Pattern=frame&Repeat=300&Delay=0&<公共请求参数>
    
    说明 在直播答题这种场景下,参数 Pattern建议取值 frameRepeat建议为3倍的关键帧间隔(示例中为 300)。这样设置可以保证在3个关键帧间隔内,即便发生丢帧,只要播放器收到1帧,即可取得SEI信息。由于SEI在多帧内重复,所以播放器需要做SEI去重的工作。
步骤四:接入答题播放器

首先需要集成阿里云播放器SDK,具体参考如下链接:播放器相关文档参见 播放器SDK > 产品介绍

针对直播答题,播放器SDK提供了SEI数据的回调,分别来看Android和iOS对应的接口
  1. Android SEI数据回调
    通过播放器设置SEI数据回调接口,来获取到SEI的数据,从而进行业务的处理。 方法如下:
    • setSEIDataListener

      public void setSEIDataListener(MediaPlayerSEIDataListener listener)

      描述:给播放器设置SEI数据的回调,获取流中的SEI数据。

      参数:回调监听。

    • MediaPlayer.MediaPlayerSEIDataListener

      public void onSEIdata(String data)

      描述:SEI数据的回调监听

      参数:data:SEI的数据。

    说明 同一次播放,如果SEI数据相同,则只回调一次,后续的相同数据不会回调。
    使用示例
    aliVcMediaPlayer = new AliVcMediaPlayer(DemoLiveAnswerActivity.this, videoSurface);
    aliVcMediaPlayer.setSEIDataListener(new MediaPlayer.MediaPlayerSEIDataListener() {
            @Override
            public void onSEIdata(String data) {
                   praseData(data);//解析SEI data数据
            }
    });
    aliVcMediaPlayer.setMaxBufferDuration(3 * 1000);
    aliVcMediaPlayer.prepareAndPlay(liveUrl);
    
    private void praseData(String data) {
    //具体格式按照自己业务的需求去解析,然后做业务处理
         JSONObject jsonObject = null;
         try {
             jsonObject = new JSONObject(data);
         } catch (JSONException e) {
             e.printStackTrace();
         }
    
         SeiInfo seiInfo = SeiInfo.getFromJson(jsonObject);
         if (seiInfo == null) {
             Toast.makeText(getApplicationContext(), "SEI 数据错误", Toast.LENGTH_SHORT).show();
             return;
         }
    
         if (seiInfo.type.equals("startAnswer")) {
         //到服务器请求题目
             requestQuestion(seiInfo.questionId);
         } else if (seiInfo.type.equals("showResult")) {
         //到服务器请求答题汇总
             requestQuestionReport(seiInfo.questionId, seiInfo.showTime);
         }
    
     }
    

    以上方法均可在Demo中找到使用方法。

  2. iOS SEI数据回调

    通过监听播放器SEI数据通知来获取SEI数据,具体的通知如下:

    AliVcMediaPlayerSeiDataNotification

    使用示例
    添加监听通知接口:
    //直播答题接收的消息
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(onSeiData:)
                                                     name:AliVcMediaPlayerSeiDataNotification object:self.mediaPlayer];
                                                    
    
    处理监听通知中SEI数据:
    //答题
    - (void)onSeiData:(NSNotification *)notification{
        /*
        {
         "questionId": "001”,
         "type": "startAnswer"
         }  这个是开始答题
         
         {
         "questionId": "001”,
         "type": "showResult",
         "showTime": "5"
         }  这个是显示答题结果
         
         */
        NSDictionary* dict = [notification userInfo];
        if (dict) {
            NSString* seiData = [dict objectForKey:@"seiData"];
            if (seiData) {
                NSLog(@"sei data is %@",seiData);
        }
         
      }
    

    可以在Demo中查询具体的使用方法。

注意事项

  • 播放器延迟处理

    需要控制每个端上的延迟是一致的,可以设置播放器最大的延迟参数来处理,一般的原则是延迟越大,越能够抗网络抖动,延迟越小,则卡顿越频繁。针对直播答题来说,需要考虑到整条链路上的整体延迟,所以这个延迟参数对题目的有效性时间会有影响。如果播放器延迟控制在3秒,答题时间是10秒,则题目的有效性时间需要加上播放器的延迟时间则是13秒。

    ios延迟控制参数,单位毫秒 @property(nonatomic, readwrite) int dropBufferDuration;

    android延迟控制接口:单位毫秒 public void setMaxBufferDuration(int duration);

  • 下发题目延迟处理

    客户端在收到SEI信号后,需要向服务器获取问题,这会产生一定的通信耗时。因此在下发题目时,可酌情加大expiredSeconds,比如在原有答题失效时间上+1秒。