Ses gözlüklerindeki ve ekran gözlüklerindeki donanıma erişmek için yansıtılan bağlamı kullanma

Uygun XR cihazlar
Bu kılavuz, bu tür XR cihazlar için deneyimler oluşturmanıza yardımcı olur.
Ses ve
Ekran Gözlükleri

Gerekli izinleri isteyip aldıktan sonra uygulamanız, ses gözlüklerindeki veya ekran gözlüklerindeki donanıma erişebilir. Gözlüğün donanımına (telefonun donanımı yerine) erişmenin anahtarı yansıtılan bağlamı kullanmaktır.

Kodunuzun yürütüldüğü yere bağlı olarak, tahmini bağlam elde etmenin iki temel yolu vardır:

Kodunuz yansıtılan bir etkinlikte çalışıyorsa yansıtılan bağlamı alma

Uygulamanızın kodu tahmini etkinliğinizden çalıştırılıyorsa kendi etkinlik bağlamı zaten bir tahmini bağlamdır. Bu senaryoda, söz konusu etkinlikte yapılan aramalar gözlüğün donanımına erişebilir.

Telefon uygulaması bileşeninde çalışan kod için tahmini bağlam alma

Uygulamanızın, planlanan etkinliğinizin dışında kalan bir bölümünün (ör. telefon etkinliği veya bir hizmet) gözlüğün donanımına erişmesi gerekiyorsa açıkça planlanan bir bağlam elde etmesi gerekir. Bunun için createProjectedDeviceContext yöntemini kullanın:

@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
    }
}

Geçerliliğini kontrol etme

createProjectedDeviceContext çağrısını ProjectedContext.isProjectedDeviceConnected içine alın. Bu yöntem true değerini döndürse de yansıtılan bağlam, bağlı cihaz için geçerli olmaya devam eder ve telefonunuzdaki uygulama etkinliği veya hizmet (ör. CameraManager) yapay zeka gözlüğünün donanımına erişebilir.

Bağlantı kesildiğinde temizleme

Yansıtılan bağlam, bağlı cihazın yaşam döngüsüne bağlı olduğundan cihazın bağlantısı kesildiğinde yok edilir. Cihazın bağlantısı kesildiğinde, ProjectedContext.isProjectedDeviceConnected, false değerini döndürür. Uygulamanız bu değişikliği dinlemeli ve bu öngörülen bağlamı kullanarak oluşturduğu sistem hizmetlerini (ör. CameraManager) veya kaynakları temizlemelidir.

Yeniden bağlandığında yeniden başlat

Gözlük yeniden bağlandığında uygulamanız createProjectedDeviceContext kullanarak başka bir yansıtılan bağlam örneği alabilir ve ardından yeni yansıtılan bağlamı kullanarak tüm sistem hizmetlerini veya kaynaklarını yeniden başlatabilir.

Gözlüğün mikrofonuyla ses kaydetme

Gözlükten ses kaydetmek için iki farklı yöntem kullanabilirsiniz:

Kayıt yöntemi seçme

Seçeceğiniz yöntem, yüksek kaliteli, XR'a özel ses işleme veya standart Bluetooth ses girişi gerekip gerekmediğine bağlıdır.

Kayıt yöntemi Mikrofon erişimi Yaygın kullanım alanı

Öngörülen Bağlam

Birden fazla mikrofon

Yansıtılan bağlam kullanılarak yapılan kayıt, uygulamanızın gözlükteki birden fazla mikrofona ve özel donanım özelliklerine (ör. aşağıdakiler) erişmesine olanak tanır:

  • XR'a özel uzamsallaştırma.
  • Gelişmiş gürültü azaltma.
  • Kullanıcının ve yakındaki kişilerin seslerini ayıran ses ayrımı.
  • Gözlükler etkin Bluetooth cihazı olmasa bile çok cihazlı ortamlarda kayıt erişimini koruyun.

Bluetooth HFP

Tek mikrofon

