请求并获得必要的权限后,您的应用便可访问 AI 眼镜硬件。访问眼镜硬件(而非手机硬件)的关键在于使用投影上下文。
获取投影上下文主要有两种方式,具体取决于代码的执行位置:
如果您的代码在 AI 眼镜 activity 中运行,则获取预测的上下文
如果您的应用代码是从 AI 眼镜 activity 中运行的,那么其自身的 activity 上下文已是投影上下文。在这种情况下,在该 activity 内进行的调用已可访问眼镜的硬件。
如果您的代码在手机应用组件中运行,则获取投影的上下文
如果应用中 AI 眼镜 activity 之外的部分(例如手机 activity 或服务)需要访问眼镜的硬件,则必须明确获取投影的 context。为此,请使用 createProjectedDeviceContext() 方法:
// From a phone Activity, get a context for the AI glasses
try {
val glassesContext = ProjectedContext.createProjectedDeviceContext(this)
// Now use glassesContext to access glasses' system services
} catch (e: IllegalStateException) {
// Projected device was not found
}
检查有效性
创建预测性上下文后,监控 ProjectedContext.isProjectedDeviceConnected。虽然此方法返回 true,但投影的上下文对已连接的设备仍然有效,并且手机应用 activity 或服务(例如 CameraManager)可以访问 AI 眼镜硬件。
断开连接时清理
投影的上下文与所连接设备的生命周期相关联,因此会在设备断开连接时被销毁。当设备断开连接时,ProjectedContext.isProjectedDeviceConnected 会返回 false。您的应用应监听此更改,并清理使用该投影上下文创建的任何系统服务(例如 CameraManager)或资源。
重新连接时重新初始化
当 AI 眼镜设备重新连接时,您的应用可以使用 createProjectedDeviceContext() 获取另一个投影的上下文实例,然后使用新的投影上下文重新初始化任何系统服务或资源。
使用蓝牙访问音频
目前,AI 眼镜会以标准蓝牙音频设备的形式连接到手机。同时支持耳机和 A2DP(高级音频分发配置文件)配置文件。通过这种方法,任何支持音频输入或输出的 Android 应用都可以在眼镜上运行,即使这些应用并非专门为支持眼镜而构建。在某些情况下,使用蓝牙可能比使用投影上下文访问眼镜的硬件更适合应用的用例。
与任何标准蓝牙音频设备一样,授予 RECORD_AUDIO 权限的权限由手机控制,而不是眼镜。
使用 AI 眼镜的摄像头拍摄图片
如需使用 AI 眼镜的相机拍摄照片,请使用应用的正确上下文设置 CameraX 的 ImageCapture 用例并将其绑定到眼镜的相机:
private fun startCamera() {
// Get the CameraProvider using the projected context.
val cameraProviderFuture = ProcessCameraProvider.getInstance(
ProjectedContext.createProjectedDeviceContext(this)
)
cameraProviderFuture.addListener({
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Select the camera. When using the projected context, DEFAULT_BACK_CAMERA maps to the AI glasses' camera.
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
// Check for the presence of a camera before initializing the ImageCapture use case.
if (!cameraProvider.hasCamera(cameraSelector)) {
Log.w(TAG, "The selected camera is not available.")
return@addListener
}
// Get supported streaming resolutions.
val cameraInfo = cameraProvider.getCameraInfo(cameraSelector)
val camera2CameraInfo = Camera2CameraInfo.from(cameraInfo)
val cameraCharacteristics = camera2CameraInfo.getCameraCharacteristic(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
// Define the resolution strategy.
val targetResolution = Size(1920, 1080)
val resolutionStrategy = ResolutionStrategy(
targetResolution,
ResolutionStrategy.FALLBACK_RULE_CLOSEST_LOWER)
val resolutionSelector = ResolutionSelector.Builder()
.setResolutionStrategy(resolutionStrategy)
.build()
// If you have other continuous use cases bound, such as Preview or ImageAnalysis, you can use Camera2 Interop's CaptureRequestOptions to set the FPS
val fpsRange = Range(30, 30)
val captureRequestOptions = CaptureRequestOptions.Builder()
.setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,fpsRange)
.build()
// Initialize the ImageCapture use case.
val imageCapture = ImageCapture.Builder()
// Optional: Configure resolution, format, etc.
.setResolutionSelector(resolutionSelector)
.build()
try {
// Unbind use cases before rebinding
cameraProvider.unbindAll()
// 4. Bind use cases to camera
cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, imageCapture)
} catch(exc: Exception) {
// This catches exceptions like IllegalStateException if use case binding fails
Log.e(TAG, "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(this))
}
代码要点
- 使用投影设备上下文获取
ProcessCameraProvider的实例。 - 在投影上下文的范围内,当选择摄像头时,AI 眼镜的主要向外摄像头会映射到
DEFAULT_BACK_CAMERA。 - 预绑定检查使用
cameraProvider.hasCamera(cameraSelector)来验证所选相机在设备上是否可用,然后再继续操作。 - 使用 Camera2 Interop 和
Camera2CameraInfo读取底层CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP,这对于对支持的分辨率进行高级检查非常有用。 - 我们构建了一个自定义
ResolutionSelector,以精确控制ImageCapture的输出图片分辨率。 - 创建配置了自定义
ResolutionSelector的ImageCapture使用情形。 - 将
ImageCapture用例绑定到 activity 的生命周期。它会根据 activity 的状态自动管理相机的打开和关闭(例如,在 activity 暂停时停止相机)。
设置好 AI 眼镜的摄像头后,您可以使用 CameraX 的 ImageCapture 类拍摄图片。请参阅 CameraX 的文档,了解如何使用 takePicture() 拍摄图片。
使用 AI 眼镜的摄像头拍摄视频
如需使用 AI 眼镜的摄像头拍摄视频而非图片,请将 ImageCapture 组件替换为相应的 VideoCapture 组件,并修改拍摄执行逻辑。
主要变化包括使用不同的使用情形、创建不同的输出文件,以及使用适当的视频录制方法来启动捕获。
如需详细了解 VideoCapture API 及其使用方法,请参阅 CameraX 的视频拍摄文档。
下表显示了建议的分辨率和帧速率,具体取决于应用的使用情形:
| 用例 | 分辨率 | 帧速率 |
|---|---|---|
| 视频通信 | 1280x720 | 15 FPS |
| 计算机视觉 | 640 x 480 | 10 FPS |
| AI 视频串流 | 640 x 480 | 1 FPS |
从 AI 眼镜 activity 访问手机的硬件
AI 眼镜活动还可以使用 createHostDeviceContext(context) 获取宿主设备(手机)的上下文,从而访问手机的硬件(例如摄像头或麦克风):
// From an AI glasses Activity, get a context for the phone
val phoneContext = ProjectedContext.createHostDeviceContext(this)
// Now use phoneContext to access the phone's hardware
在混合应用(同时包含移动设备和 AI 眼镜体验的应用)中访问主机设备(手机)特有的硬件或资源时,您必须明确选择正确的上下文,以确保应用可以访问正确的硬件:
- 使用手机中的
Activity上下文Activity或ProjectedContext.createHostDeviceContext()获取手机的上下文。 - 请勿使用
getApplicationContext(),因为如果眼镜 activity 是最近启动的组件,应用上下文可能会错误地返回 AI 眼镜的上下文。