Nachdem Sie die erforderlichen Berechtigungen angefordert und erhalten haben, kann Ihre App auf die Hardware der Audio- oder Displaybrille zugreifen. Der Schlüssel für den Zugriff auf die Hardware der Brille (anstelle der Hardware des Smartphones) ist die Verwendung eines projizierten Kontexts.
Es gibt zwei Möglichkeiten, einen projizierten Kontext zu erhalten, je nachdem, wo Ihr Code ausgeführt wird:
Projizierten Kontext abrufen, wenn Ihr Code in einer projizierten Aktivität ausgeführt wird
Wenn der Code Ihrer App in einer projizierten Aktivität ausgeführt wird, ist der eigene Aktivitätskontext bereits ein projizierter Kontext. In diesem Fall können Aufrufe innerhalb dieser Aktivität bereits auf die Hardware der Brille zugreifen.
Projizierten Kontext für Code abrufen, der in einer Smartphone-App-Komponente ausgeführt wird
Wenn ein Teil Ihrer App außerhalb der projizierten Aktivität (z. B. eine Smartphone-Aktivität oder ein Dienst) auf die Hardware der Brille zugreifen muss, muss er explizit einen projizierten Kontext abrufen. Verwenden Sie dazu die
createProjectedDeviceContext Methode:
@OptIn(ExperimentalProjectedApi::class) private fun getGlassesContext(context: Context): Context? { return try { // From a phone Activity or Service, get a context for the AI glasses. ProjectedContext.createProjectedDeviceContext(context) } catch (e: IllegalStateException) { Log.e(TAG, "Failed to create projected device context", e) null } }
Gültigkeit prüfen
Umschließen Sie den createProjectedDeviceContext Aufruf mit dem
ProjectedContext.isProjectedDeviceConnected. Solange diese Methode true zurückgibt, bleibt der projizierte Kontext für das verbundene Gerät gültig und die Smartphone-App-Aktivität oder der Dienst (z. B. ein CameraManager) kann auf die Hardware der KI-Brille zugreifen.
Beim Trennen der Verbindung bereinigen
Der projizierte Kontext ist an den Lebenszyklus des verbundenen Geräts gebunden und wird daher zerstört, wenn die Verbindung zum Gerät getrennt wird. Wenn die Verbindung zum Gerät getrennt wird,
ProjectedContext.isProjectedDeviceConnected gibt false zurück. Ihre App sollte auf diese Änderung reagieren und alle Systemdienste (z. B. einen CameraManager) oder Ressourcen bereinigen, die Ihre App mit diesem projizierten Kontext erstellt hat.
Bei erneuter Verbindung neu initialisieren
Wenn die Verbindung zur Brille wiederhergestellt wird, kann Ihre App mit createProjectedDeviceContext eine weitere projizierte
Kontextinstanz abrufen und dann
alle Systemdienste oder Ressourcen mit dem neuen projizierten Kontext neu initialisieren.
Audio mit dem Mikrofon der Brille aufzeichnen
Sie können Audio mit der Brille auf zwei verschiedene Arten aufzeichnen:
- Projizierten Kontext verwenden.
- Bluetooth Hands-Free Profile (HFP) verwenden
Aufzeichnungsmethode auswählen
Die gewählte Methode hängt davon ab, ob Sie eine hochwertige, XR‑spezifische Audioverarbeitung oder eine standardmäßige Bluetooth-Audioeingabe benötigen.
| Aufzeichnungsmethode | Mikrofonzugriff | Häufiger Anwendungsfall |
|---|---|---|
Projizierter Kontext |
Mehrere Mikrofone |
Bei der Aufzeichnung mit einem projizierten Kontext kann Ihre App auf mehrere Mikrofone der Brille und ihre speziellen Hardwarefunktionen zugreifen, z. B.:
|
Bluetooth HFP |
Einzelnes Mikrofon |
Verwendet das Bluetooth Hands-Free Profile (HFP) für sofortige, sofort einsatzbereite Kompatibilität. In diesem Modus wird die Brille über die Standardprofile für Headsets und Advanced Audio Distribution Profile (A2DP) Profile mit dem Smartphone verbunden und fungiert wie ein typisches Bluetooth-Peripheriegerät. Wenn Ihre App bereits für die standardmäßige Bluetooth-Aufzeichnung entwickelt wurde, können Sie diese Methode verwenden, um Audio von der Brille aufzuzeichnen, ohne XR‑spezifische Funktionen zu integrieren. |
Audio mit einem projizierten Kontext aufzeichnen
Wenn Sie Audio mit einem projizierten Kontext aufzeichnen möchten, fordern Sie zuerst die erforderlichen Laufzeit
Berechtigungen an und zeichnen Sie dann das Audio mit der AudioRecord API auf, wie
in den folgenden Abschnitten beschrieben.
Laufzeitberechtigungen anfordern
Wenn Sie auf mehrere Mikrofone der Brille zugreifen möchten, müssen Sie Audioberechtigungen speziell für das projizierte Gerät anfordern. Die standardmäßige, auf das Smartphone beschränkte Berechtigung RECORD_AUDIO, die ein Nutzer Ihrer App auf seinem Mobilgerät erteilt hat, reicht nicht aus.
So fordern Sie die Berechtigungen an:
- Deklarieren Sie die Berechtigung
RECORD_AUDIOin der Manifestdatei Ihrer App. Fordern Sie die auf das projizierte Gerät beschränkten Berechtigungen auf eine der folgenden Arten an, je nachdem, wo Ihr Code ausgeführt wird:
- Code, der in einer projizierten Aktivität ausgeführt wird: Verwenden Sie
ActivityResultLaunchermit demProjectedPermissionsResultContract. Weitere Informationen zur Verwendung dieser Methode finden Sie im Abschnitt Berechtigungsstarter registrieren und in den nachfolgenden Abschnitten des Leitfadens zum Anfordern von Hardwareberechtigungen. - Code, der in einer Host-Smartphone-Aktivität ausgeführt wird: Verwenden Sie
Activity#requestPermissions(permissions, requestCode, deviceId)und geben Sie die Geräte-ID an, die Sie vonprojectedDeviceContexterhalten haben, wie im Abschnitt Nutzerablauf für Berechtigungsanfragen des Leitfadens zum Anfordern von Hardwareberechtigungen beschrieben.
- Code, der in einer projizierten Aktivität ausgeführt wird: Verwenden Sie
AudioRecord mit einem projizierten Kontext initialisieren
Damit Audio von der Brille und nicht vom Host-Smartphone aufgezeichnet wird, müssen Sie das AudioRecord-Objekt dem projizierten Gerätekontext zuordnen.
Im folgenden Code wird AudioRecord.Builder verwendet und
projectedDeviceContext an die Methode setContext übergeben:
// Initialize AudioRecord with projected device context val audioRecord = AudioRecord.Builder() .setAudioSource(MediaRecorder.AudioSource.CAMCORDER) .setAudioFormat(audioFormat) .setBufferSizeInBytes(bufferSize) // pass in the projected device context .setContext(projectedDeviceContext) .build() audioRecord.startRecording()
Wichtige Punkte zum Code
Sie können die Audioquelle auf
CAMCORDER,VOICE_RECOGNITION,VOICE_COMMUNICATIONoderUNPROCESSEDsetzen, um die Audioverarbeitung an Ihren spezifischen Anwendungsfall anzupassen.Verwenden Sie beispielsweise
VOICE_COMMUNICATION, wenn Ihr Anwendungsfall eine automatische Rauschunterdrückung erfordert.VOICE_RECOGNITIONwird mit der akustischen Echounterdrückung (AEC) verarbeitet. Wenn Sie rohes, unverändertes Audio benötigen, wählen SieUNPROCESSEDoderCAMCORDERaus.Um die Kompatibilität mit der Brille zu gewährleisten, muss das
audioFormatObjekt eine Abtastrate von 16 kHz und eine Kanalkonfiguration von Mono oder Stereo definieren (mitCHANNEL_IN_MONOoderCHANNEL_IN_STEREO).Verwenden Sie
AudioRecord.getMinBufferSize(), um die Mindestpuffer größe für die Erstellung desAudioRecordObjekts zu bestimmen. Um Audioausfälle von der Brille zu vermeiden, sollten Sie diesen Puffer jedoch in kurzen, häufigen Blöcken (idealerweise 20‑ms-Abschnitten) lesen, anstatt zu warten, bis der gesamte Puffer gefüllt ist.
Nach der Verwendung bereinigen
Wenn Ihre App das Mikrofon nicht mehr benötigt oder die Aktivität beendet wird,
rufen Sie stop und release für das AudioRecord Objekt auf.
Vor der Aufzeichnung Laufzeitberechtigungen prüfen
Bevor Sie startRecording aufrufen, prüfen Sie mit dem projizierten Kontext, ob der Nutzer die
Mikrofonberechtigung für die Brille erteilt hat.
Audio mit Bluetooth HFP aufzeichnen
Wenn Sie Audio mit Bluetooth HFP aufzeichnen möchten, fordern Sie zuerst die erforderlichen Laufzeit
berechtigungen an und zeichnen Sie dann das Audio mit der AudioManager API auf, wie
in den folgenden Abschnitten beschrieben.
Berechtigungen anfordern
Wie bei jedem standardmäßigen Bluetooth-Audiogerät werden die RECORD_AUDIO,
BLUETOOTH_CONNECT und andere zugehörige Berechtigungen vom
Smartphone und nicht vom verbundenen Gerät (z. B. Audio- oder Displaybrille) gesteuert.
So fordern Sie die Berechtigungen an:
Deklarieren Sie die folgenden Berechtigungen in der Manifestdatei Ihrer App:
Fordern Sie sowohl die Berechtigung
RECORD_AUDIOals auchBLUETOOTH_CONNECTzur Laufzeit mit dem standardmäßigen Android-Berechtigungsablauf an.
Audio mit AudioManager weiterleiten
Nachdem der Nutzer Ihrer App die erforderlichen Laufzeitberechtigungen erteilt hat, legen Sie mit der
AudioManager API das Kommunikationsgerät auf
TYPE_BLUETOOTH_SCO fest, um das Audio über Bluetooth HFP weiterzuleiten. Dadurch wird das System angewiesen, Audio vom Bluetooth-Peripheriegerät abzurufen.
val audioManager = context.getSystemService(AudioManager::class.java) ?: return val devices = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS) val hfpDevice = devices.find { it.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO } hfpDevice?.let { device -> val audioRecord = AudioRecord.Builder() .setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION) .setAudioFormat(audioFormat) .setBufferSizeInBytes(bufferSize) .build() // Route recording to the Bluetooth device audioRecord.setPreferredDevice(device) audioManager.setCommunicationDevice(device) audioRecord.startRecording()
Bild mit der Kamera der Brille aufnehmen
Wenn Sie ein Bild mit der Kamera der Brille aufnehmen möchten, richten Sie den CameraX‑
ImageCapture Anwendungsfall ein und binden Sie ihn an die Kamera der Brille. Verwenden Sie dazu den richtigen
Kontext für Ihre App:
private fun startCameraOnGlasses(activity: ComponentActivity) { // 1. Get the CameraProvider using the projected context. // When using the projected context, DEFAULT_BACK_CAMERA maps to the AI glasses' camera. val projectedContext = try { ProjectedContext.createProjectedDeviceContext(activity) } catch (e: IllegalStateException) { Log.e(TAG, "AI Glasses context could not be created", e) return } val cameraProviderFuture = ProcessCameraProvider.getInstance(projectedContext) cameraProviderFuture.addListener({ val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA // 2. Check for the presence of a camera. if (!cameraProvider.hasCamera(cameraSelector)) { Log.w(TAG, "The selected camera is not available.") return@addListener } // 3. Query supported streaming resolutions using Camera2 Interop. val cameraInfo = cameraProvider.getCameraInfo(cameraSelector) val camera2CameraInfo = Camera2CameraInfo.from(cameraInfo) val cameraCharacteristics = camera2CameraInfo.getCameraCharacteristic( CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP ) // 4. 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() // 5. 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, 60) val captureRequestOptions = CaptureRequestOptions.Builder() .setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange) .build() // 6. Initialize the ImageCapture use case with options. val imageCapture = ImageCapture.Builder() // Optional: Configure resolution, format, etc. .setResolutionSelector(resolutionSelector) .build() try { // Unbind use cases before rebinding. cameraProvider.unbindAll() // Bind use cases to camera using the Activity as the LifecycleOwner. cameraProvider.bindToLifecycle( activity, cameraSelector, imageCapture ) } catch (exc: Exception) { Log.e(TAG, "Use case binding failed", exc) } }, ContextCompat.getMainExecutor(activity)) }
Wichtige Punkte zum Code
- Ruft eine Instanz von
ProcessCameraProvidermit dem projizierten Gerätekontext ab. - Im Bereich des projizierten Kontexts wird die primäre, nach außen gerichtete Kamera der Brille beim Auswählen einer Kamera
DEFAULT_BACK_CAMERAzugeordnet. - Bei einer Vorbindungsprüfung wird mit
cameraProvider.hasCamera(cameraSelector)geprüft, ob die ausgewählte Kamera auf dem Gerät verfügbar ist, bevor fortgefahren wird. - Verwendet Camera2 Interop mit
Camera2CameraInfo, um die zugrunde liegendeCameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAPzu lesen. Dies kann für erweiterte Prüfungen der unterstützten Auflösungen nützlich sein. - Ein benutzerdefiniertes
ResolutionSelectorwird erstellt, um die Ausgabe bildauflösung fürImageCapturegenau zu steuern. - Erstellt einen
ImageCapture-Anwendungsfall, der mit einem benutzerdefiniertenResolutionSelectorkonfiguriert ist. - Bindet den
ImageCapture-Anwendungsfall an den Lebenszyklus der Aktivität. Dadurch wird das Öffnen und Schließen der Kamera automatisch anhand des Aktivitätsstatus verwaltet (z. B. wird die Kamera angehalten, wenn die Aktivität pausiert wird).
Nachdem die Kamera der Brille eingerichtet wurde, können Sie mit der ImageCapture-Klasse von CameraX ein Bild aufnehmen. Informationen zur Verwendung von takePicture zum Aufnehmen eines Bildes finden Sie in der CameraX's Dokumentation, um mehr zu erfahren.
Video mit der Kamera der Brille aufnehmen
Wenn Sie mit der Kamera der Brille ein Video anstelle eines Bildes aufnehmen möchten, ersetzen Sie die
ImageCapture Komponenten durch die entsprechenden VideoCapture Komponenten
und ändern Sie die Logik für die Aufnahmeausführung.
Die wichtigsten Änderungen sind die Verwendung eines anderen Anwendungsfalls, die Erstellung einer anderen Ausgabedatei und die Initiierung der Aufnahme mit der entsprechenden Videoaufzeichnungsmethode.
Weitere Informationen zur VideoCapture API und ihrer Verwendung finden Sie in der
Dokumentation zur Videoaufnahme von CameraX.
In der folgenden Tabelle sind die empfohlene Auflösung und Framerate je nach Anwendungsfall Ihrer App aufgeführt:
| Anwendungsfall | Auflösung | Frame rate |
|---|---|---|
| Videokommunikation | 1280 × 720 | 15 FPS |
| Computer Vision | 640 × 480 | 10 FPS |
| KI-Videostreaming | 640 × 480 | 1 FPS |
Von einer projizierten Aktivität auf die Hardware eines Smartphones zugreifen
Eine projizierte Aktivität kann auch auf die Hardware des Smartphones (z. B.
Kamera oder Mikrofon) zugreifen, indem sie mit createHostDeviceContext(context) den Kontext des Hostgeräts (Smartphone) abruft:
@OptIn(ExperimentalProjectedApi::class) private fun getPhoneContext(activity: ComponentActivity): Context? { return try { // From an AI glasses Activity, get a context for the phone. ProjectedContext.createHostDeviceContext(activity) } catch (e: IllegalStateException) { Log.e(TAG, "Failed to create host device context", e) null } }
Wenn Sie in einer Hybrid-App (einer App, die sowohl mobile als auch Brillen-Erlebnisse enthält) auf Hardware oder Ressourcen zugreifen, die spezifisch für das Hostgerät (Smartphone) sind, müssen Sie explizit den richtigen Kontext auswählen, damit Ihre App auf die richtige Hardware zugreifen kann:
- Verwenden Sie den
Activity-Kontext aus dem Smartphone-Activityoder demProjectedContext.createHostDeviceContext, um den Kontext des Smartphones abzurufen. - Verwenden Sie nicht
getApplicationContext, da der Anwendungskontext fälschlicherweise den Kontext der Brille zurückgeben kann, wenn eine projizierte Aktivität die zuletzt gestartete Komponente war.