ऑडियो ग्लास और डिसप्ले ग्लास पर हार्डवेयर ऐक्सेस करने के लिए, प्रोजेक्ट किए गए कॉन्टेक्स्ट का इस्तेमाल करना

XR डिवाइसों के लिए ज़रूरी शर्तें
इस गाइड से, आपको इन XR डिवाइसों के लिए अनुभव बनाने में मदद मिलती है.
ऑडियो और
डिसप्ले वाले चश्मे

ज़रूरी अनुमतियों का अनुरोध करने और उन्हें पाने के बाद, आपका ऐप्लिकेशन ऑडियो वाले चश्मे या डिसप्ले वाले चश्मे के हार्डवेयर को ऐक्सेस कर सकता है. चश्मे के हार्डवेयर को ऐक्सेस करने के लिए (फ़ोन के हार्डवेयर के बजाय), प्रोजेक्टेड कॉन्टेक्स्ट का इस्तेमाल करना ज़रूरी है.

प्रोजेक्टेड कॉन्टेक्स्ट पाने के दो मुख्य तरीके हैं. यह इस बात पर निर्भर करता है कि आपका कोड कहां चल रहा है:

अगर आपका कोड, प्रोजेक्टेड ऐक्टिविटी में चल रहा है, तो प्रोजेक्टेड कॉन्टेक्स्ट पाएं

अगर आपके ऐप्लिकेशन का कोड, आपकी प्रोजेक्टेड ऐक्टिविटी से चल रहा है, तो उसकी अपनी ऐक्टिविटी का कॉन्टेक्स्ट पहले से ही प्रोजेक्टेड कॉन्टेक्स्ट होता है. इस स्थिति में, उस ऐक्टिविटी में किए गए कॉल, चश्मे के हार्डवेयर को पहले से ही ऐक्सेस कर सकते हैं.

फ़ोन ऐप्लिकेशन के कॉम्पोनेंट में चल रहे कोड के लिए, प्रोजेक्टेड कॉन्टेक्स्ट पाएं

अगर आपके ऐप्लिकेशन का कोई हिस्सा, प्रोजेक्टेड ऐक्टिविटी के बाहर (जैसे, फ़ोन की ऐक्टिविटी या कोई सेवा) चश्मे के हार्डवेयर को ऐक्सेस करना चाहता है, तो उसे साफ़ तौर पर प्रोजेक्टेड कॉन्टेक्स्ट पाना होगा. इसके लिए, createProjectedDeviceContext तरीके का इस्तेमाल करें:

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

मान्य है या नहीं, इसकी जांच करें

createProjectedDeviceContext कॉल को ProjectedContext.isProjectedDeviceConnected में रैप करें. जब तक यह तरीका true दिखाता है, तब तक प्रोजेक्टेड कॉन्टेक्स्ट, कनेक्ट किए गए डिवाइस के लिए मान्य रहता है. साथ ही, आपके फ़ोन ऐप्लिकेशन की ऐक्टिविटी या सेवा (जैसे, CameraManager), एआई वाले चश्मे के हार्डवेयर को ऐक्सेस कर सकती है.

डिसकनेक्ट होने पर, साफ़ करें

प्रोजेक्टेड कॉन्टेक्स्ट, कनेक्ट किए गए डिवाइस के लाइफ़साइकल से जुड़ा होता है. इसलिए, डिवाइस के डिसकनेक्ट होने पर यह खत्म हो जाता है. डिवाइस के डिसकनेक्ट होने पर, ProjectedContext.isProjectedDeviceConnected दिखाता है false. आपके ऐप्लिकेशन को इस बदलाव के लिए सुनना चाहिए. साथ ही, आपके ऐप्लिकेशन को उस प्रोजेक्टेड कॉन्टेक्स्ट का इस्तेमाल करके बनाई गई किसी भी सिस्टम सेवा (जैसे, CameraManager) या संसाधनों को साफ़ करना चाहिए.

दोबारा कनेक्ट करने पर, फिर से शुरू करें

चश्मे के दोबारा कनेक्ट होने पर, आपका ऐप्लिकेशन प्रोजेक्टेड कॉन्टेक्स्ट का दूसरा इंस्टेंस createProjectedDeviceContext का इस्तेमाल करके पा सकता है. इसके बाद, नए प्रोजेक्टेड कॉन्टेक्स्ट का इस्तेमाल करके, किसी भी सिस्टम सेवा या संसाधन को फिर से शुरू किया जा सकता है.

चश्मे के माइक्रोफ़ोन से ऑडियो रिकॉर्ड करना

चश्मे से ऑडियो रिकॉर्ड करने के लिए, दो अलग-अलग तरीकों का इस्तेमाल किया जा सकता है:

रिकॉर्डिंग के तरीके चुनना

आपके लिए कौनसा तरीका सही है, यह इस बात पर निर्भर करता है कि आपको हाई-फ़िडेलिटी, XR के लिए खास तौर पर ऑडियो प्रोसेसिंग या स्टैंडर्ड ब्लूटूथ ऑडियो इनपुट की ज़रूरत है या नहीं.

रिकॉर्डिंग का तरीका माइक्रोफ़ोन का ऐक्सेस इस्तेमाल का सामान्य उदाहरण

प्रोजेक्टेड कॉन्टेक्स्ट

एक से ज़्यादा माइक्रोफ़ोन

प्रोजेक्टेड कॉन्टेक्स्ट का इस्तेमाल करके रिकॉर्ड करने से, आपका ऐप्लिकेशन चश्मे के एक से ज़्यादा माइक्रोफ़ोन और उसके खास हार्डवेयर की सुविधाओं को ऐक्सेस कर सकता है. जैसे:

  • XR के लिए खास तौर पर तैयार की गई स्पेसियलाइज़ेशन की सुविधा.
  • बेहतर डीनॉइज़िंग की सुविधा.
  • आवाज़ अलग करने की सुविधा. इससे पहनने वाले और आस-पास मौजूद लोगों की आवाज़ों के बीच अंतर किया जा सकता है.
  • एक से ज़्यादा डिवाइस वाले एनवायरमेंट में, रिकॉर्डिंग के ऐक्सेस को बनाए रखना. भले ही, चश्मा ऐक्टिव ब्लूटूथ डिवाइस न हो.

ब्लूटूथ एचएफ़पी

एक माइक्रोफ़ोन

तुरंत, आउट-ऑफ़-द-बॉक्स कंपैटिबिलिटी के लिए, ब्लूटूथ हैंड्स-फ़्री प्रोफ़ाइल (एचएफ़पी) पर निर्भर करता है. इस मोड में, चश्मा, स्टैंडर्ड हेडसेट और एडवांस्ड ऑडियो डिस्ट्रीब्यूशन प्रोफ़ाइल (A2DP) प्रोफ़ाइल का इस्तेमाल करके फ़ोन से कनेक्ट होता है. यह एक सामान्य ब्लूटूथ पेरिफ़ेरल की तरह काम करता है.

अगर आपका ऐप्लिकेशन, स्टैंडर्ड ब्लूटूथ रिकॉर्डिंग के लिए पहले से ही डिज़ाइन किया गया है, तो XR के लिए खास तौर पर तैयार की गई किसी भी सुविधा को इंटिग्रेट किए बिना, चश्मे से ऑडियो रिकॉर्ड करने के लिए इस तरीके का इस्तेमाल किया जा सकता है.

प्रोजेक्टेड कॉन्टेक्स्ट का इस्तेमाल करके ऑडियो रिकॉर्ड करना

प्रोजेक्टेड कॉन्टेक्स्ट का इस्तेमाल करके ऑडियो रिकॉर्ड करने के लिए, सबसे पहले ज़रूरी रनटाइम अनुमतियों का अनुरोध करें. इसके बाद, AudioRecord एपीआई का इस्तेमाल करके ऑडियो रिकॉर्ड करें. इसके बारे में, यहां दिए गए सेक्शन में बताया गया है.

रनटाइम अनुमतियों का अनुरोध करना

चश्मे के एक से ज़्यादा माइक्रोफ़ोन को ऐक्सेस करने के लिए, आपको प्रोजेक्टेड डिवाइस के लिए खास तौर पर ऑडियो की अनुमतियों का अनुरोध करना होगा. फ़ोन के दायरे वाली स्टैंडर्ड RECORD_AUDIO अनुमति काफ़ी नहीं है. यह अनुमति, उपयोगकर्ता ने अपने मोबाइल डिवाइस पर आपके ऐप्लिकेशन को दी है.

अनुमतियों का अनुरोध करने के लिए, यह तरीका अपनाएं:

  1. अपने ऐप्लिकेशन की मेनिफ़ेस्ट फ़ाइल में, RECORD_AUDIO अनुमति का एलान करें.
  2. प्रोजेक्टेड-डिवाइस के दायरे वाली अनुमतियों का अनुरोध, इनमें से किसी एक तरीके से करें. यह इस बात पर निर्भर करता है कि आपका कोड कहां चल रहा है:

प्रोजेक्टेड कॉन्टेक्स्ट के साथ AudioRecord को शुरू करना

यह पक्का करने के लिए कि ऑडियो, होस्ट फ़ोन के बजाय चश्मे से रिकॉर्ड किया जाए, आपको AudioRecord ऑब्जेक्ट को प्रोजेक्टेड डिवाइस के कॉन्टेक्स्ट से जोड़ना होगा.

यहां दिए गए कोड में, AudioRecord.Builder का इस्तेमाल किया गया है. साथ ही, projectedDeviceContext को setContext तरीके में पास किया गया है:

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

कोड के बारे में अहम बातें
  • ऑडियो सोर्स को CAMCORDER, VOICE_RECOGNITION, VOICE_COMMUNICATION, या UNPROCESSED पर सेट किया जा सकता है. इससे, ऑडियो प्रोसेसिंग को अपने इस्तेमाल के उदाहरण के हिसाब से बनाया जा सकता है.

    उदाहरण के लिए, अगर आपके इस्तेमाल के उदाहरण में, आवाज़ में से शोर कम करने की सुविधा की ज़रूरत है, तो VOICE_COMMUNICATION का इस्तेमाल करें. VOICE_RECOGNITION को अकूस्टिक इको कैंसिलेशन (एईसी) के साथ प्रोसेस किया जाता है. अगर आपको बिना किसी बदलाव वाला ऑडियो चाहिए, तो UNPROCESSED या CAMCORDER चुनें.

  • चश्मे के साथ कंपैटिबिलिटी पक्का करने के लिए, audioFormat ऑब्जेक्ट में 16 किलोहर्ट्ज़ की सैंपल रेट और मोनो या स्टीरियो (CHANNEL_IN_MONO या CHANNEL_IN_STEREO का इस्तेमाल करके) का चैनल कॉन्फ़िगरेशन तय करना ज़रूरी है.

  • बफ़र साइज़ के लिए कोई तय शर्त नहीं है. हालांकि, परसीव्ड लेटेंसी को कम करने के लिए, कम से कम बफ़र साइज़ पाएं.

इस्तेमाल के बाद, साफ़ करें

जब आपके ऐप्लिकेशन को माइक्रोफ़ोन की ज़रूरत न हो या ऐक्टिविटी बंद हो जाए, तो stop और release को AudioRecord ऑब्जेक्ट पर कॉल करें.

रिकॉर्डिंग से पहले, रनटाइम अनुमतियों की जांच करना

startRecording को कॉल करने से पहले, पुष्टि करें कि उपयोगकर्ता ने प्रोजेक्टेड कॉन्टेक्स्ट का इस्तेमाल करके, चश्मे के लिए माइक्रोफ़ोन की अनुमति दी है.

