All Products
Search
Document Center

ApsaraVideo VOD:Advanced features

Last Updated:Feb 11, 2026

This topic describes how to use the advanced features of the ApsaraVideo Player SDK for iOS. For a complete description of all features, see API reference.

Important

To try out the demo, download it and follow the instructions in Run the demo to compile and run the project.

Professional Competency Verification

Note

Some player features require a Professional Edition license. For more information, see Features. To obtain a license, refer to Obtain a license.

Set the listener when your application starts or before you call any player API operations.

void premiumVeryfyCallback(AVPPremiumBizType biztype, bool isValid, NSString* errorMsg) {
    NSLog(@"onPremiumLicenseVerifyCallback: %d, isValid: %d, errorMsg: %@", biztype, isValid, errorMsg);
}

[AliPrivateService setOnPremiumLicenseVerifyCallback:premiumVeryfyCallback];

Here, AVPPremiumBizType is an enumeration of advanced features. When you use a related feature, the player verifies the license and returns the result through this callback. If isValid is false, errorMsg contains the reason for the failure.

Playback

List playback

The ApsaraVideo Player SDK for iOS provides a full-featured list playback capability. The SDK uses mechanisms such as preloading to minimize the time to first frame (TTTF) for short videos.

Procedure

  1. Create a player.

    Create an AliListPlayer instance.

    self.listPlayer = [[AliListPlayer alloc] init];
    [self.listPlayer setTraceID:@"xxxxxx"];  // The TraceID is a unique identifier for a device or user, such as an IMEI or IDFA.

  2. Optional: Set listeners.

    Listeners are optional when you create a list playback instance. However, if you do not configure them, you cannot receive event notifications from the player, such as playback failures or playback progress. We recommend that you configure them.

    The player supports setting multiple listeners, including onPlayerEvent and onError. We recommend that you set them.

    /**
     @brief Error callback.
     @param player The player pointer.
     @param errorModel The player error description. See AliVcPlayerErrorModel.
     */
    - (void)onError:(AliPlayer*)player errorModel:(AVPErrorModel *)errorModel {
        // Display an error message and stop playback.
    }
    /**
     @brief Player event callback.
     @param player The player pointer.
     @param eventType The player event type. See AVPEventType.
     */
    -(void)onPlayerEvent:(AliPlayer*)player eventType:(AVPEventType)eventType {
        switch (eventType) {
            case AVPEventPrepareDone: {
                // The player is prepared.
            }
                break;
            case AVPEventAutoPlayStart:
                // Autoplay starts.
                break;
            case AVPEventFirstRenderedStart:
                // The first frame is rendered.
                break;
            case AVPEventCompletion:
                // Playback is complete.
                break;
            case AVPEventLoadingStart:
                // Buffering starts.
                break;
            case AVPEventLoadingEnd:
                // Buffering is complete.
                break;
            case AVPEventSeekEnd:
                // Seeking is complete.
                break;
            case AVPEventLoopingStart:
                // Loop playback starts.
                break;
            default:
                break;
        }
    }
    /**
     @brief Callback for the current playback position.
     @param player The player pointer.
     @param position The current playback position.
     */
    - (void)onCurrentPositionUpdate:(AliPlayer*)player position:(int64_t)position {
        // Update the progress bar.
    }
    /**
     @brief Callback for the video's buffered position.
     @param player The player pointer.
     @param position The current buffered position.
     */
    - (void)onBufferedPositionUpdate:(AliPlayer*)player position:(int64_t)position {
        // Update the buffer progress.
    }
    /**
     @brief Callback for track information.
     @param player The player pointer.
     @param info An array of track stream information. See AVPTrackInfo.
     */
    - (void)onTrackReady:(AliPlayer*)player info:(NSArray<AVPTrackInfo*>*)info {
        // Get information about multi-bitrate streams.
    }
    /**
     @brief Callback for displaying subtitles.
     @param player The player pointer.
     @param trackIndex The index of the subtitle stream.
     @param subtitleID The subtitle ID.
     @param subtitle The string to be displayed as subtitle.
     */
    - (void)onSubtitleShow:(AliPlayer*)player trackIndex:(int)trackIndex subtitleID:(long)subtitleID subtitle:(NSString *)subtitle {
        // Display the subtitles.
    }
    /**
     @brief Callback for hiding subtitles.
     @param player The player pointer.
     @param trackIndex The index of the subtitle stream.
     @param subtitleID The subtitle ID.
     */
    - (void)onSubtitleHide:(AliPlayer*)player trackIndex:(int)trackIndex subtitleID:(long)subtitleID {
        // Hide the subtitles.
    }
    /**
     @brief Callback for taking a snapshot.
     @param player The player pointer.
     @param image The image.
     */
    - (void)onCaptureScreen:(AliPlayer *)player image:(UIImage *)image {
        // Preview and save the snapshot.
    }
    /**
     @brief Callback for when a track switch is complete.
     @param player The player pointer.
     @param info The information of the new track. See AVPTrackInfo.
     */
    - (void)onTrackChanged:(AliPlayer*)player info:(AVPTrackInfo*)info {
        // Notification for bitrate switching result.
    }
    //...
  3. Set the preload count.

    Setting a reasonable preload count can effectively improve startup speed.

    self.listPlayer.preloadCount = 2;
  4. Add or remove playback sources.

    List playback supports two source types: VidSts and UrlSource:

    • UrlSource: A playback URL from ApsaraVideo VOD or a third-party service.

      You can retrieve a playback URL for a media asset in ApsaraVideo VOD by calling the GetPlayInfo operation. We recommend integrating the ApsaraVideo VOD server-side SDK to retrieve playback URLs. This simplifies the process by handling URL signing automatically. For an example, see OpenAPI Explorer.

    • Vid: The ID of an audio or video file. This ID is generated after you upload a file in the console (path: Media Library > Audio/Video) or using a server-side API (Search for media information).

    // Add a VidSts source.
    [self.listPlayer addVidSource:videoId uid:UUIDString];
    // Add a UrlSource.
    [self.listPlayer addUrlSource:URL uid:UUIDString];
    // Remove a source.
    [self.listPlayer removeSource:UUIDString];
    Note
    • The UID is a unique identifier for a video. If UIDs are the same, the videos are considered identical. If playback results in stream mixing, you can check whether the same UID is configured in different interfaces. The UID has no format restrictions and can be any string.

  5. Set the display view.

    If the source contains video content, assign a view in the player to display it.

    self.listPlayer.playerView = self.simplePlayScrollView.playView;
  6. Play a video source.

    After adding one or more video sources, call moveTo to autoplay a video source. Example:

    // Use this API for UrlSource playback.
    - (BOOL) moveTo:(NSString*)uid;
    // Use this API for VidSts playback. You must pass the temporary STS credential and temporary AccessKey pair. Get them in advance. For more information, see Obtain an STS token.
    - (BOOL) moveTo:(NSString*)uid accId:(NSString*)accId accKey:(NSString*)accKey token:(NSString*)token region:(NSString*)region;
  7. Play the previous or next video.

    After you call moveTo to play a video source, call moveToPrev and moveToNext to play the previous or next video, using the video source from the moveTo call as an anchor. The following is an example:

    Note

    When you use the same view and call moveTo or moveToNext to switch video sources, the screen may flicker or briefly turn black. To prevent this, set the clearShowWhenStop field of PlayerConfig to false when you initialize listPlayer and call setConfig to apply the change.

    UrlSource Playback Source

    // Moves to the next video.
    - (BOOL) moveToNext;
    // Moves to the previous video.
    - (BOOL) moveToPre;

    VidSts playback source

    // Play the next video.
    - (BOOL) moveToNext:(NSString*)accId accKey:(NSString*)accKey token:(NSString*)token region:(NSString*)region;
    // Play the previous video.
    - (BOOL) moveToPre:(NSString*)accId accKey:(NSString*)accKey token:(NSString*)token region:(NSString*)region;
Note

For an enhanced list playback experience, use our short-form drama solution. For more information, see Client-side development for short-form dramas.

Play videos with an alpha channel

Overview

The ApsaraVideo Player SDK supports rendering an alpha channel to create dynamic effects, such as animated gifts. During live streaming, you can play animated gifts without obscuring the main content, enhancing the user experience.

Limits

Alpha channel rendering is supported in the all-in-one SDK V6.8.0 and later, or the ApsaraVideo Player SDK V6.9.0 and later.

Benefits

Using MP4 videos with transparency for animated effects offers better quality, smaller file sizes, and higher compatibility compared to formats like APNG and IXD.

  1. Better animation quality: MP4 videos preserve original animation details and colors more accurately than other formats.

  2. Smaller file size: MP4 video files are smaller than files in other formats, such as APNG or IXD, resulting in faster loading and reduced network bandwidth consumption.

  3. Higher compatibility: The MP4 format is widely supported across devices and browsers.

  4. Higher development efficiency: Using MP4 videos for gift effects is a straightforward approach that eliminates the need for developers to research and implement complex parsing or rendering logic, enabling them to focus on other features.

Sample code

Use the alphaRenderMode property to set the position of the alpha channel in the video material (top, bottom, left, or right). The default value is None.

Note
  • The position of the alpha channel in the video asset must match the alphaRenderMode setting.

  • The size of the view must be proportional to the resolution of the material.

/**
 @brief Alpha rendering mode. Supports alpha at the right, left, top, or bottom. The default value is none.
 @see AVPAlphaRenderMode
 */
/****
 @brief Set a rendering mode. Support alpha at right, left, top and bottom. Default value is none.
 @see AVPAlphaRenderMode
 */
@property(nonatomic) AVPAlphaRenderMode alphaRenderMode;
//--------------View usage-------------
// For the player's view, set a clear background color.
@property (weak, nonatomic) IBOutlet UIView *mediaPlayerView;
[self.aliplayerview setBackgroundColor:UIColor.clearColor];

