当前位置: 首页 > news >正文

【征文计划】Rokid CXR-M SDK全解析:从设备连接到语音交互的AR协同开发指南

【征文计划】Rokid CXR-M SDK全解析:从设备连接到语音交互的AR协同开发指南

引言

在智能穿戴设备日益普及的今天,AR眼镜作为新一代人机交互设备,正逐步改变着我们的工作与生活方式。Rokid CXR-M SDK作为专为Rokid Glasses设计的开发工具包,为开发者提供了丰富而强大的功能,使得手机与AR眼镜之间的协同交互变得前所未有的便捷与高效。本文通过详细解析Rokid CXR-M SDK的核心功能、技术原理及应用实践,帮助开发者快速上手并构建出优秀的AR应用。

一、Rokid CXR-M SDK介绍

Rokid CXR-M SDK是面向移动端(目前仅支持Android)的开发工具包,它使得开发者能够轻松构建与Rokid Glasses进行控制和协同的应用。通过SDK,开发者可以实现手机与AR眼镜之间的稳定连接、数据通信、实时音视频传输以及复杂的场景自定义等功能。无论是进行界面交互、远程控制还是与眼镜端配合完成特定任务,Rokid CXR-M SDK都能提供全面的支持。

主要功能特性

  1. 设备连接与管理:支持通过蓝牙和Wi-Fi与Rokid Glasses建立稳定连接,并获取设备状态信息。

  2. 自定义场景交互:快速接入YodaOS-Sprite操作系统定义的场景交互流程,实现自定义功能开发。

  3. AI助手服务:高效利用Rokid Assist Service中的服务,包括文件互传、录音、拍照等功能。

  4. 实时音视频传输:支持眼镜端音视频数据的实时采集与传输至手机端进行处理。

  5. 数据同步与媒体管理:支持眼镜端与手机端之间的媒体文件同步与管理。

二、核心技术原理

1. 设备连接机制

以蓝牙为基础控制通道、Wi-Fi P2P 为高带宽补充,蓝牙按 “扫描→初始化→连接” 流程,用 UUID 过滤设备,Wi-Fi 需蓝牙先连,双通道均有专属回调监听状态。

核心代码示例

import com.rokid.cxr.api.CxrApi
import com.rokid.cxr.callback.{BluetoothStatusCallback, WifiP2PStatusCallback}
import com.rokid.cxr.util.ValueUtil// 蓝牙连接核心
fun connectBluetooth(device: BluetoothDevice) {CxrApi.getInstance().initBluetooth(appContext, device, object : BluetoothStatusCallback {override fun onConnectionInfo(uuid: String?, mac: String?, _, _) {if (uuid != null && mac != null) {CxrApi.getInstance().connectBluetooth(appContext, uuid, mac, this)}}override fun onConnected() = Unitoverride fun onFailed(_) = Unitoverride fun onDisconnected() = Unit})
}// Wi-Fi P2P初始化(依赖蓝牙)
fun initWifi() {if (CxrApi.getInstance().isBluetoothConnected) {CxrApi.getInstance().initWifiP2P(object : WifiP2PStatusCallback {override fun onConnected() = Unitoverride fun onFailed(_) = Unitoverride fun onDisconnected() = Unit})}
}

2. 实时音视频传输

音频支持 PCM/Opus 编码,蓝牙传输;视频固定 30fps,先存后传。按带宽分层传输,用回调控延迟,适配不同场景需求。

核心代码示例

import com.rokid.cxr.api.CxrApi
import com.rokid.cxr.callback.AudioStreamListener
import com.rokid.cxr.util.ValueUtil// 音频采集(PCM编码)
fun startAudioCollect() {if (CxrApi.getInstance().isBluetoothConnected) {CxrApi.getInstance().setAudioStreamListener(object : AudioStreamListener {override fun onAudioStream(data: ByteArray?, o: Int, l: Int) {data?.copyOfRange(o, o + l)?.let { /* 传ASR */ }}override fun onStartAudioStream(_, _) = Unit})CxrApi.getInstance().openAudioRecord(1, "AI_assistant")}
}// 视频参数配置
fun setVideoParams() {CxrApi.getInstance().setVideoParams(5, 30, 1920, 1080, 1)CxrApi.getInstance().controlScene(ValueUtil.CxrSceneType.VIDEO_RECORD, true, null)
}

3. 数据同步与场景管理

蓝牙查未同步媒体数,Wi-Fi 传文件;场景分四类,用controlScene()启停,专属接口配参,回调监状态。

核心代码示例

