You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Android上自定义最新版Mesibo音视频通话UI?

解决Mesibo 2.7.18版本自定义通话UI的方案

Mesibo在2.x后期版本中重构了音视频通话的UI组件,旧文档里的MesiboCall.MesiboCallListener、MesiboIncomingAudioCallFragment等类确实已被替换。以下是基于2.7.18版本实现自定义通话UI的具体步骤和示例代码:

核心思路

新版本通过MesiboCallManager管理通话,自定义UI需要实现新版本的通话监听接口,并自行创建通话Activity/Fragment来控制布局、按钮逻辑和音视频渲染。


1. 实现新版通话监听接口MesiboCallListenerV2

这个接口替代了旧版的MesiboCall.MesiboCallListener,用于接收通话状态、音视频轨道等关键回调:

public class CustomCallListener implements MesiboCallListenerV2 {
    private final CustomCallActivity mActivity;

    public CustomCallListener(CustomCallActivity activity) {
        mActivity = activity;
    }

    @Override
    public void onCallStatus(MesiboCall call, int status, int reason) {
        // 处理通话状态变化:响铃、连接中、通话中、结束等
        mActivity.updateCallStatus(status);
    }

    @Override
    public void onCallTrack(MesiboCall call, int type, Object track) {
        // 获取音视频轨道,绑定到本地/远端视图
        if (type == MesiboCall.TYPE_VIDEO_LOCAL) {
            mActivity.bindLocalVideo((SurfaceView) track);
        } else if (type == MesiboCall.TYPE_VIDEO_REMOTE) {
            mActivity.bindRemoteVideo((SurfaceView) track);
        }
    }

    // 按需实现其他回调方法(音频静音状态、摄像头切换、通话统计等)
    @Override
    public void onCallAudio(MesiboCall call, boolean enabled) {}
    @Override
    public void onCallVideo(MesiboCall call, boolean enabled) {}
    @Override
    public void onCallRemoteVideo(MesiboCall call, boolean enabled) {}
    @Override
    public void onCallCameraSwitch(MesiboCall call, int camera) {}
    @Override
    public void onCallStats(MesiboCall call, MesiboCallStats stats) {}
    @Override
    public void onCallData(MesiboCall call, byte[] data) {}
}

2. 创建自定义通话布局

自行设计通话界面的布局(示例activity_custom_call.xml),包含视频渲染视图和控制按钮:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000">

    <!-- 远端视频全屏视图 -->
    <SurfaceView
        android:id="@+id/remote_video"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- 本地视频小窗口 -->
    <SurfaceView
        android:id="@+id/local_video"
        android:layout_width="120dp"
        android:layout_height="160dp"
        android:layout_alignParentEnd="true"
        android:layout_alignParentBottom="true"
        android:layout_margin="16dp" />

    <!-- 底部控制按钮栏 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal"
        android:gravity="center"
        android:padding="16dp">

        <ImageButton
            android:id="@+id/btn_mute"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:src="@drawable/ic_mute_off"
            android:background="@drawable/call_button_round" />

        <ImageButton
            android:id="@+id/btn_switch_camera"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_marginHorizontal="32dp"
            android:src="@drawable/ic_switch_camera"
            android:background="@drawable/call_button_round" />

        <ImageButton
            android:id="@+id/btn_hangup"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:src="@drawable/ic_hangup"
            android:background="@drawable/call_button_red_round" />
    </LinearLayout>
</RelativeLayout>

3. 实现自定义通话Activity逻辑

将布局、监听和通话控制逻辑绑定:

public class CustomCallActivity extends AppCompatActivity {
    private MesiboCall mCurrentCall;
    private CustomCallListener mCallListener;
    private SurfaceView mLocalVideo, mRemoteVideo;
    private ImageButton mMuteBtn, mSwitchCameraBtn, mHangupBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_call);

        // 初始化视图
        mLocalVideo = findViewById(R.id.local_video);
        mRemoteVideo = findViewById(R.id.remote_video);
        mMuteBtn = findViewById(R.id.btn_mute);
        mSwitchCameraBtn = findViewById(R.id.btn_switch_camera);
        mHangupBtn = findViewById(R.id.btn_hangup);

        // 获取当前通话实例
        mCurrentCall = MesiboCallManager.getInstance().getActiveCall();
        if (mCurrentCall == null) {
            finish();
            return;
        }

        // 设置通话监听
        mCallListener = new CustomCallListener(this);
        mCurrentCall.setListener(mCallListener);

        // 绑定按钮点击事件
        mMuteBtn.setOnClickListener(v -> toggleMute());
        mSwitchCameraBtn.setOnClickListener(v -> mCurrentCall.switchCamera());
        mHangupBtn.setOnClickListener(v -> hangupCall());
    }

    // 切换音频静音状态
    private void toggleMute() {
        boolean isMuted = mCurrentCall.isAudioMuted();
        mCurrentCall.setAudioMuted(!isMuted);
        mMuteBtn.setImageResource(isMuted ? R.drawable.ic_mute_off : R.drawable.ic_mute_on);
    }

    // 挂断通话
    private void hangupCall() {
        mCurrentCall.hangup();
        finish();
    }

    // 更新通话状态UI
    public void updateCallStatus(int status) {
        switch (status) {
            case MesiboCall.STATUS_RINGING:
                // 显示"对方正在响铃"提示
                break;
            case MesiboCall.STATUS_CONNECTED:
                // 显示"通话中"提示
                break;
            case MesiboCall.STATUS_ENDED:
                finish();
                break;
        }
    }

    // 绑定本地视频轨道到视图
    public void bindLocalVideo(SurfaceView track) {
        mLocalVideo.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                mCurrentCall.setLocalSurface(holder.getSurface());
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {}
        });
    }

    // 绑定远端视频轨道到视图
    public void bindRemoteVideo(SurfaceView track) {
        mRemoteVideo.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                mCurrentCall.setRemoteSurface(holder.getSurface());
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {}
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mCurrentCall != null) {
            mCurrentCall.setListener(null);
        }
    }
}

4. 接管来电/去电的界面跳转

在应用初始化时,通过MesiboCallManager监听通话请求,启动自定义界面而非SDK默认界面:

// 在MainActivity或Application的onCreate中添加
MesiboCallManager.getInstance().addListener(new MesiboCallManager.CallListener() {
    @Override
    public boolean onIncomingCall(MesiboCall call) {
        // 启动自定义来电界面
        Intent intent = new Intent(MainActivity.this, CustomCallActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
        return true; // 返回true表示自行处理,不使用SDK默认UI
    }

    @Override
    public boolean onOutgoingCall(MesiboCall call) {
        // 启动自定义去电界面
        Intent intent = new Intent(MainActivity.this, CustomCallActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
        return true;
    }
});

注意事项

  • 权限:确保已申请并动态获取CAMERA、RECORD_AUDIO、INTERNET权限。
  • 测试:必须在真机上测试,模拟器通常不支持摄像头和音频输入。
  • 异常处理:需处理通话实例为空、权限被拒绝等异常场景,避免崩溃。

内容的提问来源于stack exchange,提问作者Eko Yulianto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 23:16:18