Hemen kullanmaya başlamak için Bluetooth Eller Serbest Profili'ni (HFP) kullanır. Bu modda gözlük, standart mikrofonlu kulaklık ve gelişmiş ses dağıtım profili (A2DP) profillerini kullanarak telefona bağlanır ve tipik bir Bluetooth çevre birimi gibi çalışır.

Uygulamanız standart Bluetooth kaydı için tasarlanmışsa XR'a özgü özellikleri entegre etmeden gözlüklerden ses kaydetmek için bu yöntemi kullanabilirsiniz.

Yansıtılan bağlamı kullanarak ses kaydetme

Yansıtılan bir bağlam kullanarak ses kaydetmek için önce gerekli çalışma zamanı izinlerini isteyin, ardından aşağıdaki bölümlerde açıklandığı gibi AudioRecord API'sini kullanarak sesi kaydedin.

Çalışma zamanı izinleri isteme

Gözlükteki birden fazla mikrofona erişmek için ses izinlerini özellikle yansıtılan cihaz için istemeniz gerekir. Kullanıcının mobil cihazında uygulamanız için verdiği standart, telefon kapsamlı RECORD_AUDIO izin yeterli değil.

İzin istemek için şu adımları uygulayın:

  1. Uygulamanızın manifest dosyasında RECORD_AUDIO iznini beyan edin.
  2. Kodunuzun yürütüldüğü yere bağlı olarak, aşağıdaki yöntemlerden birini kullanarak yansıtılan cihaz kapsamlı izinleri isteyin:

AudioRecord'u tahmini bir bağlamla başlatma

Sesin, barındıran telefondan değil gözlükten kaydedilmesini sağlamak için AudioRecord nesnesini, yansıtılan cihaz bağlamıyla ilişkilendirmeniz gerekir.

Aşağıdaki kodda AudioRecord.Builder kullanılır ve projectedDeviceContext, setContext yöntemine iletilir:

// 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()

Kodla ilgili önemli noktalar
  • Ses işlemeyi belirli kullanım alanınıza göre uyarlamak için ses kaynağını CAMCORDER, VOICE_RECOGNITION, VOICE_COMMUNICATION veya UNPROCESSED olarak ayarlayabilirsiniz.

    Örneğin, kullanım alanınızda otomatik gürültü azaltma gerekiyorsa VOICE_COMMUNICATION simgesini kullanın. VOICE_RECOGNITION, akustik yankı giderme (AEC) ile işlenir. Değiştirilmemiş ham ses dosyasına ihtiyacınız varsa UNPROCESSED veya CAMCORDER simgesini seçin.

  • Gözlüklerle uyumluluğu sağlamak için audioFormat nesnesi 16 kHz örnekleme hızı ve mono ya da stereo (CHANNEL_IN_MONO veya CHANNEL_IN_STEREO kullanılarak) kanal yapılandırması tanımlamalıdır.

  • Arabellek boyutu için sabit bir şart olmasa da algılanan gecikmeyi en aza indirmek için minimum arabellek boyutunu elde edin.

Kullandıktan sonra temizleme

Uygulamanızın artık mikrofona ihtiyacı kalmadığında veya etkinlik durdurulduğunda AudioRecord nesnesinde stop ve release yöntemlerini çağırın.

Kayda başlamadan önce çalışma zamanı izinlerini kontrol etme

startRecording uygulamasını aramadan önce, kullanıcının yansıtılan bağlamı kullanarak gözlük için mikrofon izni verdiğini doğrulayın.

Bluetooth HFP kullanarak ses kaydetme

Bluetooth HFP kullanarak ses kaydetmek için önce gerekli çalışma zamanı izinlerini isteyin, ardından aşağıdaki bölümlerde açıklandığı gibi AudioManager API'sini kullanarak sesi kaydedin.

İzin iste

Standart Bluetooth ses cihazlarında olduğu gibi, RECORD_AUDIO, BLUETOOTH_CONNECT ve diğer ilgili izinler telefondan kontrol edilir, bağlı cihazdan (ör. ses gözlüğü veya ekran gözlüğü) kontrol edilmez.

