Android之 集成音视频通话

一,背景

1.1 最近接收一个即时通讯二开项目,即时通讯部分用的XMPP协议,音视频则是集成的国外的开源免费库jitsi-meet-sdk-2.4.0-4.aar,是基于WebRTC的开源框架。但客户想要微信那种页面的排版,后来经研究jitsi是不能修改UI的,UI部分是用混合框架ReactNative写的,这样难度就大了,于是给了客户两套方案

方案一:继续使用jitsi-meet,这个就要重新下载完整源码,修改ReactNative,重新编译,然后上传私有仓库,打包库,再引入使用

方案二:另找一套可以修改UI的SDK,音视频相关SDK确实不少,但免费又能修改UI的就不好找了,后来客户同意用收费的,那就找下吧。

1.2  音视频通话框架整理

Jitsi 
Jitsi是一个开源的,安全(ZRTP加密),高质量的SIP/XMPP视频通话、会议、聊天、桌面共享、文件传传输。可以安装在你喜欢的操作系统中并且支持多种IM网络。
官方网站:https://jitsi.org/
总结:UI部分是用ReactNative 混合框架写的,改动难度大,第一步需要下载完整源码,第二部需要编译成功,第三步修改ReactNative UI源码  第四步需要上传仓库 第五步引用私服仓库库

https://github.com/jitsi/jitsi-maven-repository/tree/master/releases/org/jitsi/react/jitsi-meet-sdk
https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-android-sdk/
https://www.linuxrumen.com/rmxx/1794.html
https://github.com/jitsi/jitsi-meet-sdk-samples
https://jitsi.org/jitsi-meet/
https://jitsi.github.io/handbook/docs/releases
https://blog.csdn.net/heibai110/article/details/119153517


SIPDroid 
SIPDroid 是开源的,sip协议栈使用JAVA实现,音频Codec使用skype的silk(Silk编解码是Skype向第三方开发人员和硬件制造商提供免版税认证(RF)的Silk宽带音频编码器)实现。NAT传输支持stun server.
官方网站:www.sipdroid.org/


Linphone
Linphone是一种开源的IP语音电话(或SIP电话),可以通过互联网与人们进行免费的语音,视频和文本即时通讯。它使用SIP协议(互联网电话的开放标准),可以与任何SIP VoIP运营商一起使用,包括一些免费的SIP音频/视频服务。
官方网站:www.linphone.org/


Imsdroid
基于doubango(Doubango 是一个基于3GPP IMS/RCS 并能用于嵌入式和桌面系统的开源框架。该框架使用ANSCI-C编写,具有很好的可移植性。并且已经被设计成非常轻便且能有效的工作在低内存和低处理能力的嵌入式系统上。苹果系统上的idoubs功能就是基于此框架编写) .音视频编码格式大部分都支持(H264(video),VP8(video),iLBC(audio),PCMA,PCMU,G722,G729)。NAT支持ICE(stun+turn)
官方网站:https://github.com/DoubangoTelecom/imsdroid     http://www.doubango.org/


openfire
openfire是开源的、基于可拓展通讯和表示协议(XMPP)、采用Java编程语言开发的实时协作服务器。 Openfire安装和使用都非常简单,并利用Web进行管理。单台服务器可支持上万并发用户。
官方网站:http://www.igniterealtime.org/projects/openfire/


