Jami 20260403.0 API 使用详解
面向要在服务器上程序化操控 Jami 的开发者,讲清 Jami 20260403.0 的进程 API 全貌:D-Bus 总线端点(cx.ring.Ring)与四个对象、199 个方法 + 78 个信号的接口清单、busctl 调用约定(签名规则、错误模型、异步事件模式),并给出账户、配置编解码、设备信任、呼叫、信号订阅等各域的可运行实测调用与响应回显。
Jami 20260403.0 API 使用详解
目标:面向要在服务器上程序化操控 Jami 的开发者,讲清 Jami 20260403.0 的进程 API 全貌:D-Bus 总线端点(cx.ring.Ring)与四个对象、199 个方法 + 78 个信号的接口清单、busctl 调用约定(签名规则、错误模型、异步事件模式),并给出账户、配置编解码、设备信任、呼叫、信号订阅等各域的可运行实测调用与响应回显。全部调用在 Ubuntu 22.04 服务器(jamisrv1,账户 ff5bdfae563e6707)实测执行。
一、环境信息
| 项 | 值 | 来源 |
|---|---|---|
| 实验系统 | Ubuntu 22.04 服务器(主机名 jamisrv1,无图形界面) | 实测 |
| 软件版本 | jami-daemon 20260403.0~dfsg1-1(Jami Core 16.0.0) | jamid --version 实测 |
| API 形态 | D-Bus 会话总线(bus name cx.ring.Ring,由 jamid 提供);底层为 libjami C++ API 的 DBus 绑定 | 实测 |
| 实验账户 | accountID ff5bdfae563e6707,RingID 813cbf71078e4d16b0462ce1c694c54bc2f52979 | 实测 |
| 调用工具 | busctl(systemd 249 自带);图形化调试可用官方文档推荐的 d-feet | 实测/官方文档 |
| 实验日期 | 2026-10-26 | 实测 |
| 关联文章 | 部署见《Ubuntu 22.04 安装 Jami 20260403.0 指南》;参数语义见《Jami 20260403.0 配置参数详解》 | 本专栏 |
二、前置条件(端点与访问控制)
- jami-daemon 运行中(安装篇的
jamiserver.service),bus name 已注册:
sudo -iu jamiserver bash -c 'source /tmp/env-jamiserver; busctl --user list | grep cx.ring'
cx.ring.Ring 4386 jamid jamiserver :1.0 jamiserver.service - -
- 访问控制 = 会话总线 UID 归属:Jami 的 D-Bus API 没有 token/密码/TLS,安全边界是「这条私有会话总线属于谁」。总线由 jamiserver 用户拉起,root 直连会报
Transport endpoint is not connected(安装篇 FAQ#2 实测),因此所有调用都必须以运行 daemon 的用户身份执行:sudo -iu jamiserver+source /tmp/env-jamiserver。外部程序(Python dbus/gRPC-DBus 桥、systemd 服务)同理——用专用账户运行 daemon,再以同一账户运行调用方。 - 对象树与总线地址获取:
busctl --user tree cx.ring.Ring
└─/cx
└─/cx/ring
└─/cx/ring/Ring
├─/cx/ring/Ring/CallManager
├─/cx/ring/Ring/ConfigurationManager
├─/cx/ring/Ring/Instance
└─/cx/ring/Ring/PresenceManager
三、API 总览
官方文档《APIs of Jami》口径:daemon API 由 5 个 Manager + 1 个 Instance 组成(CallManager / ConfigurationManager / PresenceManager / VideoManager / PluginManager 等管理器 + Instance 注册计数);其中 DBus 绑定在 jamid 20260403.0 上实际暴露 4 个对象(VideoManager 未单独出现,视频设备管理能力并入配置与媒体参数路径)——以下全部以实测树为准。
busctl --user introspect 全量方法表统计(实测):
| 对象(接口) | 方法数 | 信号数 | 职责 |
|---|---|---|---|
| ConfigurationManager | 142 | 51 | 账户/配置/联系人/会话(swarm)/证书/数据传输/名字服务 |
| CallManager | 50 | 21 | 呼叫与会议生命周期、媒体操作、通话内消息 |
| PresenceManager | 5 | 5 | 联系人在线状态订阅与发布 |
| Instance | 2 | 1 | 客户端注册计数(Register/Unregister/started) |
| 合计 | 199 | 78 |
风格约定(全部接口一致):账户用 accountID(16 位十六进制串)定位、呼叫用 callID、会话用 conversationID;批量数据一律 a{ss}(字符串键值映射)或 as(字符串数组);写操作多返回 bool,读操作返回映射/数组。
四、通用调用约定(busctl 首呼与签名规则)
4.1 首次调用
sudo -iu jamiserver bash -c 'source /tmp/env-jamiserver; busctl --user call cx.ring.Ring /cx/ring/Ring/ConfigurationManager cx.ring.Ring.ConfigurationManager getAccountList ""'
as 1 "ff5bdfae563e6707"
busctl 四要素:call 服务 对象 接口 方法,方法名在服务内唯一时接口段可省写为 cx.ring.Ring.ConfigurationManager 全称(本篇全用全称,避免歧义)。
4.2 签名规则:多参数签名必须整体传
busctl 的参数模型是「一个完整签名串 + 扁平实参」。两个实测坑:
# setAccountDetails 真实签名 sa{ss}(账户ID + 键值映射)
setAccountDetails "sa{ss}" ff5bdfae563e6707 1 Account.autoAnswer true # ✅ 成功
# 拆成 s 与 a{ss} 两段传 → 实测报错
"Too many parameters for signature" # 签名只写了 s,多出的键值对无处安放
"Too few parameters for signature" # 反向:签名给了,实参不足
同一规则适用于一切多参数方法,例如 exportToFile(签名 ssss)、placeCall(签名 ss)。先 busctl --user introspect 查签名,再整体传入是唯一可靠路径。
4.3 错误模型:空结果优先于异常
实测三类错误返回路径:
| 场景 | 实测返回 | 程序化处理 |
|---|---|---|
| accountID 不存在 | getAccountDetails s 0000000000000000 → a{ss} 0(空映射,不抛 D-Bus 错误) | 判空而不是捕获异常 |
| 方法名不存在 | Call failed: Unknown method exportOnRing or interface … | 开发期 introspect 校对(exportOnRing 是旧 Ring 时代方法名,现名 exportToFile) |
| 签名不匹配 | Too many/too few parameters for signature | busctl 阶段即失败,不会触及 daemon |
五、各 API 域详解
5.1 账户域(ConfigurationManager)
addAccount —— 创建账户(安装篇实测,键值映射入参,返回 accountID):
busctl --user call cx.ring.Ring /cx/ring/Ring/ConfigurationManager \
cx.ring.Ring.ConfigurationManager addAccount "a{ss}" 4 \
"Account.type" "RING" \
"Account.alias" "headless-srv1" \
"Account.displayName" "headless-srv1" \
"Account.archivePath" ""
s "ff5bdfae563e6707"
getAccountTemplate —— 创建前的参数模板(实测返回 59 键,别名/设备名为空、Account.archiveHasPassword 模板默认 true):
... getAccountTemplate s RING
a{ss} 59 "Account.accountDiscovery" "false" ... "Account.alias" "" ... "Account.archiveHasPassword" "true" ... "Account.deviceName" "" ...
标准用法:先取模板 → 改若干键 → 传入 addAccount。其余账户域高频方法(签名实测见 introspect):
| 方法 | 签名 | 说明 |
|---|---|---|
| getAccountDetails | s → a{ss} | 59 键全量参数(配置篇详解) |
| getVolatileAccountDetails | s → a{ss} | 9 键运行态(注册状态/宣告/DHT 端口) |
| setAccountDetails | sa{ss} → - | 写参数,触发账户重载与重注册(配置篇 3.3 闭环实测) |
| sendRegister | sb → - | 手动注册/注销(false 即离线,不删数据) |
| setAccountActive | sb → - | 启停账户但不删除 |
| removeAccount | s → - | 删除账户(本地密钥数据一并清除,不可逆) |
5.2 配置与编解码域
getCodecList / getCodecDetails(编解码器以 daemon 内部 ID 定位):
... getCodecList
au 12 27 139 12 4 86076 69660 69643 536956963 268521507 86051 65543 65542
... getCodecDetails su ff5bdfae563e6707 27
a{ss} 6 "CodecInfo.bitrate" "800" "CodecInfo.frameRate" "0" "CodecInfo.max_bitrate" "6000" "CodecInfo.min_bitrate" "200" "CodecInfo.name" "H.264/AVC" "CodecInfo.type" "VIDEO"
... getCodecDetails su ff5bdfae563e6707 139 # → "CodecInfo.name" "VP8",VIDEO
getSupportedTlsMethod(TLS 传输方法白名单):
as 4 "Default" "TLSv1.2" "TLSv1.1" "TLSv1"
音频设备/录音/历史等全局项也在此域(getAudioOutputDeviceList、getRecordPath、setHistoryLimit 等,共 142 个方法,全表可用 introspect 获取)。
5.3 设备、信任与备份域
getKnownRingDevices(本账户已链接设备):
... getKnownRingDevices s ff5bdfae563e6707
a{ss} 1 "d49eef0fb5e2a129fc0564c11c5c39bdb13675fe9f0e88c1553abfb4e3a1ab43" "jamisrv1"
exportToFile —— 导出账户备份(签名 4 个字符串:账户 ID、目标路径 + 两个可选参数实测传空串即成功;返回 bool):
... exportToFile ssss ff5bdfae563e6707 /tmp/srv1-archive "" ""
b true
$ ls -la /tmp/srv1-archive
-rw-r--r-- 1 jamiserver jamiserver 15114 Oct 26 06:25 /tmp/srv1-archive
$ head -c 8 /tmp/srv1-archive | od -A x -t x1z
000000 1f 8b 08 00 00 00 00 00 ← gzip 流(安装篇 6.6 节 archive.gz 的同形态封装)
该文件即账户的完整身份备份(密钥 + 配置),扩展名由调用方决定(桌面客户端导出为 .jac)。备份文件等同账户本体,落盘即应纳入加密保管。 信任与联系人读接口(新账户均为空集,实测回显):
getContacts → aa{ss} 0
getTrustRequests → aa{ss} 0
getConversations → as 0
5.4 呼叫域(CallManager)
placeCall —— 发起呼叫(对不可达对端实测:callID 立即分配,呼叫自行失败后从列表消失,进程不报错):
busctl --user call cx.ring.Ring /cx/ring/Ring/CallManager cx.ring.Ring.CallManager \
placeCall ss ff5bdfae563e6707 3d1112ab2bb089370c0744a44bbbb0786418d40b
s "4964305948076509" ← daemon 生成的 callID
$ sleep 6 后查询
... getCallList s ff5bdfae563e6707
as 0 ← 呼叫已终止并出清
呼叫生命周期方法全表(签名实测):accept/refuse/hangUp/hold/resume(ss → b)、placeCallWithMedia(ssaa{ss} → s,带自定义媒体参数)、transfer/attendedTransfer(sss → b)、toggleRecording(ss → b)、playDTMF(s → -)、会议族 addParticipant/joinParticipant/joinConference/createConfFromParticipantList 等。入呼是异步的:必须监听 incomingCall 信号拿到 callID 后再 accept/refuse(见 5.6)。
5.5 Presence 与 Instance
PresenceManager(5 方法):subscribeBuddy(ssb → -,订阅对端在线状态)、publish(sbs → -,发布本端状态)、getSubscriptions/setSubscriptions/answerServerRequest;通知走 newBuddyNotification(ssis)信号。Instance 仅 Register(is → -)/Unregister(i → -)与 started 信号,用于客户端向 daemon 声明存活计数,脚本化场景可忽略。
5.6 信号订阅:异步事件的唯一入口
写操作的结果与所有异步事件(入呼、来消息、注册状态变化)都通过 D-Bus 信号推送。busctl 实测监听(订阅 ConfigurationManager 全部信号,触发一次 setAccountDetails 后捕获):
busctl --user monitor --match "type=signal,interface=cx.ring.Ring.ConfigurationManager"
‣ Type=signal Sender=:1.0 Path=/cx/ring/Ring/ConfigurationManager
Interface=cx.ring.Ring.ConfigurationManager Member=registrationStateChanged
MESSAGE "ssis" {
STRING "ff5bdfae563e6707";
STRING "UNREGISTERED"; ← 账户重载瞬间先注销
INT32 0;
STRING "";
};
‣ Member=volatileAccountDetailsChanged
MESSAGE "sa{ss}" {
STRING "ff5bdfae563e6707";
ARRAY "{ss}" { STRING "Account.active"; STRING "true"; ...
STRING "Account.deviceAnnounced"; STRING "false"; ...
业务集成最常监听的信号(签名实测):
| 信号 | 接口 | 签名 | 语义 |
|---|---|---|---|
| registrationStateChanged | ConfigurationManager | ssis | 账户注册状态机变化(TRYING/REGISTERED/UNREGISTERED…) |
| incomingCall | CallManager | sssaa{ss} | 入呼(携带 accountID/callID/对端 RingID) |
| incomingAccountMessage | ConfigurationManager | ssssa{ss} | 收到点对点账户消息 |
| swarmMessageReceived | ConfigurationManager | ss(…) | 收到 swarm 会话消息 |
| callStateChanged | CallManager | sssi | 呼叫状态变化 |
| dataTransferEvent | ConfigurationManager | ssssi | 文件传输进度/结果 |
注意:安装篇互通路径里提到的「监听 messagesReceived」,在 20260403.0 的实际信号名是 incomingAccountMessage(点对点)与 swarmMessageReceived(会话),老教程命名已被取代。生产集成用 sd-bus/GIO/dbus-python 订阅同名信号即可,语义与 busctl monitor 完全一致。
六、异步事件与轮询约定
本地 IPC 无分页/限流概念,通行的取数约定是两条(实测结论):
- 状态类数据轮询读:
getVolatileAccountDetails为权威快照,配合 3~5 秒间隔轮询足够;注册收敛实测约 25 秒内完成(TRYING → REGISTERED)。 - 事件类数据订阅信号:消息/呼叫/传输必须走信号(5.6),轮询方法(getLastMessages、getCallList)只适合补漏与对账。
monitor()方法(b → -)可让 daemon 输出调试流,排障期临时打开。
七、常见问题(实测命中)
Too many/too few parameters for signature:多参数签名必须整体传(sa{ss}/ssss),见 4.2;这是 busctl 调 Jami 的第一大坑。- 传了不存在的 accountID 不报错:返回空映射
a{ss} 0(4.3 实测)。程序必须判空,否则静默失效。 - 方法名对不上:老资料里的
exportOnRing已更名exportToFile;messagesReceived信号已拆为incomingAccountMessage/swarmMessageReceived。以 introspect 实时输出为准,不要照抄历史文档。 - root 跑集成脚本连不上:会话总线归属 jamiserver(2 节实测)。systemd 集成服务加
User=jamiserver并EnvironmentFile=/tmp/env-jamiserver即可。 - placeCall 返回了 callID 但通话没建立:callID 分配 ≠ 呼叫成功;对端不可达时呼叫自行终止(5.4 实测 6 秒后列表为空)。成功与否以
callStateChanged信号为准。 - 导出备份成功但文件没有 .jac 后缀:exportToFile 只负责内容(gzip 形态),扩展名由调用方指定;后缀不影响再次导入(addAccount 时指定 archivePath)。
八、参考链接
- 官方 API 总览(APIs of Jami,DBus 文档位置
jami-daemon/bin/dbus、d-feet 调试建议):https://docs.jami.net/en_US/developer/apis-of-jami.html - 官方 Jami 标识符规范(RingID/accountID/conversationID 命名):https://docs.jami.net/en_US/developer/jami-concepts/jami-identifiers.html
- 官方服务器部署文档(Jami for servers):https://docs.jami.net/en_US/user/jami-for-servers.html
- 站内关联:《Jami 20260403.0 介绍与选型指南》、《Ubuntu 22.04 安装 Jami 20260403.0 指南》、《Jami 20260403.0 配置参数详解》