本文为您介绍实现主播端与观众端连麦互动的操作步骤和相关示例代码,帮助用户快速接入连麦互动场景。

接入RTC连麦互动方案介绍

连麦方案
直播SDK基于实时音视频RTC来实现连麦方案,帮助客户实现超低延时、更多人数的直播实时互动,一般流程如下:
  • 连麦前:主播使用RTC连麦推流地址进行推流,观众拉取CDN流进行观看。
  • 连麦中:观众从普通观众切换为连麦观众,使用RTC连麦推流地址进行推流,使用RTC连麦拉流地址拉取主播的超低延时流;主播使用RTC连麦拉流地址进行拉取连麦观众的超低延时流。
  • 结束连麦:连麦观众切换为普通观众,停止RTC推流和RTC拉流,切换为拉取CDN流进行观看。

注意事项

  • 执行该章节操作前,您需要先完成SDK Demo配置。具体操作,请参见Demo试用
  • 本文介绍推流SDK互动版的连麦功能使用,推流SDK互动版的集成方法,请参见Android端SDK集成iOS端SDK集成
  • 互动模式下主播或者连麦观众的超低延时流,只能使用AlivcLivePlayer对象。AlivcLivePlayer目前只支持播放artc://live.aliyun.com/play/前缀的超低延时流。

步骤一:开通直播连麦服务

  1. 登录视频直播控制台
  2. 在视频直播控制台左侧导航栏,单击连麦管理 > 连麦应用管理
  3. 单击创建连麦应用,跳转到如下图页面。
    开通直播连麦
  4. 填写自定义的实例名称,勾选服务协议后,单击立即购买

    提示开通成功后,刷新连麦应用管理页面,即可查看您新建的连麦应用。

  5. 选择您新建的应用,单击操作列的管理,可跳转到应用信息页面查看应用IDAppKey
  6. 若播放端需要进行CDN播放,则需要进行播放配置,可根据控制台配置域名指引添加播放域名。
    应用信息

步骤二:生成连麦互动推拉流地址

您可以通过控制台生成或通过自定义拼接主播和连麦观众的推拉流地址,及普通观众(非连麦观众)的CDN播放地址

方法一:控制台生成

若您希望快速生成主播和连麦观众的推拉流地址,及普通观众(非连麦观众)的CDN播放地址进行体验,可以借助控制台工具进行生成。具体操作,请参见连麦地址生成器

方法二:自定义拼接

通过控制台生成主播和连麦观众的推拉流地址URL中,Token为临时Token,一般用于测试使用。如果需要正式使用,为了安全起见,请使用自定义拼接的推拉流地址。自定义拼接地址中Token是基于您的SdkAppID、 AppKey、房间ID、UserID和Timestamp通过SHA256加密算法计算得到,攻击者很难通过伪造Token盗用您的云服务流量。自定义拼接详情请参见连麦互动场景主播端和连麦观众端推拉流地址普通观众的CDN播放地址

步骤三:创建推流对象

主播端和连麦观众端都需要执行该操作。

  1. 创建AlivcLivePushConfig推流配置对象

    创建AlivcLivePushConfig推流配置对象,指定当前推流模式livePushMode为AlivcLivePushInteractiveMode,设置分辨率、帧率、码率等配置信息。

    Android示例代码:
    // 初始化推流配置类
    mAlivcLivePushConfig = new AlivcLivePushConfig();
    // 设置推流模式,默认普通推流模式
    mAlivcLivePushConfig.setLivePushMode(AlivcLiveMode.AlivcLiveInteractiveMode);
    // 设置分辨率,默认540P
    mAlivcLivePushConfig.setResolution(AlivcResolutionEnum.RESOLUTION_540P);
    // 设置帧率,默认20fps
    mAlivcLivePushConfig.setFps(AlivcFpsEnum.FPS_25);
    // 设置视频编码Gop,单位秒,默认2秒
    mAlivcLivePushConfig.setVideoEncodeGop(AlivcVideoEncodeGopEnum.GOP_TWO);
    // 打开码率自适应,默认为true
    mAlivcLivePushConfig.setEnableBitrateControl(true);
    // 设置横竖屏,默认为竖屏,可设置home键向左或向右横屏
    mAlivcLivePushConfig.setPreviewOrientation(AlivcPreviewOrientationEnum.ORIENTATION_PORTRAIT);
    // 设置音频编码模式,默认AAC-LC
    mAlivcLivePushConfig.setAudioProfile(AlivcAudioAACProfileEnum.AAC_LC);
    // 设置视频编码模式,默认硬编
    mAlivcLivePushConfig.setVideoEncodeMode(AlivcEncodeModeEnum.Encode_MODE_HARD);
    // 设置音频编码模式,默认软编
    mAlivcLivePushConfig.setAudioEncodeMode(AlivcEncodeModeEnum.Encode_MODE_SOFT);
    // 设置摄像头前后置,默认前置
    mAlivcLivePushConfig.setCameraType(AlivcLivePushCameraTypeEnum.CAMERA_TYPE_FRONT);
    // 设置App推后台或暂停时推图片
    mAlivcLivePushConfig.setPausePushImage("TODO: Image Path");
    // 设置弱网推图片
    mAlivcLivePushConfig.setNetworkPoorPushImage("TODO: Image Path");
    iOS示例代码:
    AlivcLivePushConfig *rtcPushConfig = [[AlivcLivePushConfig alloc] init];
    rtcPushConfig.livePushMode = AlivcLivePushInteractiveMode;
    rtcPushConfig.resolution = AlivcLivePushResolution540P;
    rtcPushConfig.fps = AlivcLivePushFPS20;
    rtcPushConfig.enableAutoBitrate = true;
    rtcPushConfig.orientation = AlivcLivePushOrientationPortrait;
    rtcPushConfig.enableAutoResolution = YES;
  2. 创建AlivcLivePusher推流对象

    创建推流引擎对象AlivcLivePusher,传入上一步创建的AlivcLivePushConfig对象,设置相应的回调。

    Android示例代码:
    AlivcLivePusher alivcLivePusher = new AlivcLivePusher();
    alivcLivePusher.init(context, alivcLivePushConfig);
    alivcLivePusher.setLivePushErrorListener(new AlivcLivePushErrorListener() {});
    alivcLivePusher.setLivePushInfoListener(new AlivcLivePushInfoListener() {});
    alivcLivePusher.setLivePushNetworkListener(new AlivcLivePushNetworkListener() {});
    iOS示例代码:
    AlivcLivePusher *rtcPusher = [[AlivcLivePusher alloc] initWithConfig:rtcPushConfig];
    [rtcPusher setInfoDelegate:self];
    [rtcPusher setErrorDelegate:self];
    [rtcPusher setNetworkDelegate:self];
  3. 连麦互动模式下推流

    使用连麦互动模式下推流地址URL进行推流,推流地址获取方式请参见步骤二:生成连麦互动推拉流地址

    Android示例代码:
    alivcLivePusher.startPreview(context, frameLayout, isAnchor); // 主播(大窗)isAnchor为true
    alivcLivePusher.startPushAysnc("artc://live.aliyun.com/push/6375?timestamp=1661596947&token=XXX&userId=7135&sdkAppId=XXX"); //主播或连麦观众的推流地址
    iOS示例代码:
    [rtcPusher startPushWithURL:@"artc://live.aliyun.com/push/6375?timestamp=1661596947&token=XXX&userId=7135&sdkAppId=XXX"];  //主播或连麦观众的推流地址

步骤四:创建AliPlayer CDN播放

普通观众端(非连麦观众)需要执行该操作。

如果播放端需要使用AliPlayer进行CDN播放,需要先获取普通观众(非连麦观众)的CDN播放地址。具体操作,请参见步骤二:生成连麦互动推拉流地址

Android示例代码:
AliPlayer aliPlayer = AliPlayerFactory.createAliPlayer(context);
aliPlayer.setAutoPlay(true);

aliPlayer.setOnErrorListener(errorInfo -> {
    aliPlayer.prepare();
});

UrlSource urlSource = new UrlSource();
urlSource.setUri("rtmp://test.alivecdn.com/live/streamId?auth_key=XXX"); //普通观众(非连麦观众)的CDN播放地址
aliPlayer.setDataSource(urlSource);
aliPlayer.prepare();
iOS示例代码:
AliPlayer *cdnPlayer = [[AliPlayer alloc] init];
cdnPlayer.delegate = self;
cdnPlayer.autoPlay = YES;
 AVPUrlSource *source = [[AVPUrlSource alloc] urlWithString:@"rtmp://test.alivecdn.com/live/streamId?auth_key=XXX"];  //普通观众(非连麦观众)的CDN播放地址