WebRTC
WebRTC,名称源自网页实时通信(Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的技术。现在许多SDK都是使用WebRTC作为框架来实现。
官方网站: https://webrtc.org/

1.3  音视频通话SDK整理

AnyChat
视频模块是否独立: 是
Demo测试详情: 偶有马赛克以及声音有爆音
接入此SDK的其他厂商:一些银行,证券,PADROBOTD等
价格:标准版:6800元/平台 * N 企业版:36800元/平台 * N 旗舰版:56800元/平台 * N
并发:标准版:1980元/并发 * M 高版:9000元/并发 * M 服务器 618000元/台
官网: http://www.anychat.cn/
总结:比较庞大,价格也贵,服务器和客户端得一起用


JusTalk Cloud
视频模块是否独立: 是
Demo测试详情:效果较好,略有延迟
接入此SDK的其他厂商:360儿童机器人,360手表,春雨医生等
价格:一对一视频 0.039元 / 分钟
官网: http://www.justalkcloud.com/
总结:整体较好,可以修改UI,也能单独集成一对一,一对多,视频SDK

融云
视频模块是否独立: 否
Demo测试详情:效果一般般,偶尔卡顿
接入此SDK的其他厂商:悦跑,途家,优信等
价格:360P以下:0.008元/分钟 720P及以下:0.030元/分钟 720P以上:0.11元/分钟
官网: http://www.rongcloud.cn/  
文档: https://docs.rongcloud.cn/v3/views/rtc/call/ui/quick-start/android.html
总结:虽然不能单独集成,需要和IM基础库一起集成,但可以修改UI,也是不错的选择

QCloud
视频模块是否独立: 否
Demo测试详情:业界主流,效果较好,云服务稳定,集成相对于其他独立的稍稍麻烦些。
接入此SDK的其他厂商:
价格:日活少于10万免费(需与客服询问)
官网: http://www.qcloud.com

环信
视频模块是否独立: 否
Demo测试详情:偶尔有马赛克,比较普通
接入此SDK的其他厂商:猎聘等一些APP
价格:社区版(免费):0.023元/分钟   企业版(收费):0.020元/分钟
官网: http://www.easemob.com

网易云信
视频模块是否独立: 否
Demo测试详情:效果还行。
接入此SDK的其他厂商:科大讯飞、新东方、网易产品等
价格:功能费 1000 / 月 (1000分钟) + 0.025/分钟
官网: http://www.netease.im

agora.io 声网
视频模块是否独立: 是
Demo测试详情:主流的某些直播平台使用此SDK,效果较好,基本无卡顿
接入此SDK的其他厂商:小米,陌陌,途牛,乐视等
价格:360P以下:0.00099美元/分钟 720P及以下:0.00399美元/分钟 720P以上:0.01499美元/分钟
官网: http://cn.agora.io
总结:不能修改UI,想修改UI的可以放弃

容联云通信
视频模块是否独立: 是
Demo测试详情:易断开,连接上后有时卡顿,且视频质量模糊,效果不太好
接入此SDK的其他厂商:小米,百合
价格:免费
官网: http://www.yuntongxun.com/ 
总结:没找到下载SDK地方,但文档给出修改UI方法是,引入远程插件,覆盖activity


1.4 总结:

  • 考虑单独集成和UI可修改方面推荐JusTalkCloud,融云,和Jits这三个。JusTalkCloud可以单独集成并且修改UI,融云需要和基础IM库一起集成,也可以修改UI,Jitsi免费,是不能修改UI的,真要修改,得编译源码,难度比较大
  • 融云虽然要和基础通讯库一起集成(imlib,imkit,calllib,callkit),但其它单独继承的库流程是一样的,也要先注册账号,获取token才能使用。

二,融云音视频SDK的集成

2.1 集成融云音视频,需要同时集成imlib,imkit,calllib,callkit

dependencies {
    implementation 'cn.rongcloud.sdk:im_lib:5.4.0.2' // 即时通讯基础能力库
    implementation 'cn.rongcloud.sdk:im_kit:5.4.0.2' // 即时通讯 UI 基础组件
    implementation 'cn.rongcloud.sdk:call_lib:5.4.0' // 音视频呼叫能力库(内含 rtc_lib)
    implementation 'cn.rongcloud.sdk:call_kit:5.4.0' // 音视频通话能力 UI 组件
}

与老项目库可能会冲突,为了兼容老项目,可以本地集成

a0506001401a411399a6f1194592878e.png

 imkit库下面的引用

dependencies {
    api fileTree(dir: 'libs', include: ['*.jar'])
    api 'cn.rongcloud.sdk:im_lib:5.4.0'
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'androidx.fragment:fragment:1.2.5'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
    implementation "androidx.viewpager2:viewpager2:1.1.0-alpha01"
    implementation "androidx.documentfile:documentfile:1.0.1"
    implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
    implementation "androidx.room:room-runtime:2.0.0"
    annotationProcessor "androidx.room:room-compiler:2.0.0"
}

 callkit库下面的引用

dependencies {
    api fileTree(dir: 'libs', include: ['*.jar'])
    api project(':imkit')
    api 'cn.rongcloud.sdk:call_lib:5.4.0'
}

冲突一:glide版本冲突

统一下版本,统一用高版本,但老项目得做兼容,把老的glide相关代码替换为新的glide支持

冲突二:androidx.lifecycle版本冲突,可以排除冲突的库

implementation ('cn.rongcloud.sdk:im_kit:5.4.0')
{
   exclude group: 'androidx.lifecycle', module: 'lifecycle-runtime'
   exclude group: 'androidx.room', module: 'room-runtime'
}

冲突三:资源冲突,aapt这种也基本上是存在不同版本的库

9e8fefcb52a24a268b4192da968127fb.png

 定位冲突的地方,统一版本

c1716c6eaf7d4a16ab6d08d42e61666a.png

 三,融云音视频配置

3.1 初始化

RongIM.init(this, appKey);

这个地方要注意,要用IMKit库初始化,不能用IMLib初始化,不然页面显示方面会有问题,音视频黑屏没画面

//RongIMClient.init(this, appKey);

3.2 获取token

使用融云要先获取token,连接上融云服务后才能使用聊天功能,测试的话可以在融云平台生成临时token,正式需要后端接口配合。

82c5d4f6fd094d1db55b1881f8b3037e.png

 3.3 连接融云

//连接融云
RongIMClient.connect(token, new RongIMClient.ConnectCallback() {
     @Override
     public void onSuccess(String userId) {

     }

     @Override
     public void onError(RongIMClient.ConnectionErrorCode e) {
               
      }

     @Override
     public void onDatabaseOpened(RongIMClient.DatabaseOpenStatus code) {
                
     }
});

3.4 连接成功之后同步用户信息

//同步用户信息,用于展示头像昵称
RongIM.setUserInfoProvider(new UserDataProvider.UserInfoProvider() {
    @Override
    public UserInfo getUserInfo(String userId) {
          if(userId.equals(coreManager.getSelf().getUserId())){
              //同步方式同步信息
              String name = CoreManager.getSelf(MainActivity.this).getNickName();
              String portraitUri = 
              AvatarHelper.getAvatarUrl(coreManager.getSelf().getUserId(), true);
              UserInfo userInfo = new UserInfo(userId, name, Uri.parse(portraitUri));
              return userInfo;
              }else {
                 //异步方式同步用户信息,调取接口刷新本地用户缓存
                 getOtherUserInfo(userId);
                 return null;
               }
             }
}, true);

刷新用户缓存

User user = result.getData();
String name = user.getNickName();
String portraitUri = AvatarHelper.getAvatarUrl(user.getUserId(), true);
UserInfo userInfo = new UserInfo(user.getUserId(), name, Uri.parse(portraitUri));
RongUserInfoManager.getInstance().refreshUserInfoCache(userInfo);

3.5 调起语音通话

RongCallKit.startSingleCall(this, mFriend.getUserId(), RongCallKit.CallMediaType.CALL_MEDIA_TYPE_AUDIO);

3.6 监听语音通话

//监听语音通话状态
RongCallKit.setCustomerHandlerListener(new RongCallCustomerHandlerListener() {
     @Override
     public List<String> handleActivityResult(int requestCode, int resultCode, Intent data) {
        return null;
      }

     @Override
     public void addMember(Context context, ArrayList<String> currentMemberIds) {
     }

     @Override
     public void onRemoteUserInvited(String userId, RongCallCommon.CallMediaType mediaType) {
     }

     @Override
     public void onCallConnected(RongCallSession callSession, SurfaceView localVideo) {
     }

     /**
      * 通话结束。
      * 通话中,对方挂断,己方挂断,或者通话过程网络异常造成的通话中断,都会回调 
      *
      * @param callSession 通话实体。
      * @param reason      通话中断原因。
      */
      @Override
      public void onCallDisconnected(RongCallSession callSession, RongCallCommon.CallDisconnectedReason reason) {
       if(callSession.getSelfUserId().equals(callSession.getCallerUserId())) {
             //通话时长
             int longTime=(int) (callSession.getEndTime() - callSession.getStartTime()) / 1000;
             if (callSession.getEndTime()>0){
                 //挂断通话
              }else {
                 //取消通话

              }
        }
     }

     @Override
     public void onCallMissed(RongCallSession callSession, RongCallCommon.CallDisconnectedReason reason) {
     }
});

猜你喜欢

转载自blog.csdn.net/qq_29848853/article/details/129833904