import com.rokid.cxr.api.CxrApi
import com.rokid.cxr.callback.{SyncStatusCallback, SendStatusCallback}
import com.rokid.cxr.util.ValueUtil// 媒体同步
fun syncMedia(savePath: String) {if (CxrApi.getInstance().isWifiP2PConnected) {CxrApi.getInstance().startSync(savePath, arrayOf(ValueUtil.CxrMediaType.ALL), object : SyncStatusCallback {override fun onSyncStart() = Unitoverride fun onSingleFileSynced(_) = Unitoverride fun onSyncFailed() = Unitoverride fun onSyncFinished() = Unit})}
}// 提词器场景控制
fun controlWordTips(open: Boolean, content: String) {CxrApi.getInstance().controlScene(ValueUtil.CxrSceneType.WORD_TIPS, open, null)if (open) CxrApi.getInstance().sendStream(ValueUtil.CxrStreamType.WORD_TIPS, content.toByteArray(), "tips.txt", object : SendStatusCallback {override fun onSendSucceed() = Unitoverride fun onSendFailed(_) = Unit})
}

三、应用实践:基于 Rokid CXR-M SDK 实现手机与眼镜的语音协同交互解析

在工业巡检、远程协助等 AR 场景中,工程师佩戴 Rokid Glasses 时,“双手解放 + 无屏幕交互” 的需求对语音控制提出强依赖 —— 需通过自然语音完成 “唤醒响应、指令下发、结果反馈”。传统方案或旧 SDK 存在 “本地唤醒抗噪弱、语音传输延迟高” 等问题,而 Rokid CXR-M SDK(仅 Android 端)通过 “眼镜语音采集→手机端处理→指令 / 反馈回传” 的协同架构,完美解决该痛点。

1、场景定义与 SDK 语音能力适配

1.1 核心场景

针对 Rokid Glasses 的 “解放双手” 交互需求,设计以下语音协同场景:

  • 场景 1:眼镜端拾音→手机端识别:用户通过自然语音发起操作需求,眼镜内置麦克风激活拾音,CXR-M SDK 将音频流实时传输至手机端,支持边采集边传输,断连后可从眼镜端拉取完整音频文件

  • 场景 2:语音指令控制:手机解析 ASR 结果后,生成控制指令,通过 CXR-M SDK 下发至眼镜执行;

  • 场景 3:语音反馈播放:眼镜执行指令后,手机端生成语音合成(TTS)数据,下发至眼镜端播放,形成交互闭环。

1.2 CXR-M SDK 语音相关能力

根据官方文档,CXR-M SDK 支持以下语音核心能力,为场景落地提供基础:

  • 眼镜端实时音频采集(支持 16kHz/16bit 单声道 PCM 格式);

  • 双向音频数据传输(低延迟,满足语音实时交互需求,延迟≤100ms);

  • 眼镜端音频播放(支持 PCM 音频流解码,用于播放手机下发的 TTS 反馈)。

2.1 环境与依赖

2.1.1 基础环境要求

  • 操作系统:Android 9.0(API 28)及以上

  • 开发工具:Android Studio 4.0+

  • 硬件:Rokid Glasses、Android 手机(支持蓝牙 5.0+、Wi-Fi Direct)

2.1.2 SDK 导入

CXR-M SDK 采用 Maven 在线管理,需按官方文档配置仓库与依赖:

// 1. 项目级settings.gradle.kts(配置官方Maven仓库)
pluginManagement {repositories {google {content {includeGroupByRegex("com\.android.*")includeGroupByRegex("com\.google.*")includeGroupByRegex("androidx.*")}}mavenCentral()gradlePluginPortal()}
}dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositories {// 官方CXR-M SDK Maven仓库(必须配置)maven { url = uri("https://maven.rokid.com/repository/maven-public/") }google()mavenCentral()}
}// 2. 应用级build.gradle.kts(导入依赖,版本与官方一致)
android {defaultConfig {ndk {abiFilters "armeabi-v7a", "arm64-v8a" // 官方支持的架构}minSdk = 28 // 严格遵循官方最低版本要求}
}dependencies {// 核心:CXR-M SDK官方依赖(版本号与官方文档一致)implementation("com.rokid.cxr:client-m:1.0.1-20250812.080117-2")// 官方推荐的第三方依赖(避免版本冲突,需与SDK依赖一致)implementation("com.squareup.retrofit2:retrofit:2.9.0")implementation("com.squareup.retrofit2:converter-gson:2.9.0")implementation("com.squareup.okhttp3:okhttp:4.9.3")implementation("org.jetbrains.kotlin:kotlin-stdlib:2.1.0")implementation("com.squareup.okio:okio:2.8.0")implementation("com.google.code.gson:gson:2.10.1")// 基础依赖(官方示例包含)implementation("androidx.appcompat:appcompat:1.6.1")implementation("com.google.android.material:material:1.12.0")
}

2.2 权限配置

2.2.1 声明权限(AndroidManifest.xml)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><!-- 1. 蓝牙相关权限(文档“权限申请”章节核心,语音传输主通道) --><uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /><uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /><uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /><!-- 2. 定位权限(文档强制要求:蓝牙扫描需同步申请,用于设备发现) --><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><!-- 蓝牙扫描无需关联定位(避免用户误解定位用途) --><uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" tools:targetApi="s" /><!-- 3. 网络/Wi-Fi权限(文档“最小权限集”包含,用于网络状态管理+大文件同步) --><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 原配置缺失,文档必需 --><uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <!-- 原配置缺失,文档必需 --><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /><!-- 4. 语音采集权限(文档“录音功能”隐含要求,用于眼镜端语音转发至手机) --><uses-permission android:name="android.permission.RECORD_AUDIO" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.VoiceCooperate"><!-- 声明主Activity(需替换为实际Activity路径) --><activityandroid:name=".VoiceCooperateActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

2.2.2 动态申请权限

import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.MutableLiveData
import com.rokid.cxr.client.CxrApiclass VoiceCooperateActivity : AppCompatActivity() {companion object {const val REQUEST_CODE_PERMISSIONS = 100/*** 动态申请权限列表(严格按文档“必需权限”+ Android版本拆分)* - 无需动态申请BLUETOOTH/BLUETOOTH_ADMIN,仅需SCAN/CONNECT* - 需动态申请BLUETOOTH/BLUETOOTH_ADMIN + 定位 + 录音*/private val REQUIRED_PERMISSIONS: Array<String>get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.RECORD_AUDIO,          Manifest.permission.BLUETOOTH_SCAN,        Manifest.permission.BLUETOOTH_CONNECT      )} else {arrayOf(Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.RECORD_AUDIO,Manifest.permission.BLUETOOTH,          Manifest.permission.BLUETOOTH_ADMIN     )}}// 权限申请结果监听(用于触发SDK初始化)private val permissionGranted = MutableLiveData<Boolean?>(null)// CXR-M SDK核心实例(文档推荐单例模式)private val cxrApi by lazy { CxrApi.getInstance() }override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_voice_cooperate)// 步骤1:先检查是否已授予所有必需权限(避免重复申请,提升用户体验)if (checkAllPermissionsGranted()) {permissionGranted.postValue(true)} else {// 步骤2:未授予则发起动态申请(文档推荐在onCreate中执行)requestPermissions(REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)}// 步骤3:监听权限结果,通过后初始化CXR-M SDK(文档要求:权限不足时SDK不可用)permissionGranted.observe(this) { isGranted ->when (isGranted) {true -> initCXRMSDK() // 权限通过,初始化SDKfalse -> {// 明确提示缺失权限,而非笼统提示(文档未明说,但符合场景需求)Toast.makeText(this,"必需权限未授予(定位/蓝牙/录音),无法使用语音协同功能",Toast.LENGTH_LONG).show()finish() // 权限不足,退出页面(文档隐含:权限不足SDK不可用)}null -> {} // 初始状态,无操作}}}/*** 检查是否已授予所有必需权限(文档未明说,但实际开发必需)*/private fun checkAllPermissionsGranted(): Boolean {return REQUIRED_PERMISSIONS.all {checkSelfPermission(it) == PackageManager.PERMISSION_GRANTED}}/*** 权限申请结果回调*/override fun onRequestPermissionsResult(requestCode: Int,permissions: Array<out String>,grantResults: IntArray) {super.onRequestPermissionsResult(requestCode, permissions, grantResults)if (requestCode == REQUEST_CODE_PERMISSIONS) {// 检查所有权限是否均授予val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }permissionGranted.postValue(allGranted)// 提示缺失的具体权限if (!allGranted) {val deniedPermissions = permissions.filterIndexed { index, _ ->grantResults[index] != PackageManager.PERMISSION_GRANTED}.joinToString("、")Toast.makeText(this,"以下权限被拒绝:$deniedPermissions,请在设置中手动授予",Toast.LENGTH_LONG).show()}}}/*** 初始化CXR-M SDK*/private fun initCXRMSDK() {// 此处可执行SDK初始化逻辑(如蓝牙扫描、录音初始化等,参考文档“设备连接”章节)Toast.makeText(this, "权限通过,CXR-M SDK初始化中...", Toast.LENGTH_SHORT).show()// 示例:初始化蓝牙辅助类(后续步骤,参考文档“Bluetooth连接”章节)// initBluetoothHelper()}override fun onDestroy() {super.onDestroy()// 销毁时反初始化SDK资源(如蓝牙、录音)cxrApi.deinitBluetooth()}
}

2.3核心语音协同功能实现

2.3.1 步骤 1:初始化 CXR-M SDK 与蓝牙连接

语音功能完全依赖蓝牙连接,需按 “权限检查→蓝牙扫描(官方 UUID 过滤)→初始化蓝牙→建立连接” 的官方流程执行,适配工业场景 “一次配对、多次复用” 需求(减少现场重复操作)。