//-----------AliPlayer usage-----------
// Set the alpha mode.
[self.player setAlphaRenderMode:AVP_RENDERMODE_ALPHA_AT_LEFT];
// Set the material corresponding to the alpha mode.
AVPUrlSource *source = [[AVPUrlSource alloc] urlWithString:@"https://alivc-player.oss-cn-shanghai.aliyuncs.com/video/%E4%B8%9A%E5%8A%A1%E9%9C%80%E6%B1%82%E6%A0%B7%E6%9C%AC/alpha%E9%80%9A%E9%81%93/alpha_left.mp4"];
[self.player setUrlSource:source];

// Optional: Clear the screen after playback completion to prevent visual artifacts.
#pragma mark -- AVPDelegate
- (void)onPlayerEvent:(AliPlayer *)player eventType:(AVPEventType)eventType {
    switch (eventType) {
        case AVPEventCompletion:
        {
            [player clearScreen];
        }
            break;
        //...
    }
}

[self.player setAutoPlay: YES];
[self.player prepare];

Metal rendering

The ApsaraVideo Player SDK for iOS supports video rendering using the Metal framework.

Note

Currently, only background color, scaling mode, and Picture-in-Picture (PiP) are supported.

Configuration Item

/**
 @brief Video render type, 0 means default render; 1 means mixed render. Default is 0.
 */
/****
 @brief video renderType, 0 means default render; 1 means mixed render.
 */
@property(nonatomic, assign) int videoRenderType;

Example

AVPConfig *config = [self.player getConfig];
// Enable Metal rendering.
config.videoRenderType = 1;
[self.player setConfig:config];
[self.player prepare];

External subtitles

Note

For a detailed code example, see the ExternalSubtitle module in the API-Example project.

The ApsaraVideo Player SDK for iOS supports adding and switching external subtitles in SRT, SSA, ASS, and VTT formats.

Examples:

  1. Create a view to display subtitles.

    Create different views for different formats.

    // Initialize a custom subTitleLabel.
    UILabel *subTitleLabel = [[UILabel alloc] initWithFrame:frame];
    // Add the subtitle label to a custom superView. The superView is a parent view that exists in the custom interface.
    [superView addSubview:subTitleLabel];
  2. Set subtitle-related listeners.

    // External subtitle added.
    - (void)onSubtitleExtAdded:(AliPlayer*)player trackIndex:(int)trackIndex URL:(NSString *)URL {}
    // Subtitle header information callback.
    - (void)onSubtitleHeader:(AliPlayer *)player trackIndex:(int)trackIndex Header:(NSString *)header{}
    // Subtitle display callback.
    - (void)onSubtitleShow:(AliPlayer*)player trackIndex:(int)trackIndex subtitleID:(long)subtitleID subtitle:(NSString *)subtitle {
     subTitleLabel.text =subtitle;
     subTitleLabel.tag =subtitleID;
    }
    // Subtitle hide callback.
    - (void)onSubtitleHide:(AliPlayer*)player trackIndex:(int)trackIndex subtitleID:(long)subtitleID{
      [subTitleLabel removeFromSuperview];
    }
  3. Add a subtitle track.

    [self.player addExtSubtitle:URL];
  4. Switch a subtitle track.

    [self.player selectExtSubtitle:trackIndexenable:YES];

Custom-rendered external subtitles

Full support for WebVTT external subtitles is implemented using AliVttSubtitleView and AliVttRenderImpl, enabling flexible customization of font size, color, and specific fonts.

Note

Use cases:

  • Customize WebVTT subtitle styles such as font, color, and size.

  • Integrate ApsaraVideo Player SDK V7.11.0 and use AliVttSubtitleView.

  • Support multilingual subtitles (such as Arabic, Chinese, Japanese, and Korean) and automatically match appropriate fonts.

Important

Prerequisites:

  • Font files (.ttf) have been added to the Xcode project.

  • Subtitle listeners have been added and WebVTT content can be retrieved.

  • The loadFontFromBundle method has successfully loaded the font.

Steps to customize subtitle styling

  1. Create a custom render implementation class (AliVttRenderImpl).

    // CustomFontVttRenderImpl.h
    @interface CustomFontVttRenderImpl : AliVttRenderImpl
    @end
    
    // CustomFontVttRenderImpl.m
    @implementation CustomFontVttRenderImpl
    
    // Optional: Override font generation logic
    - (UIFont *)customizeFont:(UIFont *)originalFont
             contentAttribute:(VttContentAttribute *)contentAttribute
                  contentText:(NSString *)text {
        
        // Example: Automatically select font based on content
        if ([self containsArabicCharacters:text]) {
            return [UIFont fontWithName:@"NotoSansArabic-Regular" size:originalFont.pointSize];
        }
        if ([self containsCJKCharacters:text]) {
            return [UIFont fontWithName:@"NotoSansCJKsc-Regular" size:originalFont.pointSize];
        }
        
        return originalFont;
    }
    
    // Optional: Force color change
    - (void)applyColorStyle:(NSMutableDictionary *)attrs
           contentAttribute:(VttContentAttribute *)contentAttribute {
        // Force red color
        attrs[NSForegroundColorAttributeName] = [UIColor redColor];
    }
    
    // Optional: Scale font size
    - (void)applyFontStyle:(NSMutableDictionary *)attrs
          contentAttribute:(VttContentAttribute *)contentAttribute
                   context:(RenderContext *)context {
        
        CGFloat originalSize = contentAttribute.fontSizePx / context.contentsScale;
        CGFloat newSize = originalSize * 2.0; // Double the size
        
        UIFont *font = [self generateFontWithName:contentAttribute.fontName
                                        fontSize:newSize
                                          isBold:contentAttribute.mBold
                                        isItalic:contentAttribute.mItalic];
        
        attrs[NSFontAttributeName] = font;
    }
    
    // Helper method: Detect Arabic characters
    - (BOOL)containsArabicCharacters:(NSString *)text {
        for (NSUInteger i = 0; i < text.length; i++) {
            unichar c = [text characterAtIndex:i];
            if ((c >= 0x0600 && c <= 0x06FF) || (c >= 0x0750 && c <= 0x077F)) {
                return YES;
            }
        }
        return NO;
    }
    
    // Helper method: Detect CJK characters
    - (BOOL)containsCJKCharacters:(NSString *)text {
        for (NSUInteger i = 0; i < text.length; i++) {
            unichar c = [text characterAtIndex:i];
            if ((c >= 0x4E00 && c <= 0x9FFF) ||   // Chinese
                (c >= 0x3040 && c <= 0x309F) ||   // Japanese hiragana
                (c >= 0xAC00 && c <= 0xD7AF)) {   // Korean
                return YES;
            }
        }
        return NO;
    }
    
    @end
  2. (Optional) Dynamically load custom fonts.

    - (void)loadCustomFontFromBundle:(NSString *)fontName {
        NSString *path = [[NSBundle mainBundle] pathForResource:fontName ofType:@"ttf"];
        if (path) {
            NSData *fontData = [NSData dataWithContentsOfFile:path];
            CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)fontData);
            CGFontRef fontRef = CGFontCreateWithDataProvider(provider);
            
            if (CTFontManagerRegisterGraphicsFont(fontRef, NULL)) {
                NSLog(@"Font registration succeeded: %@", fontName);
            } else {
                NSLog(@"Font registration failed: %@", fontName);
            }
            
            CGFontRelease(fontRef);
            CGDataProviderRelease(provider);
        }
    }
  3. Initialize the subtitle view and bind the custom renderer.

    // Create subtitle view
    AliVttSubtitleView *subtitleView = [[AliVttSubtitleView alloc] init];
    
    // Set custom render factory
    [subtitleView setRenderImplFactory:^AliVttRenderImpl*() {
        CustomFontVttRenderImpl *impl = [[CustomFontVttRenderImpl alloc] init];
        
        // Optional: Preload font
        [impl loadCustomFontFromBundle:@"LongCang-Regular"];
        
        return impl;
    }];
    
    // Associate with player
    [player setExternalSubtitleView:subtitleView];
  4. Handle player subtitle callbacks.

    Implement the following methods in AVPDelegate:

    // Subtitle header (includes style and region definitions)
    - (void)onSubtitleHeader:(AliPlayer *)player trackIndex:(int)trackIndex Header:(NSString *)header {
        [self.subtitleView setVttHeader:player trackIndex:trackIndex Header:header];
    }
    
    // Show subtitle
    - (void)onSubtitleShow:(AliPlayer *)player trackIndex:(int)trackIndex subtitleID:(long)subtitleID subtitle:(NSString *)subtitle {
        [self.subtitleView show:player trackIndex:trackIndex subtitleID:subtitleID subtitle:subtitle];
    }
    
    // Hide subtitle
    - (void)onSubtitleHide:(AliPlayer *)player trackIndex:(int)trackIndex subtitleID:(long)subtitleID {
        [self.subtitleView hide:player trackIndex:trackIndex subtitleID:subtitleID];
    }
    
    // Subtitle added successfully (used to enable track)
    - (void)onSubtitleExtAdded:(AliPlayer *)player trackIndex:(int)trackIndex URL:(NSString *)URL {
        [player selectExtSubtitle:trackIndex enable:YES];
    }

Audio-only playback

Disable video playback to play only the audio track. Configure this setting before calling prepare.

AVPConfig *config = [self.player getConfig];
config.disableVideo = YES;
[self.player setConfig:config];

Switch between software and hardware decoding

The iOS Player SDK provides hardware decoding capability for H.264 and H.265, and includes the enableHardwareDecoder toggle. By default, hardware decoding is enabled. If hardware decoding fails to initialize, software decoding is automatically used to ensure video playback. The following example shows:

// Enable hardware decoding. It is enabled by default.
self.player.enableHardwareDecoder = YES;

If automatic switchover from hardware decoding to software decoding occurs, the onPlayerEvent callback is triggered. The following example shows:

-(void)onPlayerEvent:(AliPlayer*)player eventWithString:(AVPEventWithString)eventWithString description:(NSString *)description {
    if (eventWithString == EVENT_SWITCH_TO_SOFTWARE_DECODER) {
        // Switched to software decoding.
    }
}

H.265 adaptive playback

An adaptive fallback is triggered when the current device model is in the cloud-based H.265 blacklist or if H.265 hardware decoding fails. If an H.264 backup stream is configured, it will be played. Otherwise, the player falls back to H.265 software decoding.

