前言

小盒的直播业务一开始是打算用两套引擎切换使用的,所以需要封装一下。而且因为声网和阿里的直播sdk的官方文档都不是很全面,甚至有的还有错误(可能是文档没及时更新)导致无法正常运行,接入时问题多多,所以同时记录一下的接入过程中的问题及处理。

定义接口

首先因为需要两个引擎切换使用,所以定义了接口,定义常用的行为

public interface RtcEngine {void init(Context context, RtcInfo config);void join();void leave();void setRtcListener(RtcListener rtcListener);
}

这里RtcInfo是两个sdk需要用到的参数,由服务端提供。我们是初始化时一次性提供,当然也可以实时提供,如果实时提供,join函数也需要一些添加必要参数。

RtcInfo的定义如下:

public class RtcInfo {public AgoraConfig agoraConfig;public AliConfig aliConfig;public String rtcType;
}
public class AgoraConfig {public String liveChannel;public String appId;public int avatarUID;public int liveUID;public String liveToken;
}
public class AliConfig {public String liveChannel;public String appId;public String avatarUID;public String liveUID;public String liveToken;...
}

另外还有一个监听RtcListener,统一了两个sdk的回调,可以自行丰富

public interface RtcListener {void remoteOnline(View remoteView); //当收到流之后,将remoteView加入页面中展示void remoteOffline();
}

接入声网

声网的封装类,实现RtcEngine接口:

public class AgoraEngine implements RtcEngine {private final String TAG = this.getClass().getSimpleName();private Context mContext;private io.agora.rtc.RtcEngine engine;private RtcInfo mConfig;private RtcListener listener;private SurfaceView mRemoteView;private final IRtcEngineEventHandler iRtcEngineEventHandler = new IRtcEngineEventHandler() {@Overridepublic void onJoinChannelSuccess(String s, int i, int i1) {super.onJoinChannelSuccess(s, i, i1);}@Overridepublic void onLeaveChannel(RtcStats rtcStats) {super.onLeaveChannel(rtcStats);}@Overridepublic void onUserOffline(int i, int i1) {super.onUserOffline(i, i1);}@Overridepublic void onWarning(int i) {super.onWarning(i);}@Overridepublic void onError(int i) {super.onError(i);}@Overridepublic void onUserJoined(final int uid, int elapsed) {super.onUserJoined(uid, elapsed);//这里获取到流,设置RemoteVideo并展示//因为有两路流,我们只使用了一路,所以需要判断一下,只展示老师的流if (uid != mConfig.agoraConfig.avatarUID && uid < xxxx) {...}if (uid == mConfig.agoraConfig.avatarUID) {//发现uid与老师id一致,创建设置RemoteVideo并展示mRemoteView.setActivated(true);mRemoteView.setEnabled(true);new Handler(mContext.getMainLooper()).post(new Runnable() {@Overridepublic void run() {mRemoteView = io.agora.rtc.RtcEngine.CreateRendererView(mContext);mRemoteView.setActivated(true);mRemoteView.setEnabled(true);if(listener != null){//交给页面处理,一般是将播放器展示出来listener.joinSuccess(mRemoteView);}...}});}}@Overridepublic void onFirstRemoteVideoFrame(final int uid, int w, int h, int i3) {//官方文档表明在这里会获取第一祯流,然后设置RemoteVideo并展示。实际使用中发现这里根本不回调,而且在onUserJoined中处理RemoteVideo}};@Overridepublic void init(Context context, RtcInfo config) {mConfig = config;mContext = context.getApplicationContext();try {engine = io.agora.rtc.RtcEngine.create(mContext, config.agoraConfig.appId, iRtcEngineEventHandler);engine.setChannelProfile(Constants.CHANNEL_PROFILE_LIVE_BROADCASTING);engine.setVideoProfile(Constants.VIDEO_PROFILE_240P_4, false);engine.setClientRole(Constants.CLIENT_ROLE_AUDIENCE);engine.enableVideo();engine.setParameters("{\"che.audio.keep.audiosession\":true}");} catch (Exception e) {Log.e(TAG, TAG, e);engine = null;}}@Overridepublic void join() {if(engine != null){engine.joinChannel(mConfig.agoraConfig.liveToken, mConfig.agoraConfig.liveChannel, "", mConfig.agoraConfig.liveUID);}}@Overridepublic void leave() {if(engine != null){engine.leaveChannel();io.agora.rtc.RtcEngine.destroy();engine = null;}}@Overridepublic void setRtcListener(RtcListener rtcListener) {listener = rtcListener;}
}

重点注意onFirstRemoteVideoFrame在官方文档表明在这里会获取第一祯流,然后设置RemoteVideo并展示。实际使用中发现这里根本不回调,而且在onUserJoined中处理RemoteVideo,在官方Demo里也是这么处理的,应该是文档更新滞后了。(不知道现在更没更新)。

代码中我们没有对onUserOffline进行处理,后续实际上是补充了相关功能,这里注意的是一定要校验uid,否则可能导致问题。比如在老师退出直播间的时候我们需要做一些页面调整,但是如果这里没有校验uid,那么其他人(特殊身份)在退出时也会执行这部分代码。

接入阿里直播

阿里的封装类,同样实现RtcEngine接口:

public class AliEngine implements RtcEngine {private final String TAG = this.getClass().getSimpleName();private Context mContext;private AliRtcEngine mEngine;private RtcInfo mConfig;//private SophonSurfaceView mRemoteView;private AliRtcEngine.AliVideoCanvas mCanvas;private RtcListener listener;private AliRtcEngineEventListener aliRtcEngineEventListener = new AliRtcEngineEventListener() {...};private AliRtcEngineNotify aliRtcEngineNotify = new AliRtcEngineNotify() {...@Overridepublic void onRemoteTrackAvailableNotify(final String uid, AliRtcEngine.AliRtcAudioTrack audioTrack, final AliRtcEngine.AliRtcVideoTrack videoTrack) {super.onRemoteTrackAvailableNotify(uid, audioTrack, videoTrack);//收到流的第一祯,先判断是不是老师的流if(uid.equals(mConfig.aliConfig.avatarUID)) {
//                mEngine.configRemoteAudio(mConfig.aliConfig.avatarUID, true);
//                mEngine.configRemoteScreenTrack(mConfig.aliConfig.avatarUID, true);
//                mEngine.configRemoteCameraTrack(mConfig.aliConfig.avatarUID, true, true);
//                mEngine.subscribe(mConfig.aliConfig.avatarUID);new Handler(mContext.getMainLooper()).post(new Runnable() {@Overridepublic void run() {if(mEngine == null){return;}AliRtcRemoteUserInfo info = mEngine.getUserInfo(uid);if(info == null){return;}AliRtcEngine.AliVideoCanvas cameraCanvas = info.getCameraCanvas();AliRtcEngine.AliVideoCanvas screenCanvas = info.getScreenCanvas();if(videoTrack == AliRtcEngine.AliRtcVideoTrack.AliRtcVideoTrackNo){screenCanvas = null;cameraCanvas = null;}else if(videoTrack == AliRtcEngine.AliRtcVideoTrack.AliRtcVideoTrackCamera){//我们只需要摄像头的流。这里创建设置remoteView,并展示mCanvas = new AliRtcEngine.AliVideoCanvas();SophonSurfaceView mRemoteView = new SophonSurfaceView(mContext);if(listener != null){//交给页面处理,一般是将播放器展示出来listener.joinSuccess(mRemoteView);}mRemoteView.setZOrderOnTop(true);mRemoteView.setZOrderMediaOverlay(true);mCanvas.view = mRemoteView;...screenCanvas = null;cameraCanvas = mCanvas;mEngine.setRemoteViewConfig(cameraCanvas, uid, AliRtcEngine.AliRtcVideoTrack.AliRtcVideoTrackCamera);}}});}}...};@Overridepublic void init(Context context, RtcInfo config) {mContext = context;mConfig = config;mEngine = AliRtcEngine.getInstance(context);mEngine.setRtcEngineEventListener(aliRtcEngineEventListener);mEngine.setRtcEngineNotify(aliRtcEngineNotify);mEngine.setClientRole(AliRtcEngine.AliRTCSDK_Client_Role.AliRTCSDK_live);mEngine.setChannelProfile(AliRtcEngine.AliRTCSDK_Channel_Profile.AliRTCSDK_Interactive_live);mEngine.setAutoPublishSubscribe(false, true);}@Overridepublic void join() {AliRtcAuthInfo info = new AliRtcAuthInfo();info.setConferenceId(mConfig.aliConfig.liveChannel);info.setAppid(mConfig.aliConfig.appId);info.setUserId(mConfig.aliConfig.liveUID);...info.setToken(mConfig.aliConfig.liveToken);if(mEngine != null){mEngine.joinChannel(info, "");}}@Overridepublic void leave() {if(mEngine != null){mEngine.leaveChannel();}mEngine = null;}@Overridepublic void setRtcListener(RtcListener rtcListener) {listener = rtcListener;}
}

与声网的很类似,注意事项也差不多,因为关键部分都有注释,这里就不细说了。

总结

这样在进入直播前,通过后台获取直播配置,根据类型初始化不同的引擎来使用即可。

源码

关注公众号:BennuCTech,发送“RtcEngine”获取完整源码。

如何实现一套可切换的声网+阿里的直播引擎相关推荐

  1. 声网发布极速直播、低码高清 首创轻互动直播,节省50%带宽成本

    12月10日,实时互动云服务开创者及引领者声网Agora在北京发布了首款定义轻互动直播场景的"极速直播"与可降低50%直播带宽成本的"低码高清"两大新产品,同时 ...

  2. 声网连麦+直播+视频+游戏“史上最强”社交直播方案 打造陌陌全新8.0改版

