Android 数据与设备能力
SDK Version: 1.0.0
Package:com.xtalk.mesh.sdk.ble
除图片转码外,本页业务接口都要求 ensureInitialized() 成功;发送类接口还要求连接、认证和初始化完成。阻塞/等待设备结果的方法在 Dispatchers.IO 调用。返回值枚举的具体成员以交付核心 SDK 的 IDE 补全为准;只有明确的成功成员才算成功,不要把“非空”当作成功。
1. 二进制与 RF
| API | 选择时机 | 结果语义 |
|---|---|---|
sendBinaryFrame(data) | 普通二进制业务帧 | SendResult;空包/长度/状态/连接错误由枚举反映 |
sendRfPayloadAndWaitSendFinish(rawPayload, timeoutMs) | 需要设备完成确认 | true 表示在期限内收到发送完成;超时/错误为 false |
sendRfPayloadNoWait(rawPayload) | 实时语音/低延迟控制帧 | 只报告是否受理,不等发送完成;空包为 false |
val ok = withContext(Dispatchers.IO) {
XTalkBleClient.sendRfPayloadAndWaitSendFinish(frame, timeoutMs = 3_000L)
}
普通可靠业务优先 waited 版本;只有能自行节流、容忍丢包的实时流才使用 no-wait。不要与 Auth、Init 或自定义 AT 并发。
2. 原始 AT 与透传所有权(Advanced)
| API | 契约 |
|---|---|
runAtCommand(...) | 独占无线锁、返回响应行;详见 API 参考 |
sendAtCommand(command) | 返回 SendResult,不提供响应行 |
sendAtCommandNoWait(command) | 只报告写入受理 |
sendEncryptedAt(bytes) | 输入是已按交付协议编码的 AT 字节;成功为 true |
setPassthroughListener(listener) | 设置底层透传唯一 listener,null 释放;会影响 runAtCommand,只允许 transport 作者短期使用 |
withWirelessOpLock(block) | 让高级客户操作与 Auth/Init/AT 串行;不得从已持锁路径再次等待自身 |
val lines = withContext(Dispatchers.IO) {
XTalkBleClient.runAtCommand(
command = "AT+RATE?",
timeoutMs = 1_500L,
errorPolicy = BleAtErrorPolicy.FAIL_FAST,
)
}
BleAtErrorPolicy.COLLECT_UNTIL_COMPLETE 只和明确的 stopWhen 一起使用。drainResponseTailAfterStop = true 时 stopWhen 必填,SDK 会在载荷匹配后继续持有 listener/锁到终止行或原截止时间。
3. 文本与数据接收
private val textListener = TextReceivedCallback { sourceId, text, snr, rssi ->
// 切换到主线程更新 UI。
}
private val dataListener = DataReceivedCallback { bytes, length, snr, rssi ->
val payload = bytes.copyOf(length.coerceIn(0, bytes.size))
}
XTalkBleClient.addTextListener(textListener)
XTalkBleClient.addDataListener(dataListener)
val result = XTalkBleClient.sendText("hello")
// 生命周期结束
XTalkBleClient.removeTextListener(textListener)
XTalkBleClient.removeDataListener(dataListener)
sendText(text)返回SendResult;空文本、长度限制和状态错误按枚举处理。DataReceivedCallback在高频 I/O 路径触发,不要阻塞;数据只使用0 until length。TextReceivedCallback提供源 ID、文本、SNR、RSSI。
4. 文件发送与接收
private val sendListener = FileSendCallback { progress, sent, total, result ->
// progress/bytes/result 共同判断完成或失败。
}
private val receiveListener = FileReceiveCallback { progress, received, total, result, bytes ->
if (bytes != null) savePrivately(bytes)
}
XTalkBleClient.addFileSendListener(sendListener)
XTalkBleClient.addFileReceiveListener(receiveListener)
val accepted = XTalkBleClient.sendFile(fileBytes)
// 用户取消
XTalkBleClient.cancelFileSend()
XTalkBleClient.cancelFileReceive()
// 页面销毁
XTalkBleClient.removeFileSendListener(sendListener)
XTalkBleClient.removeFileReceiveListener(receiveListener)
sendFile/cancel 返回 SendResult 只表示请求状态;最终进度与结果看对应 callback。客户决定文件选择、大小预检、存储路径和隐私授权。一次只运行一个占用无线通道的文件/AT/Auth/Init 操作。完成或取消后可调用 restoreTextPttDefaults() 恢复文本/PTT 参数。
5. PTT 与实时语音
需要运行时 RECORD_AUDIO 权限。
| API | 参数/默认 | 生命周期 |
|---|---|---|
startPttVoiceCapture(enablePcmCallback = true) | 是否回调本地 PCM | 与 stopPttVoiceCapture() 配对 |
startRealtimeVoiceCapture(peopleCount = 2, mute = 0) | 人数和静音标志 | 与 stopRealtimeVoiceCapture() 配对 |
stopVoiceCaptureLocal() | 无 | 只结束本地采集,用于异常/快速清理 |
setRealtimeWorkModeOverride(workMode) | null 清除 | 会话前设置,会话后清除 |
getRealtimeWorkModeOverride() | 无 | 返回当前 override 或 null |
private val received = VoiceReceivedCallback { sourceId, pcm, length, snr, rssi, isLast ->
consumeRemotePcm(pcm.copyOf(length.coerceIn(0, pcm.size)), isLast)
}
private val captured = VoiceCaptureCallback { pcm, length, isLast ->
consumeLocalPcm(pcm.copyOf(length.coerceIn(0, pcm.size)), isLast)
}
XTalkBleClient.addVoiceListener(received)
XTalkBleClient.addVoiceCaptureListener(captured)
val started = XTalkBleClient.startPttVoiceCapture(enablePcmCallback = true)
// ...
XTalkBleClient.stopPttVoiceCapture()
XTalkBleClient.removeVoiceCaptureListener(captured)
XTalkBleClient.removeVoiceListener(received)
语音帧是实时路径,callback 内不要做文件 I/O、网络请求或 UI 阻塞。只在成功 start 后调用相应 stop;断线时允许调用本地 stop 做幂等清理。
6. PCM 播放
val started = XTalkBleClient.startVoicePlayback(pcmBytes)
// 用户停止或播放结束后的业务清理:
val stopped = XTalkBleClient.stopVoicePlayback()
输入必须是交付协议要求的 PCM 格式。PlaybackStartResult/PlaybackStopResult 明确表示是否启动/停止;不要依据耗时推断成功。
7. 图片转码
val output: ImageTranscodeResult = XTalkBleClient.transcodeImage(
imageBytes = encodedImage,
targetTier = ImageTargetTier.SMALL, // 以交付枚举实际成员为准
inputFormat = null, // null 表示自动识别
)
transcodeImage(imageBytes, targetTier, inputFormat = null) 是离线 CPU 操作,不要求 BLE、Auth、Init 或录音权限;大图仍应在后台线程处理。结果对象包含交付核心 SDK 定义的状态和输出,先检查其成功状态再使用输出字节。
8. 16 字节加密密钥
require(key.size == 16)
check(XTalkBleClient.setCryptoKey16(key))
key.fill(0) // 业务不再需要明文时清除客户侧副本
setCryptoKey16 必须传恰好 16 字节;返回 false 时禁止继续加密业务。不要写日志、Analytics 或持久化明文密钥。
9. 无线设置
| API | 差别 |
|---|---|
setChannelFrequency(freqHz, timeoutMs = 3000) | 通过无线配置 callback 等待 channel 设置成功 |
setFrequencyHz(freqHz, timeoutMs = 3000) | 通过 AT 同时设置四路频率 |
setRateMode(rateMode) | 把值限制到 0..255 后发送;设备是否支持仍由返回值决定 |
restoreTextPttDefaults(rate = 7, addtl = 1, work = 21) | 依次恢复三项;全部成功才返回 true |
频率只能使用客户项目和部署地区获准值。设置失败后停止发送并查询实际值;不要无限重试。
10. 硬件、固件、电量与管理回调
private val manage = DeviceManageCallback { type, value ->
// 异步管理事件;按 type 安全转换 value。
}
XTalkBleClient.addDeviceManageListener(manage)
val hw = withContext(Dispatchers.IO) { XTalkBleClient.getHardwareVersion(2_000L) }
val fw = withContext(Dispatchers.IO) { XTalkBleClient.getFirmwareVersion(2_000L) }
val battery = withContext(Dispatchers.IO) { XTalkBleClient.getBatteryLevel(4_000L) }
XTalkBleClient.removeDeviceManageListener(manage)
三项查询成功后会缓存;失败/超时/不支持返回 null。电量是设备报告的整数,不应在文档层假设额外范围或单位。断开会清空缓存。
11. 监听器总表
| 添加 | 移除 | 回调用途/线程 |
|---|---|---|
addListener | removeListener | 扫描/连接状态;主线程分发 |
addDataListener | removeDataListener | 二进制/实时数据;I/O 回调线程 |
addDeviceManageListener | removeDeviceManageListener | 版本、电量等;主线程分发 |
addTextListener | removeTextListener | 文本;主线程分发 |
addVoiceListener | removeVoiceListener | 远端 PCM;实时回调线程 |
addVoiceCaptureListener | removeVoiceCaptureListener | 本地 PCM;主线程分发 |
addFileSendListener | removeFileSendListener | 发送进度;主线程分发 |
addFileReceiveListener | removeFileReceiveListener | 接收进度/最终字节;主线程分发 |
SDK 用强引用保存 listener。必须移除同一个实例,否则会重复回调并延长 Activity/ViewModel 生命周期。