Note
  • This feature is available only after you enable adaptive playback. Adaptive playback is a value-added service. You need to submit a Yida form to apply for a license.

  • The cloud-native adaptive decoding service includes dynamic delivery of hardware decoding compatibility data and adaptive fallback from H.265 to H.264 streams.

  • The SDK still automatically switches to software decoding upon hardware decoding failure, even if this value-added service is not enabled.

Example of configuring a backup stream:

// The application layer maintains a map of original URLs to backup URLs.
NSString* getBackupUrlCallback(AVPBizScene scene, AVPCodecType codecType, NSString* oriurl){
    NSMutableDictionary *globalMap = [AliPlayerViewController getGlobalBackupUrlMap];
    NSString *backupUrl = globalMap[oriurl];
    return backupUrl; 
}

[AliPlayerGlobalSettings setAdaptiveDecoderGetBackupURLCallback:getBackupUrlCallback];

Switch video definition based on network conditions

Note

The ApsaraVideo Player SDK for iOS supports adaptive bitrate streaming of HTTP Live Streaming (HLS) video streams and Dynamic Adaptive Streaming over HTTP (DASH) video streams. After prepare succeeds, you can retrieve information about each bitrate stream through getMediaInfo, namely TrackInfo. The following example shows how to...

AVPMediaInfo *info = [self.player getMediaInfo];
NSArray<AVPTrackInfo*>* tracks = info.tracks;

During playback, you can call the player's selectTrack method to switch the bitrate stream. If you set the value to SELECT_AVPTRACK_TYPE_VIDEO_AUTO, adaptive bitrate streaming is enabled. The following code provides an example:

// Switch to a specific bitrate.
[self.player selectTrack:track.trackIndex];
// Enable adaptive bitrate switching.
[self.player selectTrack:SELECT_AVPTRACK_TYPE_VIDEO_AUTO];

Switching triggers a callback after the onTrackChanged listener is invoked. The following sample code shows how to implement this:

- (void)onTrackChanged:(AliPlayer*)player info:(AVPTrackInfo*)info {
    if (info.trackType == AVPTRACK_TYPE_VIDEO) {
        // Rendition changed.
    }
    // etc
}

Optional: Before you call the selectTrack method to switch to adaptive bitrate streaming, you can set an upper definition limit for adaptive bitrate (ABR) switching to prevent the player from automatically switching to an unexpected bitrate. For example: (For the setting to take effect, we recommend that you call the code before the player calls the prepare method or the list player calls the moveTo method.)

AVPConfig *config = [self.player getConfig];
config.maxAllowedAbrVideoPixelNumber = 921600;// Set the maximum allowed pixel count for ABR to 1280x720. The player will only switch to definitions with a pixel count less than or equal to this value.
[self.player setConfig:config];

Take a snapshot

The iOS Player SDK provides a way to take a screenshot of the current video through the snapShot interface. The screenshot captures raw data and returns it as a bitmap. The callback interface is onCaptureScreen. The following example shows how to...

// Snapshot callback.
- (void)onCaptureScreen:(AliPlayer *)player image:(UIImage *)image {
    // Process the snapshot.
}
// Take a snapshot of the current frame.
[self.player snapShot];
Note

The snapshot does not include the UI.

Preview

In combination with ApsaraVideo VOD configurations, you can implement a preview feature. This is supported for both VidSts and VidAuth (recommended) playback. For configuration instructions, see Preview videos.

After you configure the video preview feature, use the VidPlayerConfigGen interface to call the setPreviewTime method and set the preview duration for the player. The following sample code shows a VidSts-based example.

AVPVidStsSource *source = [[AVPVidStsSource alloc] init];
....
VidPlayerConfigGenerator* vp = [[VidPlayerConfigGenerator alloc] init];
[vp setPreviewTime:20];// 20-second preview
source.playConfig = [vp generatePlayerConfig];// Set for the playback source
...

When a preview duration is set, the server returns only the content for that time period.

Note

VidPlayerConfigGen supports setting various server-side request parameters. See Request parameter descriptions.

Set the Referer

The iOS player SDK supports setting the Referer, which—when used in conjunction with the Referer blacklists and whitelists in the console—enables you to control access permissions. You set the referer of the request using the AVPConfig method. The following sample code provides an example:

// Get the configuration first.
AVPConfig *config = [self.player getConfig];
// Set the Referer.
config.referer = referer;
....// Other settings
// Set the configuration for the player.
[self.player setConfig:config];

Set the User-Agent

The iOS Player SDK provides AVPConfig to set the User Agent. After you set the User Agent, the player includes the User Agent information in its requests. For example:

// Get the configuration first.
AVPConfig *config = [self.player getConfig];
// Set the User-Agent.
config.userAgent = userAgent;
....// Other settings
// Set the configuration for the player.
[self.player setConfig:config];

Configure network retry count and timeout

You can set the network timeout and the number of retries for the iOS player SDK using the AVPConfig method. The following code provides an example:

// Get the current configuration.
AVPConfig *config = [self.player getConfig];
// Specify the network timeout period. Unit: milliseconds.
config.networkTimeout = 5000;
// Specify the maximum number of retries upon a network timeout. The retry interval is the value of the networkTimeout parameter. A value of 0 indicates that no retry is performed. The application determines the retry policy. The default value is 2.
config.networkRetryCount = 2;
....// Configure other settings.
// Configure the settings for the player.
[self.player setConfig:config];
Note
  • If networkRetryCount is greater than 0, the player retries networkRetryCount times when a network problem occurs, with an interval of networkTimeout between retries.

  • If the loading state persists after all retries, the onError event is triggered with AVPErrorModel.code set to ERROR_LOADING_TIMEOUT.

  • If you set networkRetryCount to 0, the player triggers the onPlayerEvent callback with eventWithString equal to EVENT_PLAYER_NETWORK_RETRY when a network timeout occurs. You can then call the player’s reload method to reload the stream or perform other actions.

Configure cache and latency control

Cache control is important for a player. You can reduce the startup loading duration and improve playback smoothness using proper configurations. The iOS Player SDK provides the AVPConfig interface to configure the cache and delay. The following is an example:

// Retrieve the configuration.
AVPConfig *config = [self.player getConfig];
// Specify the maximum latency. Note: This parameter is valid for only live streaming. If the latency is high, Player SDK synchronizes frames to ensure that the latency is within the specified limit.
config.maxDelayTime = 5000;
// Specify the maximum buffer duration. Unit: milliseconds. This parameter specifies the maximum duration of data that the player can buffer at a time.
config.maxBufferDuration = 50000;
// Specify the peak buffer duration. Unit: milliseconds. When the player loads data due to poor network conditions, the player stops loading after the duration of the buffered data reaches this value.
config.highBufferDuration = 3000;
// Specify the startup buffer duration. Unit: milliseconds. A smaller value indicates a shorter startup loading duration. However, the player may enter the loading status soon after the playback starts.
config.startBufferDuration = 500;
// Configure other settings.
// Apply the configuration to the player.
[self.player setConfig:config];
Important
  • The buffer durations must satisfy: startBufferDuration ≤ highBufferDuration ≤ maxBufferDuration.

  • When the maximum buffer duration (mMaxBufferDuration) is greater than 5 minutes, the system defaults to a 5-minute duration to prevent excessive memory usage.

Set HTTP headers

You can use the AVPConfig method to add HTTP header parameters to requests in the player. The following is an example:

// Retrieve the configuration.
AVPConfig *config = [self.player getConfig];
// Define the headers.
NSMutableArray *httpHeaders = [[NSMutableArray alloc] init];
// For example, configure a host when you use HTTPDNS.
[httpHeaders addObject:@"Host:example.com"];
// Configure the headers.
config.httpHeaders = httpHeaders;
....// Configure other settings.
// Configure the settings for the player.
[self.player setConfig:config];

Picture-in-Picture

Note

For detailed code examples, see the PictureInPicture module in the API-Example project.

Note
  • PiP requires iOS 15 or later and ApsaraVideo Player SDK for iOS 5.4.9.0 or later.

  • For versions of ApsaraVideo Player SDK for iOS earlier than 5.5.2.0, the PiP feature provides only methods to enable and disable PiP and to display the PiP window when the app is in the background. Starting from version 5.5.2.0, the SDK supports setting the PiP delegate from the outside, which allows for more personalized PiP feature development.

  • To use PiP, ensure it is enabled in your device's settings (Settings > General > Picture in Picture).

Enable PiP

After the picture-in-picture (PiP) feature is enabled, when the application is switched to the background, the video continues playing in a floating window. When the application is switched to the foreground, the video resumes in the original playback mode. PiP is controlled by the setPictureInPictureEnable method. To enable PiP, you must call this method when the AVPEventPrepareDone event occurs. The following example shows how to enable the PiP feature:

- (void)onPlayerEvent:(AliPlayer *)player eventType:(AVPEventType)eventType {
    switch (eventType) {
        case AVPEventPrepareDone:
        {
            [self.player setPictureInPictureEnable:YES];
        }
            break;
        default:
            break;
    }
}
Note

To stop playback, first disable picture-in-picture (PiP) by calling setPictureInPictureEnable, then call stop.

Set the PiP delegate

The following code examples demonstrate common interactions between Picture-in-Picture (PiP) windows and player windows, including logic to display PiP pause, play, fast forward, fast backward, and replay buttons. For more information on delegate methods, see the Player SDK Demo — specifically, the AliPlayerPictureInPictureDelegate.h header file within the AliyunPlayer.framework folder.

  1. Set the PiP delegate.

    /**
    * @brief Set the PiP delegate.
    */
    -(void) setPictureinPictureDelegate:(id<AliPlayerPictureInPictureDelegate>)delegate;
    
    
    // Set the PiP delegate.
    [self.player setPictureinPictureDelegate:self];
  2. Add variables and implement the delegate interface.

    1. You can add a (global variable) to control the player’s state changes.

      #import "YourUIViewController.h"
      #import <AliyunPlayer/AliyunPlayer.h>
      
      @interface YourUIViewController () <AVPDelegate, AliPlayerPictureInPictureDelegate>
      // Player instance.
      @property (nonatomic, strong) AliPlayer *player;
      // Player view container.
      @property (nonatomic, strong) UIView *playerView;
      // Listen for whether PiP is currently paused.
      @property (nonatomic, assign) BOOL isPipPaused;
      // Listen for the current playback status of the player. Set it through the newStatus callback of the playback event status change listener.
      @property (nonatomic, assign) AVPStatus currentPlayerStatus;
      // Set the PiP controller. Set it in the callback method for when PiP is about to start. You need to actively set it to nil when the page is about to be destroyed. We recommend setting it.
      @property (nonatomic, weak) AVPictureInPictureController *pipController;
      // Listen for the current playback progress of the player. Set currentPosition to the value of the position parameter in the callback for the current video playback position.
      @property (nonatomic, assign) int64_t currentPosition;
      
      @end
      Note

      You must use the weak or assign modifier for pipController. If you use the assign modifier, make sure that you set the correct variables to null.

    2. Update the status of the PiP controller when you listen for the onPlayerStatusChanged event.

      - (void)onPlayerStatusChanged:(AliPlayer*)player oldStatus:(AVPStatus)oldStatus newStatus:(AVPStatus)newStatus {
          self.currentPlayerStatus = newStatus;
      
        if (_pipController) {
           [self.pipController invalidatePlaybackState];
         }
      }
    3. Update the status of the PiP controller when you listen for the onPlayerEvent event.

      - (void)onPlayerEvent:(AliPlayer*)player eventType:(AVPEventType)eventType {
          if (eventType == AVPEventCompletion) {
            if (_pipController) {
             self.isPipPaused = YES; // After playback ends, change the PiP status to paused.
             [self.pipController invalidatePlaybackState];
          }
        } else if (eventType == AVPEventSeekEnd) {
          // Seeking is complete.
            if (_pipController) {
             [self.pipController invalidatePlaybackState];
          }
        }
      }
    4. Set listeners.

      • Listen for the callback when PiP is about to start.

        /**
         @brief Picture-in-Picture is about to start.
         @param pictureInPictureController The Picture-in-Picture controller.
         */
        - (void)pictureInPictureControllerWillStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
            if (!_pipController) {
             self.pipController = pictureInPictureController;
          }
            self.isPipPaused = !(self.currentPlayerStatus == AVPStatusStarted);
          [pictureInPictureController invalidatePlaybackState];
        }
      • Listen for the callback when PiP is preparing to stop.

        /**
         @brief Picture-in-Picture is preparing to stop.
         @param pictureInPictureController The Picture-in-Picture controller.
         */
        - (void)pictureInPictureControllerWillStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
            self.isPipPaused = NO;
          [pictureInPictureController invalidatePlaybackState];
        }
      • Listen for the callback that instructs the delegate to restore the user interface before PiP stops.

        /**
         @brief Tells the delegate to restore the user interface before Picture-in-Picture stops.
         @param pictureInPictureController The Picture-in-Picture controller.
         @param completionHandler Call and pass YES to allow the system to finish restoring the player user interface.
         */
        - (void)pictureInPictureController:(AVPictureInPictureController *)pictureInPictureController restoreUserInterfaceForPictureInPictureStopWithCompletionHandler:(void (^)(BOOL restored))completionHandler {
            if (_pipController) {
              _pipController = nil;
          }
          completionHandler(YES);
        }
      • Listen for the callback that sets the current playable time range for PiP.

        /**
         @brief Notifies the Picture-in-Picture controller of the current playable time range.
         @param pictureInPictureController The Picture-in-Picture controller.
         @return The current playable time range.
         */
         - (CMTimeRange)pictureInPictureControllerTimeRangeForPlayback:(nonnull AVPictureInPictureController *)pictureInPictureController layerTime:(CMTime)layerTime{
            Float64 current64 = CMTimeGetSeconds(layerTime);
        
            Float64 start;
            Float64 end;
        
            if (currentPosition <= self.player.duration) {
                double curPostion = self.currentPosition / 1000.0;
                double duration = self.player.duration / 1000.0;
                double interval = duration - curPostion;
                start = current64 - curPostion;
                end = current64 + interval;
                CMTime t1 = CMTimeMakeWithSeconds(start, layerTime.timescale);
                CMTime t2 = CMTimeMakeWithSeconds(end, layerTime.timescale);
                return CMTimeRangeFromTimeToTime(t1, t2);
            } else {
                return CMTimeRangeMake(kCMTimeNegativeInfinity, kCMTimePositiveInfinity);
            }
        }
      • Listen for the callback that sets whether PiP is paused or playing.

        /**
         @brief Reflects the paused or playing state on the UI.
         @param pictureInPictureController The Picture-in-Picture controller.
         @return Paused or playing.
         */
        - (BOOL)pictureInPictureControllerIsPlaybackPaused:(nonnull AVPictureInPictureController *)pictureInPictureController{
            return self.isPipPaused;
        }
        Note

        This callback is triggered before PiP starts. Make sure that the return value of this callback is false at this time. Otherwise, PiP cannot be activated.

      • Listen for the callback when the user skips forward or backward to synchronize the playback progress to the player.

        /**
         @brief The fast forward or fast backward button is clicked.
         @param pictureInPictureController The Picture-in-Picture controller.
         @param skipInterval The time interval for fast forwarding or fast backwarding.
         @param completionHandler A closure that must be called to indicate that the seek operation is complete.
         */
         - (void)pictureInPictureController:(nonnull AVPictureInPictureController *)pictureInPictureController skipByInterval:(CMTime)skipInterval completionHandler:(nonnull void (^)(void))completionHandler {
            int64_t skipTime = skipInterval.value / skipInterval.timescale;
            int64_t skipPosition = self.currentPosition + skipTime * 1000;
            if (skipPosition < 0) {
                skipPosition = 0;
            } else if (skipPosition > self.player.duration) {
                skipPosition = self.player.duration;
            }
            [self.player seekToTime:skipPosition seekMode:AVP_SEEKMODE_INACCURATE];
            [pictureInPictureController invalidatePlaybackState];
        }
      • Listen for the callback when the pause or play button is clicked in PiP, and perform the required operations.

        /**
         @brief The pause button in Picture-in-Picture is clicked.
         @param pictureInPictureController The Picture-in-Picture controller.
         @param playing Whether it is playing.
         */
        - (void)pictureInPictureController:(nonnull AVPictureInPictureController *)pictureInPictureController setPlaying:(BOOL)playing {
            if (!playing){
              [self.player pause];
              self.isPipPaused = YES;
            } else {
              // Recommendation: If PiP playback is complete and needs to be replayed, you can additionally execute the code in the following if statement.
              if (self.currentPlayerStatus == AVPStatusCompletion) {
                 [self.player seekToTime:0 seekMode:AVP_SEEKMODE_ACCURATE];
              }
        
              [self.player start];
              self.isPipPaused = NO;
          }
          [pictureInPictureController invalidatePlaybackState];
        }

In-app Picture-in-Picture

By default, the Picture-in-Picture (PiP) feature operates outside the app. To implement in-app PiP, you can first use the following interface to determine whether PiP is enabled:

/**
 @brief Whether PiP is started.
 @param pictureInPictureController The PiP controller.
 @param isEnable Whether PiP is started.
 */
/****
 @brief pictureInPicture is enable or not
 @param pictureInPictureController picture in picture controller
 @param isEnable is enable or not
 */
- (void)pictureInPictureControllerIsPictureInPictureEnable:(nullable AVPictureInPictureController *)pictureInPictureController isEnable:(BOOL)isEnable;

When PiP is enabled, disable automatic activation and control it manually.

- (void) pictureInPictureControllerIsPictureInPictureEnable:(nullable AVPictureInPictureController *) pictureInPictureController isEnable:(BOOL) isEnable
{
    if (isEnable && pictureInPictureController) {
        _pipController = pictureInPictureController;
        // close pip auto start
        if (@available(iOS 15.0, *)) {
            _pipController.canStartPictureInPictureAutomaticallyFromInline = false;
        }
    } else {
        _pipController = NULL;
    }
}

- (void) switchPip:(bool) enable {
    if (_pipController == nil) {
        return;
    }
    if (enable) {
        // start pip
        [_pipController startPictureInPicture];
    } else {
        // close pip
        [_pipController stopPictureInPicture];
    }
}

Live RTS fallback

Note

For a detailed code example, see the RtsLiveStream module in the API-Example project.

For more information, see RTS live playback.

Switch between left and right audio channels

The iOS player SDK uses the outputAudioChannel property to set the output audio channel. If the input source is stereo, you can switch to the left or right audio channel using the following methods. If the input source is mono, the setting has no effect.

Note

The output audio channel setting affects both audio rendering and PCM data callbacks.

// Set the AVPOutputAudioChannel enumeration value to switch channels.
// AVP_AUDIO_CHANNEL_NONE: Do not specify a channel. Play with the input source's audio channel. This is the default value.
// AVP_AUDIO_CHANNEL_LEFT: Switch to the left audio channel for playback.
// AVP_AUDIO_CHANNEL_RIGHT: Switch to the right audio channel for playback.
self.player.outputAudioChannel = AVP_AUDIO_CHANNEL_NONE;

Set the video background color

The iOS Player SDK lets you set the background color for player rendering. The interface and usage instructions are as follows:

API example

/**
 @brief Set the background color of the video.
 @param color  the color
 */
/****
 @brief Set video background color
 @param color  the color
 */
-(void) setVideoBackgroundColor:(UIColor *)color;

Usage

// The parameter is an 8-digit hexadecimal value. The 8 digits are grouped into pairs, representing A (alpha/transparency), R (red), G (green), and B (blue) in order.
// For example, 0x0000ff00 represents green.
[self.player setVideoBackgroundColor:0x0000ff00]

Specify a playback domain for VidAuth

With the VidAuth method, you can specify parameters such as the playback domain for a vid. For a list of supported fields, see GetPlayInfo. The following content describes how to specify a domain name for vidAuth-based playback and provides sample code:

API example

/**
 @brief Play using the vid+playauth method. See https://www.alibabacloud.com/help/zh/vod/user-guide/use-playback-credentials-to-play-videos
 @param source The input type of AVPVidAuthSource.
 @see AVPVidAuthSource
 */
