本文介绍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
实现AliRTCLinuxEngineListener接口,用于接收engine回调
创建AliRTCLinuxEngineListener实现类的实例
调用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.参数配置+入会
创建authInfo,获取入会必要参数
配置JoinChannelConfig,目前先使用默认配置
调用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);
linuxEngine为2.初始化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
)