import android.Manifest
import android.app.Activity
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import com.rokid.cxr.api.CxrApi
import com.rokid.cxr.callback.BluetoothStatusCallback
import com.rokid.cxr.util.ValueUtilclass RokidBluetoothInitializer(private val activity: Activity,private val onInitSuccess: (() -> Unit)? = null,private val onInitFailed: ((errorMsg: String) -> Unit)? = null
) {private val TAG = "RokidBtInit"// 蓝牙请求码private val REQUEST_ENABLE_BT = 1001// 权限请求码private val REQUEST_PERMISSIONS = 1002// Rokid眼镜蓝牙服务UUID(用于过滤设备)private val ROKID_GLASSES_UUID = "00009100-0000-1000-8000-00805f9b34fb"// 已发现的Rokid眼镜设备private var targetGlassesDevice: BluetoothDevice? = null/*** 启动初始化流程:权限检查 → 蓝牙开启 → 设备扫描 → SDK蓝牙初始化*/fun startInit() {if (checkPermissions()) {checkBluetoothEnable()} else {requestPermissions()}}/*** 检查必要权限(蓝牙+定位)*/private fun checkPermissions(): Boolean {val requiredPermissions = mutableListOf(Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.BLUETOOTH,Manifest.permission.BLUETOOTH_ADMIN).apply {// Android 12及以上需额外申请蓝牙扫描/连接权限if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {add(Manifest.permission.BLUETOOTH_SCAN)add(Manifest.permission.BLUETOOTH_CONNECT)}}return requiredPermissions.all {activity.checkSelfPermission(it) == PackageManager.PERMISSION_GRANTED}}/*** 请求必要权限*/private fun requestPermissions() {val requiredPermissions = mutableListOf(Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.BLUETOOTH,Manifest.permission.BLUETOOTH_ADMIN).apply {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {add(Manifest.permission.BLUETOOTH_SCAN)add(Manifest.permission.BLUETOOTH_CONNECT)}}.toTypedArray()activity.requestPermissions(requiredPermissions, REQUEST_PERMISSIONS)}/*** 检查蓝牙是否开启,未开启则请求开启*/private fun checkBluetoothEnable() {val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()if (bluetoothAdapter == null) {onInitFailed?.invoke("设备不支持蓝牙")return}if (!bluetoothAdapter.isEnabled) {val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)activity.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT)} else {scanRokidGlasses(bluetoothAdapter)}}/*** 扫描Rokid眼镜设备(通过UUID过滤)*/private fun scanRokidGlasses(bluetoothAdapter: BluetoothAdapter) {Log.d(TAG, "开始扫描Rokid眼镜...")// 先检查已配对设备(避免重复扫描)val bondedDevices = bluetoothAdapter.bondedDevicesfor (device in bondedDevices) {if (device.name?.contains("Glasses") == true) {targetGlassesDevice = deviceinitSdkBluetooth(device)return}}// 未找到已配对设备,启动蓝牙扫描(需结合官方BluetoothHelper,此处简化)val bluetoothHelper = BluetoothHelper(context = activity,initStatus = {},deviceFound = {// 从扫描结果中获取第一个Rokid眼镜设备val device = bluetoothHelper.scanResultMap.values.firstOrNull {it.name?.contains("Glasses") == true}if (device != null) {targetGlassesDevice = devicebluetoothHelper.stopScan() // 找到设备后停止扫描initSdkBluetooth(device)}})bluetoothHelper.checkPermissions()bluetoothHelper.startScan()}/*** 初始化SDK蓝牙连接(核心步骤)*/private fun initSdkBluetooth(device: BluetoothDevice) {Log.d(TAG, "初始化SDK蓝牙连接,设备名:${device.name},MAC:${device.address}")CxrApi.getInstance().initBluetooth(context = activity.applicationContext,device = device,callback = object : BluetoothStatusCallback {// 连接信息回调(获取UUID和MAC,用于后续连接)override fun onConnectionInfo(socketUuid: String?,macAddress: String?,rokidAccount: String?,glassesType: Int) {Log.d(TAG, "获取连接信息:UUID=$socketUuid,MAC=$macAddress,眼镜类型=$glassesType")if (socketUuid.isNullOrEmpty() || macAddress.isNullOrEmpty()) {onInitFailed?.invoke("获取连接信息失败,UUID或MAC为空")return}// 调用SDK连接接口建立蓝牙连接connectToGlasses(socketUuid, macAddress)}// 蓝牙连接成功回调override fun onConnected() {Log.d(TAG, "蓝牙连接成功")onInitSuccess?.invoke()}// 蓝牙断开回调override fun onDisconnected() {Log.w(TAG, "蓝牙连接断开")onInitFailed?.invoke("蓝牙连接已断开")}// 连接失败回调override fun onFailed(errorCode: ValueUtil.CxrBluetoothErrorCode?) {val errorMsg = when (errorCode) {ValueUtil.CxrBluetoothErrorCode.PARAM_INVALID -> "参数无效"ValueUtil.CxrBluetoothErrorCode.BLE_CONNECT_FAILED -> "BLE连接失败"ValueUtil.CxrBluetoothErrorCode.SOCKET_CONNECT_FAILED -> "Socket连接失败"else -> "未知错误(错误码:$errorCode)"}Log.e(TAG, "蓝牙初始化失败:$errorMsg")onInitFailed?.invoke(errorMsg)}})}/*** 建立SDK蓝牙连接*/private fun connectToGlasses(socketUuid: String, macAddress: String) {CxrApi.getInstance().connectBluetooth(context = activity.applicationContext,socketUuid = socketUuid,macAddress = macAddress,callback = object : BluetoothStatusCallback {override fun onConnected() {Log.d(TAG, "SDK蓝牙连接确认成功")}override fun onDisconnected() {Log.w(TAG, "SDK蓝牙连接断开")}override fun onFailed(errorCode: ValueUtil.CxrBluetoothErrorCode?) {val errorMsg = when (errorCode) {ValueUtil.CxrBluetoothErrorCode.PARAM_INVALID -> "连接参数无效"ValueUtil.CxrBluetoothErrorCode.BLE_CONNECT_FAILED -> "BLE连接失败"ValueUtil.CxrBluetoothErrorCode.SOCKET_CONNECT_FAILED -> "Socket连接失败"else -> "连接失败(错误码:$errorCode)"}onInitFailed?.invoke(errorMsg)}override fun onConnectionInfo(socketUuid: String?,macAddress: String?,rokidAccount: String?,glassesType: Int) {// 连接信息已在init阶段获取,此处可忽略}})}/*** 权限请求结果回调(需在Activity中调用)*/fun onRequestPermissionsResult(grantResults: IntArray): Boolean {val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }if (allGranted) {checkBluetoothEnable()return true} else {onInitFailed?.invoke("部分权限被拒绝,无法初始化蓝牙")return false}}/*** 蓝牙开启请求结果回调(需在Activity中调用)*/fun onActivityResult(requestCode: Int, resultCode: Int): Boolean {if (requestCode == REQUEST_ENABLE_BT) {if (resultCode == Activity.RESULT_OK) {scanRokidGlasses(BluetoothAdapter.getDefaultAdapter())return true} else {onInitFailed?.invoke("用户拒绝开启蓝牙")return false}}return false}/*** 反初始化蓝牙(应用退出时调用)*/fun deinit() {CxrApi.getInstance().deinitBluetooth()Log.d(TAG, "蓝牙反初始化完成")}
}