- (void)setAuthSource:(AVPVidAuthSource*)source;

Usage

Add the playDomain field through the VidPlayerConfigGenerator interface.

VidPlayerConfigGenerator* gen = [[VidPlayerConfigGenerator alloc]init];
// Add the playDomain field. For the fields that can be added, see
// https://www.alibabacloud.com/help/zh/vod/developer-reference/api-vod-2017-03-21-getplayinfo
[gen addVidPlayerConfigByStringValue:@"playDomain" value: @"com.xxx.xxx"];
[source setPlayConfig:[gen generatePlayerConfig]];
[self.player setAuthSource:source]:

Background decoding

Starting from version 6.12.0, the SDK supports background decoding. When enabled, the player can continue to decode and play video streams when the app is in the background.

// A value of 1 enables background decoding. A value of 0 disables background decoding. The default value is 0.
[self.player setOption:ALLOW_DECODE_BACKGROUND valueInt:1];

H.266 decoding plugin

H.266, also known as Versatile Video Coding (VVC), is a next-generation video coding standard that offers significantly lower bitrates at the same quality. The H.266 decoding capability is provided as a separate plug-in for on-demand integration.

Prerequisites

  1. Use Player or all-in-one SDK V7.6.0 or later.

  2. The Professional Edition License authorization is complete. For more information, see Obtain a Player SDK License.

  3. ApsaraVideo Player with the H.266 decoding plugin supports only H.266 videos encoded by ApsaraVideo Transcoding.

Integrate the plugin

Player SDK

CocoaPods (recommended)

Add the dependency to your Podfile.

Note

For the latest version of the iOS SDK, see Release notes.

// x.x.x must be the same as the version number of ApsaraVideo Player SDK.
pod 'AliPlayerSDK_iOS_VVC_CODEC_PLUGIN', 'x.x.x'

Local integration

Download the latest version of the iOS Player SDK, add vvcCodecPlugin.framwork to Frameworks, Libraries, and Embedded Content, set Embed to Embed & Sign, and configure the Framework Search Paths. For details, see Local integration.

All-in-one SDK

CocoaPods (recommended)

Add the dependency to your Podfile.

// x.x.x must be the same as the version number of the integrated SDK you are using.
pod 'AliVCSDK_Standard/AliPlayerSDK_iOS_VVC_CODEC', 'x.x.x'

Local integration

Download the latest version of the iOS all-in-one package, extract it, add plugins/vvcCodecPlugin.framework to Frameworks, Libraries, and Embedded Content, set Embed to Embed & Sign, and configure the Framework Search Paths. For details, see Local integration.

Activate Plugin

Note

Starting from v7.7.0, the plug-in is enabled by default and does not need manual activation.

[AliPlayerGlobalSettings enableCodecPlugin:@"vvc" valid:true];

Related error codes

For error codes related to the H.266 plug-in, see General FAQ for players on different platforms.

Auto-refresh playback sources

Enable auto-refresh of playback sources to prevent playback interruptions caused by expired authentication. This feature triggers a listener when a source expires and retrieves a new URL to ensure smooth, uninterrupted playback.

Prerequisites

  1. Use Player or all-in-one SDK V7.9.0 or later.

  2. Use VidAuth sources or configure URL signing.

VidAuth source

API example

/**
 @brief Set the callback for VidAuth source expiration notification.

 When the player detects that the current VidAuth source has expired, this method triggers a callback.
 VidAuth source expiration includes PlayAuth expiration and playback URL expiration.
 You can refresh the VidAuth source in the callback and submit the new VidAuth source object via `callback` to ensure stable and smooth playback.

 @param callback The callback block triggered when the VidAuth source expires.
 You can use this callback to return a valid `VidAuth` object to update the player.
 */
/****
 @brief Set the callback for VidAuth source expiration notification.

 This method is triggered when the player detects that the current VidAuth source has expired.
 You can refresh the VidAuth source within the callback and use the `callback` to return the updated VidAuth source,
 ensuring uninterrupted and smooth video playback.

 @param callback The callback block triggered when the VidAuth source expires.
 Use this callback to provide a valid `VidAuth` object to update the player.
 */
-(void)setOnVidAuthExpiredCallback:(void (^)(id expiredSource, id<AVPSourceRefreshCallback> callback))callback;

Feature composition

Feature composition

/**
 @protocol AVPSourceRefreshCallback
 @brief A protocol for handling playback source refresh results, which developers need to implement.

 This protocol notifies developers when the player requests playback source refresh, such as when a resource
 has expired or needs updating. The methods in this protocol are called to provide the refresh results to the developer,
 including success or failure.

 @note This protocol applies to URL source, VidAuth source, and similar scenarios requiring refresh logic.
 */
 /****
 @brief A protocol for handling playback source refresh results, which developers need to implement.

 This protocol notifies developers when the player requests playback source refresh, such as when a resource
 has expired or needs updating. The methods in this protocol are called to provide the refresh results to the developer,
 including success or failure.

 @note This protocol applies to URL source, VidAuth source, and similar scenarios requiring refresh logic.
 */
@protocol AVPSourceRefreshCallback <NSObject>

/**
 @brief Called by the player when the refresh operation succeeds.
 @param newSource The new playback source object containing the updated information.
 
 This method indicates that the refresh operation has been successfully completed. Developers need to pass
 the updated `newSource` back to the player so that it can load the latest resource.
 */
 /****
 @brief Called by the player when the refresh operation succeeds.
 
 @param newSource The new playback source object containing the updated information.

 This method indicates that the refresh operation has been successfully completed. Developers need to pass
 the updated `newSource` back to the player so that it can load the latest resource.
 */
- (void)onSuccess:(id)newSource;

/**
 @brief Called by the player when the refresh operation fails.
 @param errorMsg A string describing the reason for the failure.
 
 This method indicates that the refresh operation has failed. Developers can use `errorMsg` to capture failure
 details and handle subsequent processing accordingly.
 */
 /****
 @brief Called by the player when the refresh operation fails.
 
 @param errorMsg A string describing the reason for the failure.

 This method indicates that the refresh operation has failed. Developers can use `errorMsg` to capture failure
 details and handle subsequent processing accordingly.
 */
- (void)onError:(NSString *)errorMsg;

@end

Usage

You can obtain video playback credentials using the GetVideoPlayAuth operation. We recommend integrating the ApsaraVideo VOD server-side SDK to obtain credentials and avoid manual signing. For details, see OpenAPI Explorer.

[self.player setOnVidAuthExpiredCallback:^(id expiredSource, id<AVPSourceRefreshCallback> callback) {
    // Get AVPVidAuthSource
    if ([expiredSource isKindOfClass:[AVPVidAuthSource class]]) {

        // ------------------- User implementation begins -------------------
        // Call your own function to get a new PlayAuth from your app server.
        // clinetGetPlayAuthFunction is a sample function name. Replace it with your own implementation.
        [self clinetGetPlayAuthFunction:vid success:^(NSString* newPlayAuth){
            // 1. Callback for successful retrieval of new credentials
            [vidAuth setPlayAuth:newPlayAuth];
            // 2. Return the updated object to the player via the SDK callback
            [callback onSuccess:vidAuth];
        } failure:^(NSString* errorMsg) {
            // Callback for failed credential retrieval.
            // errorMsg contains detailed error information.
            [callback onError:errorMsg];
        }];
        // ------------------- User implementation ends -------------------
    }
}];

URL source

API example

/**
 @brief Set the callback for URL source expiration notification.

 When the player detects that the current URL source has expired, this method triggers a callback.
 You can refresh the URL source in the callback and use `callback` to return the new URL source to ensure uninterrupted playback.

 @note For URL signing configuration, see the Alibaba Cloud documentation:
 https://www.alibabacloud.com/help/zh/vod/user-guide/configure-url-signing?spm=a2c4g.11186623.0.0.560c4140fGh8MW
 
 @param callback The callback block triggered when the URL source expires.
 You can use this callback to provide a valid `URLSource` object to update the player.
 */
 /****
 @brief Set the callback for URL source expiration notification.

 This method is triggered when the player detects that the current URL source has expired.
 You can refresh the URL source within the callback and use the `callback` to return the updated URL source,
 ensuring uninterrupted video playback.

 @param callback The callback block triggered when the URL source expires.
 Use this callback to provide a valid `URLSource` object to update the player.
 */
-(void)setOnURLSourceExpiredCallback:(void (^)(id expiredSource, id<AVPSourceRefreshCallback> callback))callback;

Feature composition

Feature composition

/**
 @protocol AVPSourceRefreshCallback
 @brief A protocol for handling playback source refresh results, which developers need to implement.

 This protocol notifies developers when the player requests playback source refresh, such as when a resource
 has expired or needs updating. The methods in this protocol are called to provide the refresh results to the developer,
 including success or failure.

 @note This protocol applies to URL source, VidAuth source, and similar scenarios requiring refresh logic.
 */
 /****
 @brief A protocol for handling playback source refresh results, which developers need to implement.

 This protocol notifies developers when the player requests playback source refresh, such as when a resource
 has expired or needs updating. The methods in this protocol are called to provide the refresh results to the developer,
 including success or failure.

 @note This protocol applies to URL source, VidAuth source, and similar scenarios requiring refresh logic.
 */
@protocol AVPSourceRefreshCallback <NSObject>

/**
 @brief Called by the player when the refresh operation succeeds.
 @param newSource The new playback source object containing the updated information.
 
 This method indicates that the refresh operation has been successfully completed. Developers need to pass
 the updated `newSource` back to the player so that it can load the latest resource.
 */
 /****
 @brief Called by the player when the refresh operation succeeds.
 
 @param newSource The new playback source object containing the updated information.

 This method indicates that the refresh operation has been successfully completed. Developers need to pass
 the updated `newSource` back to the player so that it can load the latest resource.
 */
- (void)onSuccess:(id)newSource;

/**
 @brief Called by the player when the refresh operation fails.
 @param errorMsg A string describing the reason for the failure.
 
 This method indicates that the refresh operation has failed. Developers can use `errorMsg` to capture failure
 details and handle subsequent processing accordingly.
 */
 /****
 @brief Called by the player when the refresh operation fails.
 
 @param errorMsg A string describing the reason for the failure.

 This method indicates that the refresh operation has failed. Developers can use `errorMsg` to capture failure
 details and handle subsequent processing accordingly.
 */
