全部產品
Search
文件中心

ApsaraVideo Live:主播PK互動開發指南

更新時間:Jul 19, 2024

阿里雲ApsaraVideo for Live提供主播PK互動功能,該功能允許兩位或多位主播在直播中展開PK,增強觀眾的觀看體驗。本文為您介紹主播PK互動的操作步驟和相關範例程式碼,協助使用者快速接入主播PK互動情境。

主播PK互動方案介紹

直播SDK基於即時音視頻RTC來實現主播跨房間PK,協助客戶實現超低延時、更多人數的直播即時互動,主播PK一般流程如下:

  • PK前:主播們各自用RTC推流地址進行推流,觀眾拉取CDN流進行觀看。

  • PK中:主播們使用RTC拉流地址進行相互播放對方的超低延時流。

  • PK後:主播們停止播放對方的超低延時流。

如上圖,主播A有一般觀眾C,主播B有一般觀眾D,主播A和主播B進行跨房間PK,需要做以下事情:

  • 主播A:主播A使用主播B的拉流地址播放主播B的超低延時流,同時,主播A發起混流操作,將自己和主播B的內容混成一路,供一般觀眾C觀看。

  • 主播B:主播B使用主播A的拉流地址播放主播A的超低延時流,同時,主播B發起混流操作,將自己和主播A的內容混成一路,供一般觀眾D觀看。

  • 觀眾C和觀眾D不需要任何額外操作,觀看畫面自動從單主播畫面切換成混流畫面。

注意事項

本文介紹推流SDK互動版的主播PK功能使用。

推流SDK互動版的整合,請參見:

步驟一:開通直播連麥服務

具體開通直播連麥功能方式,請參見直播連麥快速入門

步驟二:產生主播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);