ब्लूटूथ एचएफ़पी का इस्तेमाल करके ऑडियो रिकॉर्ड करना

ब्लूटूथ एचएफ़पी का इस्तेमाल करके ऑडियो रिकॉर्ड करने के लिए, सबसे पहले ज़रूरी रनटाइम अनुमतियों का अनुरोध करें. इसके बाद, AudioManager एपीआई का इस्तेमाल करके ऑडियो रिकॉर्ड करें. इसके बारे में, यहां दिए गए सेक्शन में बताया गया है.

अनुमतियों का अनुरोध करें

किसी भी स्टैंडर्ड ब्लूटूथ ऑडियो डिवाइस की तरह, RECORD_AUDIO, BLUETOOTH_CONNECT वगैरह से जुड़ी अनुमतियों को फ़ोन से कंट्रोल किया जाता है. इन्हें कनेक्ट किए गए डिवाइस (जैसे, ऑडियो वाले चश्मे या डिसप्ले वाले चश्मे) से कंट्रोल नहीं किया जाता.

अनुमतियों का अनुरोध करने के लिए, यह तरीका अपनाएं:

  1. अपने ऐप्लिकेशन की मेनिफ़ेस्ट फ़ाइल में, ये अनुमतियां तय करें:

  2. Android की अनुमति के standard फ़्लो का इस्तेमाल करके, रनटाइम में RECORD_AUDIO और BLUETOOTH_CONNECT, दोनों अनुमतियों का अनुरोध करें.

ऑडियो को रूट करने के लिए, AudioManager का इस्तेमाल करना

उपयोगकर्ता के आपके ऐप्लिकेशन को ज़रूरी रनटाइम अनुमतियां देने के बाद, AudioManager एपीआई का इस्तेमाल करके, कम्यूनिकेशन डिवाइस को TYPE_BLUETOOTH_SCO पर सेट करें. इससे, ऑडियो को ब्लूटूथ एचएफ़पी के ज़रिए रूट किया जा सकेगा. इससे सिस्टम को, ब्लूटूथ पेरिफ़ेरल से ऑडियो पाने का निर्देश मिलता है.

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

चश्मे के कैमरे से कोई इमेज कैप्चर करना

चश्मे के कैमरे से कोई इमेज कैप्चर करने के लिए, अपने ऐप्लिकेशन के लिए सही कॉन्टेक्स्ट का इस्तेमाल करके, CameraX के ImageCapture इस्तेमाल के उदाहरण को चश्मे के कैमरे से सेट अप और बाइंड करें:

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

कोड के बारे में अहम बातें

  • ProcessCameraProvider का इस्तेमाल करके, प्रोजेक्टेड डिवाइस के कॉन्टेक्स्ट का इंस्टेंस पाता है.
  • प्रोजेक्टेड कॉन्टेक्स्ट के दायरे में, कैमरा चुनते समय, चश्मे का प्राइमरी, बाहर की ओर पॉइंट करने वाला कैमरा, DEFAULT_BACK_CAMERA से मैप होता है.
  • प्री-बाइंडिंग की जांच में, यह पुष्टि करने के लिए cameraProvider.hasCamera(cameraSelector) का इस्तेमाल किया जाता है कि चुनी गई कैमरा सुविधा, डिवाइस पर उपलब्ध है या नहीं.
  • सपोर्ट किए गए रिज़ॉल्यूशन की ऐडवांस जांच के लिए, Camera2 Interop का इस्तेमाल Camera2CameraInfo के साथ किया जाता है. इससे, अंडरलाइंग CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP को पढ़ा जा सकता है.
  • ImageCapture के लिए, आउटपुट इमेज के रिज़ॉल्यूशन को सटीक तरीके से कंट्रोल करने के लिए, कस्टम ResolutionSelector बनाया जाता है.
  • ImageCapture इस्तेमाल का उदाहरण बनाता है, जिसे कस्टम ResolutionSelector के साथ कॉन्फ़िगर किया जाता है.
  • ImageCapture इस्तेमाल के उदाहरण को, ऐक्टिविटी के लाइफ़साइकल से बाइंड करता है. इससे, ऐक्टिविटी की स्थिति के आधार पर, कैमरा अपने-आप खुलता और बंद होता है. उदाहरण के लिए, ऐक्टिविटी के पॉज़ होने पर कैमरा बंद हो जाता है.

