本文将介绍在 Android 平台实现设备响应来自 App 或微信小程序的呼叫(接听/拒绝),以及通话建立后的音视频采集推流、对端画面渲染与挂断。
前提条件
说明:
音视频通话依赖摄像头与麦克风采集,请确保已在
AndroidManifest.xml 中声明 android.permission.CAMERA、android.permission.RECORD_AUDIO 权限,并在运行时向用户申请授权。接入步骤
步骤 1:注册通话事件回调
private final TXIoTCallSession.Listener mCallListener = new TXIoTCallSession.Listener() {@Overridepublic void onCallRequested(Contact contact, Option option) {// 收到来电,根据业务决定接听或拒绝(见步骤 2)}@Overridepublic void onCallAccepted(Contact contact) {// 通话正式建立,此时开启采集推流与渲染对端画面(见步骤 3)}@Overridepublic void onCallRejected(Contact contact) {// 本次呼叫被拒绝,结束本次呼叫并释放资源}@Overridepublic void onCallTimeout(Contact contact) {// 来电未及时处理超时,释放资源}@Overridepublic void onCallHangup(Contact contact) {// 对端挂断,停止采集与渲染并释放资源(见步骤 4)}};// 登录成功后注册监听TXIoTCallSession.getInstance().addListener(mCallListener);
步骤 2:响应来电
设备作为被叫,收到
onCallRequested 后,根据业务逻辑调用 accept 接听,或调用 reject 拒绝:注意:
accept 回调 onSuccess 仅代表接听请求已发出,通话尚未建立。请勿在此时立即开启采集推流,务必等到 onCallAccepted 回调触发后(通话正式建立)再开启摄像头/麦克风。@Overridepublic void onCallRequested(Contact contact, Option option) {// 示例:直接接听,实际业务可结合按键、界面弹窗等方式决定接听或拒绝TXIoTCallSession.getInstance().accept(contact.userId, new TXIoTCallback() {@Overridepublic void onSuccess() {// 接听请求已发出,等待 onCallAccepted 回调触发后再开启采集推流}@Overridepublic void onError(int code, String desc) {Log.e(TAG, "accept failed: " + code + " " + desc);}});// 拒绝来电:// TXIoTCallSession.getInstance().reject(contact.userId, callback);}
步骤 3:开启采集推流与渲染对端画面
通话正式建立(
onCallAccepted 回调触发)后,根据 onCallRequested 携带的 option.mediaContent 开启本地采集推流,直接调用如下接口即可:接口 | 说明 |
openCamera(frontCamera, view) | 开启摄像头采集并推流, frontCamera 为是否使用前置摄像头,view 为本地画面预览的 TXCloudVideoView(可为 null),视频通话时调用。 |
openMicrophone() | 开启麦克风采集并推流,音频/视频通话均需调用。 |
startRemoteView(userId, view) | 拉取并渲染对端 userId 的视频画面到指定 TXCloudVideoView。 |
// mLocalView / mRemoteView 为布局中的 TXCloudVideoView,分别用于本地预览与对端画面String userId = "peer_user_id";if (media == MediaContent.VIDEO || media == MediaContent.AUDIO_VIDEO) {TXIoTCallSession.getInstance().openCamera(true, mLocalView); // 使用前置摄像头,本地预览到 mLocalViewTXIoTCallSession.getInstance().startRemoteView(userId, mRemoteView);// 渲染对端画面}if (media == MediaContent.AUDIO || media == MediaContent.AUDIO_VIDEO) {TXIoTCallSession.getInstance().openMicrophone();}
步骤 4:挂断通话
通话中主动挂断,调用
hangup;对端挂断时会触发 onCallHangup,此时应关闭本地采集、停止对端画面渲染:// 主动挂断TXIoTCallSession.getInstance().hangup(userId, new TXIoTCallback() {@Overridepublic void onSuccess() {// 停止采集与渲染,释放资源(onCallHangup / onCallTimeout / onCallRejected 均调用)TXIoTCallSession.getInstance().stopRemoteView(userId);TXIoTCallSession.getInstance().closeCamera();TXIoTCallSession.getInstance().closeMicrophone();}@Overridepublic void onError(int code, String desc) {Log.e(TAG, "hangup failed: " + code + " " + desc);}});
说明:
来电未及时处理时会触发
onCallTimeout,处理方式与 onCallHangup 一致:关闭采集、停止渲染并释放资源。完整示例代码
以下
CallActivity 示例整合了通话事件响应、接听来电、开启采集推流与渲染对端画面、以及挂断的完整流程,实际接入时,请将布局中的 TXCloudVideoView 与业务界面对接。import android.os.Bundle;import android.util.Log;import androidx.annotation.Nullable;import androidx.appcompat.app.AppCompatActivity;import com.tencent.liteav.iot.TXIoTCallback;import com.tencent.liteav.iot.TXIoTCallSession;import com.tencent.liteav.iot.TXIoTCallSession.Contact;import com.tencent.liteav.iot.TXIoTCallSession.MediaContent;import com.tencent.liteav.iot.TXIoTCallSession.Option;import com.tencent.liteav.iot.TXIoTError;import com.tencent.rtmp.ui.TXCloudVideoView;public class CallActivity extends AppCompatActivity {private static final String TAG = "CallActivity";private TXCloudVideoView mLocalView;private TXCloudVideoView mRemoteView;// 记住当前通话的媒体类型与对端账号,供接听/挂断复用private MediaContent mCurrentMedia = MediaContent.AUDIO_VIDEO;private String mPeerUserId;private final TXIoTCallSession.Listener mCallListener = new TXIoTCallSession.Listener() {@Overridepublic void onCallRequested(Contact contact, Option option) {Log.i(TAG, "onCallRequested userId=" + contact.userId + " media=" + option.mediaContent);mPeerUserId = contact.userId;mCurrentMedia = option.mediaContent;// 示例:自动接听。实际可弹出接听/拒绝界面acceptCall(contact.userId);}@Overridepublic void onCallAccepted(Contact contact) {Log.i(TAG, "onCallAccepted userId=" + contact.userId);// 通话正式建立,此时才开启采集推流与渲染对端画面startCallStreams(contact, mCurrentMedia);}@Overridepublic void onCallRejected(Contact contact) {Log.i(TAG, "onCallRejected userId=" + contact.userId);stopCallStreams(contact.userId);}@Overridepublic void onCallTimeout(Contact contact) {Log.i(TAG, "onCallTimeout userId=" + contact.userId);stopCallStreams(contact.userId);}@Overridepublic void onCallHangup(Contact contact) {Log.i(TAG, "onCallHangup userId=" + contact.userId);stopCallStreams(contact.userId);}};@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);// setContentView(R.layout.activity_call);// mLocalView = findViewById(R.id.local_view);// mRemoteView = findViewById(R.id.remote_view);// 请确保已完成 login 登录,并已申请摄像头/麦克风运行时权限TXIoTCallSession.getInstance().addListener(mCallListener);}// 接听来电(采集推流放到 onCallAccepted 回调中执行)private void acceptCall(String userId) {TXIoTCallSession.getInstance().accept(userId, new TXIoTCallback() {@Overridepublic void onSuccess() {Log.i(TAG, "accept succeed, waiting for onCallAccepted");}@Overridepublic void onError(int code, String desc) {Log.e(TAG, "accept failed: " + code + " " + desc);}});}// 通话建立后:根据媒体类型开启采集推流并渲染对端画面private void startCallStreams(Contact contact, MediaContent media) {TXIoTCallSession session = TXIoTCallSession.getInstance();if (media == MediaContent.VIDEO || media == MediaContent.AUDIO_VIDEO) {int rc = session.openCamera(true, mLocalView);if (rc != TXIoTError.SUCCESS) {Log.e(TAG, "openCamera failed: " + rc);}session.startRemoteView(contact.userId, mRemoteView);}if (media == MediaContent.AUDIO || media == MediaContent.AUDIO_VIDEO) {int rc = session.openMicrophone();if (rc != TXIoTError.SUCCESS) {Log.e(TAG, "openMicrophone failed: " + rc);}}}// 主动挂断private void hangupCall(String userId) {TXIoTCallSession.getInstance().hangup(userId, new TXIoTCallback() {@Overridepublic void onSuccess() {stopCallStreams(userId);}@Overridepublic void onError(int code, String desc) {Log.e(TAG, "hangup failed: " + code + " " + desc);}});}// 停止采集与渲染,释放资源private void stopCallStreams(String userId) {TXIoTCallSession session = TXIoTCallSession.getInstance();if (userId != null) {session.stopRemoteView(userId);}session.closeCamera();session.closeMicrophone();}@Overrideprotected void onDestroy() {super.onDestroy();// 退出通话界面时,务必挂断并释放资源,移除监听if (mPeerUserId != null) {hangupCall(mPeerUserId);} else {stopCallStreams(null);}TXIoTCallSession.getInstance().removeListener(mCallListener);}}
常见问题
现象 | 排查建议 |
APP 发起呼叫后,设备端未收到 onCallRequested。 | 确认设备已成功登录;确认已调用 addListener 注册监听且未被提前 removeListener。 |
accept 回调 onError 返回失败。 | 确认设备已成功登录;确认 userId 有效;确认当前没有其他通话正在进行。 |
本地或对端画面不显示。 | 确认已声明并授予 CAMERA、RECORD_AUDIO 权限;确认 openCamera 传入的本地 TXCloudVideoView 与 startRemoteView 传入的对端 TXCloudVideoView 均已正确加入布局且可见。 |
多次通话后设备资源占用持续增长。 | 检查 onCallHangup / onCallTimeout / onCallRejected 是否都正确调用了 closeCamera / closeMicrophone / stopRemoteView,并在退出界面时 removeListener,避免资源泄漏。 |
联系我们