שימוש בהקשר משוער כדי לגשת לציוד של משקפי AI

מכשירי XR רלוונטיים
ההנחיות האלה יעזרו לכם ליצור חוויות למכשירי XR מהסוגים האלה.
משקפי AI

אחרי שמבקשים ומקבלים את ההרשאות הנדרשות, האפליקציה יכולה לגשת לחומרה של משקפי ה-AI. כדי לגשת לחומרה של המשקפיים (במקום לחומרה של הטלפון), צריך להשתמש בהקשר מוקרן.

יש שתי דרכים עיקריות לקבל הקשר משוער, בהתאם למקום שבו הקוד מופעל:

קבלת הקשר משוער אם הקוד פועל בפעילות של משקפי AI

אם הקוד של האפליקציה פועל מתוך הפעילות במשקפי ה-AI, הקשר של הפעילות שלה כבר מתוכנן. בתרחיש הזה, לשיחות שמתבצעות במסגרת הפעילות הזו כבר יש גישה לחומרה של המשקפיים.

קבלת הקשר המוקרן אם הקוד פועל ברכיב של אפליקציית טלפון

אם חלק מהאפליקציה שלכם מחוץ לפעילות המשקפיים מבוססת-AI (כמו פעילות בטלפון או שירות) צריך לגשת לחומרה של המשקפיים, הוא צריך לקבל הקשר מוקרן באופן מפורש. כדי לעשות את זה, משתמשים בשיטה 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, ההקשר המוקרן נשאר תקף למכשיר המחובר, והפעילות או השירות באפליקציית הטלפון (כמו CameraManager) יכולים לגשת לחומרה של משקפי ה-AI.

ניקוי לאחר ניתוק

ההקשר המוקרן קשור למחזור החיים של המכשיר המחובר, ולכן הוא נמחק כשהמכשיר מתנתק. כשהמכשיר מתנתק, ‫ProjectedContext.isProjectedDeviceConnected מחזיר false. האפליקציה שלכם צריכה להאזין לשינוי הזה ולנקות את כל שירותי המערכת (כמו CameraManager) או המשאבים שהאפליקציה יצרה באמצעות ההקשר המוקרן הזה.

הפעלה מחדש של האתחול בחיבור מחדש

כשמכשיר משקפי ה-AI מתחבר מחדש, האפליקציה יכולה לקבל עוד מופע של הקשר המוקרן באמצעות createProjectedDeviceContext(), ואז לאתחל מחדש את כל שירותי המערכת או המשאבים באמצעות ההקשר המוקרן החדש.

גישה לאודיו באמצעות Bluetooth

בשלב הזה, משקפי AI מתחברים לטלפון כמכשיר שמע Bluetooth רגיל. יש תמיכה גם באוזניות וגם בפרופיל A2DP (פרופיל מתקדם להפצת אודיו). הגישה הזו מאפשרת לכל אפליקציית Android שתומכת בקלט או בפלט אודיו לפעול במשקפיים, גם אם היא לא פותחה במיוחד כדי לתמוך במשקפיים. במקרים מסוימים, שימוש ב-Bluetooth עשוי להתאים יותר לתרחיש השימוש באפליקציה שלכם כחלופה לגישה לחומרה של המשקפיים באמצעות הקשר מוקרן.

כמו בכל מכשיר אודיו רגיל עם Bluetooth, ההרשאה להעניק את ההרשאה 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.
  • יוצרת ImageCapture תרחיש שימוש שמוגדר עם ResolutionSelector מותאם אישית.
  • קושר את תרחיש השימוש ImageCapture למחזור החיים של הפעילות. הוא מנהל אוטומטית את הפתיחה והסגירה של המצלמה בהתאם למצב הפעילות (לדוגמה, עצירת המצלמה כשהפעילות מושהית).

אחרי שמגדירים את המצלמה של משקפי ה-AI, אפשר לצלם תמונה באמצעות המחלקה ImageCapture של CameraX. במאמרי העזרה של CameraX מוסבר איך משתמשים ב-takePicture() כדי לצלם תמונה.

צילום סרטון באמצעות המצלמה של משקפי ה-AI

כדי לצלם סרטון במקום תמונה באמצעות המצלמה של משקפי ה-AI, מחליפים את הרכיבים ImageCapture ברכיבים התואמים VideoCapture ומשנים את הלוגיקה של ביצוע הצילום.

השינויים העיקריים כוללים שימוש בתרחיש שימוש אחר, יצירת קובץ פלט אחר והתחלת הצילום באמצעות שיטת הקלטת הווידאו המתאימה. מידע נוסף על VideoCapture API ועל אופן השימוש בו זמין במאמרי העזרה בנושא צילום וידאו ב-CameraX.

בטבלה הבאה מוצגים הרזולוציה וקצב הפריימים המומלצים בהתאם לתרחיש השימוש באפליקציה:

תרחיש לדוגמה רזולוציה קצב פריימים
תקשורת בווידאו ‫1280 x 720 ‫15 פריימים לשנייה (FPS)
ראייה ממוחשבת ‫640 x 480 ‫10 פריימים לשנייה (FPS)
סטרימינג של סרטוני AI ‫640 x 480 ‫1 FPS

גישה לחומרה של הטלפון מפעילות במשקפי AI

פעילות במשקפיים עם 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() כי הקשר האפליקטיבי יכול להחזיר באופן שגוי את ההקשר של משקפי ה-AI אם פעילות המשקפיים הייתה הרכיב שהופעל לאחרונה.