    做直播的,每天烧钱买流量,用户留存却是个问题.留不住用户,天天买量,天天流失.怎么破?做社交的,烧钱获客,赢得了口碑,却不知道如何变现,怎么破?做App的,装机量是上去了,用户活跃度和打开率却一直do ...

  3. 声网的视频直播与屏幕共享

    视频直播 以下是操作步骤 1. 获取当前设备的 麦克风 摄像头 扬声器 等数据 2. 创建直播实例 3. 给当前实例绑定事件 4. 初始化频道 5. 加入频道 6. 创建本地流 7. 初始化本地流 8 ...

  4. 基于声网 iOS SDK 实现视频直播应用

    视频互动直播是当前比较热门的玩法,我们经常见到有PK 连麦.直播答题.一起 KTV.电商直播.互动大班课.视频相亲等.本文将演示如何通过声网视频 SDK 在 iOS 端实现一个视频直播应用.话不多说, ...

  5. 声网实时连麦互动助力CCtalk万人互动课堂

    随着直播对于垂直行业的不断渗透,越来越多的线上教育瞄准了直播的市场红利,纷纷推出了自己的教育直播平台.沪江.新东方.学而思.尚德教育等众多教育企业纷纷发力直播. 也正是这个时候,CCtalk开启了线上 ...

  6. 主流的第三方直播SDK对比(腾讯云、即构、阿里云、声网、网易云信、网宿)

    直播业务概述 大家所熟知的直播平台虎牙.斗鱼.快手.抖音.B站,直播功能看似普遍,但从零到一开发却不简单.直播中运用到的技术难点非常之多,音频视频处理/编解码,前后处理,直播分发,即时通讯等技术,学好 ...

  7. 云直播SDK核心功能对比|腾讯云、阿里云、声网、即构等SDK厂商对比

    直播业务概述 大家所熟知的直播平台虎牙.斗鱼.快手.抖音.B站,直播功能看似普遍,但从零到一开发却不简单.直播中运用到的技术难点非常之多,音频视频处理/编解码,前后处理,直播分发,即时通讯等技术,学好 ...

  8. 人人皆可虚拟,直播还能这么玩?声网推出 MetaLive 元直播解决方案

    视频群聊.在线社交.电商带货.游戏竞技-越来越多的场景融入了直播这一功能.无可厚非,直播可以拉近人与人间的距离,让彼此间的交流更具象.但传统直播场景更为强调主播个人的表现,用户多以围观.刷弹幕.打赏等 ...

  9. 云通讯这局棋,声网、容联云怎么破?

    疫情的爆发,加速了云通讯在社交.教育.办公等多领域的落地,这让有很多云通讯企业的发展步伐得以加快.而这其中,声网也不例外. 声网赶上了疫情扩张窗口,发展突飞猛进.尤其是在2021年2月份,马斯克成功带 ...

最新文章

  1. 入门系列之使用fail2ban防御SSH服务器的暴力破解攻击
  2. 跟我一起写 Makefile(整理版)
  3. Python中面向对象的讲解(1)
  4. Windows服务器上Mysql为设置允许远程连接提示:not allowed to connect to this MySQL server
  5. CentOS 程序开机自启动方法总结
  6. EntityFramework的多种记录日志方式,记录错误并分析执行时间过长原因
  7. 关于jQuery.query.js 取参数的一个小问题
  8. 【智简联接,万物互联】华为云·云享专家董昕:Serverless和微服务下, IoT的变革蓄势待发
  9. 华为Mate40 Pro国行或定价6499元起 将会提供多个版本
  10. android 数据持久化——读写SD卡中的内容
  11. CImage类 from http://blog.sina.com.cn/s/blog_487547aa0100an6k.html
  12. 一张图看透办公网安全
  13. python可以实现那些功能_30 个Python代码实现的常用功能,精心整理版
  14. MySQL查询GROUP BY日/月/年
  15. 一维数组实验题:大奖赛现场统分。已知某大奖赛有n个选手参赛,m(m>2)个评委为参赛选手评分(最高10分,最低0分)。统分规则为:在每个选手的m个得分中,去掉一个最高分和一个最低分后,取平均分作为该选
  16. 189邮箱报404错误
  17. Outlook邮件服务器eas,配置Outlook使用Outlook.com和Hotmail的两步验证
  18. HTML——3D移动、3D透视、3D效果、3D呈现案例效果
  19. 曾国藩:成大事者不纠结
  20. BCT2186 1A低压差线性稳压器

热门文章

  1. python变量与常量内容:
  2. cmd命令:在ftp下载文件运行
  3. 趣味SQL:用SQL计算瓷砖费用
  4. linux查看文件和文件夹大小
  5. 解决Eclipse无法打开“Failed to load the JNI shared library”(转)
  6. ASP.NET使用AJAX应注意IIS有没有.ashx扩展
  7. C语言typedef小结1(转载自百度百科)
  8. python 入门第二课2 file的文件操作
  9. 马哥2016全新Linux+Python高端运维班第七周作业
  10. 简单入门——深度学习笔记(Part II)