通过阅读本文,您可以了解iOS推流SDK的使用方法。

RTMP推流

  1. 导入推流头文件。
    #import <AliLiveSdk/AliLiveSdk.h>
  2. 创建AliLiveEngine。
    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. 开始预览。
    [self.engine startPreview:self.renderView];
  4. 开始推流。
    [self.engine startPushWithURL:self.pushUrl];
  5. 结束推流。
    [self.engine stopPush];
    [self.engine stopPreview];
    [self.engine destorySdk];
    self.engine = nil;

RTMP拉流

  1. 导入头文件。
    #import <AliyunPlayer/AliyunPlayer.h>
  2. 创建播放器。
    self.player = [[AliPlayer alloc] init];
    self.player.autoPlay = YES;
    self.player.delegate = self;
    self.player.playerView = self.renderView;
  3. 开始拉流。
    AVPUrlSource *source = [[AVPUrlSource alloc] urlWithString:self.playurl];
    [self.player setUrlSource:source];
    [self.player prepare];
  4. 停止拉流。
    [self.player stop];
    [self.player destroy];

连麦

主播端

  1. 主播进入房间,开始推RTC。
    //进入房间
    //由于是连麦房间,需要通知Appserver调用合流服务
    [self.roomClient sendCmd:@"JoinRoom" param:@{@"allowMic":@(YES)}];
    //在进入房间成功的信令回调中,开始推RTC
    [self.engine startPushWithURL:self.artcUrl];
    //推送RTC成功后,发送信令通知观众主播已开播
    - (void)onLivePushStarted:(AliLiveEngine *)publisher {
        [self.roomClient sendCmd:@"Publish" param:@{@"Protocol":@"rtc"}];
    }
  2. 主播收到辅播连麦信令,同意连麦。
    [self.roomClient sendCmd:@"ApproveMic" param:@{@"approve":@(YES),@"approvedUserId":@(user.userid)}];
  3. 主播收到辅播推流成功信令,开始订阅辅播RTC。
    [self.engine subscribeStream:user.rtcPullUrl preferMaster:YES];

    在订阅成功的信令里,把辅播画面渲染到View。

    - (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. 主播收到辅播下麦信令,取消订阅RTC。
    [self.engine unSubscribeStream:user.rtcPullUrl];
    [user.renderView removeFromSuperview];

辅播端

  1. 辅播进入房间,开始拉RTMP流。
    [self.roomClient sendCmd:@"JoinRoom"];
    //在进入房间成功的回调中,开始拉RTMP
    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. 辅播申请连麦。
    [self.roomClient sendCmd:@"ApplyMic"];
  3. 辅播收到主播同意连麦信令,开始连麦。
    [self.engine setAudioSessionOperationRestriction:AliLiveAudioSessionOperationRestrictionDeactivateSession];
    [self.engine startPreview:self.selfPreviewView];
    [self.engine startPushWithURL:self.artcPushUrl];

    推送RTC成功后,发送信令通知上麦成功,同时开始拉主播RTC和其他辅播RTC。

    - (void)onLivePushStarted:(AliLiveEngine *)publisher {
        [self.roomClient sendCmd:@"Publish" param:@{@"Protocol":@"rtc"}];
        //拉主播RTC
        [self.engine subscribeStream:self.artcUrl preferMaster:YES];
    }
    //订阅其他辅播
    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;
    }

    在主播拉RTC流成功后,停止播RTMP流。

    - (void)onFirstRemoteVideoFrameDrawn:(AliLiveEngine *)publisher url:(NSString *)url {
        if ([url isEqualToString:self.artcUrl]) {
            // stopPlayRtmp here
        }
    }
  4. 辅播下麦。
    //取消订阅其他辅播流
    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];
    }
    
    //停止推RTC
    [self.roomClient sendCmd:@"UnPublish"];
    [self.engine setAudioSessionOperationRestriction:AliLiveAudioSessionOperationRestrictionDeactivateSession]; // 防止rtc底层修改AudioSession
    [self.engine stopPush];
    [self.engine stopPreview];
    [self.engine unSubscribeStream:self.artcUrl];
    
    //开始播RTMP
    //playRtmp here

主播PK

  1. 主播A发送请求至appserver,获取目前在线且符合要求的主播列表。
    [self.roomClient sendCmd:@"GetOnlineRoomList"];

    获取到主播列表后渲染到页面。

    - (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. 主播A在列表中找到一个主播B,请求PK。
    [self.roomClient sendCmd:@"ApplyPk" param:@{@"toUserId":@(toUserId),@"toRoomId":@(toRoomId)}];
  3. 主播B收到主播A的申请,并弹出提示。
    - (void)onReceiveCommandApplyPkNotice:(NSDictionary *)msg {
        // 这里拿到申请方信息,并弹出提示
    }
  4. 主播B同意了主播A的申请后,开始拉RTC流,并发送同意PK信令。
    [self.engine subscribeStream:self.pkOnlineRoom.rtcPullUrl preferMaster:YES];
    [self.roomClient sendCmd:@"ApprovePk" param:@{@"fromUserId":@(fromUserId), @"fromRoomId":@(fromRoomId), @"approve":@(approve)}];
  5. 主播A收到主播B的同意申请后,开始拉RTC流。
    [self.engine subscribeStream:self.pkOnlineRoom.rtcPullUrl preferMaster:YES];
  6. 观众端播放的RTMP地址有变化,收到NotifyPublish信令后,重新构建播放器播放新地址。
    self.rtmpUrl = anchorRtmpPullUrl;
    [self playRtmp];
  7. 主播B停止PK,发送停止PK信令,停止拉RTC流,并恢复PK前画面。
    [self.roomClient sendCmd:@"CancelPk"];
    [self.engine unSubscribeStream:self.pkOnlineRoom.rtcPullUrl];
    self.pkOnlineRoom = nil;
    self.pkRenderView = nil;
  8. 主播A收到停止PK信令,结束拉流,并恢复PK前画面。
    - (void)onReceiveCommandCancelPkNotice:(NSDictionary *)msg {
        if (self.delegate && [self.delegate respondsToSelector:@selector(anchorDidReceiveCancelPk:)]) {
            [self.delegate anchorDidReceiveCancelPk:self];
        }
    }
  9. 观众端播放的RTMP地址有变化,收到NotifyPublish信令后,重新构建播放器播放新地址。
    self.rtmpUrl = anchorRtmpPullUrl;
    [self playRtmp];