AIMA开放平台文档中心Agent SDK (Android)

超视距遥操(Teleop)示例 · Android

超视距遥操(Teleop)示例 · Android

⚠️ 尚未上线:本能力为 v1.5.0-SNAPSHOT 开发中特性,接口与协议可能调整,正式发布前请勿用于生产环境。

v1.5.0 新增。本页给出 Android 端只调用 AgentSDK 公开接口的最小遥操示例,展示 enter → startAudio → appendAudioDelta → doneAudio → exit 全流程。API 与 Java v1.5.0 · 遥操示例 完全一致,此处按 Android 惯例(Activity + 运行时权限 + 主线程回调切换)改写。视频拉流不属于 AgentSDK,见 遥操指南 · 视频拉流与拉流授权。

权限

xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

RECORD_AUDIO 是危险权限,首次 startAudio 前需 ActivityCompat.requestPermissions 申请。

最小示例

java
import com.agibot.aiem.sdk.AgentAuthCallback;
import com.agibot.aiem.sdk.AgentParam;
import com.agibot.aiem.sdk.AgentSdk;
import com.agibot.aiem.sdk.IdGenerator;
import com.agibot.aiem.sdk.teleop.TeleopEnterCallback;
import com.agibot.aiem.sdk.teleop.TeleopExitCallback;
import com.agibot.aiem.sdk.teleop.TeleopRequest;

public class TeleopDemo {

    private static final String URL        = "wss://open.agibot.com/api/V1/open-portal/app/wss/agent-sdk";
    private static final String APP_ID     = "<灵心开放平台应用 appId>";
    private static final String APP_KEY    = "<灵心开放平台应用 appKey>";
    private static final String APP_SECRET = "<灵心开放平台应用 appSecret>";
    private static final String AGENT_ID   = "<目标机器人 agentId>";

    private AgentSdk agentSdk;
    private TeleopRequest teleopRequest;
    private String audioEventId;

    // 1. 创建 SDK + 注册鉴权 + 初始化
    void connect() {
        agentSdk = AgentSdk.create(URL, APP_ID, APP_KEY, APP_SECRET);
        agentSdk.registerAuth(new AgentAuthCallback() {
            @Override
            public void onAuthState(String appId, int code, String msg) {
                // code == 0 后才可 enter(回调在非 UI 线程)
            }
        });
        agentSdk.initialize();
    }

    // 2. 注册遥操会话 + 进入
    void enter() {
        String teleopId = IdGenerator.generateTeleopId();
        teleopRequest = new TeleopRequest(agentSdk, AGENT_ID, teleopId);
        agentSdk.registerTeleop(teleopRequest);

        AgentParam enterParam = AgentParam.create();
        teleopRequest.enter(enterParam, new TeleopEnterCallback() {
            @Override
            public void onEnterAck(String teleopId, String eventId, int code, String msg) {
                // code == 0 成功;-1 服务端拒绝;1000 本地连接已关闭
                // 需要更新 UI 请 runOnUiThread / Handler.post
            }
        }, 2000);
    }

    // 3. 开麦:每段讲话一次 startAudio,拿到 eventId
    void startTalking() {
        AgentParam startParam = AgentParam.create()
                .setString("role", "male")     // male / female
                .setInteger("threshold", 0);   // -14 ~ 14
        audioEventId = teleopRequest.startAudio(startParam);
    }

    // 4. 推流:麦克风回调里每 20ms 一片,base64 后 append
    void onPcmFrame(byte[] pcm20ms) {  // 640 bytes @16kHz mono s16le
        String base64 = android.util.Base64.encodeToString(pcm20ms, android.util.Base64.NO_WRAP);
        teleopRequest.appendAudioDelta(audioEventId, base64);
    }

    // 5. 关麦(结束一段讲话,不退出遥操)
    void stopTalking() {
        teleopRequest.doneAudio(audioEventId);
    }

    // 6. 退出 + 释放
    void exit() {
        teleopRequest.exit(new TeleopExitCallback() {
            @Override
            public void onExitAck(String teleopId, String eventId, int code, String msg) {
                agentSdk.unregisterTeleop(teleopId);
            }
        }, 2000);
    }
}

定时探活(keepalive)

enter 拿到 code == 0 后,业务侧应每 10 秒探活一次;onKeepaliveAck 收到 code != 0 即视为机器人离线,需停止定时、退出遥操、注销资源。Android 侧用 Handler + postDelayed 最自然:

java
private final Handler mainHandler = new Handler(Looper.getMainLooper());
private final AtomicBoolean robotOnline = new AtomicBoolean(true);
private Runnable keepaliveTick;

void startKeepAlive() {
    keepaliveTick = () -> {
        if (!robotOnline.get()) return;
        teleopRequest.keepalive(new TeleopKeepaliveCallback() {
            @Override
            public void onKeepaliveAck(String teleopId, String eventId, int code, String msg) {
                if (code == 0) {                       // 在线,安排下一轮
                    mainHandler.postDelayed(keepaliveTick, 10_000);
                    return;
                }
                if (!robotOnline.compareAndSet(true, false)) return;
                mainHandler.removeCallbacks(keepaliveTick);   // 离线:停止定时 + 退出
                teleopRequest.exit(new TeleopExitCallback() {
                    @Override
                    public void onExitAck(String teleopId, String eventId, int code, String msg) {
                        agentSdk.unregisterTeleop(teleopId);
                    }
                }, 2000);
            }
        }, 2000);
    };
    mainHandler.postDelayed(keepaliveTick, 10_000);
}

主动 exit 后也应 mainHandler.removeCallbacks(keepaliveTick) 停止探活。

回调线程:onEnterAck / onKeepaliveAck / onExitAck 均在 SDK 消息分发线程(非 UI 线程)回调,更新界面请切回主线程。

常见改写要点

想做改哪里
一次遥操中多次讲话每段重新 startAudio(startParam) 拿新 eventId,appendAudioDelta / doneAudio 用该 eventId;无需 exit 再 enter
切换音色 / 灵敏度每段 startAudio 时重填 AgentParam 的 role / threshold;不影响前一段
中途取消遥操直接 exit(...),不再补 doneAudio
感知鉴权 / 断连在 AgentAuthCallback.onAuthState 维护 authed 标志,enter 前 double-check;或在 onEnterAck 收到 code == 1000 后等重连
多机器人同时遥操每个 agentId 建一个 TeleopRequest;SDK 按 teleopId 索引,互不冲突
叠加视频拉流见 遥操指南 · 视频拉流与拉流授权(拉流由第三方 WebRTC SDK 承担,不属于 AgentSDK)