[self.cdnPlayer setUrlSource:source];
[self.cdnPlayer prepare];

步骤五:观众连麦

  1. 主播A RTC推流

    主播A开始推流,调用AlivcLivePusher推流引擎开始主播A的推流。

    Android代码示例:
    alivcLivePusher.startPreview(context, frameLayout, isAnchor);
    alivcLivePusher.startPushAysnc("artc://live.aliyun.com/push/123?timestamp=1661596947&token=XXX&userId=userA&sdkAppId=XXX"); //主播的推流地址
    iOS代码示例:
    [rtcPusher startPushWithURL:@"artc://live.aliyun.com/push/123?timestamp=1661596947&token=XXX&userId=userA&sdkAppId=XXX"];  //主播的推流地址
  2. 普通观众(非连麦观众)的CDN播放主播A的流

    所有观众观看主播A的直播,调用AliPlayer开始播放主播A的流。

    Android示例代码:
    AliPlayer aliPlayer = AliPlayerFactory.createAliPlayer(context);
    aliPlayer.setAutoPlay(true);
    
    aliPlayer.setOnErrorListener(errorInfo -> {
        aliPlayer.prepare();
    });
    
    UrlSource urlSource = new UrlSource();
    urlSource.setUri("rtmp://test.alivecdn.com/live/streamId?auth_key=XXX");  //普通观众(非连麦观众)的CDN播放地址
    aliPlayer.setDataSource(urlSource);
    aliPlayer.prepare();
    iOS示例代码:
    AliPlayer *cdnPlayer = [[AliPlayer alloc] init];
    cdnPlayer.delegate = self;
    cdnPlayer.autoPlay = YES;
    AVPUrlSource *source = [[AVPUrlSource alloc] urlWithString:@"rtmp://test.alivecdn.com/live/streamId?auth_key=XXX"];  //普通观众(非连麦观众)的CDN播放地址
    [self.cdnPlayer setUrlSource:source];
    [self.cdnPlayer prepare];
  3. 观众D发起连麦
    • 观众D创建AlivcLivePusher对象,使用D的互动推流地址开始推流,观众D角色从普通观众切换为连麦观众。
      Android示例代码:
      // 初始化推流配置类
      AlivcLivePushConfig alivcLivePushConfig = new AlivcLivePushConfig();
      alivcLivePushConfig.setLivePushMode(AlivcLiveMode.AlivcLiveInteractiveMode);
      // 分辨率540P,最大支持720P
      alivcLivePushConfig.setResolution(AlivcResolutionEnum.RESOLUTION_540P);
      // 建议用户使用20fps
      alivcLivePushConfig.setFps(AlivcFpsEnum.FPS_20);
      // 打开码率自适应,默认为true
      alivcLivePushConfig.setEnableBitrateControl(true);
      // 默认为竖屏,可设置home键向左或向右横屏
      alivcLivePushConfig.setPreviewOrientation(AlivcPreviewOrientationEnum.ORIENTATION_PORTRAIT);
      // 设置音频编码模式
      alivcLivePushConfig.setAudioProfile(AlivcAudioAACProfileEnum.AAC_LC);
      
      AlivcLivePusher alivcLivePusher = new AlivcLivePusher();
      alivcLivePusher.init(context, alivcLivePushConfig);
      alivcLivePusher.setLivePushErrorListener(new AlivcLivePushErrorListener() {});
      alivcLivePusher.setLivePushInfoListener(new AlivcLivePushInfoListener() {});
      alivcLivePusher.setLivePushNetworkListener(new AlivcLivePushNetworkListener() {});
      
      alivcLivePusher.startPreview(context, frameLayout, isAnchor); // 普通观众isAnchor为false
      alivcLivePusher.startPushAysnc("artc://live.aliyun.com/push/123?timestamp=1661596947&token=XXX&userId=userD&sdkAppId=XXX");  //连麦观众的推流地址
      iOS示例代码:
      AlivcLivePusher *rtcPusher = [[AlivcLivePusher alloc] initWithConfig:rtcPushConfig];
      [rtcPusher startPushWithURL:@"artc://live.aliyun.com/push/123?timestamp=1661596947&token=XXX&userId=userD&sdkAppId=XXX"]; //连麦观众的推流地址
    • 主播A获取连麦观众D的互动模式直播拉流地址,创建AlivcLivePlayer对象拉取连麦观众D的实时流。
      Android示例代码:
      AlivcLivePlayConfig config = new AlivcLivePlayConfig();
      config.isFullScreen = isAnchor;
      
      AlivcLivePlayer alivcLivePlayer = new AlivcLivePlayerImpl(context, AlivcLiveMode.AlivcLiveInteractiveMode);
      alivcLivePlayer.setPlayInfoListener(new AlivcLivePlayInfoListener() {});
      
      mAlivcLivePlayer.setupWithConfig(config);
      mAlivcLivePlayer.setPlayView(frameLayout);
      
      alivcLivePlayer.startPlay(artc://live.aliyun.com/play/123?timestamp=1661596947&token=XXX&userId=userD&sdkAppId=XXX");  //连麦互动模式下的对端拉流地址URL,主播使用连麦观众端的拉流地址URL。
      iOS示例代码:
      AlivcLivePlayer *rtcPlayer = [[AlivcLivePlayer alloc] init];
      [rtcPlayer setLivePlayerDelegate:self];
      [rtcPlayer setPlayView:self.playerView  playCofig:self.rtcPlayConfig];
      [rtcPlayer startPlayWithURL:@"artc://live.aliyun.com/play/123?timestamp=1661596947&token=XXX&userId=userD&sdkAppId=XXX"];"];  //连麦互动模式下的对端拉流地址URL,主播使用连麦观众端的拉流地址URL。
    • 同时,连麦观众D获取主播A的互动模式直播拉流地址创建AlivcLivePlayer对象拉取主播A的实时流。
      Android示例代码:
      AlivcLivePlayConfig config = new AlivcLivePlayConfig();
      config.isFullScreen = isAnchor;
      
      AlivcLivePlayer alivcLivePlayer = new AlivcLivePlayerImpl(context, AlivcLiveMode.AlivcLiveInteractiveMode);
      alivcLivePlayer.setPlayInfoListener(new AlivcLivePlayInfoListener() {});
      
      mAlivcLivePlayer.setupWithConfig(config);
      mAlivcLivePlayer.setPlayView(frameLayout);
      
      alivcLivePlayer.startPlay(artc://live.aliyun.com/play/123?timestamp=1661596947&token=XXX&userId=userA&sdkAppId=XXX"); //连麦互动模式下的对端拉流地址URL,连麦观众使用主播端的拉流地址URL。
      iOS示例代码:
      AlivcLivePlayer *rtcPlayer = [[AlivcLivePlayer alloc] init];
      [rtcPlayer setLivePlayerDelegate:self];
      [rtcPlayer setPlayView:self.playerView  playCofig:self.rtcPlayConfig];
      [rtcPlayer startPlayWithURL:@"artc://live.aliyun.com/play/123?timestamp=1661596947&token=XXX&userId=userA&sdkAppId=XXX"];"];  //连麦互动模式下的对端拉流地址URL,连麦观众使用主播端的拉流地址URL。

      此时,主播A和连麦观众D进入超低延时实时互动场景中。

    • 连麦成功后,更新混流。

      为了保证普通观众B和C(非连麦观众)可以看到连麦观众D的画面,主播A此时需要发起一次混流操作,即将主播A和连麦观众D的画面,混合成一路流给到CDN观众播放。主播A调用setLiveMixTranscodingConfig接口启动云端混流(转码)任务,设置需要混流的对象。混流出来的视频画面的分辨率、帧率等使用的是主播A创建AlivcLivePusher引擎时指定的AlivcLivePushConfig中的配置。即如果主播A创建AlivcLivePusher引擎时AlivcLivePushConfig中配置分辨率为720P,则混流出来的视频画面的分辨率也是720P。

      Android示例代码:
      AlivcLiveTranscodingConfig transcodingConfig = new AlivcLiveTranscodingConfig();
      
      AlivcLiveMixStream anchorMixStream = new AlivcLiveMixStream();
      anchorMixStream.setUserId(anchorId);
      anchorMixStream.setX(0);
      anchorMixStream.setY(0);
      anchorMixStream.setWidth(mAlivcLivePushConfig.getWidth());
      anchorMixStream.setHeight(mAlivcLivePushConfig.getHeight());
      anchorMixStream.setZOrder(1);
      
      AlivcLiveMixStream audienceMixStream = new AlivcLiveMixStream();
      audienceMixStream.setUserId(audience);
      audienceMixStream.setX((int) mAudienceFrameLayout.getX() / 3);
      audienceMixStream.setY((int) mAudienceFrameLayout.getY() / 3);
      audienceMixStream.setWidth(mAudienceFrameLayout.getWidth() / 2);
      audienceMixStream.setHeight(mAudienceFrameLayout.getHeight() / 2);
      audienceMixStream.setZOrder(2);
      
      ArrayList<AlivcLiveMixStream> mixStreams = new ArrayList<>();
      mixStreams.add(anchorMixStream);
      mixStreams.add(audienceMixStream);
      transcodingConfig.setMixStreams(mixStreams);
      
      alivcLivePusher.setLiveMixTranscodingConfig(transcodingConfig);
      iOS示例代码:
       AlivcLiveTranscodingConfig *liveTranscodingConfig = [[AlivcLiveTranscodingConfig alloc] init];
      
      AlivcLiveMixStream *anchorMixStream = [[AlivcLiveMixStream alloc] init];
      anchorMixStream.userId = userA;
      anchorMixStream.x = 0;
      anchorMixStream.y = 0;
      anchorMixStream.width = [self.rtcPushConfig getPushResolution].width;
      anchorMixStream.height = [self.rtcPushConfig getPushResolution].height;
      anchorMixStream.zOrder = 1;
      
      AlivcLiveMixStream *audienceMixStream = [[AlivcLiveMixStream alloc] init];
      audienceMixStream.userId = userD;
      audienceMixStream.x = 100;
      audienceMixStream.y = 200;
      audienceMixStream.width = 200;
      audienceMixStream.height = 300;
      audienceMixStream.zOrder = 2;
      
      liveTranscodingConfig.mixStreams = [NSArray arrayWithObjects:anchorMixStream, audienceMixStream, nil];
      [self.rtcPusher setLiveMixTranscodingConfig:liveTranscodingConfig];

      这样,普通观众即可以看到主播A和连麦观众D的连麦互动。

  4. 连麦观众D结束连麦
    • 连麦观众D结束连麦,需要调用AlivcLivePusher推流引擎的结束推流接口,并将AlivcLivePusher推流引擎销毁。
      Android示例代码:
      alivcLivePusher.stopPush();
      alivcLivePusher.destroy();
      alivcLivePusher = null;
      iOS示例代码:
      [self.rtcPusher stopPush];
      [self.rtcPusher destory];
      self.rtcPusher = nil;
    • 同时,连麦观众D需要调用AlivcLivePlayer拉流引擎的结束播放接口,并将AlivcLivePlayer拉流引擎销毁。
      Android示例代码:
      alivcLivePlayer.stopPlay();
      alivcLivePlayer.destroy();
      alivcLivePlayer = null;
      iOS示例代码:
      [self.rtcPlayer stopPlay];
      self.rtcPlayer = nil;
    • 连麦观众D切换为普通观众,通过步骤四:创建AliPlayer CDN播放进行CDN播放。
    • 主播A 需要调用AlivcLivePlayer拉流引擎的结束播放接口,并将AlivcLivePlayer拉流引擎销毁。
      Android示例代码:
      alivcLivePlayer.stopPlay();
      alivcLivePlayer.destroy();
      alivcLivePlayer = null;
      iOS示例代码:
      [self.rtcPlayer stopPlay];
      self.rtcPlayer = nil;
    • 同时,主播A调用setLiveMixTranscodingConfig接口,参数传入空值,从混流切换为旁路模式。
      重要
      • 需要注意当不再需要混流,普通观众只需要观看主播A一个人画面时,可以调用setLiveMixTranscodingConfig接口,参数传入空值即可。
      • 若主播还在房间中但不再需要混流,请务必传入空值进行取消。因为当发起混流后,云端混流模块就会开始工作,不及时取消混流可能会引起不必要的计费损失。
      Android示例代码:
      alivcLivePusher.setLiveMixTranscodingConfig(null);
      iOS示例代码:
      [self.rtcPusher setLiveMixTranscodingConfig:nil];