主播PK互动开发指南

重要

本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。

阿里云视频直播提供主播PK互动功能,该功能允许两位或多位主播在直播中展开PK,增强观众的观看体验。本文为您介绍主播PK互动的操作步骤和相关示例代码,帮助用户快速接入主播PK互动场景。

主播PK互动方案介绍

直播SDK基于实时音视频RTC来实现主播跨房间PK,帮助客户实现超低延时、更多人数的直播实时互动,主播PK一般流程如下:

  • PK前:主播们各自用RTC推流地址进行推流,观众拉取CDN流进行观看。

  • PK中:主播们使用RTC拉流地址进行相互播放对方的超低延时流。

  • PK后:主播们停止播放对方的超低延时流。

image

如上图,主播A有普通观众C,主播B有普通观众D,主播A和主播B进行跨房间PK,需要做以下事情:

  • 主播A:主播A使用主播B的拉流地址播放主播B的超低延时流,同时,主播A发起混流操作,将自己和主播B的内容混成一路,供普通观众C观看。

  • 主播B:主播B使用主播A的拉流地址播放主播A的超低延时流,同时,主播B发起混流操作,将自己和主播A的内容混成一路,供普通观众D观看。

  • 观众C和观众D不需要任何额外操作,观看画面自动从单主播画面切换成混流画面。

注意事项

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

具体开通直播连麦功能方式,请参见直播连麦快速入门

步骤二:生成主播PK互动推拉流地址

您可以通过自定义拼接主播PK互动场景下不同主播端的推拉流地址,以及普通观众(非连麦观众)的CDN播放地址,详细操作,请参见主播PK互动场景不同主播端的推拉流地址普通观众的CDN播放地址

步骤三:主播A开始推流

  1. 创建AlivcLivePushConfig 推流配置对象

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

    重要

    如果使用场景为Native与Web连麦互通,则Native端(Android/iOS)必须使用H5兼容模式。否则,Web用户查看Native用户将是黑屏。请在Native端调用AlivcLivePushConfig#setH5CompatibleMode接口,接口详细说明请参考Native SDK API文档。

    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;

    windows示例代码

    AlivcLivePushConfig rtcPushConfig;
    rtcPushConfig.mLivePushMode = AlivcLivePushInteractiveMode;
    rtcPushConfig.mResolution = AlivcLivePushResolution540P;
    rtcPushConfig.frameRate = AlivcLivePushFPS20;
    rtcPushConfig.mPreviewOrientation = AlivcLivePushOrientationPortrait;
  2. 创建AlivcLivePusher推流对象

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

    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];

    windows示例代码

    	if (!pusher_) {
    		pusher_ = AlivcLivePusher::Create("");
    	}
    	pusher_->init(config_);
    
    	pusher_->setLivePushErrorListener(this);
    	pusher_->setLivePushInfoListener(this);
    	pusher_->setLivePushNetworkListener(this);
  3. 连麦PK互动模式下推流

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

    Android示例代码:

    alivcLivePusher.startPreview(context, frameLayout, isAnchor);
    alivcLivePusher.startPushAysnc("artc://live.aliyun.com/push/123?timestamp=1661596947&token=XXX&userId=123&sdkAppId=XXX");  //主播A的推流地址

    iOS示例代码:

    [rtcPusher startPushWithURL:@"artc://live.aliyun.com/push/123?timestamp=1661596947&token=XXX&userId=123&sdkAppId=XXX"]; //主播A的推流地址

    windows示例代码:

    pusher_->startPush("artc://live.aliyun.com/push/123?timestamp=1661596947&token=XXX&userId=123&sdkAppId=XXX");

步骤四:主播B开始推流

  1. 创建AlivcLivePushConfig 推流配置对象

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

    重要

    如果使用场景为Native与Web连麦互通,则Native端(Android/iOS)必须使用H5兼容模式。否则,Web用户查看Native用户将是黑屏。请在Native端调用AlivcLivePushConfig#setH5CompatibleMode接口,接口详细说明请参考Native SDK API文档。

    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;

    windows示例代码

    AlivcLivePushConfig rtcPushConfig;
    rtcPushConfig.mLivePushMode = AlivcLivePushInteractiveMode;
    rtcPushConfig.mResolution = AlivcLivePushResolution540P;
    rtcPushConfig.frameRate = AlivcLivePushFPS20;
    rtcPushConfig.mPreviewOrientation = AlivcLivePushOrientationPortrait;
  2. 创建AlivcLivePusher推流对象

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

    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];

    windows示例代码

    	if (!pusher_) {
    		pusher_ = AlivcLivePusher::Create("");
    	}
    	pusher_->init(config_);
    
    	pusher_->setLivePushErrorListener(this);
    	pusher_->setLivePushInfoListener(this);
    	pusher_->setLivePushNetworkListener(this);
  3. 连麦PK互动模式下推流

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

    Android示例代码:

    alivcLivePusher.startPreview(context, frameLayout, isAnchor);
    alivcLivePusher.startPushAysnc("artc://live.aliyun.com/push/456?timestamp=1661596947&token=XXX&userId=456&sdkAppId=XXX");  //主播B的推流地址

    iOS示例代码:

    [rtcPusher startPushWithURL:@"artc://live.aliyun.com/push/456?timestamp=1661596947&token=XXX&userId=456&sdkAppId=XXX"]; //主播B的推流地址

    windows示例代码:

    pusher_->startPush("artc://live.aliyun.com/push/456?timestamp=1661596947&token=XXX&userId=456&sdkAppId=XXX");

