⽤腾讯即时通讯IM和实时⾳视频实现完整语⾳通话功能
说来奇怪,即时通讯领域的霸主QQ,,旗下产品出的腾讯即时通讯IM就像个残疾⼈⼀样,这⾥不对那⾥不对,要达到⽣产级别,就不得不去改它很多源码才⾏。今天先不吐槽其他的,我们看看如何在腾讯Im⾥⾯完成语⾳通话功能。
⼤致分为以下⼏步:
原材料准备
初步实现语⾳通话
完善通话逻辑
铃声震动实现、悬浮窗实现
细节优化
原材料准备
腾讯最新版实时⾳视频SDK(我这⾥下载的是精简版TRTC)
Android Studio 3.5+(需要升级Android Studio的可以参考⼀下我写的
)的⽂章,Android 4.1及以上系统(腾讯要求)
初步实现语⾳通话(根据腾讯的⽂档集成SDK)
1、集成SDK
在模块的adle中的 dependencies中添加
dependencies {
implementation 't.liteav:LiteAVSDK_lease'
}
在defaultCOnfig中,指定CPU架构
defaultConfig {
ndk {
如何办理社保卡
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a"
}
}
配置权限
最后,如果这篇对你有⼀丁点帮助,请点个赞再⾛吧,谢谢了喂。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
selina 俞灏明
<uses- permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
设置混淆
-keep t.** { *; }
设置打包参数
packagingOptions {
pickFirst '**/libc++_shared.so'
doNotStrip "*/armeabi/libYTCommon.so"
doNotStrip "*/armeabi-v7a/libYTCommon.so"
电脑内存doNotStrip "*/x86/libYTCommon.so"
苑琼丹年轻
doNotStrip "*/arm64-v8a/libYTCommon.so"
}
2、实现通话
复制源码⽂件夹trtcaudiocalldemo 中的ui和model到项⽬中。这⾥看⾃⼰的需求进⾏选择,实现语⾳通话,我们只需
要TRTCAudioCallActivity.java⽂件
复制CallService 到项⽬中,这个Service主要负责处理接听电话的事务(接听电话需要进房需要查询⽤户信息,⽣成⼀
个beingCallUserModel传⼊)
调⽤ TRTCAudioCallActivity.startCallSomeone(getContext(), mContactList);发起语⾳通话,这⾥的mContactList 如果是单聊或者聊只邀请⼀个⼈,只会有⼀个model,查询设置这个model的avatar、phone、userid、username、groupId即可。到此初步集成完毕,可以进⾏语⾳通话了。
完善通话逻辑
1、Android端的通话逻辑并不完善,让我们来看看它的问题
不会发送结束消息,任何情况下的挂断都是发送 取消命令
通话远端⽤户离开房间不会触发通话挂断
问题所在:TRTCAuduiCallImpl中的hangup 在通话进⾏中或者发起⼈主动挂断的情况下只会发送取消通话命令
腾讯⾃⼰也知道⾃⼰有问题,留了⼀个todo。那么我们如何修改呢?
根据正常的打电话逻辑,A打给B,会有以下⼏种情况
未通话:A取消,B拒绝,
通话中:A挂断 ,B挂断
⾸先B拒绝,会在hangup⽅法中进⼊reject()⽅法中,发送⼀个拒绝的消息,这个我们不⽤处理;然后是A取消的情况,可以通过判断邀请列表的⼈,如果邀请列表的⼈⼤于0,这个时候挂断,那么⼀定是A取消;再是A挂断和B挂断,这⾥得区分⼀下在聊通话,还是单聊通话,如果是单聊通话,那么A挂断 就是A判断房间中⽤户数未0,发送⼀个通话结束消息出去,同理B⼀样。如果是聊中,那么就是最后⼀个退出房间的⼈判断,发送⼀个通话结束的消息出去。
所以在聊和单聊中没我们可以这样判断:
Log.d(TAG, "Hangup: " + mCurRoomUserSet + " " + mCurInvitedList + "  " + mIsInRoom);
if (mIsInRoom) {
if (isCollectionEmpty(mCurRoomUserSet)) {教师节的作文
if (mCurInvitedList.size() > 0) {
//取消
sendModel("", CallModel.VIDEO_CALL_ACTION_SPONSOR_CANCEL);
} else {
//通话结束
sendModel("", CallModel.VIDEO_CALL_ACTION_HANGUP);
}
}
}
stopCall();
exitRoom();
}
并且如果是聊 ,需要在远端⽤户退出主,并且主⾥⾯没有⽤户的时候发送通话结束的消息即 在preExitRoom⽅法⾥⾯调
⽤groupHangup⽅法,并且退房相关操作需要注释掉,因为groupHangup⽅法⾥⾯会对房间参数进⾏判断,需要发消息,然后退房。
当然发送消息并退房并不是所有情况都适⽤,⽐如忙线,拒接、超时的时候,就只需要执⾏退房操作,所以在这些情况下不能调
⽤groupHangup⽅法,只判断执⾏退房操作。
2、解析⾃定义消息
这个东西看需求,⼀般情况下,⼀次通话都会有两条消息,即⼀条发起通话消息,⼀条结束(拒绝、忙线、挂断、超时等情况),我这⾥贴⼀下我的解析⽅式和效果图:
private void buildVoiceCallView(ICustomMessageViewGroup parent, MessageInfo info, TRTCAudioCallImpl.CallModel data) {
if (data.action == TRTCAudioCallImpl.CallModel.VIDEO_CALL_ACTION_DIALING) {
// 把⾃定义消息view添加到TUIKit内部的⽗容器⾥
View view = LayoutInflater.Instance()).inflate(R.layout.dial_senc_call_message, null, false);
parent.addMessageItemView(view);
TextView tv = view.findViewById(R.id.tv_content);
if (info.isSelf()) {
tv.setText("您发起了语⾳通话");
} else {
tv.setText("对⽅发起了语⾳通话");
}
return;
}
// 把⾃定义消息view添加到TUIKit内部的⽗容器⾥
View view = LayoutInflater.Instance()).inflate(R.layout.dial_custom_message, null, false);
parent.addMessageContentView(view);
// ⾃定义消息view的实现,这⾥仅仅展⽰⽂本信息,并且实现超链接跳转
TextView textView = view.findViewById(R.id.tv_dial_status);
ImageView ivLeft = view.findViewById(R.id.iv_left);
ImageView ivRight = view.findViewById(R.id.iv_right);
if (info.isSelf()) {
ivRight.setVisibility(View.VISIBLE);
ivLeft.setVisibility(View.GONE);
textView.setTextColor(getResources().lor.white));
} else {
ivRight.setVisibility(View.GONE);
ivLeft.setVisibility(View.VISIBLE);
textView.setTextColor(getResources().lor_333333));
}
String text;
switch (data.action) {
case TRTCAudioCallImpl.CallModel.VIDEO_CALL_ACTION_SPONSOR_CANCEL:
text = "已取消";
break;
case TRTCAudioCallImpl.CallModel.VIDEO_CALL_ACTION_REJECT:
text = "已拒绝";
break;
case TRTCAudioCallImpl.CallModel.VIDEO_CALL_ACTION_SPONSOR_TIMEOUT:
text = "⽆⼈接听";
break;
case TRTCAudioCallImpl.CallModel.VIDEO_CALL_ACTION_HANGUP:
if (data.duration == 0) {
text = "通话结束";
} else {
text = "通话结束 " + TimeUtils.millis2StringByCorrect(data.duration * 1000, data.duration >= 60 * 60 ? "HH:mm:ss" : "mm:ss");                    }
小公爷娶了谁break;
case TRTCAudioCallImpl.CallModel.VIDEO_CALL_ACTION_LINE_BUSY:
text = "忙线中";
break;
default:
text = "未知通话错误";
break;
}
textView.setText(text);
}