鸿蒙端实现RTS拉流

通过阅读本文,您可以了解HarmonyOS NEXT播放器SDK实现超低延时直播的方法。

SDK集成

获取SDK

下载信息:

重要
  • 目前HarmonyOS NEXT版播放器SDK已支持在mac m1、m2设备上运行模拟器,不支持在x86设备上运行模拟器。

  • 播放器版本请参考SDK下载,建议使用最新版本。播放器版本要求:推荐V7.6.0或以上版本,最低支持V6.5.1。

  • 播放器与RTS低延时直播组件的桥接层(artclibrary)需与播放器版本号保持对应关系,且必须与RTS低延时直播组件同时集成。具体对应关系请参见集成SDK

集成SDK

oh-package.json5中进行配置:

"dependencies": {
  "premierlibrary": "file:./libs/AliyunPlayer-7.7.0.har",
  "artclibrary": "file:./libs/artclibrary_7.8.0.har",
  // Rts低延时直播组件
  "RTS": "file:./libs/RtsSDK_7.8.0.har",
}

阿里云播放器SDK接口使用

调用阿里云播放器SDK接口实现超低延时直播功能。更多阿里云播放器SDK功能,请参见进阶功能

说明
  • 基于阿里云播放器实现RTS拉流时,不能调用pause暂停直播流。您可以先调用stop停止播放,再调用prepare重新播放。

  • 不支持seek(拖动)。

加载RTS

根据实际需求,在适当位置加载RTS库,建议在应用初始化时完成。

// 由于动态库存在依赖关系,需先导入ArtcSource库再导入RtsSDK库。
import {ArtcSource} from 'artclibrary'
import {RtsSDK} from 'RTS'

onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
  RtsSDK.RegisterRtsSDK();
  ArtcSource.InitService();
  log.i('Ability onCreate');
}