- (void)onError:(NSString *)errorMsg;

@end

Usage

[self.player setOnURLSourceExpiredCallback:^(id expiredSource, id<AVPSourceRefreshCallback> callback) {
    // Get AVPUrlSource
    if ([expiredSource isKindOfClass:[AVPUrlSource class]]) {
        AVPUrlSource *expiredUrlSource = (AVPUrlSource *)expiredSource;
        NSString *expiredUrl = [expiredUrlSource.playerUrl absoluteString];

        // Check if auth_key is included
        if (![expiredUrl containsString:@"auth_key="]) {
            return;
        }

        // 1. Extract the original URL from the expired URL
        NSRange authKeyQuestionRange = [expiredUrl rangeOfString:@"?auth_key="];
        NSRange authKeyAmpersandRange = [expiredUrl rangeOfString:@"&auth_key="];

        NSInteger authKeyIndex = NSNotFound;
        if (authKeyQuestionRange.location != NSNotFound) {
            authKeyIndex = authKeyQuestionRange.location;
        } else if (authKeyAmpersandRange.location != NSNotFound) {
            authKeyIndex = authKeyAmpersandRange.location;
        }

        NSString *originalUrl = nil;
        if (authKeyIndex != NSNotFound) {
            originalUrl = [expiredUrl substringToIndex:authKeyIndex];
        } else {
            // If auth_key is not found, treat the entire URL as the original URL
            originalUrl = expiredUrl;
        }

        // 2. Prepare new authentication parameters: authKey and expiration time
        // If the class member authKey is valid, use it
        NSString *key = (self.authKey.length > 0) ? self.authKey : @"";
        if (!NOT_EMPTY(key)) {
            [callback onError:@"REFRESH_ERROR:key fail"];
            return;
        }       
        
        // If the class member validTime is valid, use it; otherwise, use the default value
        NSTimeInterval validTime = (self.validTime > 0) ? self.validTime : 3600; // Default 3600 seconds
        NSTimeInterval newExpireTime = [[NSDate date] timeIntervalSince1970] + validTime;

         // 3. Generate a new authenticated URL using CdnAuthUtil (Method A)
        NSString *newAuthUrl = [CdnAuthUtil aAuthWithUri:originalUrl key:key exp:newExpireTime];
        AVPUrlSource *resultSource = [[AVPUrlSource alloc] urlWithString:newAuthUrl];

        // 4. Callback handling
        if (newAuthUrl) {
            [callback onSuccess:resultSource];
        } else {
            [callback onError:@"REFRESH_ERROR:refresh fail"];
        }
    }
}];

Utility functions

Example using signing method A.

Utility functions

#import "CdnAuthUtil.h"
#import <CommonCrypto/CommonDigest.h>

@implementation CdnAuthUtil

#pragma mark - Auth Method A
+ (NSString *)aAuthWithUri:(NSString *)uri key:(NSString *)key exp:(NSTimeInterval)exp {
    NSDictionary *components = [self matchUri:uri];
    if (!components) return nil;

    NSString *scheme = components[@"scheme"];
    NSString *host = components[@"host"];
    NSString *path = components[@"path"];
    NSString *args = components[@"args"];

    NSString *rand = @"0";
    NSString *uid = @"0";

    NSString *sstring = [NSString stringWithFormat:@"%@-%lld-%@-%@-%@", path, (long long)exp, rand, uid, key];
    NSString *hashvalue = [self md5sum:sstring];
    NSString *authKey = [NSString stringWithFormat:@"%lld-%@-%@-%@", (long long)exp, rand, uid, hashvalue];

    if (args.length > 0) {
        return [NSString stringWithFormat:@"%@%@%@%@&auth_key=%@", scheme, host, path, args, authKey];
    } else {
        return [NSString stringWithFormat:@"%@%@%@%@?auth_key=%@", scheme, host, path, args, authKey];
    }
}

#pragma mark - Private Helper: MD5
+ (NSString *)md5sum:(NSString *)src {
    const char *cStr = [src UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(cStr, (unsigned int)strlen(cStr), result);

    NSMutableString *hexString = [NSMutableString string];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [hexString appendFormat:@"%02x", result[i]];
    }
    return hexString.copy;
}

#pragma mark - Private Helper: Regex Match
+ (NSDictionary *)matchUri:(NSString *)uri {
    NSError *error = nil;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^(https?://)?([^/?]+)(/[^?]*)?(\\?.*)?$"
                                  options:0
                                  error:&error];
    if (error) {
        NSLog(@"Regex error: %@", error.localizedDescription);
        return nil;
    }

    NSTextCheckingResult *match = [regex firstMatchInString:uri
                                   options:0
                                   range:NSMakeRange(0, uri.length)];
    if (!match) return nil;

    __block NSString *scheme = nil, *host = nil, *path = nil, *args = nil;

    void (^setStringFromRange)(NSInteger, NSString**) = ^(NSInteger idx, NSString **outStr) {
        NSRange range = [match rangeAtIndex:idx];
        if (range.location != NSNotFound && range.length > 0) {
            *outStr = [uri substringWithRange:range];
        } else {
            *outStr = nil;
        }
    };

    setStringFromRange(1, &scheme);
    setStringFromRange(2, &host);
    setStringFromRange(3, &path);
    setStringFromRange(4, &args);

    // Default value handling
    if (!scheme) scheme = @"http://";
    if (!path) path = @"/";

    return @{
        @"scheme": scheme,
        @"host": host,
        @"path": path,
        @"args": args ?: @""
        };
}
@end

Performance

Set the playback scenario

Setting the playback scenario automatically configures optimal parameters (including buffer settings and feature toggles) while preserving custom parameters set via the setConfig interface (custom settings take precedence).

Note
  • After setting the playback scenario, use the getConfig interface to view the parameter configuration.

API examples

/**
 @brief Set player scenario.
 @param scene Player scenario.
 @see AVPScenario
 */
/****
 @brief Set player scene.
 @param scene Player scene.
 @see AVPScene
 */
-(void) setPlayerScene:(AVPScene)scene;

Playback scenarios

typedef enum _AVPScene {
    /**
     * Scenario: None
     */
    /****
     * scene none
     */
    SceneNone,
    /**
     * Long-video scenario: Applies to videos longer than 30 minutes
     */
    /****
     * long scene: apply to more than 30min
     */
    SceneLong,
    /**
     * Medium-video scenario: Applies to videos 5–30 minutes long
     */
    /****
     * middle scene: apply to 5min-30min
     */
    SceneMedium,
    /**
     * Short-video scenario: Applies to videos up to 5 minutes long
     */
    /****
     * short scene: apply to 0s-5min
     */
    SceneShort,
    /**
     * Live-streaming scenario
     */
    /****
     * live scene
     */
    SceneLive,
    /**
     * Ultra-low-latency live-streaming scenario
     */
    /****
     * RTS live scene
     */
    SceneRTSLive
} AVPScene;

Usage

// Set short-video scenario
[self.player setPlayerScene:SceneShort];

// Set medium-video scenario
[self.player setPlayerScene:SceneMedium]; 

// Set long-video scenario
[self.player setPlayerScene:SceneLong];  

// Set live-streaming scenario
[self.player setPlayerScene:SceneLive];   

Pre-rendering

The iOS Player SDK supports quickly rendering the first frame before playback starts, improving startup speed.

Note
  1. This feature is disabled by default.

  2. When enabled, it affects the order of the preparation-complete and first-frame-rendered events: By default, the preparation-complete event fires first, followed by the first-frame-rendered event. With pre-rendering enabled, the first-frame-rendered event may fire before the preparation-complete event depending on decoding and rendering speed, but playback remains unaffected.

Example:

[self.player setOption:ALLOW_PRE_RENDER valueInt:1];

Local cache

Note

For detailed code examples, see the PreloadUrl module in the API-Example project.

The iOS Player SDK provides local caching to improve startup speed, seek speed, and reduce stuttering for repeated video playback, while saving bandwidth.

Enable local cache

By default, the local caching feature is disabled. To use this feature, you must manually enable it. This feature is configured through the AliPlayerGlobalSettings class using the enableLocalCache property. The following example shows how to configure this setting:

/**
 * Enable local cache. After enabling, it caches to local files.
 * @param enable: Local cache toggle. true: enable, false: disable. Default is disable.
 * @param maxBufferMemoryKB: Deprecated since V5.4.7.1. No effect.
 * @param localCacheDir: Required. Absolute path to the local cache directory.
 */
[AliPlayerGlobalSettings enableLocalCache:true maxBufferMemoryKB:1024 localCacheDir:@""];

/**
 @brief Settings for automatic clearing of local cache files.
 @param expireMin: Deprecated since V5.4.7.1. No effect.
 @param maxCapacityMB: Maximum cache capacity in megabytes. Default is 20 GB. During cleanup, if the total cache capacity exceeds this size, the oldest cache files will be deleted one by one, sorted by the last cache time of the cacheItem, until the capacity is less than or equal to the maximum cache capacity.
 @param freeStorageMB: Minimum free disk space in megabytes. Default is 0. During cleanup, similar to the maximum cache capacity, if the current disk space is less than this value, cache files will also be deleted one by one according to the rules until freeStorage is greater than or equal to this value or all caches are cleared.
 */
[AliPlayerGlobalSettings setCacheFileClearConfig:0 maxCapacityMB:0 freeStorageMB:0];

/**
 * Callback to get the hash value of the loaded URL. Used as a unique ID for the URL. You must ensure that each URL is different.
 */

// You need to implement this function yourself and pass the function pointer to setCacheUrlHashCallback.
static NSString *CaheUrlHashHandle(NSString *url) {
    return @"xxx";
}

[AliPlayerGlobalSettings setCacheUrlHashCallback:&CaheUrlHashHandle];
Note
  • If the video playback URL has authentication parameters, these parameters will change during local caching and playback. To improve the cache hit rate for the same URL with different authentications, you can remove the authentication parameters from the URL before calculating the hash value (for example, MD5) with the setCacheUrlHashCallback interface. For example, if the playback URL with authentication is http://****.mp4?aaa, use http://****.mp4 to calculate the hash value when loading. However, if the video is an encrypted M3U8 video, processing its keyURL by removing authentication parameters before calculating the hash value will cause different videos to hit the same key in the cache, leading to playback failure. Solution: In the setCacheUrlHashCallback callback, you can perform a domain check and only remove authentication parameters for the playback domain (http(s)://xxxxx.m3u8?aaaa), while not removing them for the keyURL's domain (http(s)://yyyyy?bbbb).进阶功能-本地缓存.png

  • If the server supports both HTTP and HTTPS protocols, but the media files pointed to by different protocols are identical, you can remove or unify the request headers before calculating the MD5 value. For example:

    • If the video playback URLs are https://****.mp4 and http://****.mp4, use ****.mp4 to calculate the MD5 value.

    • If the video playback URL is https://****.mp4, unify it to http://****.mp4 before you calculate the MD5 value.

  • For ApsaraVideo Player SDK V5.5.4.0 and later, if the video playback URL contains authentication parameters and the playback protocol is HLS, you can set the AVPConfig.enableStrictAuthMode field to select different authentication modes. The default value is false for earlier versions. The default value is true for V7.13.0 and later.:

    • Non-strict authentication (false): Authentication is cached. If only part of the media was cached previously, the player uses the cached authentication to request non-cached parts. If the URL authentication validity period is short, or playback resumes long after pausing, authentication may expire. Combine with auto-refresh playback sources to handle authentication expiration during resume.

    • Strict authentication (true): Authentication is not cached. Authentication is performed every time playback starts. Playback fails without network connectivity.

Enable or disable local cache for a single URL

If you want to disable the local caching feature for a specific URL, you can set it in the player config. The following example shows how to do this:

// Get the configuration first.
AVPConfig *config = [self.player getConfig];
// Whether to enable local cache for the playback URL. Default is true. When local cache is enabled globally via AliPlayerGlobalSettings and also enabled here (set to true), the local cache for this URL takes effect. If set to false here, the local cache for this URL is disabled.
config.enableLocalCache = false;
....// Other settings

// Set the configuration for the player.
[self.player setConfig:config];

Use the default cache path

If you want to use the default path for caching, you can configure it as follows through AliPlayerGlobalSettings.

[AliPlayerGlobalSettings enableLocalCache:true];

Preloading

The iOS Player SDK provides preloading, an upgrade to local caching that downloads part of a video into the cache before playback starts, further improving startup speed.

Preloading limits:

  • Preloading supports single media files such as MP4, MP3, FLV, and HLS.

Note

The iOS Player SDK schedules preload network requests by default to avoid interfering with the currently playing video. The preload request is sent only after the buffered content reaches a specific threshold. To disable this and manage requests in real-time, use the following:

[AliPlayerGlobalSettings enableNetworkBalance:false];
  1. Enable the local cache feature as described in Local cache.

  2. Set the source.

    VidAuth (recommended)

    AVPVidAuthSource* vidAuthSource = [[AVPVidAuthSource alloc] init];
    [vidAuthSource setVid:@"Vid information"]; // Required. The video ID (VideoId).
    [vidAuthSource setPlayAuth:@"<yourPlayAuth>"]; // Required. The playback credential. You need to call the GetVideoPlayAuth operation of ApsaraVideo VOD to generate it.
    [vidAuthSource setRegion:@"Access region"]; // For Player SDK V5.5.5.0 and later, this parameter is deprecated. You do not need to set the region. The player will automatically parse the region. For Player SDK versions earlier than 5.5.5.0, this parameter is required. The access region of ApsaraVideo VOD. The default is cn-shanghai.
    [vidAuthSource setQuality:@"Selected definition"]; // "AUTO" represents adaptive bitrate.

    VidSts

    AVPVidStsSource* vidStsSource = [[AVPVidStsSource alloc] init];
    [vidStsSource setVid: @"Vid information"]; // Required. The video ID (VideoId).
    [vidStsSource setRegion:@"Access region"]; // Required. The access region of ApsaraVideo VOD. The default is cn-shanghai.
    [vidStsSource setSecurityToken: @"<yourSecurityToken>"]; // Required. The STS security token. You need to call the AssumeRole operation of STS to generate it.
    [vidStsSource setAccessKeySecret: @"<yourAccessKeySecret>"]; // Required. The AccessKey secret of the temporary STS AccessKey pair. You need to call the AssumeRole operation of STS to generate it.
    [vidStsSource setAccessKeyId: @"<yourAccessKeyId>"]; // Required. The AccessKey ID of the temporary STS AccessKey pair. You need to call the AssumeRole operation of STS to generate it.
    [vidStsSource setQuality:@"Selected definition"]; // "AUTO" represents adaptive bitrate.

    UrlSource

    NSString* url = @"Playback URL"; // Required. The playback URL. It can be a third-party VOD URL or a playback URL from ApsaraVideo VOD.
    AVPUrlSource* urlSource = [[AVPUrlSource alloc]urlWithString:url];
  3. Set task parameters.

    Note

    This applies only to multi-bitrate videos. You can choose any one of setDefaultBandWidth, setDefaultResolution, or setDefaultQuality.

    AVPPreloadConfig *config = [[AVPPreloadConfig alloc]init];
    // Set the preload bitrate for a multi-bitrate stream.
    [config setDefaultBandWidth:400000];
    // Set the preload resolution for a multi-bitrate stream.
    [config setDefaultResolution:640 * 480];
    // Set the preload quality for a multi-bitrate stream.
    [config setDefaultQuality:@"FD"];
    // Set the preload duration.
    [config setDuration:1000];
  4. Add a task listener.

    Expand to view the code

    @interface YourViewController () <OnPreloadListener>
    
    @property(nonatomic,strong) AliMediaLoaderV2* vodMedialoader; // Preloader
    @property(nonatomic,strong) AVPVidAuthSource* vidSource; // vidAuth data source
    @property(nonatomic,strong) AVPUrlSource* urlSource; // url data source
    @property(nonatomic,strong) AVPVidStsSource* vidStsSource; // vidSts data source
    
    @end
    
    @implementation YourViewController
    
    - (void)onCompleted:(NSString *)taskId urlOrVid:(NSString *)urlOrVid {
        NSLog(@"Current task (%@) completed:%@", taskId,urlOrVid);
    }
    
    - (void)onError:(NSString *)taskId urlOrVid:(NSString *)urlOrVid errorModel:(AVPErrorModel *)errorModel {
        NSLog(@"An exception occurred:%@", urlOrVid);
    }
    
    - (void)onCanceled:(NSString *)taskId urlOrVid:(NSString *)urlOrVid {
        NSLog(@"Task canceled:%@", urlOrVid);
    }
    
    @end
  5. Build the task, add it to the MediaLoaderV2 instance, and start preloading.

    VidAuth (recommended)

    // Build the preload task.
    AVPPreloadTask* mPreloadTask = [[AVPPreloadTask alloc]initWithVidAuthSource:vidAuthSource preloadConfig:config];
    // Get the MediaLoaderV2 instance.
    AliMediaLoaderV2* vodMedialoader = [AliMediaLoaderV2 shareInstance];
    // Add the task and start preloading.
    NSString* taskId = [vodMedialoader addTask:mPreloadTask listener:self];

    VidSts

    // Build the preload task.
    AVPPreloadTask* mPreloadTask = [[AVPPreloadTask alloc]initWithVidStsSource:vidStsSource preloadConfig:config];
    // Get the MediaLoaderV2 instance.
    AliMediaLoaderV2* vodMedialoader = [[AliMediaLoaderV2 alloc]init];
    // Add the task and start preloading.
    NSString* taskId = [vodMedialoader addTask:mPreloadTask listener:self];

    UrlSource

    // Build the preload task.
    AVPPreloadTask* mPreloadTask = [[AVPPreloadTask alloc]initWithUrlSource:urlSource preloadConfig:config];
    // Get the MediaLoaderV2 instance.
    AliMediaLoaderV2* vodMedialoader = [[AliMediaLoaderV2 alloc]init];
    // Add the task and start preloading.
    NSString* taskId = [vodMedialoader addTask:mPreloadTask listener:self];
  6. Optional: Manage tasks.

    [vodMedialoader cancelTask:taskId];// Cancel the preload task with the specified task ID.
    [vodMedialoader pauseTask:taskId];// Pause the preload task with the specified task ID.
    [vodMedialoader resumeTask:taskId];// Resume the preload task with the specified task ID.
  7. Optional: Delete loaded files.

    You can delete loaded files as needed to save space. The SDK does not provide a delete interface. You need to delete the files in the loading directory in the app.

Dynamic preloading

The dynamic preloading strategy lets you balance playback experience and cost by controlling the cache of the current video and the number of preloaded items.

Expand to view the code

// Enable recommended configuration and dynamic preload
[self.listPlayer setScene:AVP_SHORT_VIDEO];

// Configure base preload duration
// Set preload duration to 1000ms
AVPPreloadConfig *config = [[AVPPreloadConfig alloc] init];
config.preloadDuration = 1000;
[self.listPlayer updatePreloadConfig:config];

// Configure preload count, supports bidirectional
// 1 for previous preload count, 3 for next preload count
[self.listPlayer setPreloadCount:1 nextCount:3];

// Configure the decreasing offset for dynamic preload
[self.listPlayer enableStrategy:AVP_STRATEGY_DYNAMIC_PRELOAD enable:true];
[self.listPlayer setStrategyParam:AVP_STRATEGY_DYNAMIC_PRELOAD strategyParam:@"{\"algorithm\": \"sub\",\"offset\": \"200\"}"];

Preload multi-bitrate HLS videos

In listPlayer scenarios with multi-bitrate HLS videos, you can preload a stream that matches the current playback definition and choose a preload mode based on your business needs.

Expand to view supported preloading modes

