This topic describes how to implement ultra-low-latency live streaming with the Alibaba Cloud Player SDK for HarmonyOS NEXT.
Integrate the SDK
Get the SDK
Download the required components:
Alibaba Cloud Player SDK for HarmonyOS NEXT
Download link: Download Player SDK.
Player-to-RTS bridge layer (artclibrary)
Download link: artclibrary.har
RTS low-latency live streaming component
Download link: RtsSDK_7.12.0.har
Integrate the SDK
Configure the dependencies in your oh-package.json5 file:
"dependencies": {
"premierlibrary": "file:./libs/AliyunPlayer-x.x.x.har",
"artclibrary": "file:./libs/artclibrary_x.x.x.har",
// RTS low-latency live streaming component, which is versioned independently.
"RTS": "file:./libs/RtsSDK_7.12.0.har",
}The artclibrary version must match the player version, and it must be integrated with the RTS component.
The Alibaba Cloud Player SDK for HarmonyOS NEXT supports emulators on Mac devices with M1 or M2 chips, but not on x86 devices.
For player versions, see SDK download. We recommend that you use the latest version. The minimum required version is V6.5.1.
Alibaba Cloud Player SDK API usage
Call the Alibaba Cloud Player SDK API to implement RTS. For more information about the features of the Alibaba Cloud Player SDK, see Advanced features.
When using RTS stream pulling, you cannot pause the live stream with
pause. Instead, callstopand thenprepareto resume playback.Seek (scrubbing) is not supported.
Load the RTS library
Load the RTS library at an appropriate point in your application's lifecycle. We recommend loading it during application initialization.
// Import `ArtcSource` before `RtsSDK` due to a dependency. We recommend placing these imports at the top of the file.
import {ArtcSource} from 'artclibrary'
import {RtsSDK} from 'RTS'
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
RtsSDK.RegisterRtsSDK();
ArtcSource.InitService();
log.i('Ability onCreate');
}Create the player
Create a player instance.
Create an instance of AliPlayer.
// Import player-related definitions from the SDK's HAR package. import { AliPlayerFactory, AliPlayer } from 'premierlibrary'; // Create a player instance. // 'traceId' is optional. private mAliPlayer: AliPlayer = AliPlayerFactory.createAliPlayer(getContext(), 'traceId'); // Sets the trace ID. mAliPlayer.setTraceId("traceId");NoteThe player provides features such as playback quality monitoring, single-point tracking, and video playback statistics. These features rely on analytics log reporting.
When you create a player, the available features vary depending on the setting of the
setTraceIDparameter, as follows:If you do not pass a value for the
setTraceIdparameter (default): Analytics log reporting is enabled. You can use the playback quality monitoring and video playback statistics features, but not the single-point tracking feature.For the
setTraceIDparameter, pass a trace ID. The trace ID must be a unique identifier that you define for a user or their device, such as a user ID from your service, an IMEI, or an IDFA. After you pass the trace ID, the analytics log reporting feature is enabled. You can then use the playback quality monitoring, single-point tracking, and video playback statistics features.If you set the
setTraceIdparameter toDisableAnalytics: Analytics log reporting is disabled. The playback quality monitoring, single-point tracking, and video playback statistics features will be unavailable.
Set listeners.
The Alibaba Cloud Player SDK for HarmonyOS NEXT allows you to set listeners for player events and playback status.
// For best practices and a quick start, refer to the demo project's ReadMe.md file. // Import the player event callback type definitions as needed. import { OnPreparedListener, OnCompletionListener, OnAudioInterruptEventListener,OnErrorListener,OnInfoListener,OnLoadingStatusListener, AudioStatus } from 'premierlibrary/src/main/ets/com/aliyun/player/IPlayer'; // Player instance const mAliPlayer: AliPlayer = AliPlayerFactory.createAliPlayer(getContext(), traceId); // Define callback listeners. const mPreparedEventHandler: OnPreparedListener = { // Called when the preparation is complete. onPrepared: () => { console.log("prepared"); } }; const mOnAudioInterruptListener: OnAudioInterruptEventListener = { // Called when an audio interruption event occurs. 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(); // Resume playback. break; case AudioStatus.AUDIO_STATUS_PAUSE: statusInfo = "AUDIO_STATUS_PAUSE" mAliPlayer.pause(); // Pause playback. break; case AudioStatus.AUDIO_STATUS_STOP: statusInfo = "AUDIO_STATUS_STOP" mAliPlayer.stop(); // Stop playback. 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 = { // Called when an error occurs. onError:(errorInfo) => { let errorCode:PlayerErrorCode = errorInfo.getCode(); // The error code. let errorMsg:string = errorInfo.getMsg(); // The error message. // The errorExtra parameter provides additional error information in a JSON string format. // Example: // { "Url": "xxx", // "Module": "NetWork", // "ModuleCode": "-377", // "ModuleMessage": "Redirect to a url that is not a media"} // Note that ModuleCode may not be identical to errorCode. let errorExtra:string = errorInfo.getExtra(); // You must stop the player after an error occurs. mAliPlayer.stop(); } } const mOnVideoInfo: OnInfoListener = { // Called when video information is available. // Provides information from the player, such as the current position and buffered position. onInfo: (bean: InfoBean) => { // Current position: InfoCode.CurrentPosition // Buffered position: 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 = { // Called during loading or stalling states. onLoadingBegin: () => { // Loading starts. The video and audio data is insufficient for playback. // You can display a loading spinner here. }, onLoadingProgress: (percent: number, netSpeed: number) => { // Loading progress. Provides percentage and network speed. // The network speed field is reserved and currently returns 0. }, onLoadingEnd: () => { // Loading ends. The video and audio data is sufficient for playback. // You can hide the loading spinner here. } } // Register the listeners with the player instance. mAliPlayer.setOnPreparedListener(mPreparedEventHandler); mAliPlayer.setOnAudioInterruptEventListener(mOnAudioInterruptListener); mAliPlayer.setOnErrorListener(mOnErrorEventListener); mAliPlayer.setOnInfoListener(mOnVideoInfo); mAliPlayer.setOnLoadingStatusListener(mOnLoadingProgressEventListener);Create the data source.
The player supports four data source types: VidSts, VidAuth, VidMps, and UrlSource. To use the RTS service, you must use UrlSource and set the URL to use the
artc://scheme.// Create a data source object and set the playback URL. let urlSource: UrlSource = new UrlSource(); // Required parameter urlSource.setUri("your_playback_url"); mAliPlayer.setUrlDataSource(urlSource);Set the display view.
Bind the player to a HarmonyOS XComponent to render the video frames.
XComponent({ id: '0', // unique XC id type: XComponentType.SURFACE, libraryname: 'premierlibrary', controller: this.xComponentController }) .onLoad(async () => { // Set the data source and control playback. // (Required) Bind the URL and XC_SurfaceId. this.mAliPlayer.setSurfaceId('0'); // The surface ID corresponds to the XC ID. }) .width('100%') .height(200)Configure playback parameters.
Configure playback parameters to enhance the RTS experience.
NoteThe Player SDK supports an automatic optimal low-latency configuration: if a playback URL starts with "artc://" and you have not manually modified the
mMaxDelayTime,mHighBufferDuration, ormStartBufferDurationvalues inPlayerConfig, the SDK automatically uses the values 1000, 10, and 10 for these parameters, respectively.To customize these settings, see the following example:
let config:PlayerConfig | undefined = mAliPlayer.getConfig(); if (config) { // Set the maximum latency to 1000 ms. config.mMaxDelayTime = 1000; // Set the start buffer duration to 10 ms. config.mStartBufferDuration = 10; // Set the stall recovery buffer duration to 10 ms. config.mHighBufferDuration = 10; mAliPlayer.setConfig(config); }Optional: Enable autoplay. This feature is disabled by default.
mAliPlayer.setAutoPlay(true);Prepare for playback.
Call
mAliPlayer.prepare()to start reading and parsing the stream data.mAliPlayer.prepare();Start playback.
If autoplay is not enabled, after the
OnPrepardcallback occurs, callmAliPlayer.start()to start playing the video.If autoplay is enabled, you do not need to call
mAliPlayer.start(). Playback starts automatically after the data is parsed.
mAliPlayer.start();
Control playback
The Alibaba Cloud Player SDK for HarmonyOS NEXT supports operations such as starting and stopping playback.
Start playback.
Starts video playback, which is implemented by the
startAPI. An example is as follows:mAliPlayer.start();Stop playback.
Stops the video playback by using the
stopAPI. The following is an example:mAliPlayer.stop();Release the player.
To release the player instance, you can use a synchronous or asynchronous method:
// Synchronously release the player. This method automatically calls the stop method internally. mAliPlayer.release(); // Asynchronously release the player. This method also automatically calls the stop method internally. mAliPlayer.releaseAsync();NoteThe synchronous release method waits for all player resources to be fully released before returning. If your application requires a highly responsive UI, we recommend using the asynchronous release method. Keep the following points in mind:
Do not perform any other operations on the player object while it is being asynchronously released.
You do not need to manually stop the player before calling the asynchronous release method. The stop process is already included in the asynchronous release flow.
Helper features
Enable and configure logging.
// Logger is located in com.cicada.player.utils. import { Logger, LogLevel, OnLogCallback } from 'premierlibrary/src/main/ets/com/cicada/player/utils/Logger' // Enable console logging. Logger.getInstance(context).enableConsoleLog(true); // Set the log level. The default is AF_LOG_LEVEL_INFO. For troubleshooting, you can set it to AF_LOG_LEVEL_TRACE. Logger.getInstance(context).setLogLevel(LogLevel.AF_LOG_LEVEL_INFO);Automatic RTS fallback.
NoteAutomatic fallback is triggered only in timeout scenarios. If automatic RTS fallback is enabled, the player attempts to fall back when a playback timeout occurs. Otherwise, the player's
onErrorcallback is triggered. Errors such as 404 or 403, or a stream terminated by the host, do not trigger a fallback.Automatic RTS fallback uses the same domain to fall back from RTS to FLV.
Automatic RTS fallback
When playing a stream by using an RTS URL, if a fallback URL is not set and RTS stream pulling fails, the player automatically falls back to the corresponding default FLV URL. The following example shows how to enable this feature:
// Set to 1 to enable automatic fallback, 0 to disable. Enabled by default. AliPlayerGlobalSettings.setOptionNum(AliPlayerGlobalSettings.ALLOW_RTS_DEGRADE, 1);Get the trace ID.
Each low-latency playback session has a traceId for troubleshooting. You can obtain the
traceidthrough a player event callback.private mOnVideoInfo: OnInfoListener = { // Listen for the player's onInfo callback and parse the DemuxerTraceID. onInfo: (infoBean: InfoBean) => { if (infoBean.getCode() == InfoCode.DemuxerTraceID) { var traceId :String = infoBean.getExtraMsg(); } } } mAliPlayer.setOnInfoListener(this.mOnVideoInfo);