This topic describes how to use the AliLiveSDK for iOS.

Pushes stream over RTMP

  1. Import the header file for stream push.
    #import <AliLiveSdk/AliLiveSdk.h>
  2. Create an AliLiveEngine object.
    AliLiveConfig *config = [[AliLiveConfig alloc] init];
    config.videoProfile = AliLiveVideoProfile_540P;
    config.videoFPS = 20;
    myConfig.pauseImage = [UIImage imageNamed:@"background_img.png"];
    myConfig.accountID = @"";
    AliLiveEngine *engine = [[AliLiveEngine alloc] initWithConfig:myConfig];
    [engine setAudioSessionOperationRestriction:AliLiveAudioSessionOperationRestrictionDeactivateSession];
    [engine setRtsDelegate:self];
    [engine setStatusDelegate:self];
  3. Start the preview.
    [self.engine startPreview:self.renderView];
  4. Start to push streams.
    [self.engine startPushWithURL:self.pushUrl];
  5. Stop pushing streams.
    [self.engine stopPush];
    [self.engine stopPreview];
    [self.engine destorySdk];
    self.engine = nil;

Stream pulling over RTMP

  1. Import the header file.
    #import <AliyunPlayer/AliyunPlayer.h>
  2. Create a player.
    self.player = [[AliPlayer alloc] init];
    self.player.autoPlay = YES;
    self.player.delegate = self;
    self.player.playerView = self.renderView;
  3. Start to pull streams.
    AVPUrlSource *source = [[AVPUrlSource alloc] urlWithString:self.playurl];
    [self.player setUrlSource:source];
    [self.player prepare];
  4. Stop pulling streams.
    [self.player stop];
    [self.player destroy];

Co-stream

Anchor side

  1. The anchor enters the room and starts to push Real-Time Communication (RTC) streams.
    // Enter the room.
    // Inform the AppServer to call the stream merging service to merge streams in the co-stream scenarios.
    [self.roomClient sendCmd:@"JoinRoom" param:@{@"allowMic":@(YES)}];
    // Start to push RTC streams after a callback indicating a successful entry into the room is received.
    [self.engine startPushWithURL:self.artcUrl];
    // After RTC streams are pushed, send a message to notify the audience that the anchor has started live streaming.
    - (void)onLivePushStarted:(AliLiveEngine *)publisher {
        [self.roomClient sendCmd:@"Publish" param:@{@"Protocol":@"rtc"}];
    }
  2. The anchor receives and accepts the co-stream request from the audience.
    [self.roomClient sendCmd:@"ApproveMic" param:@{@"approve":@(YES),@"approvedUserId":@(user.userid)}];
  3. When the anchor receives a message indicating that the audience has pushed RTC streams, the anchor subscribes to the RTC streams that are pushed by the audience.
    [self.engine subscribeStream:user.rtcPullUrl preferMaster:YES];

    The anchor renders the UI of the audience to the view after a message indicating successful subscription is received.

    - (void)onSubscribe:(AliLiveEngine *)publisher result:(AliLiveResult *)result url:(NSString *)url {
        LiveRoomMicUser *user = [self findUserByUrl:uid];
        AliLiveRenderView *renderView = [[AliLiveRenderView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
        user.renderView = renderView;
        [publisher renderRemoteStreamWithView:renderView url:url];
        // Add user.renderView to vc.view
    }
  4. When the anchor receives a message indicating that the audience has turned off the microphone, the anchor unsubscribes from the RTC streams that are published by the audience.
    [self.engine unSubscribeStream:user.rtcPullUrl];
    [user.renderView removeFromSuperview];

Audience side

  1. The audience enters the room and starts to pull RTMP streams.
    [self.roomClient sendCmd:@"JoinRoom"];
    // Start to pull RTMP streams after a callback indicating a successful entry into the room is received.
    self.player = [[AliPlayer alloc] init];
    self.player.autoPlay = YES;
    self.player.delegate = self;
    UIView *playerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.mainRenderView.frame.size.width, self.mainRenderView.frame.size.height)];
    [self.mainRenderView addSubview:playerView];
    self.player.playerView = playerView;
    AVPUrlSource *source = [[AVPUrlSource alloc] urlWithString:self.rtmpUrl];
    [self.player setUrlSource:source];
    [self.player prepare];
  2. The audience sends a co-stream request.
    [self.roomClient sendCmd:@"ApplyMic"];
  3. The co-stream begins after the audience receives a message indicating that the anchor accepts the co-stream request.
    [self.engine setAudioSessionOperationRestriction:AliLiveAudioSessionOperationRestrictionDeactivateSession];
    [self.engine startPreview:self.selfPreviewView];
    [self.engine startPushWithURL:self.artcPushUrl];

    After RTC streams are pushed, the audience sends a message notifying the anchor that the co-stream begins. The audience starts to pull the RTC streams that are pushed by the anchor and other audiences.

    - (void)onLivePushStarted:(AliLiveEngine *)publisher {
        [self.roomClient sendCmd:@"Publish" param:@{@"Protocol":@"rtc"}];
        // Pull the RTC streams that are pushed by the anchor.
        [self.engine subscribeStream:self.artcUrl preferMaster:YES];
    }
    // Subscribe to the RTC streams that are pushed by other audiences.
    for (int i = 0; i < rtcPullUrls.count; i++) {
        NSDictionary *userDic = rtcPullUrls[i];
        NSInteger userId = [userDic[@"userId"] integerValue];
        NSString *userName = userDic[@"userName"];
        NSString *rtcPullUrl = userDic[@"rtcPullUrl"];
        LiveRoomMicUser *user = [[LiveRoomMicUser alloc] initWithUserid:userId userName:userName rtcPullUrl:rtcPullUrl];
        [self.connectedMicUsers addObject:user];
        [self.engine subscribeStream:user.rtcPullUrl preferMaster:YES];
        user.isSubscribed = YES;
    }

    After the anchor pulls RTC streams, the audience stops the playback of RTMP streams.

    - (void)onFirstRemoteVideoFrameDrawn:(AliLiveEngine *)publisher url:(NSString *)url {
        if ([url isEqualToString:self.artcUrl]) {
            // stopPlayRtmp here
        }
    }
  4. The audience turns off the microphone.
    // Unsubscribe from the RTC streams that are pushed by other audiences.
    NSArray *connectedUserArray = [self.connectedMicUsers copy];
    for (int i = 0; i < connectedUserArray.count; i++) {
        LiveRoomMicUser *user = connectedUserArray[i];
        [self.engine unSubscribeStream:user.rtcPullUrl];
        [user.renderView removeFromSuperview];
        [self.connectedMicUsers removeObject:user];
    }
    
    // Stop pushing RTC streams.
    [self.roomClient sendCmd:@"UnPublish"];
    [self.engine setAudioSessionOperationRestriction:AliLiveAudioSessionOperationRestrictionDeactivateSession]; // Prevent the AudioSession operation from being modified at the underlying layer of RTC.
    [self.engine stopPush];
    [self.engine stopPreview];
    [self.engine unSubscribeStream:self.artcUrl];
    
    // Start the playback of RTMP streams.
    //playRtmp here

