场景与价值

连麦是直播中的一种常见场景,指两位及以上主播或主播与粉丝进行实时音视频交互,实现跨空间共同直播的模式,广泛应用于娱乐互动、电商带货、在线教育等领域。
image.png
应用场景:

  • 娱乐场景:主播PK、合唱互动,提升观众参与感
  • 电商场景:品牌主播与达人连麦能整合双方流量,扩大商品曝光
  • 教育场景:师生连麦可实现实时答疑,模拟线下课堂体验

对于直播应用开发者而言,客户端开播侧的核心技术为音视频采集与编码,在直播连麦场景下,新增对连麦方(主播/粉丝)音视频流的解码与渲染开发。

本文聚焦于客户端开播侧的音视频流解码播放,详细介绍对应的技术实现方案。

直播连麦架构

以两路主播连麦场景为例,直播连麦的整个流程可以分为"发起连麦"、"连麦建立"和"观众观看"三个主要阶段。
image.png

第一阶段:发起连麦

主播1通过其应用客户端发起连麦申请,云端业务服务器接收到连麦申请后,向主播2发送连麦请求,主播2通过其应用客户端向云端业务服务器发送同意连麦申请。

第二阶段:连麦建立

主播1的客户端应用SDK采集主播1的音视频信息,编码后发送至云端信令服务器,同时从云端服务器拉取主播2的音视频码流,在本地客户端进行解码和渲染后,根据应用业务层设计的连麦UI布局在本端手机屏幕上合成画面后,同时展示主播1和主播2的连麦画面。主播2的流程与此类似。

第三阶段:观众观看

云端信令服务器接收到主播1和主播2的音视频信息后,在云端进行合流操作,包括根据连麦UI布局合成主播1和主播2的画面为视频帧,以及将两路音频流混音为一路音频流。合流后,最终通过CDN分发至各观众客户端,观众客户端依据传输协议拉取连麦后的音视频码流,并通过本地播放器解码播放。

业务调度、信令通信等云端服务是可以跨端通用的。与基础单播场景相比,连麦场景的主要差异在于开播端需要新增音频和视频的解码播放能力,该能力可通过系统底座的Audio Kit、AVCodec Kit、Graphic Kit等接口进行开发实现。

看播端拉流的音频和视频数据来源于云端,并在云端完成了合流操作,因此连麦场景看播端解决方案与单播场景一致。

开播端解决方案

以两路主播连麦场景为例,主播1在录制的过程中,设备从云端服务器拉取主播2的音频和视频码流,并与主播1的预览画面同步播放。
image.png

实现原理

主播1客户端从云端拉取主播2的视频码流(通常为H.264或H.265格式)并解码,与连麦UI布局XComponent创建的Surface ID关联后,即可直接渲染上屏显示。

本端开播录制

开播端本端主播连麦录制的场景与单播场景解决方案一致,可以参考媒体直播单播场景的开播端解决方案。

对端解码播放

创建视频解码器实例
int32_t VideoDecoder::Create(const std::string &videoCodecMime) {
    // Create a video decoder instance
    decoder = OH_VideoDecoder_CreateByMime(videoCodecMime.c_str());
    CHECK_AND_RETURN_RET_LOG(decoder != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Create failed");
    return AVCODEC_SAMPLE_ERR_OK;
}
配置视频解码器
int32_t VideoDecoder::Configure(const SampleInfo &sampleInfo) {
    // Configure the video decoder
    OH_AVFormat *format = OH_AVFormat_Create();
    CHECK_AND_RETURN_RET_LOG(format != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "AVFormat create failed");

    OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, sampleInfo.videoInfo.videoRotation);
    OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, sampleInfo.videoInfo.videoHeight);
    OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, sampleInfo.videoInfo.videoWidth);
    OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, sampleInfo.videoInfo.frameRate);
    OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, sampleInfo.videoInfo.pixelFormat);

    int ret = OH_VideoDecoder_Configure(decoder, format);
    CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Config failed, ret: %{public}d", ret);
    OH_AVFormat_Destroy(format);
    format = nullptr;

    return AVCODEC_SAMPLE_ERR_OK;
}
注册解码回调函数
int32_t VideoDecoder::SetCallback(CodecUserData *codecUserData) {
    int32_t ret = AV_ERR_OK;
    // Register the decoding callback function
    ret = OH_VideoDecoder_RegisterCallback(decoder,
                                           {SampleCallback::OnCodecError, SampleCallback::OnCodecFormatChange,
                                            SampleCallback::OnNeedInputBuffer, SampleCallback::OnNewOutputBuffer},
                                           codecUserData);
    CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Set callback failed, ret: %{public}d", ret);

    return AVCODEC_SAMPLE_ERR_OK;
}
绑定解码器SurfaceID
int32_t VideoDecoder::Config(const SampleInfo &sampleInfo, CodecUserData *codecUserData) {
    // ...
    // SetSurface from video decoder
    if (sampleInfo.videoInfo.window != nullptr) {
        int ret = OH_VideoDecoder_SetSurface(decoder, sampleInfo.videoInfo.window);
        CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK && sampleInfo.videoInfo.window, AVCODEC_SAMPLE_ERR_ERROR,
                                 "Set surface failed, ret: %{public}d", ret);
    }
    // ...

    return AVCODEC_SAMPLE_ERR_OK;
}
启动解码器后,上屏显示
int32_t VideoDecoder::Start() {
    CHECK_AND_RETURN_RET_LOG(decoder != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Decoder is null");
    // Start the decoder
    int ret = OH_VideoDecoder_Start(decoder);
    CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Start failed, ret: %{public}d", ret);
    return AVCODEC_SAMPLE_ERR_OK;
}

看播端解决方案

看播端拉流的音频和视频数据来源于云端,并在云端完成了合流操作。因此,看播端解决方案与基础单播场景一致,开发者可参考媒体直播单播场景的看播端解决方案。

技术要点

连麦场景与单播场景的差异

连麦场景的主要差异在于开播端需要新增音频和视频的解码播放能力:

  • 开播端本端采集编码推流(与单播一致)
  • 开播端对端拉流解码渲染(新增能力)
  • 看播端拉流播放(与单播一致,云端已完成合流)

核心技术栈

系统底座提供的能力:

  • Audio Kit:音频解码播放
  • AVCodec Kit:视频解码
  • Graphic Kit:渲染上屏

开发流程

完整的开发流程包括:

  1. 本端开播录制(参考单播方案)
  2. 创建视频解码器实例
  3. 配置视频解码器参数(旋转、高度、宽度、帧率、像素格式)
  4. 注册解码回调函数(错误、格式变化、输入缓冲区、输出缓冲区)
  5. 绑定解码器SurfaceID(关联XComponent)
  6. 启动解码器,上屏显示

云端合流

云端信令服务器负责:

  • 接收主播1和主播2的音视频信息
  • 根据连麦UI布局合成画面为视频帧
  • 将两路音频流混音为一路音频流
  • 通过CDN分发至各观众客户端

实际应用场景

娱乐互动场景

主播PK、合唱互动,提升观众参与感。两位主播实时音视频交互,观众可以看到合流后的画面。

电商带货场景

品牌主播与达人连麦能整合双方流量,扩大商品曝光。主播之间实时互动,观众可以同时看到两位主播的推荐。

在线教育场景

师生连麦可实现实时答疑,模拟线下课堂体验。老师和学生实时音视频交互,实现更好的教学效果。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