This topic describes how to integrate Native RTS SDK into ApsaraVideo Player SDK to implement Real-Time Streaming (RTS) on an iOS client.
Prerequisites
CocoaPods is installed in your development environment.
Integrate SDKs
Use CocoaPods to install ApsaraVideo Player SDK and Native RTS SDK.
Open a terminal window.
Run the following command in the directory of your project to create a Podfile:
pod init
In the Podfile, add the latest versions of the SDKs as dependencies.
pod 'RtsSDK' pod 'AliPlayerSDK_iOS' pod 'AliPlayerSDK_iOS_ARTC'
NoteAfter you add the
AliPlayerSDK_iOS_ARTC
andRtsSDK
dependencies, RTS SDK is automatically integrated into ApsaraVideo Player SDK as a plug-in.If you want to use another version of an SDK, specify the version number. Example:
pod 'RtsSDK','2.1.0'
. For more information about the latest version of ApsaraVideo Player SDK for iOS, see Release notes for ApsaraVideo Player SDK for iOS. For more information about the latest version of RTS SDK for iOS, see Download SDKs.The version of Native RTS SDK must match the version of ApsaraVideo Player SDK. For more information, see Release notes.
Run the following command to install the SDKs. After the SDKs are installed, a *.xcworkspace file is generated.
pod install
Call the methods provided by ApsaraVideo Player SDK
Call the methods provided by ApsaraVideo Player SDK for iOS to implement the RTS feature. For information about other features of ApsaraVideo Player SDK, see Advanced features and API operations for ApsaraVideo Player SDK for Android.
This section provides the key code snippets. For the complete sample code, see the AUILiveRtsPlayPullViewController class under the AUILiveRtsPlay component in the open source project MONE_demo_opensource_iOS.
When you use ApsaraVideo Player SDK to pull streams over RTS, you cannot call the pause method to pause the playback of a stream. To pause the playback of a stream, call the stop method to stop the playback, and then call the prepare method to resume the playback.
When you use ApsaraVideo Player SDK to pull streams over RTS, seeking is not supported.
Initialize AliPlayer
- (AliPlayer *)aliPlayer{ if (!_aliPlayer) { _aliPlayer = [[AliPlayer alloc] init]; _aliPlayer.scalingMode = AVP_SCALINGMODE_SCALEASPECTFIT; _aliPlayer.rate = 1; // If you want to use AVPDelegate, add the following line: _aliPlayer.delegate = self; // Configure the user interface (UI) view and apply the UI view to AliPlayer. _aliPlayer.playerView = self.basePlayerView.playerView; _aliPlayer.autoPlay = YES; } return _aliPlayer; }
Configure the streaming URL
AVPUrlSource *source = [[AVPUrlSource alloc] urlWithString:_url]; [self.aliPlayer setUrlSource:source];
Configure playback parameters
Configure the following playback parameters to improve the performance of RTS. You must configure the parameters before you call the
prepare
method. Otherwise, the configuration does not take effect.AVPConfig *config = self.aliPlayer.getConfig; // The maximum streaming latency. [config setMaxDelayTime:1000]; // The buffer period. [config setHighBufferDuration:10]; // The maximum startup latency. [config setStartBufferDuration:10]; [_aliPlayer setConfig:config]; // By default, hardware decoding is enabled. If hardware decoding fails during the preparation stage of the player, the player automatically switches to software decoding. _aliPlayer.enableHardwareDecoder = YES;
Enable or disable logging
// Enable logging. [AliPlayer setEnableLog:YES]; [AliPlayer setLogCallbackInfo:LOG_LEVEL_TRACE callbackBlock:nil]; // Disable logging. [AliPlayer setEnableLog:NO]; [AliPlayer setLogCallbackInfo:LOG_LEVEL_NONE callbackBlock:nil];
NoteIf the stream is pulled over Real-Time Messaging Protocol (RTMP), we recommend that you disable logging when you debug on physical devices.
Control the player
[self.aliPlayer prepare]; [self.aliPlayer stop]; [self.aliPlayer destroy]; [self.aliPlayer reload];
Register a delegate before playback
-(void)createAliPlayer { // 1. Create a player instance. AliPlayer *aliPlayer = [[AliPlayer alloc] init]; AVPConfig *config = [aliPlayer getConfig]; config.maxDelayTime = 1000; config.highBufferDuration = 10; config.startBufferDuration = 10; // 2. Register a delegate. aliPlayer.delegate = self; [aliPlayer setConfig:config]; aliPlayer.autoPlay = YES; NSString *url = "artc://xxxx"; AVPUrlSource *source = [[AVPUrlSource alloc] urlWithString:self.url]; [aliPlayer setUrlSource:source]; [aliPlayer prepare]; } // 3. Listen for player events. -(void)onPlayerEvent:(AliPlayer*)player eventWithString:(AVPEventWithString )eventWithString description:(NSString *)description { }
Revert to Standard Streaming
To revert to Standard Streaming when RTS encounters playback failure, convert the streaming URL that is prefixed with artc:// to the HTTP-FLV format and use the new URL for playback.
self.playUrl = @"artc://xxxx"; // Stop the playback. [self.aliplayer stop]; // Obtain the prefix of the streaming URL. NSArray *urlSeparated = [self.playUrl componentsSeparatedByString:@"://"]; NSString *urlPrefix = urlSeparated.firstObject; // Check whether the prefix of the URL is artc. If the prefix is artc, convert the URL to the HTTP-FLV format. if ([urlPrefix isEqualToString:@"artc"]) { self.playUrl = @"http://xxxx.flv"; // Set the value to your actual streaming URL in the HTTP-FLV format. // Re-configure the playback source and prepare for playback. AVPConfig *config = [self.player getConfig]; config.maxDelayTime = 10000; config.highBufferDuration = 100; config.startBufferDuration = 100; [self.aliplayer setConfig:config]; AVPUrlSource *source = [[AVPUrlSource alloc] urlWithString:self.playUrl]; [self.aliplayer setUrlSource:source]; // Start the playback. [self.aliplayer prepare]; }
Use an event listener to check whether RTS SDK runs as expected. If the event listener receives a message from the player component during playback initiation or live streaming, extract the RTS SDK details from the message by using the code parameter. If the value of the code parameter is E_DNS_FAIL, E_AUTH_FAIL, E_CONN_TIMEOUT, E_SUB_TIMEOUT, or E_SUB_NO_STREAM, revert to Standard Streaming. If the value is E_STREAM_BROKEN, retry the playback once. If the value is E_STREAM_BROKEN after you retry the playback, revert to Standard Streaming. If the value is E_RECV_STOP_SIGNAL, you can continue to use RTS.
To implement this logic, make sure that you import the required API of RTS SDK.
#import <RtsSDK/rts_messages.h>
Sample code for an event listener:
self.retryStartPlay = YES; ...... /** @brief The callback for player events. @param player The pointer for the player. @param eventWithString The type of the player event. @param description The description of the player event. @see AVPEventType */ - (void)onPlayerEvent:(AliPlayer*)player eventWithString:(AVPEventWithString)eventWithString description:(NSString *)description { switch (eventWithString) { case EVENT_PLAYER_DIRECT_COMPONENT_MSG: { NSDictionary *descriptionDic = [[description rts_toDictionary] copy]; NSString *contentStr = [descriptionDic objectForKey:@"content"]; NSDictionary *kv = [contentStr rts_paramsToDictionaryWithSeparator:@"="]; NSNumber *type = [kv objectForKey:@"code"]; switch (type.intValue) { case E_DNS_FAIL: // DNS resolution failed. case E_AUTH_FAIL: // Authentication failed. case E_CONN_TIMEOUT: // Connection timed out. case E_SUB_TIMEOUT: // An error occurred during subscription or subscription timed out. case E_SUB_NO_STREAM: // The stream to which the user subscribes does not exist. { // Revert to Standard Streaming. } break; case E_STREAM_BROKEN: // Audio and video packet transmission were interrupted due to a timeout. { // The first time you receive the message, retry the playback once. if (self.retryStartPlay) { [self onStartPlay]; self.retryStartPlay = NO; } else { // If you receive the message again, revert to Standard Streaming. } } break; case E_RECV_STOP_SIGNAL: { // Stop the playback. [self.aliplayer stop]; } break; default: break; } } break; default: break; } } ...... #pragma mark -- Categorize NSString, extract common methods, and parse the JSON string. - (NSDictionary *)rts_toDictionary { if (self == nil) { return nil; } NSData *jsonData = [self dataUsingEncoding:NSUTF8StringEncoding]; NSError *err; NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err]; if(err) { NSLog(@"JSON parsing failed: %@",err); return nil; } return dic; } - (NSDictionary *)rts_paramsToDictionaryWithSeparator:(NSString*)split { if (self == nil) { return nil; } NSMutableDictionary *multiDic = @{}.mutableCopy; NSString *content = [self stringByReplacingOccurrencesOfString:@"\"" withString:@""]; NSArray *arr = [content componentsSeparatedByString:@","]; if (arr.count>0) { for (NSString *str in arr) { NSArray *kvArr = [str componentsSeparatedByString:split]; if (kvArr.count==2) { [multiDic setValue:kvArr[1] forKey:kvArr[0]]; } } } return multiDic; }
Obtain the RTS TraceID
Use an event listener to obtain the RTS TraceID. If the event listener receives a message from the player component, extract the RTS SDK details from the message by using the code parameter. If the value of the code parameter is E_HELP_SUPPORT_ID_SUBSCRIBE, the TraceId is appended after "-sub-" in the returned JSON string.
- (void)onPlayerEvent:(AliPlayer*)player eventWithString:(AVPEventWithString)eventWithString description:(NSString *)description { switch (eventWithString) { case EVENT_PLAYER_DIRECT_COMPONENT_MSG: { NSDictionary *descriptionDic = [[description rts_toDictionary] copy]; NSString *contentStr = [descriptionDic objectForKey:@"content"]; NSDictionary *kv = [contentStr rts_paramsToDictionaryWithSeparator:@"="]; NSNumber *type = [kv objectForKey:@"code"]; switch (type.intValue) { case E_HELP_SUPPORT_ID_SUBSCRIBE: // Obtain the TraceId. { NSString *desc = [kv objectForKey:@"desc"]; if ([desc containsString:@"-sub-"]) { NSString *traceId = [desc componentsSeparatedByString:@"-sub-"].lastObject; self.traceId = traceId; } } break; default: break; } } break; default: break; } }