创建播放器

  1. 创建播放器。

    创建AliPlayer播放器。

    // 从SDK har包中import播放器相关定义
    import { AliPlayerFactory, AliPlayer } from 'premierlibrary';
    // 创建播放器 
    // 'traceId'为可选项
    private mAliPlayer: AliPlayer = AliPlayerFactory.createAliPlayer(getContext(), 'traceId');
    // 传入traceId
    mAliPlayer.setTraceId("traceId");
    说明

    播放器提供的播放质量监控(可查看播放器整体播放质量相关数据)、单点追查(可定位到具体的用户或设备,分析其播放行为,快速定位播放异常等问题)及视频播放统计功能都依赖埋点日志上报功能而实现。

    在创建播放器时,根据setTraceID参数的设置不同,其后续可实现的功能不同,具体如下:

    • setTraceID参数不传(默认):埋点日志上报功能开启,后续可以使用播放质量监控和视频播放统计功能,无法使用单点追查功能。

    • setTraceID参数传入traceid:traceid的值由您自行定义,需为您的用户或用户设备的唯一标识符,例如传入您业务的userid或者IMEI、IDFA等您业务用户的设备ID。传入traceid后,埋点日志上报功能开启,后续可以使用播放质量监控、单点追查和视频播放统计功能。

    • setTraceID参数设置为DisableAnalytics:关闭埋点日志上报,后续无法使用播放质量监控、单点追查和视频播放统计功能。

  2. 设置监听器。

    鸿蒙HarmonyOS NEXT播放器SDK支持设置播放器监听和监听播放状态。

    // 推荐下载Demo工程,参阅ReadMe.md了解最佳实践方式,帮助您快速集成。
    
    // 按需 引入播放器事件回调类型定义
    import { OnPreparedListener, OnCompletionListener, OnAudioInterruptEventListener,OnErrorListener,OnInfoListener,OnLoadingStatusListener, AudioStatus } from 'premierlibrary/src/main/ets/com/aliyun/player/IPlayer';
    
    // 播放器实例
    const mAliPlayer: AliPlayer = AliPlayerFactory.createAliPlayer(getContext(), traceId);
    
    // 定义回调监听
    const mPreparedEventHandler: OnPreparedListener = { // prepare完成
      onPrepared: () => {
        console.log("prepared");
      }
    };
    
    const mOnAudioInterruptListener: OnAudioInterruptEventListener = { // 音频打断
      onAudioInterruptEvent: (audioStatus: AudioStatus) => {
        if(mAliPlayer){
          console.log("[HOS DEMO] [AUDIO INTERRUPT]: " + audioStatus);
          let statusInfo: string = "";
          switch (audioStatus) {
            case AudioStatus.AUDIO_STATUS_DEFAULT:
              statusInfo = "AUDIO_STATUS_DEFAULT"
              break;
            case AudioStatus.AUDIO_STATUS_RESUME:
              statusInfo = "AUDIO_STATUS_RESUME"
              mAliPlayer.start(); // 继续播放
              break;
            case AudioStatus.AUDIO_STATUS_PAUSE:
              statusInfo = "AUDIO_STATUS_PAUSE"
              mAliPlayer.pause(); // 暂停播放
              break;
            case AudioStatus.AUDIO_STATUS_STOP:
              statusInfo = "AUDIO_STATUS_STOP"
              mAliPlayer.stop(); // 停止播放
              break;
            case AudioStatus.AUDIO_STATUS_DUCK:
              statusInfo = "AUDIO_STATUS_DUCK"
              break;
            case AudioStatus.AUDIO_STATUS_UNDUCK:
              statusInfo = "AUDIO_STATUS_UNDUCK"
              break;
            default:
              break;
          }
          showToast("CALLBACK: onAudioInterrupt " + statusInfo);
        }
      }
    }
    const mOnErrorEventListener: OnErrorListener = { // 错误回调
      onError:(errorInfo) => {
        let errorCode:PlayerErrorCode = errorInfo.getCode(); //错误码
        let errorMsg:string = errorInfo.getMsg(); //错误描述
        //errorExtra为额外错误信息,形式为json字符串,示例如下,需要注意ModuleCode并不完全等同于errorCode
        // { "Url": "xxx",
     		//	"Module": "NetWork",
      	//	"ModuleCode": "-377",
     		//  "ModuleMessage": "Redirect to a url that is not a media"}
        let errorExtra:string = errorInfo.getExtra();
        
        //出错后需要停止掉播放器。
        mAliPlayer.stop();
      }
    }
    const mOnVideoInfo: OnInfoListener = { // 视频信息回调
      //播放器中的一些信息,包括:当前进度、缓存位置等等。
      onInfo: (bean: InfoBean) => {
        //当前进度:InfoCode.CurrentPosition
        //当前缓存位置:InfoCode.BufferedPosition
        if (bean.getCode() === InfoCode.CurrentPosition) {
          this.videoProgress = bean.getExtraValue() / this.mVideoDuration * 100;
          this.mDuration = CommonUtils.getDurationString(this.mVideoDuration, bean.getExtraValue());
        } else if (bean.getCode() === InfoCode.BufferedPosition) {
          this.buffer = CommonUtils.secondToTime(Math.floor(bean.getExtraValue() / 1000));
          this.bufferedProgress = bean.getExtraValue() / this.mVideoDuration * 100;
        }
      }
    }
    const mOnLoadingProgressEventListener: OnLoadingStatusListener = { // 加载、卡顿状态下回调
      onLoadingBegin: () => {
          //开始加载。画面和声音不足以播放。
          //一般在此处显示圆形加载
      },
      onLoadingProgress: (percent: number, netSpeed: number) => {
         //加载进度。百分比和网速。
         //网速为预留字段,暂时为0。
      },
      onLoadingEnd: () => {
          //结束加载。画面和声音可以播放。
          //一般在此处隐藏圆形加载。
      }
    }
    
    // 将监听注册到播放器实例中
    mAliPlayer.setOnPreparedListener(mPreparedEventHandler);
    mAliPlayer.setOnAudioInterruptEventListener(mOnAudioInterruptListener);
    mAliPlayer.setOnErrorListener(mOnErrorEventListener);
    mAliPlayer.setOnInfoListener(mOnVideoInfo);
    mAliPlayer.setOnLoadingStatusListener(mOnLoadingProgressEventListener);
  3. 创建DataSource。

    播放器支持4种播放源:VidSts、VidAuth、VidMpsUrlSource。其中UrlSource是直接URL播放,需要将URL设置为artc://协议,才可以使用RTS服务。

    // 创建播放源对象并设置播放地址
    let urlSource: UrlSource = new UrlSource();
    // 必选参数
    urlSource.setUri("播放地址");
    mAliPlayer.setUrlDataSource(urlSource);
  4. 设置显示View。

    绑定播放器与鸿蒙XComponent组件,实现视频画面渲染。

    XComponent({
      id: '0', // unique XC id
      type: XComponentType.SURFACE,
      libraryname: 'premierlibrary',
      controller: this.xComponentController
    })
      .onLoad(async () => {
        // 设置播放源、控制播放
        
        //(必须)绑定URL & XC_SurfaceId
        this.mAliPlayer.setSurfaceId('0'); // surface ID 对应 XC ID      
      })
      .width('100%')
      .height(200)
  5. 播放参数配置

    配置播放参数,提升超低延时直播效果。

    说明

    播放器SDK均支持自动低延时最佳配置,当播放URL为“artc://”开头,且客户没有手工修改过PlayerConfigmMaxDelayTimemHighBufferDurationmStartBufferDuration值时,SDK会自动分别使用1000、10、10值进行实际的播放。

    若想自定义控制,请参考如下示例:

    let config:PlayerConfig | undefined = mAliPlayer.getConfig();
    if (config) {
      //最大延时为1000毫秒
      config.mMaxDelayTime = 1000;
      //起播缓存时长,10毫秒
      config.mStartBufferDuration = 10;
      //卡顿恢复缓存时长,10毫秒
      config.mHighBufferDuration = 10;
      mAliPlayer.setConfig(config);
    }
  6. 可选:开启自动播放,默认为关闭状态。

    mAliPlayer.setAutoPlay(true);
  7. 准备播放。

    调用mAliPlayer.prepare()开始读取并解析数据。

    mAliPlayer.prepare();
  8. 开始播放。

    • 如果未开启自动播放,需要在OnPrepard回调发生之后,择机调用mAliPlayer.start()开始播放视频。

    • 如果开启了自动播放,则不需要调用mAliPlayer.start(),数据解析完成后将开始自动播放视频。

    mAliPlayer.start();// 开始之后可以调用pause()暂停播放视频。