चश्मे का कैमरा सेट अप होने के बाद, CameraX की ImageCapture क्लास से कोई इमेज कैप्चर की जा सकती है. कोई इमेज कैप्चर करने के लिए, capture an image के लिए takePicture का इस्तेमाल करने के बारे में जानने के लिए , CameraX का दस्तावेज़ देखें.

चश्मे के कैमरे से कोई वीडियो कैप्चर करना

चश्मे के कैमरे से इमेज के बजाय वीडियो कैप्चर करने के लिए, ImageCapture कॉम्पोनेंट को, उनसे जुड़े VideoCapture कॉम्पोनेंट से बदलें. साथ ही, कैप्चर करने की प्रोसेस के लॉजिक में बदलाव करें.

मुख्य बदलावों में, अलग इस्तेमाल के उदाहरण का इस्तेमाल करना, अलग आउटपुट फ़ाइल बनाना, और वीडियो रिकॉर्ड करने के सही तरीके का इस्तेमाल करके कैप्चर करना शामिल है. VideoCapture एपीआई और इसका इस्तेमाल करने के तरीके के बारे में ज़्यादा जानने के लिए, CameraX का वीडियो कैप्चर करने से जुड़ा दस्तावेज़ देखें.

यहां दी गई टेबल में, आपके ऐप्लिकेशन के इस्तेमाल के उदाहरण के हिसाब से, सुझाया गया रिज़ॉल्यूशन और फ़्रेम रेट दिखाया गया है:

इस्तेमाल का उदाहरण रिज़ॉल्यूशन फ़्रेम दर
वीडियो कम्यूनिकेशन 1280 x 720 15 एफ़पीएस
कंप्यूटर विज़न 640 x 480 10 एफ़पीएस
एआई वीडियो स्ट्रीमिंग 640 x 480 1 एफ़पीएस

प्रोजेक्टेड ऐक्टिविटी से फ़ोन के हार्डवेयर को ऐक्सेस करना

प्रोजेक्टेड ऐक्टिविटी, फ़ोन के हार्डवेयर (जैसे, कैमरा या माइक्रोफ़ोन) को भी ऐक्सेस कर सकती है. इसके लिए, होस्ट डिवाइस (फ़ोन) का कॉन्टेक्स्ट पाने के लिए, createHostDeviceContext(context) का इस्तेमाल करें:

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

हाइब्रिड ऐप्लिकेशन (ऐसा ऐप्लिकेशन जिसमें मोबाइल और चश्मे, दोनों के अनुभव शामिल हों) में, होस्ट डिवाइस (फ़ोन) के लिए खास तौर पर तैयार किए गए हार्डवेयर या संसाधनों को ऐक्सेस करते समय, आपको सही कॉन्टेक्स्ट साफ़ तौर पर चुनना होगा. इससे यह पक्का किया जा सकेगा कि आपका ऐप्लिकेशन, सही हार्डवेयर को ऐक्सेस कर सके:

  • फ़ोन का Activity कॉन्टेक्स्ट पाने के लिए, फ़ोन की Activity या ProjectedContext.createHostDeviceContext का इस्तेमाल करें.
  • getApplicationContext का इस्तेमाल न करें, क्योंकि ऐप्लिकेशन कॉन्टेक्स्ट अगर प्रोजेक्टेड ऐक्टिविटी, हाल ही में लॉन्च किया गया कॉम्पोनेंट है, तो चश्मे का कॉन्टेक्स्ट गलत तरीके से दिखा सकता है.