typedef enum AVPMultiBitratesMode : NSUInteger {
    /**
     * Default configuration. Play and preload the default bitrate.
     */
    /****
     * default mode, play and preload default bitrate of a stream
     */
    AVPMultiBitratesMode_Default = 0,
    /**
     * First frame priority configuration. The video starts playing at the bitrate that has finished preloading.
     */
    /****
     * First frame cost (FC) priority, decrease first frame cost. only play bitrate of the hls stream which has been preloaded.
     */
    AVPMultiBitratesMode_FCPrio = 1,
    /**
     * Balances first frame and smooth playback. The video bitrate is consistent before and after switching (moveToNext), and first frame performance is also considered.
     */
    /****
     * First frame and play smooth, play the same bitrate before and after moveToNext
     */
    AVPMultiBitratesMode_FC_AND_SMOOTH = 2,
    /**
     * Smooth playback priority configuration. The video starts playing at the bitrate of the previous video.
     */
    /****
     * Play Smooth priority, play the same bitrate before and after moveToNext.
     */
    AVPMultiBitratesMode_SmoothPrio = 3,
} AVPMultiBitratesMode;

Expand to view the integration code

// Select the multi-bitrate loading mode.
[self.listPlayer->SetMultiBitratesMode(preLoadMode)];

// (Optional) Select the startup bitrate.
[self.listPlayer setDefaultBandWidth:defaultBandWidth];

// (Optional) In the preparedone callback, select the ABR mode.
-(void)onPlayerEvent:(AliPlayer*)player eventType:(AVPEventType)eventType {
    switch (eventType) {
        case AVPEventPrepareDone: {
            [self.listPlayer selectTrack:-1];
        }
            break;
        case AVPEventFirstRenderedStart: {
        }
            break;
        default:
            break;
    }
}

Get the download speed

Retrieve the download speed of the currently playing video in the onCurrentDownloadSpeed callback.

- (void)onCurrentDownloadSpeed:(AliPlayer *)player speed:(int64_t)speed{
  intspeed_=speed;
}

Network features

HTTPDNS

HTTPDNS uses DNS resolution technology to send domain name resolution requests to a specific HTTPDNS server to obtain faster and more stable domain name resolution results, reducing the risk of DNS hijacking.

ApsaraVideo Player SDK provides an enhanced HTTPDNS feature, specifically for Alibaba Cloud CDN domain names, supporting precise scheduling and real-time resolution for the Alibaba Cloud CDN network, effectively improving network performance.

Enhanced HTTPDNS usage example

Enhanced HTTPDNS only provides HTTPDNS services for Alibaba Cloud CDN domain names. Ensure that the domain name you configure is an Alibaba Cloud CDN domain name and that the domain name configuration is complete and can be used normally. To add and configure a CDN domain name in ApsaraVideo VOD, see Add an accelerated domain name. For more information about CDN domain names, see Alibaba Cloud CDN.

// Enable enhanced HTTPDNS.
[AliPlayerGlobalSettings enableEnhancedHttpDns:YES];
// Optional. Add a domain name for HTTPDNS pre-resolution.
[[AliDomainProcessor shareInstance] addPreResolveDomain:@"player.***alicdn.com"];

HTTP/2

Note

The iOS Player SDK enables HTTP/2 by default starting from version 5.5.0.0.

The iOS Player SDK supports HTTP/2, which uses multiplexing to avoid head-of-line blocking and improve playback performance.

[AliPlayerGlobalSettings setUseHttp2:true];

Pre-establish TCP connections for HTTP

For HTTP (not HTTPS) video playback requests, pre-establishing TCP connections significantly improves user experience, reduces connection time, ensures playback immediacy and continuity, and optimizes network and system resource usage.

// Domain format is host[:port]. Port is optional. Multiple domains are separated by semicolons (;).
// Global setting.
// Each time the full interface is set, the current string is used (add for more, delete for less). An empty string stops pre-connection.
[AliPlayerGlobalSettings setOption:SET_PRE_CONNECT_DOMAIN value: @"domain1;domain2"];

Video download

Note

For detailed code examples, see the Download module in the API-Example project.

The iOS Player SDK provides a video download feature for ApsaraVideo VOD content, with standard and secure modes.

  • Standard download: The downloaded video is not encrypted and can be played by third-party players.

  • Secure download: The downloaded video is encrypted and can only be played by ApsaraVideo Player.

Usage notes

  • The video download feature is supported only by the VidSts and VidAuth methods.

  • Enable and configure the download mode in the ApsaraVideo VOD console. For more information, see Offline download.

  • Video downloads support resumable transfers.

Procedure

  1. Optional: Configure the encryption verification file for secure download. Configure this only for secure download. Standard download does not require configuration.

    Note

    Ensure the encryption verification file matches your app information. Otherwise, the video download fails.

    If you use secure download, configure the key file generated in the ApsaraVideo VOD console in the Player SDK. The key file is used to decrypt and verify the video for download and playback. For more information about how to generate the key file, see Enable secure download.

    We recommend configuring the key file once in the Application.

    NSString *encrptyFilePath = [[NSBundle mainBundle] pathForResource:@"encryptedApp" ofType:@"dat"];
    [AliPrivateService initKey:encrptyFilePath];
  2. Create and set up the downloader.

    Example:

    AliMediaDownloader *downloader = [[AliMediaDownloader alloc] init];
    [downloader setSaveDirectory:self.downLoadPath];
    [downloader setDelegate:self];
  3. Set event listeners.

    The downloader provides multiple listeners.

    -(void)onPrepared:(AliMediaDownloader *)downloader mediaInfo:(AVPMediaInfo *)info {
        // The download item is successfully prepared.
    }
    -(void)onError:(AliMediaDownloader *)downloader errorModel:(AVPErrorModel *)errorModel {
        // A download error occurred.
    }
    -(void)onDownloadingProgress:(AliMediaDownloader *)downloader percentage:(int)percent {
        // Download progress percentage.
    }
    -(void)onProcessingProgress:(AliMediaDownloader *)downloader percentage:(int)percent {
        // Processing progress percentage.
    }
    -(void)onCompletion:(AliMediaDownloader *)downloader {
        // The download is successful.
    }
  4. Prepare the download source.

    You can call the prepare method to prepare a download source. Supported source types include VidStsSource and VidAuthSource.

    • VidSts

      // Create VidSts.
      AVPVidStsSource* stsSource = [[AVPVidStsSource alloc] init];
      stsSource.region = @"Access region"; // The access region of ApsaraVideo VOD. The default is cn-shanghai.
      stsSource.vid = @"Vid information"; // The video ID (VideoId).
      stsSource.securityToken = @"<yourSecurityToken>"; // The STS security token. You need to call the AssumeRole operation of STS to generate it.
      stsSource.accessKeySecret = @"<yourAccessKeySecret>"; // The AccessKey secret of the temporary STS AccessKey pair. You need to call the AssumeRole operation of STS to generate it.
      stsSource.accessKeyId = @"<yourAccessKeyId>"; // The AccessKey ID of the temporary STS AccessKey pair. You need to call the AssumeRole operation of STS to generate it.
      
      // If you have enabled HLS standard encryption parameter pass-through in the VOD console, and the default parameter name is MtsHlsUriToken, you need to set the config and pass it into the vid. See below.
      // If you have not enabled HLS standard encryption parameter pass-through in the VOD console, you do not need to integrate the following code.
      VidPlayerConfigGenerator* vp = [[VidPlayerConfigGenerator alloc] init];
      [vp setHlsUriToken:yourMtsHlsUriToken];
      stsSource.playConfig = [vp generatePlayerConfig];
      // Prepare the download source.
      [downloader prepareWithVid:stsSource];
    • VidAuth

      // Create VidAuth.
      AVPVidAuthSource *authSource = [[AVPVidAuthSource alloc] init];
      authSource.vid = @"Vid information"; // The video ID (VideoId).
      authSource.playAuth = @"<yourPlayAuth>"; // The playback credential. You need to call the GetVideoPlayAuth operation of ApsaraVideo VOD to generate it.
      authSource.region = @"Access region"; // For Player SDK V5.5.5.0 and later, this parameter is deprecated. You do not need to set the region. The player will automatically parse the region. For Player SDK versions earlier than 5.5.5.0, this parameter is required. The access region of ApsaraVideo VOD. The default is cn-shanghai.
      // If you have enabled HLS standard encryption parameter pass-through in the VOD console, and the default parameter name is MtsHlsUriToken, you need to set the config and pass it into the vid. See below.
      // If you have not enabled HLS standard encryption parameter pass-through in the VOD console, you do not need to integrate the following code.
      VidPlayerConfigGenerator* vp = [[VidPlayerConfigGenerator alloc] init];
      [vp setHlsUriToken:yourMtsHlsUriToken];
      authSource.playConfig = [vp generatePlayerConfig];
      // Prepare the download source.
      [downloader prepareWithVid:authSource];
    Note

    If you enable parameter pass-through for HLS encryption in the ApsaraVideo VOD console, the default parameter is MtsHIsUriToken. For more information, see Parameter pass-through for HLS encryption. Then, set the MtsHIsUriToken value to the ApsaraVideo VOD source by following the preceding code.

  5. Select a download item after preparation succeeds.

    After the download source is prepared, the onPrepared method is called. The returned TrackInfo contains information about each video track, such as its definition. You can then select a track to download. The following sample code provides an example:

    -(void)onPrepared:(AliMediaDownloader *)downloader mediaInfo:(AVPMediaInfo *)info {
        NSArray<AVPTrackInfo*>* tracks = info.tracks;
        // For example, download the first TrackInfo.
        [downloader selectTrack:[tracks objectAtIndex:0].trackIndex];
    }
  6. Update the download source and start the download.

    VidSts or VidAuth may expire before the download. Therefore, we recommend updating the download source before you start the download.

    // Update the download source.
    [downloader updateWithVid:vidSource]
    // Start the download.
    [downloader start];
  7. Release the downloader after the download succeeds or fails.

    After the download is successful, call destroy to release the downloader.

    [self.downloader destroy];
    self.downloader = nil;

Encrypted playback

ApsaraVideo VOD supports HLS standard encryption, Alibaba Cloud proprietary encryption, and DRM encryption. For instructions, see Play an encrypted video.

Native RTS playback

The SDK integrates the Native RTS SDK to implement low-latency live streaming. For more information, see Implement RTS-based stream pulling on iOS.

References