步骤五:开始PK

  1. 主播A调用AlivcLivePlayer播放主播B的流;同时,主播B调用AlivcLivePlayer播放主播A的流。

    此时,主播A和主播B可以播放对方的实时流,开始进入PK场景。

    主播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/456?timestamp=1661596947&token=XXX&userId=456&sdkAppId=XXX");  //主播B的拉流地址
    • iOS示例代码:

      AlivcLivePlayer *rtcPlayer = [[AlivcLivePlayer alloc] init];
      [rtcPlayer setLivePlayerDelegate:self];
      [rtcPlayer setPlayView:self.playerView  playCofig:self.rtcPlayConfig];
      [rtcPlayer startPlayWithURL:@"artc://live.aliyun.com/play/456?timestamp=1661596947&token=XXX&userId=456&sdkAppId=XXX"];  //主播B的拉流地址
    • windows示例代码:

      player_ = AlivcLivePlayer::Create("");
      if (player_) {
          AlivcLivePlayConfig config;
          player_->setupWithConfig(config);
          player_->startPlay("artc://live.aliyun.com/play/456?timestamp=1661596947&token=XXX&userId=456&sdkAppId=XXX");
          player_->setPlayView(hwnd, width, height);
      }

    主播B示例代码

    • 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=123&sdkAppId=XXX"); //主播A的拉流地址
    • 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=123&sdkAppId=XXX"];  //主播A的拉流地址
    • windows示例代码:

      player_ = AlivcLivePlayer::Create("");
      if (player_) {
          AlivcLivePlayConfig config;
          player_->setupWithConfig(config);
          player_->startPlay("artc://live.aliyun.com/play/123?timestamp=1661596947&token=XXX&userId=123&sdkAppId=XXX");
          player_->setPlayView(hwnd, width, height);
      }
  2. 主播A和主播B分别更新混流。

    为了保证普通观众C和观众D可以看到主播A和主播B的PK的画面,主播A和主播B此时需要分别发起一次混流操作,即将主播A和主播B的画面,混合成一路流给到CDN观众播放。

    主播A和主播B分别调用setLiveMixTranscodingConfig接口启动云端混流(转码)任务,设置需要混流的对象。混流出来的视频画面的分辨率、帧率等使用的是主播A创建AlivcLivePusher引擎时指定的AlivcLivePushConfig中的配置。即如果主播A创建AlivcLivePusher引擎时AlivcLivePushConfig中配置分辨率为720P,则混流出来的视频画面的分辨率也是720P。

    Android示例代码:

    AlivcLiveTranscodingConfig transcodingConfig = new AlivcLiveTranscodingConfig();
    
    AlivcLiveMixStream anchorMixStream = new AlivcLiveMixStream();
    anchorMixStream.setUserId(123);
    anchorMixStream.setX(0);
    anchorMixStream.setY(0);
    anchorMixStream.setWidth(mAlivcLivePushConfig.getWidth());
    anchorMixStream.setHeight(mAlivcLivePushConfig.getHeight());
    anchorMixStream.setZOrder(1);
    
    AlivcLiveMixStream audienceMixStream = new AlivcLiveMixStream();
    audienceMixStream.setUserId(456);
    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 = 123;
    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 = 456;
    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];

    windows示例代码:

    AlivcLiveTranscodingConfig liveTranscodingConfig;
    
    AlivcLiveMixStream anchorMixStream ;
    anchorMixStream.userId = userA;
    anchorMixStream.x = 0;
    anchorMixStream.y = 0;
    anchorMixStream.width = width;
    anchorMixStream.height = height;
    anchorMixStream.zOrder = 1;
    
    AlivcLiveMixStream audienceMixStream;
    audienceMixStream.userId = userD;
    audienceMixStream.x = 100;
    audienceMixStream.y = 200;
    audienceMixStream.width = 200;
    audienceMixStream.height = 300;
    audienceMixStream.zOrder = 2;
    
    liveTranscodingConfig.mixStreams.Add(anchorMixStream);
    liveTranscodingConfig.mixStreams.Add(audienceMixStream);
    pusher_->setLiveMixTranscodingConfig(&liveTranscodingConfig);

步骤六:结束PK

  1. 主播A和主播B分别结束播放对方的流

    主播A和主播B分别结束播放对方实时流,结束PK场景,切换成单主播推流。

    Android示例代码:

    alivcLivePlayer.stopPlay();
    alivcLivePlayer.destroy();
    alivcLivePlayer = null;

    iOS示例代码:

    [self.rtcPlayer stopPlay];
    self.rtcPlayer = nil;

    windows示例代码:

    	if (player_) {
    		player_->stopPlay();
    		player_->destroy();
    		player_ = nullptr;
    	}
  2. 主播A和主播B分别更新混流

    主播A和主播B结束PK后,需要更新混流画面,分别调用setLiveMixTranscodingConfig接口,参数传入空值,从混流切换为旁路模式。

    当不再需要混流,普通观众只需要观看主播A或者主播B一个人画面时,可以调用setLiveMixTranscodingConfig接口,参数传入空值即可。

    警告

    若主播还在房间中但不再需要混流,请务必传入空值进行取消。因为当发起混流后,云端混流模块就会开始工作,不及时取消混流可能会引起不必要的计费损失。

    Android示例代码:

    alivcLivePusher.setLiveMixTranscodingConfig(null);

    iOS示例代码:

    [self.rtcPusher setLiveMixTranscodingConfig:nil];

    windows示例代码:

    pusher_->setLiveMixTranscodingConfig(nullptr);