控制播放

HarmonyOS NEXT播放器SDK支持从指定时间点播放、开始、暂停、停止播放等操作。

  1. 开始播放。

    指开始播放视频,由start接口实现。示例如下:

    mAliPlayer.start();
  2. 停止播放。

    指停止播放视频,由stop接口实现。示例如下:

    mAliPlayer.stop();
  3. 销毁播放器。

    销毁播放器实例,有同步和异步两种销毁方式,示例如下:

    //同步销毁,内部会自动调用stop接口
    mAliPlayer.release();
    //异步销毁,内部会自动调用stop接口
    mAliPlayer.releaseAsync();	
    说明

    调用同步销毁接口需等待播放器资源完全释放后才返回。如果您对界面的响应速度有较高要求,建议使用异步销毁接口,并注意以下几点:

    1. 避免在异步销毁过程中对播放器对象执行任何其他操作。

    2. 无需在调用异步销毁之前手动停止播放器,因为该过程内部已经包含了异步化的停止流程。

辅助功能

  1. 日志开关。

    // Loggercom.cicada.player.utils下
    import { Logger, LogLevel, OnLogCallback } from 'premierlibrary/src/main/ets/com/cicada/player/utils/Logger'
    
    // 打开日志开关
    Logger.getInstance(context).enableConsoleLog(true);
    // 设置日志级别,默认为AF_LOG_LEVEL_INFO,如需排查问题,可设置为AF_LOG_LEVEL_TRACE
    Logger.getInstance(context).setLogLevel(LogLevel.AF_LOG_LEVEL_INFO);
  2. 直播RTS降级。

    RTS自动降级

    在使用超低延时直播RTS地址播放的场景下,当不设置RTS降级地址且RTS拉流失败时,会自动降级到RTS对应的默认FLV地址进行播放。示例如下:

    // 1表示开启,0表示关闭。默认开启
    AliPlayerGlobalSettings.setOptionNum(AliPlayerGlobalSettings.ALLOW_RTS_DEGRADE, 1);
  3. 获取TraceID。

    每一次低延时播放都会有一个traceId,可用于问题排查,可以通过播放器事件回调拿到traceid

    private mOnVideoInfo: OnInfoListener = {
      // 监听播放器 onInfo回调,并解析DemuxerTraceID信息
      onInfo: (infoBean: InfoBean) => {
        if (infoBean.getCode() == InfoCode.DemuxerTraceID) {
          var traceId :String = infoBean.getExtraMsg();
        }
      }
    }
    mAliPlayer.setOnInfoListener(this.mOnVideoInfo);