@mentra/engine 0.1.0-dev.0 → 3.1.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -18
- package/build/bluetooth-sdk/debug.d.ts +2 -0
- package/build/bluetooth-sdk/debug.d.ts.map +1 -0
- package/build/bluetooth-sdk/debug.js +2 -0
- package/build/bluetooth-sdk/debug.js.map +1 -0
- package/build/bluetooth-sdk/index.d.ts +3 -0
- package/build/bluetooth-sdk/index.d.ts.map +1 -0
- package/build/bluetooth-sdk/index.js +3 -0
- package/build/bluetooth-sdk/index.js.map +1 -0
- package/build/bluetooth-sdk/photo-receiver.d.ts +3 -0
- package/build/bluetooth-sdk/photo-receiver.d.ts.map +1 -0
- package/build/bluetooth-sdk/photo-receiver.js +3 -0
- package/build/bluetooth-sdk/photo-receiver.js.map +1 -0
- package/build/bluetooth-sdk/react.d.ts +2 -0
- package/build/bluetooth-sdk/react.d.ts.map +1 -0
- package/build/bluetooth-sdk/react.js +2 -0
- package/build/bluetooth-sdk/react.js.map +1 -0
- package/build/bluetooth-sdk/types.d.ts +2 -0
- package/build/bluetooth-sdk/types.d.ts.map +1 -0
- package/build/bluetooth-sdk/types.js +2 -0
- package/build/bluetooth-sdk/types.js.map +1 -0
- package/build/engine.d.ts +24 -16
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +9 -4
- package/build/engine.js.map +1 -1
- package/build/facades/dev.d.ts +3 -2
- package/build/facades/dev.d.ts.map +1 -1
- package/build/facades/dev.js +18 -12
- package/build/facades/dev.js.map +1 -1
- package/build/facades/display.d.ts +1 -1
- package/build/facades/display.d.ts.map +1 -1
- package/build/facades/display.js +1 -1
- package/build/facades/display.js.map +1 -1
- package/build/facades/gallery.js +1 -1
- package/build/facades/gallery.js.map +1 -1
- package/build/facades/glasses.d.ts +4 -13
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +21 -6
- package/build/facades/glasses.js.map +1 -1
- package/build/facades/glassesSettings.d.ts.map +1 -1
- package/build/facades/glassesSettings.js +1 -0
- package/build/facades/glassesSettings.js.map +1 -1
- package/build/facades/miniapps.d.ts +4 -0
- package/build/facades/miniapps.d.ts.map +1 -1
- package/build/facades/miniapps.js +5 -0
- package/build/facades/miniapps.js.map +1 -1
- package/build/facades/ota.d.ts +14 -16
- package/build/facades/ota.d.ts.map +1 -1
- package/build/facades/ota.js +22 -7
- package/build/facades/ota.js.map +1 -1
- package/build/facades/pairing.d.ts +8 -5
- package/build/facades/pairing.d.ts.map +1 -1
- package/build/facades/pairing.js +12 -10
- package/build/facades/pairing.js.map +1 -1
- package/build/facades/permissions.d.ts +10 -0
- package/build/facades/permissions.d.ts.map +1 -1
- package/build/facades/permissions.js +10 -0
- package/build/facades/permissions.js.map +1 -1
- package/build/facades/phoneNotifications.d.ts +0 -4
- package/build/facades/phoneNotifications.d.ts.map +1 -1
- package/build/facades/phoneNotifications.js +4 -14
- package/build/facades/phoneNotifications.js.map +1 -1
- package/build/facades/speech.d.ts +7 -6
- package/build/facades/speech.d.ts.map +1 -1
- package/build/facades/speech.js +1 -1
- package/build/facades/speech.js.map +1 -1
- package/build/generated/releaseMetadata.d.ts +12 -0
- package/build/generated/releaseMetadata.d.ts.map +1 -0
- package/build/generated/releaseMetadata.js +10 -0
- package/build/generated/releaseMetadata.js.map +1 -0
- package/build/index.d.ts +10 -8
- package/build/index.d.ts.map +1 -1
- package/build/index.js +6 -5
- package/build/index.js.map +1 -1
- package/build/react/MentraLiveOtaFlow.d.ts +38 -0
- package/build/react/MentraLiveOtaFlow.d.ts.map +1 -0
- package/build/react/MentraLiveOtaFlow.js +528 -0
- package/build/react/MentraLiveOtaFlow.js.map +1 -0
- package/build/react/index.d.ts +2 -0
- package/build/react/index.d.ts.map +1 -0
- package/build/react/index.js +2 -0
- package/build/react/index.js.map +1 -0
- package/build/react/useEngineSnapshot.d.ts +2 -0
- package/build/react/useEngineSnapshot.d.ts.map +1 -0
- package/build/react/useEngineSnapshot.js +14 -0
- package/build/react/useEngineSnapshot.js.map +1 -0
- package/build/runtime/bootstrap.d.ts +24 -1
- package/build/runtime/bootstrap.d.ts.map +1 -1
- package/build/runtime/bootstrap.js +17 -0
- package/build/runtime/bootstrap.js.map +1 -1
- package/build/runtime/scanQrSeam.d.ts +7 -0
- package/build/runtime/scanQrSeam.d.ts.map +1 -0
- package/build/runtime/scanQrSeam.js +16 -0
- package/build/runtime/scanQrSeam.js.map +1 -0
- package/build/services/AppRegistry.d.ts +41 -57
- package/build/services/AppRegistry.d.ts.map +1 -1
- package/build/services/AppRegistry.js +208 -144
- package/build/services/AppRegistry.js.map +1 -1
- package/build/services/AudioCloudUplink.d.ts +12 -0
- package/build/services/AudioCloudUplink.d.ts.map +1 -1
- package/build/services/AudioCloudUplink.js +22 -1
- package/build/services/AudioCloudUplink.js.map +1 -1
- package/build/services/AudioPlaybackService.d.ts +41 -2
- package/build/services/AudioPlaybackService.d.ts.map +1 -1
- package/build/services/AudioPlaybackService.js +250 -33
- package/build/services/AudioPlaybackService.js.map +1 -1
- package/build/services/BlobStore.d.ts +2 -1
- package/build/services/BlobStore.d.ts.map +1 -1
- package/build/services/BlobStore.js +17 -9
- package/build/services/BlobStore.js.map +1 -1
- package/build/services/CloudAudioSubscriptionSync.d.ts.map +1 -1
- package/build/services/CloudAudioSubscriptionSync.js +13 -1
- package/build/services/CloudAudioSubscriptionSync.js.map +1 -1
- package/build/services/CloudClientService.d.ts +15 -0
- package/build/services/CloudClientService.d.ts.map +1 -1
- package/build/services/CloudClientService.js +93 -1
- package/build/services/CloudClientService.js.map +1 -1
- package/build/services/DeviceEventRouter.js +5 -5
- package/build/services/DeviceEventRouter.js.map +1 -1
- package/build/services/ForegroundLocationPermission.d.ts +13 -0
- package/build/services/ForegroundLocationPermission.d.ts.map +1 -0
- package/build/services/ForegroundLocationPermission.js +12 -0
- package/build/services/ForegroundLocationPermission.js.map +1 -0
- package/build/services/GlassesSettingsSync.d.ts.map +1 -1
- package/build/services/GlassesSettingsSync.js +9 -3
- package/build/services/GlassesSettingsSync.js.map +1 -1
- package/build/services/GlassesStatusProjection.d.ts +2 -1
- package/build/services/GlassesStatusProjection.d.ts.map +1 -1
- package/build/services/GlassesStatusProjection.js +15 -8
- package/build/services/GlassesStatusProjection.js.map +1 -1
- package/build/services/HotspotOtaTransport.d.ts +29 -0
- package/build/services/HotspotOtaTransport.d.ts.map +1 -0
- package/build/services/HotspotOtaTransport.js +146 -0
- package/build/services/HotspotOtaTransport.js.map +1 -0
- package/build/services/HotspotShutdown.d.ts +17 -0
- package/build/services/HotspotShutdown.d.ts.map +1 -0
- package/build/services/HotspotShutdown.js +29 -0
- package/build/services/HotspotShutdown.js.map +1 -0
- package/build/services/LocalDisplayManager.d.ts +15 -0
- package/build/services/LocalDisplayManager.d.ts.map +1 -1
- package/build/services/LocalDisplayManager.js +106 -20
- package/build/services/LocalDisplayManager.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +74 -2
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +785 -291
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/LocalMiniappStorage.d.ts +32 -0
- package/build/services/LocalMiniappStorage.d.ts.map +1 -0
- package/build/services/LocalMiniappStorage.js +66 -0
- package/build/services/LocalMiniappStorage.js.map +1 -0
- package/build/services/LocalMiniappUserIdentity.d.ts +20 -0
- package/build/services/LocalMiniappUserIdentity.d.ts.map +1 -0
- package/build/services/LocalMiniappUserIdentity.js +43 -0
- package/build/services/LocalMiniappUserIdentity.js.map +1 -0
- package/build/services/LocalSttFallbackCoordinator.d.ts +9 -6
- package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.js +18 -12
- package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
- package/build/services/MicStateCoordinator.d.ts +42 -1
- package/build/services/MicStateCoordinator.d.ts.map +1 -1
- package/build/services/MicStateCoordinator.js +141 -3
- package/build/services/MicStateCoordinator.js.map +1 -1
- package/build/services/MiniappLauncher.d.ts.map +1 -1
- package/build/services/MiniappLauncher.js +23 -3
- package/build/services/MiniappLauncher.js.map +1 -1
- package/build/services/MiniappLiveness.d.ts +12 -0
- package/build/services/MiniappLiveness.d.ts.map +1 -0
- package/build/services/MiniappLiveness.js +16 -0
- package/build/services/MiniappLiveness.js.map +1 -0
- package/build/services/NativeHttpResponse.d.ts +3 -0
- package/build/services/NativeHttpResponse.d.ts.map +1 -0
- package/build/services/NativeHttpResponse.js +6 -0
- package/build/services/NativeHttpResponse.js.map +1 -0
- package/build/services/OtaArtifactDownloader.d.ts +65 -0
- package/build/services/OtaArtifactDownloader.d.ts.map +1 -0
- package/build/services/OtaArtifactDownloader.js +226 -0
- package/build/services/OtaArtifactDownloader.js.map +1 -0
- package/build/services/OtaAutoChain.d.ts +34 -0
- package/build/services/OtaAutoChain.d.ts.map +1 -0
- package/build/services/OtaAutoChain.js +83 -0
- package/build/services/OtaAutoChain.js.map +1 -0
- package/build/services/OtaErrorMapping.d.ts +18 -0
- package/build/services/OtaErrorMapping.d.ts.map +1 -0
- package/build/services/OtaErrorMapping.js +63 -0
- package/build/services/OtaErrorMapping.js.map +1 -0
- package/build/services/OtaInstallCoordinator.d.ts +95 -15
- package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
- package/build/services/OtaInstallCoordinator.js +577 -130
- package/build/services/OtaInstallCoordinator.js.map +1 -1
- package/build/services/OtaService.d.ts.map +1 -1
- package/build/services/OtaService.js +8 -1
- package/build/services/OtaService.js.map +1 -1
- package/build/services/OtaUpdateCheckService.d.ts +39 -4
- package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
- package/build/services/OtaUpdateCheckService.js +138 -22
- package/build/services/OtaUpdateCheckService.js.map +1 -1
- package/build/services/PhoneCalendarHelpers.d.ts +32 -0
- package/build/services/PhoneCalendarHelpers.d.ts.map +1 -0
- package/build/services/PhoneCalendarHelpers.js +157 -0
- package/build/services/PhoneCalendarHelpers.js.map +1 -0
- package/build/services/PhoneCalendarService.d.ts +5 -0
- package/build/services/PhoneCalendarService.d.ts.map +1 -0
- package/build/services/PhoneCalendarService.js +45 -0
- package/build/services/PhoneCalendarService.js.map +1 -0
- package/build/services/PhoneCameraFovCoordinator.d.ts +30 -0
- package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -0
- package/build/services/PhoneCameraFovCoordinator.js +194 -0
- package/build/services/PhoneCameraFovCoordinator.js.map +1 -0
- package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
- package/build/services/PhoneNotificationsSync.js +12 -10
- package/build/services/PhoneNotificationsSync.js.map +1 -1
- package/build/services/PhonePhotoCoordinator.d.ts +26 -2
- package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
- package/build/services/PhonePhotoCoordinator.js +79 -9
- package/build/services/PhonePhotoCoordinator.js.map +1 -1
- package/build/services/PhoneStreamCoordinator.d.ts +8 -1
- package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
- package/build/services/PhoneStreamCoordinator.js +125 -13
- package/build/services/PhoneStreamCoordinator.js.map +1 -1
- package/build/services/PhoneVideoCoordinator.d.ts +2 -0
- package/build/services/PhoneVideoCoordinator.d.ts.map +1 -1
- package/build/services/PhoneVideoCoordinator.js +10 -0
- package/build/services/PhoneVideoCoordinator.js.map +1 -1
- package/build/services/SceneRenderer.d.ts.map +1 -1
- package/build/services/SceneRenderer.js +15 -0
- package/build/services/SceneRenderer.js.map +1 -1
- package/build/services/SentenceTtsPipeline.d.ts +31 -0
- package/build/services/SentenceTtsPipeline.d.ts.map +1 -0
- package/build/services/SentenceTtsPipeline.js +67 -0
- package/build/services/SentenceTtsPipeline.js.map +1 -0
- package/build/services/SupportProfileSync.d.ts +22 -0
- package/build/services/SupportProfileSync.d.ts.map +1 -0
- package/build/services/SupportProfileSync.js +213 -0
- package/build/services/SupportProfileSync.js.map +1 -0
- package/build/services/TranscriptionRouting.d.ts +12 -0
- package/build/services/TranscriptionRouting.d.ts.map +1 -0
- package/build/services/TranscriptionRouting.js +24 -0
- package/build/services/TranscriptionRouting.js.map +1 -0
- package/build/services/TtsTextSanitizer.d.ts +5 -0
- package/build/services/TtsTextSanitizer.d.ts.map +1 -0
- package/build/services/TtsTextSanitizer.js +61 -0
- package/build/services/TtsTextSanitizer.js.map +1 -0
- package/build/services/WifiAdbRequest.d.ts +17 -0
- package/build/services/WifiAdbRequest.d.ts.map +1 -0
- package/build/services/WifiAdbRequest.js +35 -0
- package/build/services/WifiAdbRequest.js.map +1 -0
- package/build/services/asg/asgCameraApi.d.ts +43 -0
- package/build/services/asg/asgCameraApi.d.ts.map +1 -1
- package/build/services/asg/asgCameraApi.js +509 -26
- package/build/services/asg/asgCameraApi.js.map +1 -1
- package/build/services/asg/cameraRollExportCoordinator.d.ts +60 -0
- package/build/services/asg/cameraRollExportCoordinator.d.ts.map +1 -0
- package/build/services/asg/cameraRollExportCoordinator.js +618 -0
- package/build/services/asg/cameraRollExportCoordinator.js.map +1 -0
- package/build/services/asg/cameraRollExportLedger.d.ts +44 -0
- package/build/services/asg/cameraRollExportLedger.d.ts.map +1 -0
- package/build/services/asg/cameraRollExportLedger.js +78 -0
- package/build/services/asg/cameraRollExportLedger.js.map +1 -0
- package/build/services/asg/galleryNotices.d.ts +1 -1
- package/build/services/asg/galleryNotices.d.ts.map +1 -1
- package/build/services/asg/galleryNotices.js.map +1 -1
- package/build/services/asg/galleryPathMigration.d.ts +3 -0
- package/build/services/asg/galleryPathMigration.d.ts.map +1 -0
- package/build/services/asg/galleryPathMigration.js +26 -0
- package/build/services/asg/galleryPathMigration.js.map +1 -0
- package/build/services/asg/gallerySettingsService.d.ts +1 -0
- package/build/services/asg/gallerySettingsService.d.ts.map +1 -1
- package/build/services/asg/gallerySettingsService.js +2 -0
- package/build/services/asg/gallerySettingsService.js.map +1 -1
- package/build/services/asg/gallerySyncService.d.ts.map +1 -1
- package/build/services/asg/gallerySyncService.js +162 -56
- package/build/services/asg/gallerySyncService.js.map +1 -1
- package/build/services/asg/galleryTransferLedger.d.ts +58 -0
- package/build/services/asg/galleryTransferLedger.d.ts.map +1 -0
- package/build/services/asg/galleryTransferLedger.js +225 -0
- package/build/services/asg/galleryTransferLedger.js.map +1 -0
- package/build/services/asg/localNetworkTransport.d.ts +15 -0
- package/build/services/asg/localNetworkTransport.d.ts.map +1 -0
- package/build/services/asg/localNetworkTransport.js +144 -0
- package/build/services/asg/localNetworkTransport.js.map +1 -0
- package/build/services/asg/localStorageService.d.ts +18 -0
- package/build/services/asg/localStorageService.d.ts.map +1 -1
- package/build/services/asg/localStorageService.js +168 -19
- package/build/services/asg/localStorageService.js.map +1 -1
- package/build/services/asg/mediaProcessingQueue.d.ts +10 -0
- package/build/services/asg/mediaProcessingQueue.d.ts.map +1 -1
- package/build/services/asg/mediaProcessingQueue.js +193 -62
- package/build/services/asg/mediaProcessingQueue.js.map +1 -1
- package/build/services/audioPlaybackAssets.d.ts +8 -0
- package/build/services/audioPlaybackAssets.d.ts.map +1 -0
- package/build/services/audioPlaybackAssets.js +7 -0
- package/build/services/audioPlaybackAssets.js.map +1 -0
- package/build/services/gallerySyncClock.js +1 -1
- package/build/services/gallerySyncClock.js.map +1 -1
- package/build/services/glassesClockSync.d.ts.map +1 -1
- package/build/services/glassesClockSync.js +6 -2
- package/build/services/glassesClockSync.js.map +1 -1
- package/build/services/manifestActions.d.ts +7 -0
- package/build/services/manifestActions.d.ts.map +1 -0
- package/build/services/manifestActions.js +25 -0
- package/build/services/manifestActions.js.map +1 -0
- package/build/services/otaDisplayState.d.ts +23 -12
- package/build/services/otaDisplayState.d.ts.map +1 -1
- package/build/services/otaDisplayState.js +36 -14
- package/build/services/otaDisplayState.js.map +1 -1
- package/build/services/otaInstallPolicy.d.ts +16 -4
- package/build/services/otaInstallPolicy.d.ts.map +1 -1
- package/build/services/otaInstallPolicy.js +24 -3
- package/build/services/otaInstallPolicy.js.map +1 -1
- package/build/services/otaLegacyMapping.d.ts +1 -1
- package/build/services/otaLegacyMapping.d.ts.map +1 -1
- package/build/services/otaLegacyMapping.js.map +1 -1
- package/build/services/otaManifestPolicy.d.ts +14 -0
- package/build/services/otaManifestPolicy.d.ts.map +1 -0
- package/build/services/otaManifestPolicy.js +19 -0
- package/build/services/otaManifestPolicy.js.map +1 -0
- package/build/services/otaManifestUrl.d.ts +3 -0
- package/build/services/otaManifestUrl.d.ts.map +1 -0
- package/build/services/otaManifestUrl.js +38 -0
- package/build/services/otaManifestUrl.js.map +1 -0
- package/build/services/slimStreamStatus.d.ts +11 -0
- package/build/services/slimStreamStatus.d.ts.map +1 -1
- package/build/services/slimStreamStatus.js +14 -4
- package/build/services/slimStreamStatus.js.map +1 -1
- package/build/stores/apps.d.ts.map +1 -1
- package/build/stores/apps.js +11 -0
- package/build/stores/apps.js.map +1 -1
- package/build/stores/bluetoothSettingKeys.d.ts.map +1 -1
- package/build/stores/bluetoothSettingKeys.js +2 -0
- package/build/stores/bluetoothSettingKeys.js.map +1 -1
- package/build/stores/gallerySync.d.ts +2 -0
- package/build/stores/gallerySync.d.ts.map +1 -1
- package/build/stores/gallerySync.js +2 -0
- package/build/stores/gallerySync.js.map +1 -1
- package/build/stores/glasses.d.ts.map +1 -1
- package/build/stores/glasses.js +3 -0
- package/build/stores/glasses.js.map +1 -1
- package/build/stores/settings.d.ts +17 -0
- package/build/stores/settings.d.ts.map +1 -1
- package/build/stores/settings.js +157 -17
- package/build/stores/settings.js.map +1 -1
- package/build/types/applet.d.ts +2 -0
- package/build/types/applet.d.ts.map +1 -1
- package/build/types/applet.js.map +1 -1
- package/build/types/asg.d.ts +7 -0
- package/build/types/asg.d.ts.map +1 -1
- package/build/types/asg.js.map +1 -1
- package/build/types/enums.d.ts +2 -25
- package/build/types/enums.d.ts.map +1 -1
- package/build/types/enums.js +2 -27
- package/build/types/enums.js.map +1 -1
- package/build/types/hardware.d.ts +4 -13
- package/build/types/hardware.d.ts.map +1 -1
- package/build/types/hardware.js +15 -3
- package/build/types/hardware.js.map +1 -1
- package/build/types/index.d.ts +2 -6
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js +2 -6
- package/build/types/index.js.map +1 -1
- package/build/utils/configuredDevHost.d.ts +6 -0
- package/build/utils/configuredDevHost.d.ts.map +1 -0
- package/build/utils/configuredDevHost.js +19 -0
- package/build/utils/configuredDevHost.js.map +1 -0
- package/build/utils/devMiniappLaunch.d.ts +19 -8
- package/build/utils/devMiniappLaunch.d.ts.map +1 -1
- package/build/utils/devMiniappLaunch.js +144 -21
- package/build/utils/devMiniappLaunch.js.map +1 -1
- package/build/utils/diagnosticContext.d.ts.map +1 -1
- package/build/utils/diagnosticContext.js +15 -17
- package/build/utils/diagnosticContext.js.map +1 -1
- package/build/utils/hardware/hardware.d.ts.map +1 -1
- package/build/utils/hardware/hardware.js +7 -3
- package/build/utils/hardware/hardware.js.map +1 -1
- package/build/utils/miniappDiagnostics.d.ts +64 -0
- package/build/utils/miniappDiagnostics.d.ts.map +1 -0
- package/build/utils/miniappDiagnostics.js +173 -0
- package/build/utils/miniappDiagnostics.js.map +1 -0
- package/build/utils/permissions/MediaLibraryPermissions.d.ts +11 -0
- package/build/utils/permissions/MediaLibraryPermissions.d.ts.map +1 -1
- package/build/utils/permissions/MediaLibraryPermissions.js +27 -4
- package/build/utils/permissions/MediaLibraryPermissions.js.map +1 -1
- package/build/utils/timers/timers.d.ts.map +1 -1
- package/build/utils/timers/timers.js +55 -18
- package/build/utils/timers/timers.js.map +1 -1
- package/package.json +59 -31
- package/src/assets/silence.wav +0 -0
- package/src/bluetooth-sdk/debug.ts +1 -0
- package/src/bluetooth-sdk/index.ts +2 -0
- package/src/bluetooth-sdk/photo-receiver.ts +2 -0
- package/src/bluetooth-sdk/react.ts +1 -0
- package/src/bluetooth-sdk/types.ts +1 -0
- package/src/engine.ts +9 -4
- package/src/facades/dev.ts +17 -12
- package/src/facades/display.ts +1 -1
- package/src/facades/gallery.ts +1 -1
- package/src/facades/glasses.ts +20 -7
- package/src/facades/glassesSettings.ts +5 -0
- package/src/facades/miniapps.ts +7 -0
- package/src/facades/ota.ts +23 -8
- package/src/facades/pairing.ts +15 -11
- package/src/facades/permissions.ts +14 -0
- package/src/facades/phoneNotifications.ts +4 -13
- package/src/facades/speech.ts +21 -7
- package/src/generated/releaseMetadata.ts +20 -0
- package/src/index.ts +39 -13
- package/src/react/MentraLiveOtaFlow.tsx +856 -0
- package/src/react/index.ts +7 -0
- package/src/react/useEngineSnapshot.ts +16 -0
- package/src/runtime/bootstrap.ts +33 -1
- package/src/runtime/scanQrSeam.ts +20 -0
- package/src/services/AppRegistry.ts +240 -149
- package/src/services/AudioCloudUplink.ts +23 -1
- package/src/services/AudioPlaybackService.ts +287 -38
- package/src/services/BlobStore.ts +22 -9
- package/src/services/CloudAudioSubscriptionSync.ts +13 -1
- package/src/services/CloudClientService.ts +96 -1
- package/src/services/DeviceEventRouter.ts +5 -5
- package/src/services/ForegroundLocationPermission.ts +24 -0
- package/src/services/GlassesSettingsSync.ts +9 -3
- package/src/services/GlassesStatusProjection.ts +16 -8
- package/src/services/HotspotOtaTransport.ts +184 -0
- package/src/services/HotspotShutdown.ts +41 -0
- package/src/services/LocalDisplayManager.ts +112 -21
- package/src/services/LocalMiniappRuntime.ts +967 -346
- package/src/services/LocalMiniappStorage.ts +82 -0
- package/src/services/LocalMiniappUserIdentity.ts +46 -0
- package/src/services/LocalSttFallbackCoordinator.ts +19 -12
- package/src/services/MicStateCoordinator.ts +169 -4
- package/src/services/MiniappLauncher.ts +30 -3
- package/src/services/MiniappLiveness.ts +24 -0
- package/src/services/NativeHttpResponse.ts +6 -0
- package/src/services/OtaArtifactDownloader.ts +312 -0
- package/src/services/OtaAutoChain.ts +106 -0
- package/src/services/OtaErrorMapping.ts +80 -0
- package/src/services/OtaInstallCoordinator.ts +649 -144
- package/src/services/OtaService.ts +11 -5
- package/src/services/OtaUpdateCheckService.ts +181 -21
- package/src/services/PhoneCalendarHelpers.ts +212 -0
- package/src/services/PhoneCalendarService.ts +65 -0
- package/src/services/PhoneCameraFovCoordinator.ts +210 -0
- package/src/services/PhoneNotificationsSync.ts +12 -10
- package/src/services/PhonePhotoCoordinator.ts +116 -18
- package/src/services/PhoneStreamCoordinator.ts +139 -25
- package/src/services/PhoneVideoCoordinator.ts +11 -0
- package/src/services/SceneRenderer.ts +16 -0
- package/src/services/SentenceTtsPipeline.ts +106 -0
- package/src/services/SupportProfileSync.ts +218 -0
- package/src/services/TranscriptionRouting.ts +37 -0
- package/src/services/TtsTextSanitizer.ts +66 -0
- package/src/services/WifiAdbRequest.ts +53 -0
- package/src/services/asg/asgCameraApi.ts +615 -33
- package/src/services/asg/cameraRollExportCoordinator.ts +627 -0
- package/src/services/asg/cameraRollExportLedger.ts +122 -0
- package/src/services/asg/galleryNotices.ts +1 -0
- package/src/services/asg/galleryPathMigration.ts +22 -0
- package/src/services/asg/gallerySettingsService.ts +3 -0
- package/src/services/asg/gallerySyncService.ts +184 -73
- package/src/services/asg/galleryTransferLedger.ts +312 -0
- package/src/services/asg/localNetworkTransport.ts +169 -0
- package/src/services/asg/localStorageService.ts +179 -24
- package/src/services/asg/mediaProcessingQueue.ts +209 -62
- package/src/services/audioPlaybackAssets.ts +8 -0
- package/src/services/gallerySyncClock.ts +1 -1
- package/src/services/glassesClockSync.ts +6 -2
- package/src/services/manifestActions.ts +30 -0
- package/src/services/otaDisplayState.ts +58 -17
- package/src/services/otaInstallPolicy.ts +30 -4
- package/src/services/otaLegacyMapping.ts +1 -1
- package/src/services/otaManifestPolicy.ts +42 -0
- package/src/services/otaManifestUrl.ts +44 -0
- package/src/services/slimStreamStatus.ts +16 -5
- package/src/stores/apps.ts +12 -0
- package/src/stores/bluetoothSettingKeys.ts +2 -0
- package/src/stores/gallerySync.ts +4 -0
- package/src/stores/glasses.ts +3 -0
- package/src/stores/settings.ts +179 -18
- package/src/types/applet.ts +2 -0
- package/src/types/asg.ts +7 -0
- package/src/types/enums.ts +3 -28
- package/src/types/hardware.ts +20 -13
- package/src/types/index.ts +2 -6
- package/src/utils/configuredDevHost.ts +17 -0
- package/src/utils/devMiniappLaunch.ts +151 -23
- package/src/utils/diagnosticContext.ts +17 -17
- package/src/utils/hardware/hardware.ts +7 -9
- package/src/utils/miniappDiagnostics.ts +226 -0
- package/src/utils/permissions/MediaLibraryPermissions.ts +35 -4
- package/src/utils/timers/timers.ts +57 -21
- package/build/devtools.d.ts +0 -11
- package/build/devtools.d.ts.map +0 -1
- package/build/devtools.js +0 -13
- package/build/devtools.js.map +0 -1
- package/build/internal.d.ts +0 -66
- package/build/internal.d.ts.map +0 -1
- package/build/internal.js +0 -89
- package/build/internal.js.map +0 -1
- package/build/services/asgOtaVersionUrl.d.ts +0 -2
- package/build/services/asgOtaVersionUrl.d.ts.map +0 -1
- package/build/services/asgOtaVersionUrl.js +0 -36
- package/build/services/asgOtaVersionUrl.js.map +0 -1
- package/src/devtools.ts +0 -13
- package/src/internal.ts +0 -158
- package/src/services/asgOtaVersionUrl.ts +0 -41
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { createAudioPlayer, setAudioModeAsync } from "expo-audio";
|
|
2
2
|
import BluetoothSdk from "@mentra/bluetooth-sdk/internal";
|
|
3
|
+
import { AppState, Platform } from "react-native";
|
|
3
4
|
import { BgTimer } from "../utils/timers";
|
|
5
|
+
import { setAudioCloudUplinkSuppressed } from "./AudioCloudUplink";
|
|
6
|
+
import { SILENT_AUDIO_SOURCE } from "./audioPlaybackAssets";
|
|
4
7
|
const RESTORE_GLASSES_VOLUME_AFTER_PLAYBACK = false;
|
|
5
8
|
class AudioPlaybackService {
|
|
6
9
|
static instance = null;
|
|
7
10
|
// Reuse a single AudioPlayer to avoid AudioTrack exhaustion
|
|
8
11
|
// Creating new ExoPlayer instances per request leads to -12 ENOMEM errors
|
|
9
12
|
player = null;
|
|
13
|
+
// The source currently loaded into the reusable player. Keep object identity
|
|
14
|
+
// so a delayed tail cleanup from an older request cannot unload a newer one.
|
|
15
|
+
loadedPlayback = null;
|
|
10
16
|
currentPlayback = null;
|
|
17
|
+
// Requests that entered play() but have not yet reached the native player.
|
|
18
|
+
// Keeping these addressable prevents a cancelled request from starting after
|
|
19
|
+
// an async audio-mode or stream-cleanup step finishes.
|
|
20
|
+
pendingPlaybacks = new Map();
|
|
11
21
|
// Live PCM streams (speaker.createStream), keyed by streamId. The runtime
|
|
12
22
|
// enforces one per app; stopOtherAudio interrupts across apps.
|
|
13
23
|
streams = new Map();
|
|
@@ -16,10 +26,25 @@ class AudioPlaybackService {
|
|
|
16
26
|
// Prevents mic toggle flicker when playing back-to-back audio
|
|
17
27
|
// Uses BgTimer to work reliably when app is backgrounded on Android
|
|
18
28
|
audioStopDebounceTimer = null;
|
|
29
|
+
// Mentra Live's A2DP route may go idle between prompts. Keep a short warm
|
|
30
|
+
// window after actual audio so we only pre-roll the first sound after idle.
|
|
31
|
+
audioRouteWarmUntil = 0;
|
|
32
|
+
audioRouteWarmupPromise = null;
|
|
33
|
+
// Playback that opted into suppression stays suppressed briefly while its
|
|
34
|
+
// A2DP tail drains. Track those completed sources so a later unsuppressed
|
|
35
|
+
// sound can resume listening immediately instead of inheriting that gate.
|
|
36
|
+
tailUplinkSuppressions = new Set();
|
|
19
37
|
// Original glasses media volume captured before we bump it for A2DP playback.
|
|
20
38
|
glassesVolumeRestoreLevel = null;
|
|
21
39
|
static AUDIO_STOP_DEBOUNCE_MS = 1500;
|
|
22
|
-
static A2DP_TAIL_DRAIN_MS =
|
|
40
|
+
static A2DP_TAIL_DRAIN_MS = 700;
|
|
41
|
+
static AUDIO_ROUTE_WARM_WINDOW_MS = 1500;
|
|
42
|
+
static AUDIO_ROUTE_PREWARM_MS = 200;
|
|
43
|
+
static AUDIO_ROUTE_PREWARM_SAMPLE_RATE = 16_000;
|
|
44
|
+
/** Break accidental same-app replay storms without affecting deliberate later replays. */
|
|
45
|
+
static DUPLICATE_PLAY_WINDOW_MS = 750;
|
|
46
|
+
static AUDIO_ROUTE_PREWARM_PCM_BASE64 = "AAAA".repeat(Math.floor((AudioPlaybackService.AUDIO_ROUTE_PREWARM_MS * AudioPlaybackService.AUDIO_ROUTE_PREWARM_SAMPLE_RATE * 2) /
|
|
47
|
+
(1000 * 3))) + "AA==";
|
|
23
48
|
/** If glasses report step volume at or below this, bump to FLOOR before A2DP playback. */
|
|
24
49
|
static GLASSES_VOLUME_LOW_THRESHOLD = 2;
|
|
25
50
|
static GLASSES_VOLUME_FLOOR = 9;
|
|
@@ -77,6 +102,67 @@ class AudioPlaybackService {
|
|
|
77
102
|
}
|
|
78
103
|
return this.player;
|
|
79
104
|
}
|
|
105
|
+
markAudioRouteWarm() {
|
|
106
|
+
this.audioRouteWarmUntil = Date.now() + AudioPlaybackService.AUDIO_ROUTE_WARM_WINDOW_MS;
|
|
107
|
+
}
|
|
108
|
+
isAudioRouteWarm() {
|
|
109
|
+
return this.currentPlayback !== null || this.streams.size > 0 || Date.now() < this.audioRouteWarmUntil;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Wake a cold Android A2DP route with silent PCM before a user-facing sound.
|
|
113
|
+
*
|
|
114
|
+
* Do not call pcmStreamClose here: some Bluetooth routes do not advance an
|
|
115
|
+
* idle AudioTrack playback head, so close waits for its drain timeout. After
|
|
116
|
+
* exactly 200ms of silence we abort the stream instead, which releases the
|
|
117
|
+
* pre-roll immediately and lets the real URL playback begin.
|
|
118
|
+
*/
|
|
119
|
+
async prewarmAudioRouteIfCold() {
|
|
120
|
+
if (Platform.OS !== "android" || this.isAudioRouteWarm())
|
|
121
|
+
return;
|
|
122
|
+
// This silent PCM pre-roll is only an anti-clipping optimization. Some
|
|
123
|
+
// Android devices defer opening its AudioTrack until the host Activity
|
|
124
|
+
// resumes even though the real URL player supports background playback.
|
|
125
|
+
// Never let that optional pre-roll block a glasses-initiated prompt.
|
|
126
|
+
if (AppState.currentState !== "active") {
|
|
127
|
+
console.log(`AUDIO: Skipping cold-route prewarm while app is ${AppState.currentState}`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (this.audioRouteWarmupPromise)
|
|
131
|
+
return this.audioRouteWarmupPromise;
|
|
132
|
+
const streamId = `audio-route-prewarm-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
133
|
+
const warmup = (async () => {
|
|
134
|
+
let opened = false;
|
|
135
|
+
const startedAt = Date.now();
|
|
136
|
+
try {
|
|
137
|
+
console.log(`AUDIO: Cold route; prewarming with ${AudioPlaybackService.AUDIO_ROUTE_PREWARM_MS}ms silence`);
|
|
138
|
+
await BluetoothSdk.pcmStreamOpen(streamId, AudioPlaybackService.AUDIO_ROUTE_PREWARM_SAMPLE_RATE, 1, 1);
|
|
139
|
+
opened = true;
|
|
140
|
+
await BluetoothSdk.pcmStreamWrite(streamId, AudioPlaybackService.AUDIO_ROUTE_PREWARM_PCM_BASE64);
|
|
141
|
+
await new Promise((resolve) => {
|
|
142
|
+
BgTimer.setTimeout(resolve, AudioPlaybackService.AUDIO_ROUTE_PREWARM_MS);
|
|
143
|
+
});
|
|
144
|
+
await BluetoothSdk.pcmStreamAbort(streamId);
|
|
145
|
+
opened = false;
|
|
146
|
+
this.markAudioRouteWarm();
|
|
147
|
+
console.log(`AUDIO: Cold-route prewarm completed in ${Date.now() - startedAt}ms`);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
console.warn("AUDIO: Cold-route prewarm failed; continuing with requested audio:", error);
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
if (opened)
|
|
154
|
+
await BluetoothSdk.pcmStreamAbort(streamId).catch(() => { });
|
|
155
|
+
}
|
|
156
|
+
})();
|
|
157
|
+
this.audioRouteWarmupPromise = warmup;
|
|
158
|
+
try {
|
|
159
|
+
await warmup;
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
if (this.audioRouteWarmupPromise === warmup)
|
|
163
|
+
this.audioRouteWarmupPromise = null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
80
166
|
async getGlassesMediaVolumeWithTiming() {
|
|
81
167
|
const startedAt = Date.now();
|
|
82
168
|
try {
|
|
@@ -170,40 +256,111 @@ class AudioPlaybackService {
|
|
|
170
256
|
this.glassesVolumeRestoreLevel = null;
|
|
171
257
|
}
|
|
172
258
|
}
|
|
173
|
-
|
|
259
|
+
unloadPlaybackSource(playback, reason) {
|
|
260
|
+
if (this.loadedPlayback !== playback)
|
|
261
|
+
return;
|
|
262
|
+
const player = this.player;
|
|
263
|
+
if (!player) {
|
|
264
|
+
this.loadedPlayback = null;
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
try {
|
|
268
|
+
player.pause();
|
|
269
|
+
}
|
|
270
|
+
catch (e) {
|
|
271
|
+
console.warn(`AUDIO: Error pausing ${playback.requestId} during ${reason}:`, e);
|
|
272
|
+
}
|
|
273
|
+
try {
|
|
274
|
+
// replace(null) fails native argument casting on iOS, while remove()
|
|
275
|
+
// destroys the ExoPlayer that Android must reuse to avoid AudioTrack
|
|
276
|
+
// exhaustion. Replacing with bundled silence detaches the previous media
|
|
277
|
+
// item on both platforms and leaves the native player alive.
|
|
278
|
+
player.replace(SILENT_AUDIO_SOURCE);
|
|
279
|
+
console.log(`AUDIO: Cleared source for ${playback.requestId} during ${reason}`);
|
|
280
|
+
}
|
|
281
|
+
catch (e) {
|
|
282
|
+
console.warn(`AUDIO: Error clearing ${playback.requestId} during ${reason}:`, e);
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
285
|
+
if (this.loadedPlayback === playback)
|
|
286
|
+
this.loadedPlayback = null;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
clearFinishedPlayerAfterTail(playback) {
|
|
290
|
+
if (playback.suppressCloudUplink) {
|
|
291
|
+
this.tailUplinkSuppressions.add(playback.uplinkSuppressionId);
|
|
292
|
+
}
|
|
174
293
|
BgTimer.setTimeout(() => {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
this.player.pause();
|
|
181
|
-
console.log(`AUDIO: Paused finished player for ${playback.requestId} after ${AudioPlaybackService.A2DP_TAIL_DRAIN_MS}ms tail drain`);
|
|
182
|
-
}
|
|
183
|
-
catch (e) {
|
|
184
|
-
console.warn("AUDIO: Error pausing player after tail drain:", e);
|
|
294
|
+
// ExoPlayer's completion event precedes the final A2DP audio reaching the
|
|
295
|
+
// glasses. Keep cloud STT gated until that audible tail has drained, then
|
|
296
|
+
// accept fresh microphone audio immediately without restarting LC3.
|
|
297
|
+
if (playback.suppressCloudUplink && this.tailUplinkSuppressions.delete(playback.uplinkSuppressionId)) {
|
|
298
|
+
setAudioCloudUplinkSuppressed(playback.uplinkSuppressionId, false);
|
|
185
299
|
}
|
|
300
|
+
this.unloadPlaybackSource(playback, `${AudioPlaybackService.A2DP_TAIL_DRAIN_MS}ms A2DP tail drain`);
|
|
186
301
|
}, AudioPlaybackService.A2DP_TAIL_DRAIN_MS);
|
|
187
302
|
}
|
|
303
|
+
releaseTailUplinkSuppressions() {
|
|
304
|
+
for (const sourceId of this.tailUplinkSuppressions) {
|
|
305
|
+
setAudioCloudUplinkSuppressed(sourceId, false);
|
|
306
|
+
}
|
|
307
|
+
this.tailUplinkSuppressions.clear();
|
|
308
|
+
}
|
|
188
309
|
/**
|
|
189
310
|
* Play audio from a URL.
|
|
190
311
|
* Returns a promise that resolves with playback result when audio finishes or errors.
|
|
191
312
|
*/
|
|
192
313
|
async play(request, onComplete) {
|
|
193
|
-
const { requestId, audioUrl, appId, volume = 1.0, stopOtherAudio = true } = request;
|
|
314
|
+
const { requestId, audioUrl, appId, volume = 1.0, stopOtherAudio = true, suppressCloudUplink = false } = request;
|
|
315
|
+
const now = Date.now();
|
|
316
|
+
const activeDuplicate = this.currentPlayback &&
|
|
317
|
+
!this.currentPlayback.completed &&
|
|
318
|
+
this.currentPlayback.appId === appId &&
|
|
319
|
+
this.currentPlayback.audioUrl === audioUrl &&
|
|
320
|
+
now - this.currentPlayback.startTime < AudioPlaybackService.DUPLICATE_PLAY_WINDOW_MS;
|
|
321
|
+
const pendingDuplicate = [...this.pendingPlaybacks.values()].some((candidate) => !candidate.cancelled &&
|
|
322
|
+
candidate.appId === appId &&
|
|
323
|
+
candidate.audioUrl === audioUrl &&
|
|
324
|
+
now - candidate.createdAt < AudioPlaybackService.DUPLICATE_PLAY_WINDOW_MS);
|
|
325
|
+
if (activeDuplicate || pendingDuplicate) {
|
|
326
|
+
console.warn(`AUDIO: Suppressed duplicate play request ${requestId}${appId ? ` from ${appId}` : ""}`);
|
|
327
|
+
onComplete(requestId, false, "Duplicate audio request suppressed", 0, "error");
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const pending = { cancelled: false, audioUrl, appId, createdAt: now };
|
|
331
|
+
this.pendingPlaybacks.set(requestId, pending);
|
|
194
332
|
console.log(`AUDIO: Play request ${requestId}${appId ? ` from ${appId}` : ""}: ${audioUrl}`);
|
|
195
333
|
try {
|
|
196
334
|
// Ensure audio mode is configured for background playback
|
|
197
335
|
await this.ensureAudioModeConfigured();
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
336
|
+
if (pending.cancelled) {
|
|
337
|
+
onComplete(requestId, true, null, 0, "interrupted");
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
await this.prewarmAudioRouteIfCold();
|
|
341
|
+
if (pending.cancelled) {
|
|
342
|
+
onComplete(requestId, true, null, 0, "interrupted");
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
// URL playback reuses one native player, so replacing its source always
|
|
346
|
+
// interrupts the previous URL even when stopOtherAudio is false. Notify
|
|
347
|
+
// that request before replacing it so its promise cannot hang. The option
|
|
348
|
+
// still controls whether separate PCM streams are interrupted below.
|
|
349
|
+
if (this.currentPlayback && !this.currentPlayback.completed) {
|
|
350
|
+
console.log(`AUDIO: Interrupting current URL playback for new request`);
|
|
201
351
|
this.interruptCurrentPlayback(true);
|
|
202
352
|
}
|
|
203
353
|
// Live PCM streams count as "other audio" too.
|
|
204
354
|
if (stopOtherAudio) {
|
|
205
355
|
await this.abortAllStreams();
|
|
206
356
|
}
|
|
357
|
+
if (pending.cancelled) {
|
|
358
|
+
onComplete(requestId, true, null, 0, "interrupted");
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (!suppressCloudUplink) {
|
|
362
|
+
this.releaseTailUplinkSuppressions();
|
|
363
|
+
}
|
|
207
364
|
// Get or create the reusable player
|
|
208
365
|
const player = this.ensurePlayer();
|
|
209
366
|
// Set volume
|
|
@@ -211,15 +368,24 @@ class AudioPlaybackService {
|
|
|
211
368
|
// Store the new playback state
|
|
212
369
|
const playback = {
|
|
213
370
|
requestId,
|
|
371
|
+
audioUrl,
|
|
372
|
+
uplinkSuppressionId: `url:${requestId}`,
|
|
214
373
|
appId,
|
|
215
374
|
startTime: Date.now(),
|
|
216
375
|
completed: false,
|
|
376
|
+
suppressCloudUplink,
|
|
217
377
|
onComplete,
|
|
218
378
|
};
|
|
219
379
|
this.currentPlayback = playback;
|
|
380
|
+
this.pendingPlaybacks.delete(requestId);
|
|
381
|
+
this.markAudioRouteWarm();
|
|
382
|
+
if (playback.suppressCloudUplink) {
|
|
383
|
+
setAudioCloudUplinkSuppressed(playback.uplinkSuppressionId, true);
|
|
384
|
+
}
|
|
220
385
|
// Replace the source and play
|
|
221
386
|
// Using replace() reuses the existing ExoPlayer/AudioTrack instead of creating new ones
|
|
222
387
|
player.replace({ uri: audioUrl });
|
|
388
|
+
this.loadedPlayback = playback;
|
|
223
389
|
player.play();
|
|
224
390
|
// Mentra Live volume reads can block up to 5s when the glasses don't
|
|
225
391
|
// answer. Do not put that in front of playback; guard it against late
|
|
@@ -239,10 +405,41 @@ class AudioPlaybackService {
|
|
|
239
405
|
console.log(`AUDIO: Started playback for ${requestId}`);
|
|
240
406
|
}
|
|
241
407
|
catch (error) {
|
|
408
|
+
if (suppressCloudUplink) {
|
|
409
|
+
setAudioCloudUplinkSuppressed(`url:${requestId}`, false);
|
|
410
|
+
}
|
|
411
|
+
const failedPlayback = this.currentPlayback?.requestId === requestId ? this.currentPlayback : null;
|
|
412
|
+
if (failedPlayback) {
|
|
413
|
+
failedPlayback.completed = true;
|
|
414
|
+
this.currentPlayback = null;
|
|
415
|
+
this.unloadPlaybackSource(failedPlayback, "playback start failure");
|
|
416
|
+
}
|
|
417
|
+
if (pending.cancelled) {
|
|
418
|
+
onComplete(requestId, true, null, 0, "interrupted");
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
242
421
|
const errorMessage = error instanceof Error ? error.message : "Unknown error loading audio";
|
|
243
422
|
console.error(`AUDIO: Failed to play ${requestId}:`, errorMessage);
|
|
244
423
|
void this.restoreGlassesMediaVolume();
|
|
245
|
-
onComplete(requestId, false, errorMessage, null);
|
|
424
|
+
onComplete(requestId, false, errorMessage, null, "error");
|
|
425
|
+
}
|
|
426
|
+
finally {
|
|
427
|
+
if (this.pendingPlaybacks.get(requestId) === pending) {
|
|
428
|
+
this.pendingPlaybacks.delete(requestId);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Cancel one URL playback without touching audio owned by another request.
|
|
434
|
+
* Pending requests are prevented from reaching the native player; active
|
|
435
|
+
* requests are paused synchronously before their completion callback fires.
|
|
436
|
+
*/
|
|
437
|
+
cancelPlayback(requestId) {
|
|
438
|
+
const pending = this.pendingPlaybacks.get(requestId);
|
|
439
|
+
if (pending)
|
|
440
|
+
pending.cancelled = true;
|
|
441
|
+
if (this.currentPlayback?.requestId === requestId && !this.currentPlayback.completed) {
|
|
442
|
+
this.interruptCurrentPlayback();
|
|
246
443
|
}
|
|
247
444
|
}
|
|
248
445
|
/**
|
|
@@ -254,15 +451,13 @@ class AudioPlaybackService {
|
|
|
254
451
|
const playback = this.currentPlayback;
|
|
255
452
|
playback.completed = true;
|
|
256
453
|
this.currentPlayback = null;
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
try {
|
|
260
|
-
this.player.pause();
|
|
261
|
-
}
|
|
262
|
-
catch (error) {
|
|
263
|
-
console.error("AUDIO: Error pausing player:", error);
|
|
264
|
-
}
|
|
454
|
+
if (playback.suppressCloudUplink) {
|
|
455
|
+
setAudioCloudUplinkSuppressed(playback.uplinkSuppressionId, false);
|
|
265
456
|
}
|
|
457
|
+
this.markAudioRouteWarm();
|
|
458
|
+
// Pausing alone leaves the URI available to OS/Bluetooth media Play.
|
|
459
|
+
// Unload it unless a newer request has already replaced this source.
|
|
460
|
+
this.unloadPlaybackSource(playback, "interruption");
|
|
266
461
|
// Notify native that our app stopped playing audio (debounced)
|
|
267
462
|
this.notifyAudioStopDebounced();
|
|
268
463
|
if (!preserveGlassesMediaVolume) {
|
|
@@ -270,7 +465,7 @@ class AudioPlaybackService {
|
|
|
270
465
|
}
|
|
271
466
|
// Notify that playback was interrupted
|
|
272
467
|
const elapsedMs = Date.now() - playback.startTime;
|
|
273
|
-
playback.onComplete(playback.requestId, true, null, elapsedMs);
|
|
468
|
+
playback.onComplete(playback.requestId, true, null, elapsedMs, "interrupted");
|
|
274
469
|
console.log(`AUDIO: Interrupted ${playback.requestId} after ${elapsedMs}ms`);
|
|
275
470
|
}
|
|
276
471
|
/**
|
|
@@ -289,10 +484,11 @@ class AudioPlaybackService {
|
|
|
289
484
|
playback.completed = true;
|
|
290
485
|
// ExoPlayer can report finished before an A2DP sink has audibly drained
|
|
291
486
|
// the last buffered audio. Pausing immediately can clip the tail on
|
|
292
|
-
// Mentra Live; defer cleanup
|
|
293
|
-
this.
|
|
294
|
-
playback.onComplete(playback.requestId, true, null, durationMs);
|
|
487
|
+
// Mentra Live; defer cleanup and guard it against a newer loaded source.
|
|
488
|
+
this.clearFinishedPlayerAfterTail(playback);
|
|
295
489
|
this.currentPlayback = null;
|
|
490
|
+
playback.onComplete(playback.requestId, true, null, durationMs, "completed");
|
|
491
|
+
this.markAudioRouteWarm();
|
|
296
492
|
// Notify native that our app stopped playing audio (debounced)
|
|
297
493
|
this.notifyAudioStopDebounced();
|
|
298
494
|
void this.restoreGlassesMediaVolume();
|
|
@@ -307,8 +503,13 @@ class AudioPlaybackService {
|
|
|
307
503
|
if (elapsedMs > 1500) {
|
|
308
504
|
console.error(`AUDIO: Playback failed for ${playback.requestId} (player went idle after ${elapsedMs}ms)`);
|
|
309
505
|
playback.completed = true;
|
|
310
|
-
playback.onComplete(playback.requestId, false, "Playback failed (player went idle)", null);
|
|
311
506
|
this.currentPlayback = null;
|
|
507
|
+
if (playback.suppressCloudUplink) {
|
|
508
|
+
setAudioCloudUplinkSuppressed(playback.uplinkSuppressionId, false);
|
|
509
|
+
}
|
|
510
|
+
this.unloadPlaybackSource(playback, "playback failure");
|
|
511
|
+
playback.onComplete(playback.requestId, false, "Playback failed (player went idle)", null, "error");
|
|
512
|
+
this.markAudioRouteWarm();
|
|
312
513
|
this.notifyAudioStopDebounced();
|
|
313
514
|
void this.restoreGlassesMediaVolume();
|
|
314
515
|
}
|
|
@@ -327,6 +528,11 @@ class AudioPlaybackService {
|
|
|
327
528
|
// Uses BgTimer to work reliably when app is backgrounded on Android
|
|
328
529
|
this.audioStopDebounceTimer = BgTimer.setTimeout(() => {
|
|
329
530
|
this.audioStopDebounceTimer = null;
|
|
531
|
+
// URL playback and live PCM streams may overlap when stopOtherAudio is false.
|
|
532
|
+
// A URL that ends must not clear the native playback signal while another
|
|
533
|
+
// source is still active, or the mic watchdog can interrupt that source.
|
|
534
|
+
if (this.isPlaying())
|
|
535
|
+
return;
|
|
330
536
|
BluetoothSdk.setOwnAppAudioPlaying(false).catch((e) => {
|
|
331
537
|
console.warn("AUDIO: Failed to notify native of audio stop:", e);
|
|
332
538
|
});
|
|
@@ -342,6 +548,7 @@ class AudioPlaybackService {
|
|
|
342
548
|
const { streamId, appId, sampleRate, channels, volume = 1.0, stopOtherAudio = true } = request;
|
|
343
549
|
console.log(`AUDIO: Stream open ${streamId} from ${appId}: rate=${sampleRate} ch=${channels}`);
|
|
344
550
|
await this.ensureAudioModeConfigured();
|
|
551
|
+
await this.prewarmAudioRouteIfCold();
|
|
345
552
|
if (stopOtherAudio) {
|
|
346
553
|
if (this.currentPlayback && !this.currentPlayback.completed) {
|
|
347
554
|
console.log("AUDIO: Interrupting current playback for new stream");
|
|
@@ -350,10 +557,18 @@ class AudioPlaybackService {
|
|
|
350
557
|
await this.abortAllStreams(streamId);
|
|
351
558
|
}
|
|
352
559
|
await BluetoothSdk.pcmStreamOpen(streamId, sampleRate, channels, Math.max(0, Math.min(1, volume)));
|
|
353
|
-
|
|
560
|
+
this.releaseTailUplinkSuppressions();
|
|
561
|
+
const stream = {
|
|
562
|
+
streamId,
|
|
563
|
+
appId,
|
|
564
|
+
startTime: Date.now(),
|
|
565
|
+
ended: false,
|
|
566
|
+
onEnded: request.onEnded,
|
|
567
|
+
};
|
|
354
568
|
this.streams.set(streamId, stream);
|
|
355
|
-
|
|
356
|
-
// notification and mark our app as playing
|
|
569
|
+
this.markAudioRouteWarm();
|
|
570
|
+
// Cancel any pending "stopped" notification and mark our app as playing
|
|
571
|
+
// audio. PCM streams intentionally do not suppress cloud STT.
|
|
357
572
|
if (this.audioStopDebounceTimer !== null) {
|
|
358
573
|
BgTimer.clearTimeout(this.audioStopDebounceTimer);
|
|
359
574
|
this.audioStopDebounceTimer = null;
|
|
@@ -423,6 +638,7 @@ class AudioPlaybackService {
|
|
|
423
638
|
return;
|
|
424
639
|
stream.ended = true;
|
|
425
640
|
this.streams.delete(stream.streamId);
|
|
641
|
+
this.markAudioRouteWarm();
|
|
426
642
|
// Only signal "audio stopped" when nothing else is making noise.
|
|
427
643
|
if (this.streams.size === 0 && (!this.currentPlayback || this.currentPlayback.completed)) {
|
|
428
644
|
this.notifyAudioStopDebounced();
|
|
@@ -525,6 +741,7 @@ class AudioPlaybackService {
|
|
|
525
741
|
console.error("AUDIO: Error releasing player:", error);
|
|
526
742
|
}
|
|
527
743
|
this.player = null;
|
|
744
|
+
this.loadedPlayback = null;
|
|
528
745
|
}
|
|
529
746
|
}
|
|
530
747
|
}
|