核心代码解析

  1. 初始化流程逻辑:采用 “权限检查→蓝牙开启→设备扫描→SDK 初始化→连接建立” 的线性流程,确保每一步依赖前置条件满足。

  2. 关键函数说明

    • startInit():初始化入口,触发整个流程;

    • scanRokidGlasses():通过 UUID 过滤 Rokid 眼镜设备,优先检查已配对设备(减少扫描耗时);

    • initSdkBluetooth():调用 SDK 核心接口CxrApi.initBluetooth(),通过BluetoothStatusCallback监听连接状态;

    • connectToGlasses():基于onConnectionInfo回调的 UUID 和 MAC,调用CxrApi.connectBluetooth()完成最终连接。

2.3.2 步骤 2:眼镜端语音采集→手机端 ASR 识别

通过 SDK 的AudioStreamListener监听眼镜端录音数据流,将 PCM/Opus 格式的音频数据传输到手机端,再调用第三方 ASR 接口(如百度、讯飞)完成语音识别,最终得到文本结果。

import android.content.Context
import android.util.Log
import com.rokid.cxr.api.CxrApi
import com.rokid.cxr.callback.AudioStreamListener
import com.rokid.cxr.util.ValueUtilclass RokidVoiceCollector(private val context: Context,private val onAsrResult: ((text: String) -> Unit)? = null,private val onError: ((errorMsg: String) -> Unit)? = null
) {private val TAG = "RokidVoiceCollector"// 录音流类型(与眼镜端AI助手关联)private val STREAM_TYPE = "AI_assistant"// 音频编码类型:1=PCM,2=Opus(此处选择PCM,便于ASR处理)private val CODEC_TYPE = 1// 第三方ASR客户端(需自行集成,此处以示例形式存在)private val asrClient = ThirdPartyAsrClient(onResult = { asrText -> onAsrResult?.invoke(asrText) },onError = { errorMsg -> onError?.invoke(errorMsg) })/*** 启动语音采集(需在蓝牙连接成功后调用)*/fun startCollect(): Boolean {// 1. 检查蓝牙连接状态if (!CxrApi.getInstance().isBluetoothConnected) {onError?.invoke("蓝牙未连接,无法启动语音采集")return false}// 2. 设置音频流监听器(接收眼镜端录音数据)CxrApi.getInstance().setAudioStreamListener(object : AudioStreamListener {// 录音流开始回调override fun onStartAudioStream(codecType: Int, streamType: String?) {Log.d(TAG, "语音采集开始,编码类型:$codecType,流类型:$streamType")// 初始化ASR客户端(传入音频参数:PCM、16kHz、单声道等)asrClient.init(sampleRate = 16000,channelCount = 1,bitDepth = 16,codecType = codecType)}// 录音数据流回调(核心:接收音频数据并传给ASR)override fun onAudioStream(data: ByteArray?, offset: Int, length: Int) {if (data == null || length <= 0) {Log.w(TAG, "接收空音频数据,忽略")return}Log.d(TAG, "接收音频数据:长度=$length 字节")// 将音频数据传给ASR客户端(需截取有效数据:从offset开始,长度为length)val validData = data.copyOfRange(offset, offset + length)asrClient.sendAudioData(validData)}// 录音流结束回调(SDK未明确定义,需结合业务触发停止)// 注:实际场景中可通过“长按眼镜AI键”或“手机端停止按钮”触发停止})// 3. 调用SDK接口开启录音val status = CxrApi.getInstance().openAudioRecord(CODEC_TYPE, STREAM_TYPE)return if (status == ValueUtil.CxrStatus.REQUEST_SUCCEED) {Log.d(TAG, "语音采集启动成功")true} else {val errorMsg = when (status) {ValueUtil.CxrStatus.REQUEST_WAITING -> "录音请求等待中,请勿重复调用"ValueUtil.CxrStatus.REQUEST_FAILED -> "录音请求失败"else -> "未知状态:$status"}onError?.invoke(errorMsg)false}}/*** 停止语音采集*/fun stopCollect() {// 1. 停止ASR识别asrClient.stop()// 2. 调用SDK接口关闭录音val status = CxrApi.getInstance().closeAudioRecord(STREAM_TYPE)if (status == ValueUtil.CxrStatus.REQUEST_SUCCEED) {Log.d(TAG, "语音采集停止成功")} else {Log.e(TAG, "语音采集停止失败,状态:$status")}// 3. 移除音频流监听器CxrApi.getInstance().setAudioStreamListener(null)}/*** 第三方ASR客户端(示例类,需替换为实际ASR SDK)*/private class ThirdPartyAsrClient(private val onResult: ((text: String) -> Unit)?,private val onError: ((errorMsg: String) -> Unit)?) {/*** 初始化ASR(传入音频参数)*/fun init(sampleRate: Int, channelCount: Int, bitDepth: Int, codecType: Int) {// 实际ASR初始化逻辑(如百度ASR的init方法)Log.d("AsrClient", "初始化ASR:采样率=$sampleRate,声道数=$channelCount")}/*** 发送音频数据给ASR*/fun sendAudioData(data: ByteArray) {// 实际ASR发送数据逻辑(如百度ASR的send方法)Log.d("AsrClient", "发送音频数据:长度=${data.size} 字节")}/*** 停止ASR并获取结果*/fun stop() {// 实际ASR停止逻辑,此处模拟返回识别结果val mockResult = "打开提词器并显示欢迎文本" // 模拟ASR识别结果onResult?.invoke(mockResult)Log.d("AsrClient", "ASR识别完成,结果:$mockResult")}}
}

核心代码解析

  1. 核心流程

    • 启动采集:startCollect()→检查蓝牙连接→设置AudioStreamListener→调用openAudioRecord()开启录音;

    • 数据传输:onAudioStream()回调接收眼镜端音频数据→截取有效数据→传给第三方 ASR;

    • 停止采集:stopCollect()→停止 ASR→调用closeAudioRecord()关闭录音→移除监听器。

  2. 关键参数说明

    • STREAM_TYPE = "AI_assistant":与眼镜端 AI 助手服务关联,确保录音数据来自正确的音频流;

    • CODEC_TYPE = 1:选择 PCM 编码(无压缩),避免 Opus 解码复杂度过高,适合 ASR 直接处理;

    • asrClient:第三方 ASR 客户端示例,实际需集成百度、讯飞等 ASR SDK,传入正确的音频参数(采样率 16kHz、单声道、16bit 位深)。

2.3.3 步骤 3:语音指令下发→眼镜执行 + TTS 反馈

对 ASR 识别结果进行语义解析,提取指令类型(如 “打开提词器”“设置亮度”),调用 SDK 对应接口下发指令到眼镜执行;执行完成后,通过 SDK 的sendTtsContent()接口将 TTS 文本发送到眼镜,由眼镜端播放语音反馈。

import android.util.Log
import com.rokid.cxr.api.CxrApi
import com.rokid.cxr.util.ValueUtilclass RokidVoiceCommandExecutor(private val onCommandExecuted: ((success: Boolean, feedback: String) -> Unit)? = null
) {private val TAG = "RokidCommandExecutor"// 提词器默认文本(Base64编码,实际需根据需求生成)private val DEFAULT_WORD_TIPS_TEXT = "欢迎使用Rokid眼镜语音协同功能".toByteArray()// 提词器文件名(用于SDK识别数据类型)private val WORD_TIPS_FILE_NAME = "welcome_tips.txt"/*** 解析ASR结果并执行对应指令*/fun executeCommand(asrText: String) {// 1. 检查蓝牙连接状态if (!CxrApi.getInstance().isBluetoothConnected) {val feedback = "蓝牙未连接,无法执行指令"onCommandExecuted?.invoke(false, feedback)sendTtsFeedback(feedback)return}// 2. 语义解析:提取指令类型(实际需用NLP优化,此处简化匹配)when {asrText.contains("打开提词器") -> {executeOpenWordTips(asrText)}asrText.contains("设置亮度") -> {// 提取亮度值(如“设置亮度为10”)val brightness = extractBrightness(asrText)if (brightness != null) {executeSetBrightness(brightness)} else {val feedback = "未识别到亮度值,请重新指令"onCommandExecuted?.invoke(false, feedback)sendTtsFeedback(feedback)}}asrText.contains("关闭提词器") -> {executeCloseWordTips()}else -> {val feedback = "未识别指令:$asrText"onCommandExecuted?.invoke(false, feedback)sendTtsFeedback(feedback)}}}/*** 执行“打开提词器”指令*/private fun executeOpenWordTips(asrText: String) {// 步骤1:打开提词器场景val openStatus = CxrApi.getInstance().controlScene(sceneType = ValueUtil.CxrSceneType.WORD_TIPS,openOrClose = true,otherParams = null)if (openStatus != ValueUtil.CxrStatus.REQUEST_SUCCEED) {val feedback = "打开提词器失败,状态:$openStatus"onCommandExecuted?.invoke(false, feedback)sendTtsFeedback(feedback)return}// 步骤2:发送提词器文本(如从ASR中提取自定义文本,此处用默认文本)val sendStatus = CxrApi.getInstance().sendStream(type = ValueUtil.CxrStreamType.WORD_TIPS,stream = DEFAULT_WORD_TIPS_TEXT,fileName = WORD_TIPS_FILE_NAME,cb = object : com.rokid.cxr.callback.SendStatusCallback {override fun onSendSucceed() {val feedback = "提词器已打开,显示欢迎文本"onCommandExecuted?.invoke(true, feedback)sendTtsFeedback(feedback)}override fun onSendFailed(errorCode: ValueUtil.CxrSendErrorCode?) {val feedback = "提词器文本发送失败,错误码:$errorCode"onCommandExecuted?.invoke(false, feedback)sendTtsFeedback(feedback)}})if (sendStatus != ValueUtil.CxrStatus.REQUEST_SUCCEED) {val feedback = "提词器文本发送请求失败,状态:$sendStatus"onCommandExecuted?.invoke(false, feedback)sendTtsFeedback(feedback)}}/*** 执行“设置亮度”指令(亮度范围0-15)*/private fun executeSetBrightness(brightness: Int) {if (brightness < 0 || brightness > 15) {val feedback = "亮度值需在0-15之间,当前值:$brightness"onCommandExecuted?.invoke(false, feedback)sendTtsFeedback(feedback)return}val status = CxrApi.getInstance().setGlassBrightness(brightness)if (status == ValueUtil.CxrStatus.REQUEST_SUCCEED) {val feedback = "亮度已设置为$brightness"onCommandExecuted?.invoke(true, feedback)sendTtsFeedback(feedback)} else {val feedback = "亮度设置失败,状态:$status"onCommandExecuted?.invoke(false, feedback)sendTtsFeedback(feedback)}}/*** 执行“关闭提词器”指令*/private fun executeCloseWordTips() {val status = CxrApi.getInstance().controlScene(sceneType = ValueUtil.CxrSceneType.WORD_TIPS,openOrClose = false,otherParams = null)if (status == ValueUtil.CxrStatus.REQUEST_SUCCEED) {val feedback = "提词器已关闭"onCommandExecuted?.invoke(true, feedback)sendTtsFeedback(feedback)} else {val feedback = "提词器关闭失败,状态:$status"onCommandExecuted?.invoke(false, feedback)sendTtsFeedback(feedback)}}/*** 发送TTS反馈到眼镜端(由眼镜播放语音)*/private fun sendTtsFeedback(feedbackText: String) {Log.d(TAG, "发送TTS反馈:$feedbackText")val status = CxrApi.getInstance().sendTtsContent(feedbackText)if (status != ValueUtil.CxrStatus.REQUEST_SUCCEED) {Log.e(TAG, "TTS反馈发送失败,状态:$status")} else {// 通知眼镜TTS播放结束(可选,根据业务需求)CxrApi.getInstance().notifyTtsAudioFinished()}}/*** 从ASR文本中提取亮度值(简单正则匹配)*/private fun extractBrightness(asrText: String): Int? {val regex = Regex("亮度(为|设置为)?(\d+)")val matchResult = regex.find(asrText)return matchResult?.groupValues?.get(2)?.toIntOrNull()}
}
核心代码解析
  1. 执行流程

    • 语义解析:executeCommand()通过关键词匹配(如 “打开提词器”“设置亮度”)提取指令类型;

    • 指令执行:

      • 打开提词器:executeOpenWordTips()→调用controlScene()打开场景→sendStream()发送提词器文本;

      • 设置亮度:executeSetBrightness()→提取亮度值(0-15)→调用setGlassBrightness()设置亮度;

    • TTS 反馈:sendTtsFeedback()→调用sendTtsContent()将反馈文本发送到眼镜,由眼镜端播放语音。

  2. 关键接口说明

    • controlScene():控制眼镜场景(打开 / 关闭提词器、录像等),sceneType需指定为ValueUtil.CxrSceneType.WORD_TIPS

    • sendStream():发送提词器文本数据,type需指定为ValueUtil.CxrStreamType.WORD_TIPS,确保眼镜端识别为提词器内容;

    • sendTtsContent():发送 TTS 文本到眼镜,支持中文语音播放,需配合notifyTtsAudioFinished()通知播放结束。

2.4 核心总结

  1. 初始化阶段:手机通过蓝牙扫描并连接 Rokid 眼镜,完成 SDK 初始化,为后续数据传输奠定基础;

  2. 语音采集与识别阶段:眼镜端启动录音,通过AudioStreamListener将音频数据传输到手机端,第三方 ASR 将音频转为文本;

  3. 指令执行与反馈阶段:解析 ASR 文本得到指令,调用 SDK 接口下发到眼镜执行,同时通过 TTS 将执行结果反馈给用户。

  4. 实用价值

    • 解放双手:用户无需操作手机,通过语音指令控制眼镜(如打开提词器、拍照、设置亮度),适合工业巡检、医疗会诊等场景;

    • 远程协同:手机端可实时获取眼镜端音频数据,结合 ASR 和 TTS 实现远程指导(如工程师通过语音指导现场人员操作)。

四、总结与展望

Rokid CXR-M SDK为开发者提供了丰富而强大的功能,使得手机与AR眼镜之间的协同交互变得前所未有的便捷与高效。通过深入了解SDK的核心技术原理与功能,开发者能够更好地利用这些功能,开发出满足用户需求的AR应用。未来,随着AR技术的不断发展和普及,Rokid CXR-M SDK将继续迭代优化,为开发者提供更多元数据通信、实时音视频处理等高级功能,进一步拓展AR眼镜在工业巡检、远程协助等场景中的应用。

同时,期待Rokid CXR-M SDK能够在未来支持更多设备类型、提供更丰富的API接口以及更广泛的开发者工具集,助力AR眼镜在工业领域发挥更大的价值。

http://www.dtcms.com/a/486808.html

相关文章:

  • 川崎焊接机器人弧焊气体节约
  • 做网站横幅价格wordpress 36kr
  • Java-Spring入门指南(二十六)Android Studio下载与安装
  • 14.C 语言实现一个迷你 Shell
  • 【理解React Hooks与JavaScript类型系统】
  • 如何使用PyTorch高效实现张量的批量归一化原理与代码实战
  • 文心快码Comate3.5S更新,用多智能体协同做个健康管理应用
  • 江苏赛孚建设工程有限公司网站做php门户网站那个系统好
  • OpenCV5-图像特征harris-sift-特征匹配-图像全景拼接-答题卡识别判卷
  • 计算机网络经典问题透视:以太网发送512bit后,碰撞还可能发生吗?
  • 免费网站管理系统昌邑建设网站
  • 初始Spring
  • wordpress站点标题看不到合肥建站企业
  • 网站空间哪家公司的好上海专业网站建设价
  • 考研数学笔记(概率统计篇)
  • HT6809:重塑音频体验的立体声 D 类功率放大器
  • Flutter对话框AlertDialog使用指南
  • 玩Android Flutter版本,通过项目了解Flutter项目快速搭建开发
  • 大数据毕业设计选题推荐-基于大数据的商店购物趋势分析与可视化系统-大数据-Spark-Hadoop-Bigdata
  • 网站标题符号的应用龙岩整站优化
  • 运维知识图谱的构建与应用
  • MySQL中RUNCATE、DELETE、DROP 的基本介绍
  • php企业网站 源码asp网站耗资源
  • 【LeetCode】四数之和
  • 网站进不去怎么解决网络营销策略
  • 旗讯 OCR:破解全行业表格处理痛点,让数据从 “识别” 到 “可用” 一步到位
  • 测试开发笔试
  • 数据库的创建,查看,修改,删除,字符集编码和校验操作
  • C语言初步学习:数组的增删查改
  • 【组队学习】Post-training-of-LLMs TASK02