İzin istemek için şu adımları uygulayın:

  1. Uygulamanızın manifest dosyasında aşağıdaki izinleri beyan edin:

  2. Standart Android izin akışını kullanarak çalışma zamanında hem RECORD_AUDIO hem de BLUETOOTH_CONNECT izinlerini isteyin.

Sesi yönlendirmek için AudioManager'ı kullanma

Kullanıcı, uygulamanıza gerekli çalışma zamanı izinlerini verdikten sonra, sesi Bluetooth HFP üzerinden yönlendirmek için iletişim cihazını AudioManager API'sini kullanarak TYPE_BLUETOOTH_SCO olarak ayarlayın. Bu, sistemin sesi Bluetooth çevre biriminden almasını sağlar.

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()

Gözlüğün kamerasıyla görüntü yakalama

Gözlüğün kamerasıyla görüntü yakalamak için CameraX'in ImageCapture kullanım alanını uygulamanız için doğru bağlamı kullanarak gözlüğün kamerasına ayarlayın ve bağlayın:

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))
}

Kodla ilgili önemli noktalar

  • Yansıtılan cihaz bağlamını kullanarak ProcessCameraProvider örneğini alır.
  • Gözlüğün birincil, dışa dönük kamerası, yansıtılan bağlamın kapsamı içinde bir kamera seçilirken DEFAULT_BACK_CAMERA ile eşlenir.
  • Ön bağlama kontrolü, devam etmeden önce seçilen kameranın cihazda kullanılabilir olduğunu doğrulamak için cameraProvider.hasCamera(cameraSelector) kullanır.
  • Desteklenen çözünürlüklerle ilgili gelişmiş kontroller için yararlı olabilecek temel CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP'yi okumak üzere Camera2CameraInfo ile Camera2 birlikte çalışabilirliği'ni kullanır.
  • ResolutionSelector, ImageCapture için çıkış görüntüsü çözünürlüğünü hassas bir şekilde kontrol etmek üzere özel olarak oluşturulur.
  • ImageCapture ile yapılandırılmış bir kullanım alanı oluşturur ResolutionSelector.
  • ImageCapture kullanım alanını etkinliğin yaşam döngüsüne bağlar. Bu, etkinliğin durumuna göre kameranın açılmasını ve kapanmasını otomatik olarak yönetir (örneğin, etkinlik duraklatıldığında kamerayı durdurur).

Gözlüğün kamerası ayarlandıktan sonra CameraX'in ImageCapture sınıfıyla görüntü yakalayabilirsiniz. takePicture kullanarak görüntü yakalama hakkında bilgi edinmek için CameraX'in belgelerine bakın.

Gözlüğün kamerasıyla video çekme

Gözlüğün kamerasıyla resim yerine video çekmek için ImageCapture bileşenlerini ilgili VideoCapture bileşenleriyle değiştirin ve çekim yürütme mantığını değiştirin.

Başlıca değişiklikler arasında farklı bir kullanım alanı kullanma, farklı bir çıkış dosyası oluşturma ve uygun video kaydı yöntemini kullanarak yakalama işlemini başlatma yer alır. VideoCapture API ve nasıl kullanılacağı hakkında daha fazla bilgi için CameraX'in video yakalama belgelerine bakın.

Aşağıdaki tabloda, uygulamanızın kullanım alanına bağlı olarak önerilen çözünürlük ve kare hızı gösterilmektedir:

Kullanım alanı Çözünürlük Kare hızı
Video İletişimi 1280 x 720 15 FPS
Bilgisayar Görüşü 640 x 480 10 FPS
Yapay Zeka Video Akışı 640 x 480 1 FPS

Yansıtılan bir etkinlikten telefonun donanımına erişme

Yansıtılan etkinlikler, ana makine cihazının (telefon) bağlamını almak için createHostDeviceContext(context) kullanarak telefonun donanımına (ör. kamera veya mikrofon) da erişebilir:

@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
    }
}

Karma bir uygulamada (hem mobil hem de gözlük deneyimlerini içeren bir uygulama) ana cihaza (telefon) özgü donanıma veya kaynaklara erişirken uygulamanızın doğru donanıma erişebilmesi için doğru bağlamı açıkça seçmeniz gerekir: