快速接入

本文介绍Java 集成实时音视频Linux ARTC SDK。

一,准备工作

解压Linux SDK压缩包,打开解压后的文件夹里面的Java文件夹,交付产物包括:libs、Demo/MainTest.java

目录结构:

|   README.md
|
+---com
|   \---alivc
|       \---rtc
|           \---multiprocess ##此目录包含了alirtc_linux_java_multiprocess.jar的源代码,您可以自定义修改其中的逻辑,并替换libs的jar包
|                   AliRTCLinuxEngine.java
|                   AliRTCLinuxEngineImpl.java
|                   AliRTCLinuxEngineListener.java
|
+---Demo
|       MainTest.java ##示例程序代码
|       run.sh ##通过此文件执行示例程序
|
\---libs ##此目录中是业务执行程序必须依赖的jar和so库
        AliRtcCoreService
        alirtc_linux_java_multiprocess.jar
        fastjson2-2.0.40.jar
        libAliRtcCentralEngine.so
        libAliRtcLinuxEngine.so
        libPluginOpus.so
说明

执行示例程序:cd Demo=>sh run.sh; 退出示例程序:命令输入exit

二,基础使用

1.指定elf文件目录

SDK底层用C实现,Java接口通过多进程方式进行多个RTC引擎实例的管理。libs目录下的alirtc_linux_java_multiprocess.jar,负责Java层与C引擎的桥接。其中启动进程需要用到已编译好的elf文件libs/AliRtcCoreService,因此,必须正确指定该文件路径,才能确保后续工作正常执行。

String coreServicePath = "/mnt/AliRTCSDK_Linux-v6.8.2/Java/libs/AliRtcCoreService";

2.初始化SDK

  1. 实现AliRTCLinuxEngineListener接口,用于接收engine回调

  2. 创建AliRTCLinuxEngineListener实现类的实例

  3. 调用AliRTCLinuxEngine.createInstance创建engine实例,并将Listener绑定到engine

示例代码:

//初始化SDK
AliRTCLinuxEngineListener engineEventHandler = new EngineListener();
boolean h5mode = true; // 与web端互通必须开启h5兼容模式
String extra = "";
AliRTCLinuxEngine linuxEngine = AliRTCLinuxEngine.createInstance(engineEventHandler, 0, 0, "/tmp", "", h5mode, extra);
说明

EngineListener为自定义的AliRTCLinuxEngineListener实现类,内部实现自己的业务逻辑。

重要
  • Java SDK基于tcp实现进程间通信,createInstance时,第2、3参数不能忽略,指定了进程间通信的端口号范围。

  • logPath(第四个参数)路径设置为null会默认放在/tmp路径下。

3.参数配置+入会

  1. 创建authInfo,获取入会必要参数

  2. 配置JoinChannelConfig,目前先使用默认配置

  3. 调用JoinChannel

// 获取authInfo
AliRTCLinuxEngine.AuthInfo authInfo = new AliRTCLinuxEngine.AuthInfo();
authInfo.appid = "";
authInfo.channel = "";
authInfo.userid = "";
authInfo.username = "";
authInfo.nonce = "";
authInfo.token = "";
authInfo.timestamp = 1591350597; // sample

int gslbCount = 1;
authInfo.gslb_count = gslbCount;
String[] gslbArray = new String[gslbCount];
if (gslbCount > 0) {
    for (int i = 0; i < gslbCount; i++) {
        gslbArray[i] = "https://******";
    }
    authInfo.gslb = gslbArray;
}

int agentCount = 0; // 根据实际情况设置agent,可以不设置
authInfo.agent_count = agentCount;
String[] agentArray = new String[agentCount];
if (agentCount > 0) {
    for (int i = 0; i < agentCount; i++) {
        agentArray[i] = "https://******";
    }
    authInfo.agent = agentArray;
}

// 初始化入会的设置
AliRTCLinuxEngine.JoinChannelConfig joinConfig = new AliRTCLinuxEngine.JoinChannelConfig();

joinConfig.channelProfile = AliRTCLinuxEngine.ChannelProfile.ChannelProfileInteractiveLive;
// 设置是否订阅音频数据,以及订阅方式
joinConfig.subscribeAudioFormat = AliRTCLinuxEngine.AudioFormat.AudioFormatPcmBeforeMixing;
// 设置是否订阅视频数据
joinConfig.subscribeVideoFormat = AliRTCLinuxEngine.VideoFormat.VideoFormatH264;

// 音画同步选项,选择立即发送数据或根据时间戳进行同步
joinConfig.publishAvsyncMode = AliRTCLinuxEngine.PublishAvsyncMode.PublishAvysncWithPts;

// 自动订阅功能【根据实际需求设置手动订阅】
joinConfig.subscribeMode = AliRTCLinuxEngine.SubscribeMode.SubscribeAutomatically;
// 开启自动推流【可根据实际需求设置手动推流】
joinConfig.publishMode = AliRTCLinuxEngine.PublishMode.PublishAutomatically; 

// 设置是否推camera流【可根据实际需求设置】
linuxEngine.publishLocalVideoStream(true);
// 设置是否推音频流【可根据实际需求设置】
linuxEngine.publishLocalAudioStream(true);

// 设置camera流的编码选项【可根据实际需求设置】
AliRTCLinuxEngine.AliEngineVideoEncoderConfiguration videoConfig = new AliRTCLinuxEngine.AliEngineVideoEncoderConfiguration();

linuxEngine.setVideoEncoderConfiguration(videoConfig);

// 开启Yuv输入,使用camera流进行推送, 指定填充模式
linuxEngine.setExternalVideoSource(true, AliRTCLinuxEngine.VideoSource.VideoSourceCamera, AliRTCLinuxEngine.RenderMode.RenderModeFill);

// 开启Pcm输入
// 第二个参数为pcm的采样率,请根据实际情况设置
// 第三个参数为pcm的channel数,请根据实际情况设置
linuxEngine.setExternalAudioSource(true, 16000, 2);

// 设置入会角色
linuxEngine.setClientRole(AliRTCLinuxEngine.AliEngineClientRole.AliEngineClientRoleInteractive);

// 入会
linuxEngine.joinChannel(authInfo, joinConfig);
说明

linuxEngine2.初始化SDK创建的engine实例

3.推流

通过setExternalVideoSource设置采用外部视频源后,使用下述方法推送每个原始视频帧(I420格式)。

/**
 * @param frame  帧数据
 * @param source 流类型
 * @brief 输入外部输视频
 * @note 支持的输入视频类型请见VideoDataFormat
 */
public abstract int pushExternalVideoFrame(VideoDataSample frame, VideoSource source);
说明

调用linuxEngine的pushExternalVideoFrame方法。

音频帧同理:

/**
 * @param audioSamples 音频数据
 * @param sampleLength 音频数据长度
 * @param timestamp    时间戳
 * @return <0表示失败,返回值为ERR_AUDIO_BUFFER_FULL时,需要在间隔投递数据时间长度后再次重试投递
 * @brief 输入外部音频数据推流
 */
public abstract int pushExternalAudioFrameRawData(byte[] audioSamples, int sampleLength, long timestamp);

4. 订阅

需要保证设置audioFormat和videoFormat时启动了订阅。

回调API可观察远端用户是否上线以及是否推流。

说明

onRemoteUserOnLineNotify和onRemoteTrackAvailableNotify 方法位于AliRTCLinuxEngineListener接口中,需要自定义EngineListener进行实现。

/**
 * @brief 远端用户(通信模式)/(互动模式,主播角色)加入频道回调
 *
 * @param uid 用户ID 从App server分配的唯一标示符
 * @note 互动模式下回调行为
 * - 主播间可以互相收到加入频道回调
 * - 观众可以收到主播加入频道回调
 * - 主播无法收到观众加入频道回调
 */
void onRemoteUserOnLineNotify(String uid);

/**
 * @brief 远端用户的音视频流发生变化回调
 * @details 该回调在以下场景会被触发
 * - 当远端用户从未推流变更为推流(包括音频和视频)
 * - 当远端用户从已推流变更为未推流(包括音频和视频)
 * - 互动模式下,调用 {@link AliEngine::SetClientRole} 切换为主播角色 {@link AliEngineClientRoleInteractive},同时设置了推流时,会触发该回调
 * @param uid userId,从App server分配的唯一标示符
 * @param audioTrack 音频流类型,详见 {@link AliEngineAudioTrack}
 * @param videoTrack 视频流类型,详见 {@link AliEngineVideoTrack}
 * @note 该回调仅在通信模式用户和互动模式下的主播角色才会触发
 */
void onRemoteTrackAvailableNotify(String uid, AliRTCLinuxEngine.AudioTrack audioTrack, AliRTCLinuxEngine.VideoTrack videoTrack);
重要

若joinConfig.subscribeMode为手动订阅,需要在onRemoteTrackAvailableNotify观察到远端推流后,调用subscribeRemoteAudioStream(uid,true)subscribeRemoteVideoStream(uid, videoTrack, true)手动订阅该用户的音视频流。

(1)视频回调:每个远端用户的音频流订阅时都是分开的,用uid区分

说明

onRemoteVideoSample 方法位于AliRTCLinuxEngineListener接口中,需要自定义EngineListener进行实现。

/**
 * @brief 订阅的远端视频数据回调
 * @param uid 用户ID
 * @param frame 视频裸数据
 * @return
 */
void onRemoteVideoSample(String uid, AliRTCLinuxEngine.VideoFrame frame);

(2)混合音频回调:订阅到的所有远端用户的音频数据被混合成一路流回调回来

说明
  • onSubscribeMixedAudioFrame 方法位于AliRTCLinuxEngineListener接口中,需要自定义EngineListener进行实现。

  • 回调的数据为原始音频,frame.pcm.channels表示接收的音频通道数,frame.pcm.sample_rates为采样率,frame.pcm.sample_bits为采样深度,通常16bit,即两个字节。

/**
 * @brief 本地订阅音频混合数据回调
 * @details 远端所有用户混音后待播放的音频数据,{@link IAliEngineMediaEngine::SubscribeAudioData}订阅类型为 AliEngineAudiosourceSub 时触发此回调
 * @param frame 音频数据,详见{@link AliEngineAudioRawData}
 */
void onSubscribeMixedAudioFrame(AliRTCLinuxEngine.AudioFrame frame);

(3)分流音频回调:不同远端用户的音频数据用uid加以区分

说明
  • onSubscribeAudioFrame 方法位于AliRTCLinuxEngineListener接口中,需要自定义EngineListener进行实现。

  • 回调的数据均原始音频,frame.pcm.channels表示接收的音频通道数,frame.pcm.sample_rates为采样率,frame.pcm.sample_bits为采样深度,通常16bit,即两个字节。

/**
 * @brief 本地订阅音频数据回调
 * @details 远端单一用户混音的音频数据,用uid区分{@link IAliEngineMediaEngine::SubscribeAudioData}订阅类型为 AliEngineAudiosourceSub 时触发此回调
 * @param frame 音频数据,详见{@link AliEngineAudioRawData}
 */
void onSubscribeAudioFrame(String uid, AliRTCLinuxEngine.AudioFrame frame);
重要

注意:切勿在回调方法中做耗时操作,收到数据请立即抛到业务层,否则可能阻塞住SDK内部线程

5.离会

若停止推流但不离会,请手动调用。

linuxEngine.publishLocalVideoStream(0);
linuxEngine.publishLocalAudioStream(0);

若要直接离会,可调用下述接口自动停止推流。

linuxEngine.leaveChannel();

6.销毁SDK

linuxEngine.destroy();
linuxEngine = null;

三、其他能力

1. extra字段配置

创建引擎传入的extra字段为JSON格式,可以用于设置部分选项,辅助您使用其他能力,比如可以设置成下述内容。

关闭Audio Ranking
user_specified_disable_audio_ranking":"true"
支持音频AAC转码

-> 音频回调模式
"user_specified_audio_observer_codec":
    AliRTCLinuxEngine.AudioTranscodingCodec.AudioTranscodingCodecAac.getValue()

-> AAC格式,当前仅支持adts
"user_specified_audio_observer_codec_format": 0 // adts

-> resample_rate非0则重采样,此处指定重采样率
"user_specified_audio_observer_resample_rate":16000

-> AAC转码的目标码率
"user_specified_audio_observer_codec_bitrate":64000
支持直接获取H264码流

-> 视频回调模式
"user_specified_video_observer_codec":
    AliRTCLinuxEngine.VideoTranscodingCodec。VideoTranscodingCodecH264.getValue()

-> H264格式,当前仅支持annexb
"user_specified_video_observer_codec_format":0 // annexb

说明

上面的extra字段主要配置了两项能力:

  • 关闭Audio Ranking:Audio Ranking用于在多人语聊下,仅选取音量较高的几路音频订阅,从而使用户在内容感受上更为清晰。此能力默认开启状态,若要关闭,可将user_specified_disable_audio_ranking设置为true,之后房间内的所有音频均将被订阅。

  • 支持获取编码压缩后的音视频数据:对于有存档需求的场景,支持直接获取音频AAC编码后的数据,和视频的H264码流。

2. 消息收发:DataChannel 或 SEI

除音视频数据外,您还可以通过RTC SDK进行实时消息互动。SDK支持Data Channel和SEI (Supplemental Enhancement Information) 两种实时消息的收发,区别在于前者独立于音、视频通道,是更为建议的选择,而后者依赖于视频数据的收发。

打开DataChannel请调用:engineIns.setParameter("{\"data\":{\"enablePubDataChannel\":true,\"enableSubDataChannel\":true}}");

  • Data Channel发送消息:

/**
  * @brief 通过dataChannel发送消息
  * @param controlMsg 待发送的信息
  * @return
  * - 0: 成功
  * - 非0: 失败
  */
int 
sendDataChannelMsg(
  AliRtcDataChannelMsg controlMsg
);
  • Data Channel接收消息:

void 
onDataChannelMsg(
  String uid, 
  AliRTCLinuxEngine.AliRtcDataChannelMsg msg
)
  • SEI 发送消息:

/**
  * @brief 发送 媒体扩展信息(SEI), 最大长度为4*1024字节,用于业务的少量数据传输
  * @param message 扩展信息内容,可以传递4K Bytes数据
  * @param repeatCount 重复次数,用于防止网络丢包导致的消息丢失
  * @param delay 延迟多久发出去,单位:毫秒
  * @param isKeyFrame 是否只在关键帧上增加SEI
  */
int 
sendMediaExtensionMsg(
  byte[] message, int repeatCount, 
  int delay, boolean isKeyFrame
);
  • SEI 接收消息:

void 
onMediaExtensionMsgReceived(
  String uid, byte[] msg
)