Anchor PK

  1. Anchor A sends a request to the AppServer to query other anchors that are online.
    [self.roomClient sendCmd:@"GetOnlineRoomList"];

    Anchor A renders the obtained list of anchors to the view.

    - (void)onReceiveCommandGetOnlineRoomList:(NSDictionary *)msg {
        NSArray *roomArray = [OnlineRoom roomArrayWithOnlineRoomArray:msg[@"onlineRoomList"]];
        if (self.delegate && [self.delegate respondsToSelector:@selector(anchor:didReceiveOnlineRoomArray:)]) {
            [self.delegate anchor:self didReceiveOnlineRoomArray:roomArray];
        }
    }
  2. Anchor A sends a PK request to Anchor B in the list.
    [self.roomClient sendCmd:@"ApplyPk" param:@{@"toUserId":@(toUserId),@"toRoomId":@(toRoomId)}];
  3. Anchor B receives a notification about the PK request from Anchor A.
    - (void)onReceiveCommandApplyPkNotice:(NSDictionary *)msg {
        // Receive a notification about the PK request from Anchor A.
    }
  4. Anchor B accepts the PK request from Anchor A, starts to pull RTC streams, and then sends a message indicating that the PK request is accepted.
    [self.engine subscribeStream:self.pkOnlineRoom.rtcPullUrl preferMaster:YES];
    [self.roomClient sendCmd:@"ApprovePk" param:@{@"fromUserId":@(fromUserId), @"fromRoomId":@(fromRoomId), @"approve":@(approve)}];
  5. After Anchor A receives the message indicating that Anchor B accepts the PK request, Anchor A starts to pull RTC streams.
    [self.engine subscribeStream:self.pkOnlineRoom.rtcPullUrl preferMaster:YES];
  6. The RTMP streaming URL on the audience clients changes. After the NotifyPublish message is received, the audience clients construct a new streaming URL for the player.
    self.rtmpUrl = anchorRtmpPullUrl;
    [self playRtmp];
  7. Anchor B stops PK, sends a message indicating that PK is stopped, stops pulling RTC streams, and then restores the UI before PK.
    [self.roomClient sendCmd:@"CancelPk"];
    [self.engine unSubscribeStream:self.pkOnlineRoom.rtcPullUrl];
    self.pkOnlineRoom = nil;
    self.pkRenderView = nil;
  8. After Anchor A receives the message indicating that Anchor B stops PK, Anchor A stops pulling streams and restores the UI before PK.
    - (void)onReceiveCommandCancelPkNotice:(NSDictionary *)msg {
        if (self.delegate && [self.delegate respondsToSelector:@selector(anchorDidReceiveCancelPk:)]) {
            [self.delegate anchorDidReceiveCancelPk:self];
        }
    }
  9. The RTMP streaming URL on the audience clients changes. After the NotifyPublish message is received, the audience clients construct a new streaming URL for the player.
    self.rtmpUrl = anchorRtmpPullUrl;
    [self playRtmp];